Make IStorage interface and classes less complex

This commit is contained in:
Alex Barney 2019-01-21 16:57:41 -06:00
parent 30b42eaf34
commit 8e151c4a1c
30 changed files with 165 additions and 262 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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)

View file

@ -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);
}

View file

@ -2,7 +2,7 @@
namespace LibHac.IO
{
public class FileStorage : Storage
public class FileStorage : StorageBase
{
private IFile BaseFile { get; }

View file

@ -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);
}

View file

@ -12,16 +12,6 @@ namespace LibHac.IO
/// <param name="offset">The offset in the <see cref="IStorage"/> to begin reading from.</param>
void Read(Span<byte> destination, long offset);
/// <summary>
/// Reads a sequence of bytes from the current <see cref="IStorage"/>.
/// </summary>
/// <param name="buffer">The buffer where the read bytes will be stored.</param>
/// <param name="offset">The zero-based byte offset in <paramref name="buffer"/>
/// at which to begin storing the data read from the current <see cref="IStorage"/>.</param>
/// <param name="count">The number of bytes to be read from the <see cref="IStorage"/>.</param>
/// <param name="bufferOffset">The offset in the <see cref="IStorage"/> to begin reading from.</param>
void Read(byte[] buffer, long offset, int count, int bufferOffset);
/// <summary>
/// Writes a sequence of bytes to the current <see cref="IStorage"/>.
/// </summary>
@ -29,16 +19,6 @@ namespace LibHac.IO
/// <param name="offset">The offset in the <see cref="IStorage"/> to begin writing to.</param>
void Write(ReadOnlySpan<byte> source, long offset);
/// <summary>
/// Writes a sequence of bytes to the current <see cref="IStorage"/>.
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset">The zero-based byte offset in <paramref name="buffer"/>
/// at which to begin begin copying bytes to the current <see cref="IStorage"/>.</param>
/// <param name="count">The number of bytes to be written to the <see cref="IStorage"/>.</param>
/// <param name="bufferOffset">The offset in the <see cref="IStorage"/> to begin writing to.</param>
void Write(byte[] buffer, long offset, int count, int bufferOffset);
/// <summary>
/// Causes any buffered data to be written to the underlying device.
/// </summary>

View file

@ -4,7 +4,7 @@ using System.Linq;
namespace LibHac.IO
{
public class IndirectStorage : Storage
public class IndirectStorage : StorageBase
{
private List<RelocationEntry> RelocationEntries { get; }
private List<long> 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)

View file

@ -116,16 +116,10 @@ namespace LibHac.IO
public void Read(Span<byte> 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<byte> source, long offset)
{
long blockIndex = offset / SectorSize;

View file

@ -2,7 +2,7 @@
namespace LibHac.IO
{
public class MemoryStorage : Storage
public class MemoryStorage : StorageBase
{
private byte[] Buffer { get; }
private int Start { get; }

View file

@ -5,7 +5,7 @@ namespace LibHac.IO
/// <summary>
/// An <see cref="IStorage"/> that returns all zeros when read, and does nothing on write.
/// </summary>
public class NullStorage : Storage
public class NullStorage : StorageBase
{
public NullStorage() { }
public NullStorage(long length) => Length = length;

View file

@ -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

View file

@ -2,7 +2,7 @@
namespace LibHac.IO.Save
{
public class AllocationTableStorage : Storage
public class AllocationTableStorage : StorageBase
{
private IStorage BaseStorage { get; }
private int BlockSize { get; }

View file

@ -2,7 +2,7 @@
namespace LibHac.IO.Save
{
public class DuplexStorage : Storage
public class DuplexStorage : StorageBase
{
private int BlockSize { get; }
private IStorage BitmapStorage { get; }

View file

@ -2,7 +2,7 @@
namespace LibHac.IO.Save
{
public class HierarchicalDuplexStorage : Storage
public class HierarchicalDuplexStorage : StorageBase
{
private DuplexStorage[] Layers { get; }
private DuplexStorage DataLayer { get; }

View file

@ -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

View file

@ -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

View file

@ -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)
{

View file

@ -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()
{

View file

@ -2,7 +2,7 @@
namespace LibHac.IO
{
public class SectorStorage : Storage
public class SectorStorage : StorageBase
{
protected IStorage BaseStorage { get; }

View file

@ -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<IDisposable> ToDispose { get; } = new List<IDisposable>();
protected abstract void ReadImpl(Span<byte> destination, long offset);
protected abstract void WriteImpl(ReadOnlySpan<byte> source, long offset);
public abstract void Flush();
public abstract long Length { get; }
protected FileAccess Access { get; set; } = FileAccess.ReadWrite;
public void Read(Span<byte> 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<byte> 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<byte> 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");
}
}
}
}

View file

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
namespace LibHac.IO
{
public abstract class StorageBase : IStorage
{
private bool _isDisposed;
protected internal List<IDisposable> ToDispose { get; } = new List<IDisposable>();
protected abstract void ReadImpl(Span<byte> destination, long offset);
protected abstract void WriteImpl(ReadOnlySpan<byte> source, long offset);
public abstract void Flush();
public abstract long Length { get; }
public void Read(Span<byte> destination, long offset)
{
ValidateParameters(destination, offset);
ReadImpl(destination, offset);
}
public void Write(ReadOnlySpan<byte> 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<byte> 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");
}
}
}
}

View file

@ -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);

View file

@ -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; }

View file

@ -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<byte> destination, long offset)
{
#if STREAM_SPAN
@ -54,9 +36,17 @@ namespace LibHac.IO
byte[] buffer = ArrayPool<byte>.Shared.Rent(destination.Length);
try
{
Read(buffer, offset, destination.Length, 0);
lock (Locker)
{
if (BaseStream.Position != offset)
{
BaseStream.Position = offset;
}
new Span<byte>(buffer, 0, destination.Length).CopyTo(destination);
BaseStream.Read(buffer, 0, destination.Length);
}
buffer.AsSpan(0, destination.Length).CopyTo(destination);
}
finally { ArrayPool<byte>.Shared.Return(buffer); }
#endif
@ -66,8 +56,12 @@ namespace LibHac.IO
{
#if STREAM_SPAN
lock (Locker)
{
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<byte>.Shared.Return(buffer); }
#endif

View file

@ -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<byte> 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<byte> 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;
}
}
}

View file

@ -75,7 +75,7 @@ namespace LibHac
/// <returns>The <see cref="IStorage"/> that provides access to the entire raw NCA file.</returns>
public IStorage GetStorage()
{
return BaseStorage.WithAccess(FileAccess.Read);
return BaseStorage.AsReadOnly();
}
public bool CanOpenSection(int index)

View file

@ -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);