diff --git a/src/LibHac.Nand/Nand.cs b/src/LibHac.Nand/Nand.cs
index f83483ea..ae02b956 100644
--- a/src/LibHac.Nand/Nand.cs
+++ b/src/LibHac.Nand/Nand.cs
@@ -33,16 +33,14 @@ namespace LibHac.Nand
{
IStorage encStorage = ProdInfo.Open().AsStorage();
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[0], 0x4000, true), 0x4000, 4, true);
- decStorage.SetReadOnly();
- return decStorage.AsStream();
+ return decStorage.AsStream(FileAccess.Read);
}
public FatFileSystemProvider OpenProdInfoF()
{
IStorage encStorage = ProdInfoF.Open().AsStorage();
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[0], 0x4000, true), 0x4000, 4, true);
- decStorage.SetReadOnly();
- var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None);
+ var fat = new FatFileSystem(decStorage.AsStream(FileAccess.Read), Ownership.None);
return new FatFileSystemProvider(fat);
}
@@ -50,8 +48,7 @@ namespace LibHac.Nand
{
IStorage encStorage = Safe.Open().AsStorage();
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[1], 0x4000, true), 0x4000, 4, true);
- decStorage.SetReadOnly();
- var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None);
+ var fat = new FatFileSystem(decStorage.AsStream(FileAccess.Read), Ownership.None);
return new FatFileSystemProvider(fat);
}
@@ -59,8 +56,7 @@ namespace LibHac.Nand
{
IStorage encStorage = System.Open().AsStorage();
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[2], 0x4000, true), 0x4000, 4, true);
- decStorage.SetReadOnly();
- var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None);
+ var fat = new FatFileSystem(decStorage.AsStream(FileAccess.Read), Ownership.None);
return new FatFileSystemProvider(fat);
}
@@ -68,8 +64,7 @@ namespace LibHac.Nand
{
IStorage encStorage = User.Open().AsStorage();
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[3], 0x4000, true), 0x4000, 4, true);
- decStorage.SetReadOnly();
- var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None);
+ var fat = new FatFileSystem(decStorage.AsStream(FileAccess.Read), Ownership.None);
return new FatFileSystemProvider(fat);
}
}
diff --git a/src/LibHac/IO/Aes128CtrExStorage.cs b/src/LibHac/IO/Aes128CtrExStorage.cs
index 70931a72..6cefd4e8 100644
--- a/src/LibHac/IO/Aes128CtrExStorage.cs
+++ b/src/LibHac/IO/Aes128CtrExStorage.cs
@@ -60,8 +60,6 @@ namespace LibHac.IO
throw new NotImplementedException();
}
- public override bool CanWrite => false;
-
private AesSubsectionEntry GetSubsectionEntry(long offset)
{
int index = SubsectionOffsets.BinarySearch(offset);
diff --git a/src/LibHac/IO/AesXtsFile.cs b/src/LibHac/IO/AesXtsFile.cs
index 6fb98bc4..f2aec314 100644
--- a/src/LibHac/IO/AesXtsFile.cs
+++ b/src/LibHac/IO/AesXtsFile.cs
@@ -31,7 +31,7 @@ namespace LibHac.IO
throw new ArgumentException("NAX0 key derivation failed.");
}
- Storage encStorage = new FileStorage(BaseFile).Slice(HeaderLength, Header.Size);
+ IStorage encStorage = new FileStorage(BaseFile).Slice(HeaderLength, Header.Size);
BaseStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Header.DecryptedKey1, Header.DecryptedKey2, BlockSize, true), 4, true);
}
diff --git a/src/LibHac/IO/CachedStorage.cs b/src/LibHac/IO/CachedStorage.cs
index 1ca66a73..6e849e8e 100644
--- a/src/LibHac/IO/CachedStorage.cs
+++ b/src/LibHac/IO/CachedStorage.cs
@@ -4,7 +4,7 @@ using System.Collections.Generic;
namespace LibHac.IO
{
- public class CachedStorage : Storage
+ public class CachedStorage : StorageBase
{
private IStorage BaseStorage { get; }
private int BlockSize { get; }
@@ -148,7 +148,7 @@ namespace LibHac.IO
if (!block.Dirty) return;
long offset = block.Index * BlockSize;
- BaseStorage.Write(block.Buffer, offset, block.Length, 0);
+ BaseStorage.Write(block.Buffer.AsSpan(0, block.Length), offset);
block.Dirty = false;
}
diff --git a/src/LibHac/IO/ConcatenationStorage.cs b/src/LibHac/IO/ConcatenationStorage.cs
index 48d7b4ae..cc6e53ce 100644
--- a/src/LibHac/IO/ConcatenationStorage.cs
+++ b/src/LibHac/IO/ConcatenationStorage.cs
@@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace LibHac.IO
{
- public class ConcatenationStorage : Storage
+ public class ConcatenationStorage : StorageBase
{
private ConcatSource[] Sources { get; }
public override long Length { get; }
@@ -72,22 +72,6 @@ namespace LibHac.IO
}
}
- public override Storage Slice(long start, long length, bool leaveOpen)
- {
- ConcatSource startSource = FindSource(start);
- ConcatSource endSource = FindSource(start + length - 1);
-
- if (startSource != endSource)
- {
- return base.Slice(start, length, leaveOpen);
- }
-
- Storage storage = startSource.Storage.Slice(start - startSource.StartOffset, length, true);
- if (!leaveOpen) storage.ToDispose.Add(this);
-
- return storage;
- }
-
private ConcatSource FindSource(long offset)
{
foreach (ConcatSource info in Sources)
diff --git a/src/LibHac/IO/DeltaFragment.cs b/src/LibHac/IO/DeltaFragment.cs
index 4d279383..2c202eac 100644
--- a/src/LibHac/IO/DeltaFragment.cs
+++ b/src/LibHac/IO/DeltaFragment.cs
@@ -57,7 +57,7 @@ namespace LibHac.IO
IStorage source = segment.IsInOriginal ? Original : Delta;
// todo Do this without tons of SubStorages
- Storage sub = source.Slice(segment.SourceOffset, segment.Size);
+ IStorage sub = source.Slice(segment.SourceOffset, segment.Size);
storages.Add(sub);
}
diff --git a/src/LibHac/IO/FileStorage.cs b/src/LibHac/IO/FileStorage.cs
index 7de4bdb8..60cfbb93 100644
--- a/src/LibHac/IO/FileStorage.cs
+++ b/src/LibHac/IO/FileStorage.cs
@@ -2,7 +2,7 @@
namespace LibHac.IO
{
- public class FileStorage : Storage
+ public class FileStorage : StorageBase
{
private IFile BaseFile { get; }
diff --git a/src/LibHac/IO/HierarchicalIntegrityVerificationStorage.cs b/src/LibHac/IO/HierarchicalIntegrityVerificationStorage.cs
index 913810c5..c91c2932 100644
--- a/src/LibHac/IO/HierarchicalIntegrityVerificationStorage.cs
+++ b/src/LibHac/IO/HierarchicalIntegrityVerificationStorage.cs
@@ -6,7 +6,7 @@ using System.Text;
namespace LibHac.IO
{
- public class HierarchicalIntegrityVerificationStorage : Storage
+ public class HierarchicalIntegrityVerificationStorage : StorageBase
{
public IStorage[] Levels { get; }
public IStorage DataLevel { get; }
@@ -128,7 +128,7 @@ namespace LibHac.IO
if (validities[i] == Validity.Unchecked)
{
int toRead = (int)Math.Min(storage.Length - blockSize * i, buffer.Length);
- storage.Read(buffer, blockSize * i, toRead, 0, IntegrityCheckLevel.IgnoreOnInvalid);
+ storage.Read(buffer.AsSpan(0, toRead), blockSize * i, IntegrityCheckLevel.IgnoreOnInvalid);
}
if (validities[i] == Validity.Invalid)
@@ -209,6 +209,9 @@ namespace LibHac.IO
}
SaltSource = reader.ReadBytes(0x20);
+
+ if (reader.BaseStream.Position + 0x20 >= reader.BaseStream.Length) return;
+
MasterHash = reader.ReadBytes(0x20);
}
diff --git a/src/LibHac/IO/IStorage.cs b/src/LibHac/IO/IStorage.cs
index cda45dfb..be5c6d2f 100644
--- a/src/LibHac/IO/IStorage.cs
+++ b/src/LibHac/IO/IStorage.cs
@@ -12,16 +12,6 @@ namespace LibHac.IO
/// The offset in the to begin reading from.
void Read(Span destination, long offset);
- ///
- /// Reads a sequence of bytes from the current .
- ///
- /// The buffer where the read bytes will be stored.
- /// The zero-based byte offset in
- /// at which to begin storing the data read from the current .
- /// The number of bytes to be read from the .
- /// The offset in the to begin reading from.
- void Read(byte[] buffer, long offset, int count, int bufferOffset);
-
///
/// Writes a sequence of bytes to the current .
///
@@ -29,16 +19,6 @@ namespace LibHac.IO
/// The offset in the to begin writing to.
void Write(ReadOnlySpan source, long offset);
- ///
- /// Writes a sequence of bytes to the current .
- ///
- ///
- /// The zero-based byte offset in
- /// at which to begin begin copying bytes to the current .
- /// The number of bytes to be written to the .
- /// The offset in the to begin writing to.
- void Write(byte[] buffer, long offset, int count, int bufferOffset);
-
///
/// Causes any buffered data to be written to the underlying device.
///
diff --git a/src/LibHac/IO/IndirectStorage.cs b/src/LibHac/IO/IndirectStorage.cs
index 7fbfcc19..3a470840 100644
--- a/src/LibHac/IO/IndirectStorage.cs
+++ b/src/LibHac/IO/IndirectStorage.cs
@@ -4,7 +4,7 @@ using System.Linq;
namespace LibHac.IO
{
- public class IndirectStorage : Storage
+ public class IndirectStorage : StorageBase
{
private List RelocationEntries { get; }
private List RelocationOffsets { get; }
@@ -62,8 +62,6 @@ namespace LibHac.IO
throw new NotImplementedException();
}
- public override bool CanWrite => false;
-
public override long Length { get; }
private RelocationEntry GetRelocationEntry(long offset)
diff --git a/src/LibHac/IO/IntegrityVerificationStorage.cs b/src/LibHac/IO/IntegrityVerificationStorage.cs
index 050173d7..23aefa45 100644
--- a/src/LibHac/IO/IntegrityVerificationStorage.cs
+++ b/src/LibHac/IO/IntegrityVerificationStorage.cs
@@ -116,16 +116,10 @@ namespace LibHac.IO
public void Read(Span destination, long offset, IntegrityCheckLevel integrityCheckLevel)
{
- ValidateSpanParameters(destination, offset);
+ ValidateParameters(destination, offset);
ReadImpl(destination, offset, integrityCheckLevel);
}
- public void Read(byte[] buffer, long offset, int count, int bufferOffset, IntegrityCheckLevel integrityCheckLevel)
- {
- ValidateArrayParameters(buffer, offset, count, bufferOffset);
- ReadImpl(buffer.AsSpan(bufferOffset, count), offset, integrityCheckLevel);
- }
-
protected override void WriteImpl(ReadOnlySpan source, long offset)
{
long blockIndex = offset / SectorSize;
diff --git a/src/LibHac/IO/MemoryStorage.cs b/src/LibHac/IO/MemoryStorage.cs
index 82d966a1..3a3ca272 100644
--- a/src/LibHac/IO/MemoryStorage.cs
+++ b/src/LibHac/IO/MemoryStorage.cs
@@ -2,7 +2,7 @@
namespace LibHac.IO
{
- public class MemoryStorage : Storage
+ public class MemoryStorage : StorageBase
{
private byte[] Buffer { get; }
private int Start { get; }
diff --git a/src/LibHac/IO/NullStorage.cs b/src/LibHac/IO/NullStorage.cs
index 38cd4e13..37831ce5 100644
--- a/src/LibHac/IO/NullStorage.cs
+++ b/src/LibHac/IO/NullStorage.cs
@@ -5,7 +5,7 @@ namespace LibHac.IO
///
/// An that returns all zeros when read, and does nothing on write.
///
- public class NullStorage : Storage
+ public class NullStorage : StorageBase
{
public NullStorage() { }
public NullStorage(long length) => Length = length;
diff --git a/src/LibHac/IO/Save/AllocationTable.cs b/src/LibHac/IO/Save/AllocationTable.cs
index 6269912a..654f7dc3 100644
--- a/src/LibHac/IO/Save/AllocationTable.cs
+++ b/src/LibHac/IO/Save/AllocationTable.cs
@@ -34,8 +34,8 @@ namespace LibHac.IO.Save
}
}
- public IStorage GetBaseStorage() => BaseStorage.WithAccess(FileAccess.Read);
- public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
+ public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
+ public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
}
public class AllocationTableEntry
diff --git a/src/LibHac/IO/Save/AllocationTableStorage.cs b/src/LibHac/IO/Save/AllocationTableStorage.cs
index afd22f0d..0eea011a 100644
--- a/src/LibHac/IO/Save/AllocationTableStorage.cs
+++ b/src/LibHac/IO/Save/AllocationTableStorage.cs
@@ -2,7 +2,7 @@
namespace LibHac.IO.Save
{
- public class AllocationTableStorage : Storage
+ public class AllocationTableStorage : StorageBase
{
private IStorage BaseStorage { get; }
private int BlockSize { get; }
diff --git a/src/LibHac/IO/Save/DuplexStorage.cs b/src/LibHac/IO/Save/DuplexStorage.cs
index 51c2d439..b8f5a9e3 100644
--- a/src/LibHac/IO/Save/DuplexStorage.cs
+++ b/src/LibHac/IO/Save/DuplexStorage.cs
@@ -2,7 +2,7 @@
namespace LibHac.IO.Save
{
- public class DuplexStorage : Storage
+ public class DuplexStorage : StorageBase
{
private int BlockSize { get; }
private IStorage BitmapStorage { get; }
diff --git a/src/LibHac/IO/Save/HierarchicalDuplexStorage.cs b/src/LibHac/IO/Save/HierarchicalDuplexStorage.cs
index 15f22402..e569471b 100644
--- a/src/LibHac/IO/Save/HierarchicalDuplexStorage.cs
+++ b/src/LibHac/IO/Save/HierarchicalDuplexStorage.cs
@@ -2,7 +2,7 @@
namespace LibHac.IO.Save
{
- public class HierarchicalDuplexStorage : Storage
+ public class HierarchicalDuplexStorage : StorageBase
{
private DuplexStorage[] Layers { get; }
private DuplexStorage DataLayer { get; }
diff --git a/src/LibHac/IO/Save/JournalMap.cs b/src/LibHac/IO/Save/JournalMap.cs
index 44ddfbf5..8acf3500 100644
--- a/src/LibHac/IO/Save/JournalMap.cs
+++ b/src/LibHac/IO/Save/JournalMap.cs
@@ -50,11 +50,11 @@ namespace LibHac.IO.Save
return map;
}
- public IStorage GetMapStorage() => MapStorage.WithAccess(FileAccess.Read);
- public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
- public IStorage GetModifiedPhysicalBlocksStorage() => ModifiedPhysicalBlocks.WithAccess(FileAccess.Read);
- public IStorage GetModifiedVirtualBlocksStorage() => ModifiedVirtualBlocks.WithAccess(FileAccess.Read);
- public IStorage GetFreeBlocksStorage() => FreeBlocks.WithAccess(FileAccess.Read);
+ public IStorage GetMapStorage() => MapStorage.AsReadOnly();
+ public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
+ public IStorage GetModifiedPhysicalBlocksStorage() => ModifiedPhysicalBlocks.AsReadOnly();
+ public IStorage GetModifiedVirtualBlocksStorage() => ModifiedVirtualBlocks.AsReadOnly();
+ public IStorage GetFreeBlocksStorage() => FreeBlocks.AsReadOnly();
}
public class JournalMapHeader
diff --git a/src/LibHac/IO/Save/JournalStorage.cs b/src/LibHac/IO/Save/JournalStorage.cs
index 336f718a..6617c755 100644
--- a/src/LibHac/IO/Save/JournalStorage.cs
+++ b/src/LibHac/IO/Save/JournalStorage.cs
@@ -3,7 +3,7 @@ using System.IO;
namespace LibHac.IO.Save
{
- public class JournalStorage : Storage
+ public class JournalStorage : StorageBase
{
private IStorage BaseStorage { get; }
private IStorage HeaderStorage { get; }
@@ -80,8 +80,8 @@ namespace LibHac.IO.Save
BaseStorage.Flush();
}
- public IStorage GetBaseStorage() => BaseStorage.WithAccess(FileAccess.Read);
- public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
+ public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
+ public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
}
public class JournalHeader
diff --git a/src/LibHac/IO/Save/RemapStorage.cs b/src/LibHac/IO/Save/RemapStorage.cs
index 7c260e37..30b27195 100644
--- a/src/LibHac/IO/Save/RemapStorage.cs
+++ b/src/LibHac/IO/Save/RemapStorage.cs
@@ -4,7 +4,7 @@ using System.IO;
namespace LibHac.IO.Save
{
- public class RemapStorage : Storage
+ public class RemapStorage : StorageBase
{
private IStorage BaseStorage { get; }
private IStorage HeaderStorage { get; }
@@ -102,9 +102,9 @@ namespace LibHac.IO.Save
BaseStorage.Flush();
}
- public IStorage GetBaseStorage() => BaseStorage.WithAccess(FileAccess.Read);
- public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
- public IStorage GetMapEntryStorage() => MapEntryStorage.WithAccess(FileAccess.Read);
+ public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
+ public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
+ public IStorage GetMapEntryStorage() => MapEntryStorage.AsReadOnly();
private static RemapSegment[] InitSegments(RemapHeader header, MapEntry[] mapEntries)
{
diff --git a/src/LibHac/IO/Save/SaveDataFileSystemCore.cs b/src/LibHac/IO/Save/SaveDataFileSystemCore.cs
index 787692ee..4ddc9b60 100644
--- a/src/LibHac/IO/Save/SaveDataFileSystemCore.cs
+++ b/src/LibHac/IO/Save/SaveDataFileSystemCore.cs
@@ -152,8 +152,8 @@ namespace LibHac.IO.Save
throw new System.NotImplementedException();
}
- public IStorage GetBaseStorage() => BaseStorage.WithAccess(FileAccess.Read);
- public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
+ public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
+ public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
private void ReadFileInfo()
{
diff --git a/src/LibHac/IO/SectorStorage.cs b/src/LibHac/IO/SectorStorage.cs
index a8b7ff5b..96b080ee 100644
--- a/src/LibHac/IO/SectorStorage.cs
+++ b/src/LibHac/IO/SectorStorage.cs
@@ -2,7 +2,7 @@
namespace LibHac.IO
{
- public class SectorStorage : Storage
+ public class SectorStorage : StorageBase
{
protected IStorage BaseStorage { get; }
diff --git a/src/LibHac/IO/Storage.cs b/src/LibHac/IO/Storage.cs
deleted file mode 100644
index 0a7cfc7e..00000000
--- a/src/LibHac/IO/Storage.cs
+++ /dev/null
@@ -1,114 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-
-namespace LibHac.IO
-{
- public abstract class Storage : IStorage
- {
- private bool _isDisposed;
- protected internal List ToDispose { get; } = new List();
-
- protected abstract void ReadImpl(Span destination, long offset);
- protected abstract void WriteImpl(ReadOnlySpan source, long offset);
- public abstract void Flush();
- public abstract long Length { get; }
-
- protected FileAccess Access { get; set; } = FileAccess.ReadWrite;
-
- public void Read(Span destination, long offset)
- {
- EnsureCanRead();
- ValidateSpanParameters(destination, offset);
- ReadImpl(destination, offset);
- }
-
- public virtual void Read(byte[] buffer, long offset, int count, int bufferOffset)
- {
- ValidateArrayParameters(buffer, offset, count, bufferOffset);
- Read(buffer.AsSpan(bufferOffset, count), offset);
- }
-
- public void Write(ReadOnlySpan source, long offset)
- {
- EnsureCanWrite();
- ValidateSpanParameters(source, offset);
- WriteImpl(source, offset);
- }
-
- public virtual void Write(byte[] buffer, long offset, int count, int bufferOffset)
- {
- ValidateArrayParameters(buffer, offset, count, bufferOffset);
- Write(buffer.AsSpan(bufferOffset, count), offset);
- }
-
- public virtual Storage Slice(long start, long length, bool leaveOpen)
- {
- return new SubStorage(this, start, length, leaveOpen);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (_isDisposed) return;
-
- if (disposing)
- {
- Flush();
- foreach (IDisposable item in ToDispose)
- {
- item?.Dispose();
- }
- }
-
- _isDisposed = true;
- }
-
- public void SetReadOnly() => Access = FileAccess.Read;
-
- public virtual bool CanRead => (Access & FileAccess.Read) != 0;
- public virtual bool CanWrite => (Access & FileAccess.Write) != 0;
-
- private void EnsureCanRead()
- {
- if (!CanRead) throw new InvalidOperationException("Storage is not readable");
- }
-
- private void EnsureCanWrite()
- {
- if (!CanWrite) throw new InvalidOperationException("Storage is not writable");
- }
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected void ValidateArrayParameters(byte[] buffer, long offset, int count, int bufferOffset)
- {
- if (_isDisposed) throw new ObjectDisposedException(null);
- if (buffer == null) throw new ArgumentNullException(nameof(buffer));
- if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative.");
- if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Argument must be non-negative.");
- if (bufferOffset < 0) throw new ArgumentOutOfRangeException(nameof(bufferOffset), "Argument must be non-negative.");
- if (buffer.Length - bufferOffset < count) throw new ArgumentException("bufferOffset, length, and count were out of bounds for the array.");
-
- if (Length != -1)
- {
- if (offset + count > Length) throw new ArgumentException("The given offset and count exceed the length of the Storage");
- }
- }
-
- protected void ValidateSpanParameters(ReadOnlySpan destination, long offset)
- {
- if (_isDisposed) throw new ObjectDisposedException(null);
- if (destination == null) throw new ArgumentNullException(nameof(destination));
- if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative.");
-
- if (Length != -1)
- {
- if (offset + destination.Length > Length) throw new ArgumentException("The given offset and count exceed the length of the Storage");
- }
- }
- }
-}
diff --git a/src/LibHac/IO/StorageBase.cs b/src/LibHac/IO/StorageBase.cs
new file mode 100644
index 00000000..41ba3c88
--- /dev/null
+++ b/src/LibHac/IO/StorageBase.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+
+namespace LibHac.IO
+{
+ public abstract class StorageBase : IStorage
+ {
+ private bool _isDisposed;
+ protected internal List ToDispose { get; } = new List();
+
+ protected abstract void ReadImpl(Span destination, long offset);
+ protected abstract void WriteImpl(ReadOnlySpan source, long offset);
+ public abstract void Flush();
+ public abstract long Length { get; }
+
+ public void Read(Span destination, long offset)
+ {
+ ValidateParameters(destination, offset);
+ ReadImpl(destination, offset);
+ }
+
+ public void Write(ReadOnlySpan source, long offset)
+ {
+ ValidateParameters(source, offset);
+ WriteImpl(source, offset);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_isDisposed) return;
+
+ if (disposing)
+ {
+ Flush();
+ foreach (IDisposable item in ToDispose)
+ {
+ item?.Dispose();
+ }
+ }
+
+ _isDisposed = true;
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected void ValidateParameters(ReadOnlySpan span, long offset)
+ {
+ if (_isDisposed) throw new ObjectDisposedException(null);
+ if (span == null) throw new ArgumentNullException(nameof(span));
+ if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset), "Argument must be non-negative.");
+
+ if (Length != -1)
+ {
+ if (offset + span.Length > Length) throw new ArgumentException("The given offset and count exceed the length of the Storage");
+ }
+ }
+ }
+}
diff --git a/src/LibHac/IO/StorageExtensions.cs b/src/LibHac/IO/StorageExtensions.cs
index f4d5bcd7..f91b4d07 100644
--- a/src/LibHac/IO/StorageExtensions.cs
+++ b/src/LibHac/IO/StorageExtensions.cs
@@ -6,7 +6,7 @@ namespace LibHac.IO
{
public static class StorageExtensions
{
- public static Storage Slice(this IStorage storage, long start)
+ public static IStorage Slice(this IStorage storage, long start)
{
if (storage.Length == -1)
{
@@ -16,33 +16,29 @@ namespace LibHac.IO
return storage.Slice(start, storage.Length - start);
}
- public static Storage Slice(this IStorage storage, long start, long length)
+ public static IStorage Slice(this IStorage storage, long start, long length)
{
return storage.Slice(start, length, true);
}
- public static Storage Slice(this IStorage storage, long start, long length, bool leaveOpen)
+ public static IStorage Slice(this IStorage storage, long start, long length, bool leaveOpen)
{
- if (storage is Storage s)
- {
- return s.Slice(start, length, leaveOpen);
- }
-
return new SubStorage(storage, start, length, leaveOpen);
}
- public static Storage WithAccess(this IStorage storage, FileAccess access)
+ public static IStorage AsReadOnly(this IStorage storage)
{
- return storage.WithAccess(access, true);
+ return storage.AsReadOnly(true);
}
- public static Storage WithAccess(this IStorage storage, FileAccess access, bool leaveOpen)
+ public static IStorage AsReadOnly(this IStorage storage, bool leaveOpen)
{
- return new SubStorage(storage, 0, storage.Length, leaveOpen, access);
+ return new SubStorage(storage, 0, storage.Length, leaveOpen, FileAccess.Read);
}
- public static Stream AsStream(this IStorage storage) => new StorageStream(storage, true);
- public static Stream AsStream(this IStorage storage, bool keepOpen) => new StorageStream(storage, keepOpen);
+ public static Stream AsStream(this IStorage storage) => new StorageStream(storage, FileAccess.ReadWrite, true);
+ public static Stream AsStream(this IStorage storage, FileAccess access) => new StorageStream(storage, access, true);
+ public static Stream AsStream(this IStorage storage, FileAccess access, bool keepOpen) => new StorageStream(storage, access, keepOpen);
public static void CopyTo(this IStorage input, IStorage output, IProgressReport progress = null)
{
@@ -96,7 +92,7 @@ namespace LibHac.IO
while (remaining > 0)
{
int toWrite = (int) Math.Min(buffer.Length, remaining);
- input.Read(buffer, inOffset, toWrite, 0);
+ input.Read(buffer.AsSpan(0, toWrite), inOffset);
output.Write(buffer, 0, toWrite);
remaining -= toWrite;
@@ -107,31 +103,31 @@ namespace LibHac.IO
public static void CopyToStream(this IStorage input, Stream output) => CopyToStream(input, output, input.Length);
- public static Storage AsStorage(this Stream stream)
+ public static IStorage AsStorage(this Stream stream)
{
if (stream == null) return null;
return new StreamStorage(stream, true);
}
- public static Storage AsStorage(this Stream stream, bool keepOpen)
+ public static IStorage AsStorage(this Stream stream, bool keepOpen)
{
if (stream == null) return null;
return new StreamStorage(stream, keepOpen);
}
- public static Storage AsStorage(this Stream stream, long start)
+ public static IStorage AsStorage(this Stream stream, long start)
{
if (stream == null) return null;
return new StreamStorage(stream, true).Slice(start);
}
- public static Storage AsStorage(this Stream stream, long start, int length)
+ public static IStorage AsStorage(this Stream stream, long start, int length)
{
if (stream == null) return null;
return new StreamStorage(stream, true).Slice(start, length);
}
- public static Storage AsStorage(this Stream stream, long start, int length, bool keepOpen)
+ public static IStorage AsStorage(this Stream stream, long start, int length, bool keepOpen)
{
if (stream == null) return null;
return new StreamStorage(stream, keepOpen).Slice(start, length);
diff --git a/src/LibHac/IO/StorageStream.cs b/src/LibHac/IO/StorageStream.cs
index c25cd809..7cd63045 100644
--- a/src/LibHac/IO/StorageStream.cs
+++ b/src/LibHac/IO/StorageStream.cs
@@ -8,17 +8,20 @@ namespace LibHac.IO
private IStorage BaseStorage { get; }
private bool LeaveOpen { get; }
- public StorageStream(IStorage baseStorage, bool leaveOpen)
+ public StorageStream(IStorage baseStorage, FileAccess access, bool leaveOpen)
{
BaseStorage = baseStorage;
LeaveOpen = leaveOpen;
Length = baseStorage.Length;
+
+ CanRead = access.HasFlag(FileAccess.Read);
+ CanWrite = access.HasFlag(FileAccess.Write);
}
public override int Read(byte[] buffer, int offset, int count)
{
int toRead = (int) Math.Min(count, Length - Position);
- BaseStorage.Read(buffer, Position, toRead, offset);
+ BaseStorage.Read(buffer.AsSpan(offset, count), Position);
Position += toRead;
return toRead;
@@ -26,7 +29,7 @@ namespace LibHac.IO
public override void Write(byte[] buffer, int offset, int count)
{
- BaseStorage.Write(buffer, Position, count, offset);
+ BaseStorage.Write(buffer.AsSpan(offset, count), Position);
Position += count;
}
@@ -58,9 +61,9 @@ namespace LibHac.IO
throw new NotImplementedException();
}
- public override bool CanRead => (BaseStorage as Storage)?.CanRead ?? true;
+ public override bool CanRead { get; }
public override bool CanSeek => true;
- public override bool CanWrite => (BaseStorage as Storage)?.CanWrite ?? true;
+ public override bool CanWrite { get; }
public override long Length { get; }
public override long Position { get; set; }
diff --git a/src/LibHac/IO/StreamStorage.cs b/src/LibHac/IO/StreamStorage.cs
index 47171143..81efa251 100644
--- a/src/LibHac/IO/StreamStorage.cs
+++ b/src/LibHac/IO/StreamStorage.cs
@@ -7,7 +7,7 @@ using System.Buffers;
namespace LibHac.IO
{
- public class StreamStorage : Storage
+ public class StreamStorage : StorageBase
{
private Stream BaseStream { get; }
private object Locker { get; } = new object();
@@ -20,24 +20,6 @@ namespace LibHac.IO
if (!leaveOpen) ToDispose.Add(BaseStream);
}
- public override void Read(byte[] buffer, long offset, int count, int bufferOffset)
- {
- lock (Locker)
- {
- BaseStream.Position = offset;
- BaseStream.Read(buffer, bufferOffset, count);
- }
- }
-
- public override void Write(byte[] buffer, long offset, int count, int bufferOffset)
- {
- lock (Locker)
- {
- BaseStream.Position = offset;
- BaseStream.Write(buffer, bufferOffset, count);
- }
- }
-
protected override void ReadImpl(Span destination, long offset)
{
#if STREAM_SPAN
@@ -54,9 +36,17 @@ namespace LibHac.IO
byte[] buffer = ArrayPool.Shared.Rent(destination.Length);
try
{
- Read(buffer, offset, destination.Length, 0);
+ lock (Locker)
+ {
+ if (BaseStream.Position != offset)
+ {
+ BaseStream.Position = offset;
+ }
- new Span(buffer, 0, destination.Length).CopyTo(destination);
+ BaseStream.Read(buffer, 0, destination.Length);
+ }
+
+ buffer.AsSpan(0, destination.Length).CopyTo(destination);
}
finally { ArrayPool.Shared.Return(buffer); }
#endif
@@ -67,7 +57,11 @@ namespace LibHac.IO
#if STREAM_SPAN
lock (Locker)
{
- BaseStream.Position = offset;
+ if (BaseStream.Position != offset)
+ {
+ BaseStream.Position = offset;
+ }
+
BaseStream.Write(source);
}
#else
@@ -75,7 +69,16 @@ namespace LibHac.IO
try
{
source.CopyTo(buffer);
- Write(buffer, offset, source.Length, 0);
+
+ lock (Locker)
+ {
+ if (BaseStream.Position != offset)
+ {
+ BaseStream.Position = offset;
+ }
+
+ BaseStream.Write(buffer, 0, source.Length);
+ }
}
finally { ArrayPool.Shared.Return(buffer); }
#endif
diff --git a/src/LibHac/IO/SubStorage.cs b/src/LibHac/IO/SubStorage.cs
index b54f6d76..ebcdd803 100644
--- a/src/LibHac/IO/SubStorage.cs
+++ b/src/LibHac/IO/SubStorage.cs
@@ -3,11 +3,12 @@ using System.IO;
namespace LibHac.IO
{
- public class SubStorage : Storage
+ public class SubStorage : StorageBase
{
private IStorage BaseStorage { get; }
private long Offset { get; }
public override long Length { get; }
+ private FileAccess Access { get; } = FileAccess.ReadWrite;
public SubStorage(IStorage baseStorage, long offset, long length)
{
@@ -16,6 +17,13 @@ namespace LibHac.IO
Length = length;
}
+ public SubStorage(SubStorage baseStorage, long offset, long length)
+ {
+ BaseStorage = baseStorage.BaseStorage;
+ Offset = baseStorage.Offset + offset;
+ Length = length;
+ }
+
public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen)
: this(baseStorage, offset, length)
{
@@ -30,11 +38,13 @@ namespace LibHac.IO
protected override void ReadImpl(Span destination, long offset)
{
+ if((Access & FileAccess.Read) == 0) throw new InvalidOperationException("Storage is not readable");
BaseStorage.Read(destination, offset + Offset);
}
protected override void WriteImpl(ReadOnlySpan source, long offset)
{
+ if((Access & FileAccess.Write) == 0) throw new InvalidOperationException("Storage is not writable");
BaseStorage.Write(source, offset + Offset);
}
@@ -42,13 +52,5 @@ namespace LibHac.IO
{
BaseStorage.Flush();
}
-
- public override Storage Slice(long start, long length, bool leaveOpen)
- {
- Storage storage = BaseStorage.Slice(Offset + start, length, true);
- if (!leaveOpen) storage.ToDispose.Add(this);
-
- return storage;
- }
}
}
diff --git a/src/LibHac/Nca.cs b/src/LibHac/Nca.cs
index 1299807d..82d8e4b0 100644
--- a/src/LibHac/Nca.cs
+++ b/src/LibHac/Nca.cs
@@ -75,7 +75,7 @@ namespace LibHac
/// The that provides access to the entire raw NCA file.
public IStorage GetStorage()
{
- return BaseStorage.WithAccess(FileAccess.Read);
+ return BaseStorage.AsReadOnly();
}
public bool CanOpenSection(int index)
diff --git a/src/NandReaderGui/ViewModel/NandViewModel.cs b/src/NandReaderGui/ViewModel/NandViewModel.cs
index 422a0bc1..275b2671 100644
--- a/src/NandReaderGui/ViewModel/NandViewModel.cs
+++ b/src/NandReaderGui/ViewModel/NandViewModel.cs
@@ -46,8 +46,7 @@ namespace NandReaderGui.ViewModel
{
DiskInfo disk = SelectedDisk;
var storage = new CachedStorage(new DeviceStream(disk.PhysicalName, disk.Length).AsStorage(), disk.SectorSize * 100, 4, true);
- storage.SetReadOnly();
- Stream stream = storage.AsStream();
+ Stream stream = storage.AsStream(FileAccess.Read);
Keyset keyset = OpenKeyset();
var nand = new Nand(stream, keyset);