mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Make IStorage interface and classes less complex
This commit is contained in:
parent
30b42eaf34
commit
8e151c4a1c
30 changed files with 165 additions and 262 deletions
|
@ -33,16 +33,14 @@ namespace LibHac.Nand
|
||||||
{
|
{
|
||||||
IStorage encStorage = ProdInfo.Open().AsStorage();
|
IStorage encStorage = ProdInfo.Open().AsStorage();
|
||||||
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[0], 0x4000, true), 0x4000, 4, true);
|
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[0], 0x4000, true), 0x4000, 4, true);
|
||||||
decStorage.SetReadOnly();
|
return decStorage.AsStream(FileAccess.Read);
|
||||||
return decStorage.AsStream();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public FatFileSystemProvider OpenProdInfoF()
|
public FatFileSystemProvider OpenProdInfoF()
|
||||||
{
|
{
|
||||||
IStorage encStorage = ProdInfoF.Open().AsStorage();
|
IStorage encStorage = ProdInfoF.Open().AsStorage();
|
||||||
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[0], 0x4000, true), 0x4000, 4, true);
|
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[0], 0x4000, true), 0x4000, 4, true);
|
||||||
decStorage.SetReadOnly();
|
var fat = new FatFileSystem(decStorage.AsStream(FileAccess.Read), Ownership.None);
|
||||||
var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None);
|
|
||||||
return new FatFileSystemProvider(fat);
|
return new FatFileSystemProvider(fat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,8 +48,7 @@ namespace LibHac.Nand
|
||||||
{
|
{
|
||||||
IStorage encStorage = Safe.Open().AsStorage();
|
IStorage encStorage = Safe.Open().AsStorage();
|
||||||
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[1], 0x4000, true), 0x4000, 4, true);
|
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[1], 0x4000, true), 0x4000, 4, true);
|
||||||
decStorage.SetReadOnly();
|
var fat = new FatFileSystem(decStorage.AsStream(FileAccess.Read), Ownership.None);
|
||||||
var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None);
|
|
||||||
return new FatFileSystemProvider(fat);
|
return new FatFileSystemProvider(fat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +56,7 @@ namespace LibHac.Nand
|
||||||
{
|
{
|
||||||
IStorage encStorage = System.Open().AsStorage();
|
IStorage encStorage = System.Open().AsStorage();
|
||||||
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[2], 0x4000, true), 0x4000, 4, true);
|
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[2], 0x4000, true), 0x4000, 4, true);
|
||||||
decStorage.SetReadOnly();
|
var fat = new FatFileSystem(decStorage.AsStream(FileAccess.Read), Ownership.None);
|
||||||
var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None);
|
|
||||||
return new FatFileSystemProvider(fat);
|
return new FatFileSystemProvider(fat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,8 +64,7 @@ namespace LibHac.Nand
|
||||||
{
|
{
|
||||||
IStorage encStorage = User.Open().AsStorage();
|
IStorage encStorage = User.Open().AsStorage();
|
||||||
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[3], 0x4000, true), 0x4000, 4, true);
|
var decStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Keyset.BisKeys[3], 0x4000, true), 0x4000, 4, true);
|
||||||
decStorage.SetReadOnly();
|
var fat = new FatFileSystem(decStorage.AsStream(FileAccess.Read), Ownership.None);
|
||||||
var fat = new FatFileSystem(decStorage.AsStream(), Ownership.None);
|
|
||||||
return new FatFileSystemProvider(fat);
|
return new FatFileSystemProvider(fat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,8 +60,6 @@ namespace LibHac.IO
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanWrite => false;
|
|
||||||
|
|
||||||
private AesSubsectionEntry GetSubsectionEntry(long offset)
|
private AesSubsectionEntry GetSubsectionEntry(long offset)
|
||||||
{
|
{
|
||||||
int index = SubsectionOffsets.BinarySearch(offset);
|
int index = SubsectionOffsets.BinarySearch(offset);
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace LibHac.IO
|
||||||
throw new ArgumentException("NAX0 key derivation failed.");
|
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);
|
BaseStorage = new CachedStorage(new Aes128XtsStorage(encStorage, Header.DecryptedKey1, Header.DecryptedKey2, BlockSize, true), 4, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class CachedStorage : Storage
|
public class CachedStorage : StorageBase
|
||||||
{
|
{
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private int BlockSize { get; }
|
private int BlockSize { get; }
|
||||||
|
@ -148,7 +148,7 @@ namespace LibHac.IO
|
||||||
if (!block.Dirty) return;
|
if (!block.Dirty) return;
|
||||||
|
|
||||||
long offset = block.Index * BlockSize;
|
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;
|
block.Dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class ConcatenationStorage : Storage
|
public class ConcatenationStorage : StorageBase
|
||||||
{
|
{
|
||||||
private ConcatSource[] Sources { get; }
|
private ConcatSource[] Sources { get; }
|
||||||
public override long Length { 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)
|
private ConcatSource FindSource(long offset)
|
||||||
{
|
{
|
||||||
foreach (ConcatSource info in Sources)
|
foreach (ConcatSource info in Sources)
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace LibHac.IO
|
||||||
IStorage source = segment.IsInOriginal ? Original : Delta;
|
IStorage source = segment.IsInOriginal ? Original : Delta;
|
||||||
|
|
||||||
// todo Do this without tons of SubStorages
|
// 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);
|
storages.Add(sub);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class FileStorage : Storage
|
public class FileStorage : StorageBase
|
||||||
{
|
{
|
||||||
private IFile BaseFile { get; }
|
private IFile BaseFile { get; }
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ using System.Text;
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class HierarchicalIntegrityVerificationStorage : Storage
|
public class HierarchicalIntegrityVerificationStorage : StorageBase
|
||||||
{
|
{
|
||||||
public IStorage[] Levels { get; }
|
public IStorage[] Levels { get; }
|
||||||
public IStorage DataLevel { get; }
|
public IStorage DataLevel { get; }
|
||||||
|
@ -128,7 +128,7 @@ namespace LibHac.IO
|
||||||
if (validities[i] == Validity.Unchecked)
|
if (validities[i] == Validity.Unchecked)
|
||||||
{
|
{
|
||||||
int toRead = (int)Math.Min(storage.Length - blockSize * i, buffer.Length);
|
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)
|
if (validities[i] == Validity.Invalid)
|
||||||
|
@ -209,6 +209,9 @@ namespace LibHac.IO
|
||||||
}
|
}
|
||||||
|
|
||||||
SaltSource = reader.ReadBytes(0x20);
|
SaltSource = reader.ReadBytes(0x20);
|
||||||
|
|
||||||
|
if (reader.BaseStream.Position + 0x20 >= reader.BaseStream.Length) return;
|
||||||
|
|
||||||
MasterHash = reader.ReadBytes(0x20);
|
MasterHash = reader.ReadBytes(0x20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,16 +12,6 @@ namespace LibHac.IO
|
||||||
/// <param name="offset">The offset in the <see cref="IStorage"/> to begin reading from.</param>
|
/// <param name="offset">The offset in the <see cref="IStorage"/> to begin reading from.</param>
|
||||||
void Read(Span<byte> destination, long offset);
|
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>
|
/// <summary>
|
||||||
/// Writes a sequence of bytes to the current <see cref="IStorage"/>.
|
/// Writes a sequence of bytes to the current <see cref="IStorage"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -29,16 +19,6 @@ namespace LibHac.IO
|
||||||
/// <param name="offset">The offset in the <see cref="IStorage"/> to begin writing to.</param>
|
/// <param name="offset">The offset in the <see cref="IStorage"/> to begin writing to.</param>
|
||||||
void Write(ReadOnlySpan<byte> source, long offset);
|
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>
|
/// <summary>
|
||||||
/// Causes any buffered data to be written to the underlying device.
|
/// Causes any buffered data to be written to the underlying device.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class IndirectStorage : Storage
|
public class IndirectStorage : StorageBase
|
||||||
{
|
{
|
||||||
private List<RelocationEntry> RelocationEntries { get; }
|
private List<RelocationEntry> RelocationEntries { get; }
|
||||||
private List<long> RelocationOffsets { get; }
|
private List<long> RelocationOffsets { get; }
|
||||||
|
@ -62,8 +62,6 @@ namespace LibHac.IO
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool CanWrite => false;
|
|
||||||
|
|
||||||
public override long Length { get; }
|
public override long Length { get; }
|
||||||
|
|
||||||
private RelocationEntry GetRelocationEntry(long offset)
|
private RelocationEntry GetRelocationEntry(long offset)
|
||||||
|
|
|
@ -116,16 +116,10 @@ namespace LibHac.IO
|
||||||
|
|
||||||
public void Read(Span<byte> destination, long offset, IntegrityCheckLevel integrityCheckLevel)
|
public void Read(Span<byte> destination, long offset, IntegrityCheckLevel integrityCheckLevel)
|
||||||
{
|
{
|
||||||
ValidateSpanParameters(destination, offset);
|
ValidateParameters(destination, offset);
|
||||||
ReadImpl(destination, offset, integrityCheckLevel);
|
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)
|
protected override void WriteImpl(ReadOnlySpan<byte> source, long offset)
|
||||||
{
|
{
|
||||||
long blockIndex = offset / SectorSize;
|
long blockIndex = offset / SectorSize;
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class MemoryStorage : Storage
|
public class MemoryStorage : StorageBase
|
||||||
{
|
{
|
||||||
private byte[] Buffer { get; }
|
private byte[] Buffer { get; }
|
||||||
private int Start { get; }
|
private int Start { get; }
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace LibHac.IO
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An <see cref="IStorage"/> that returns all zeros when read, and does nothing on write.
|
/// An <see cref="IStorage"/> that returns all zeros when read, and does nothing on write.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NullStorage : Storage
|
public class NullStorage : StorageBase
|
||||||
{
|
{
|
||||||
public NullStorage() { }
|
public NullStorage() { }
|
||||||
public NullStorage(long length) => Length = length;
|
public NullStorage(long length) => Length = length;
|
||||||
|
|
|
@ -34,8 +34,8 @@ namespace LibHac.IO.Save
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage GetBaseStorage() => BaseStorage.WithAccess(FileAccess.Read);
|
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
||||||
public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
|
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AllocationTableEntry
|
public class AllocationTableEntry
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace LibHac.IO.Save
|
namespace LibHac.IO.Save
|
||||||
{
|
{
|
||||||
public class AllocationTableStorage : Storage
|
public class AllocationTableStorage : StorageBase
|
||||||
{
|
{
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private int BlockSize { get; }
|
private int BlockSize { get; }
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace LibHac.IO.Save
|
namespace LibHac.IO.Save
|
||||||
{
|
{
|
||||||
public class DuplexStorage : Storage
|
public class DuplexStorage : StorageBase
|
||||||
{
|
{
|
||||||
private int BlockSize { get; }
|
private int BlockSize { get; }
|
||||||
private IStorage BitmapStorage { get; }
|
private IStorage BitmapStorage { get; }
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace LibHac.IO.Save
|
namespace LibHac.IO.Save
|
||||||
{
|
{
|
||||||
public class HierarchicalDuplexStorage : Storage
|
public class HierarchicalDuplexStorage : StorageBase
|
||||||
{
|
{
|
||||||
private DuplexStorage[] Layers { get; }
|
private DuplexStorage[] Layers { get; }
|
||||||
private DuplexStorage DataLayer { get; }
|
private DuplexStorage DataLayer { get; }
|
||||||
|
|
|
@ -50,11 +50,11 @@ namespace LibHac.IO.Save
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage GetMapStorage() => MapStorage.WithAccess(FileAccess.Read);
|
public IStorage GetMapStorage() => MapStorage.AsReadOnly();
|
||||||
public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
|
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
||||||
public IStorage GetModifiedPhysicalBlocksStorage() => ModifiedPhysicalBlocks.WithAccess(FileAccess.Read);
|
public IStorage GetModifiedPhysicalBlocksStorage() => ModifiedPhysicalBlocks.AsReadOnly();
|
||||||
public IStorage GetModifiedVirtualBlocksStorage() => ModifiedVirtualBlocks.WithAccess(FileAccess.Read);
|
public IStorage GetModifiedVirtualBlocksStorage() => ModifiedVirtualBlocks.AsReadOnly();
|
||||||
public IStorage GetFreeBlocksStorage() => FreeBlocks.WithAccess(FileAccess.Read);
|
public IStorage GetFreeBlocksStorage() => FreeBlocks.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class JournalMapHeader
|
public class JournalMapHeader
|
||||||
|
|
|
@ -3,7 +3,7 @@ using System.IO;
|
||||||
|
|
||||||
namespace LibHac.IO.Save
|
namespace LibHac.IO.Save
|
||||||
{
|
{
|
||||||
public class JournalStorage : Storage
|
public class JournalStorage : StorageBase
|
||||||
{
|
{
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private IStorage HeaderStorage { get; }
|
private IStorage HeaderStorage { get; }
|
||||||
|
@ -80,8 +80,8 @@ namespace LibHac.IO.Save
|
||||||
BaseStorage.Flush();
|
BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage GetBaseStorage() => BaseStorage.WithAccess(FileAccess.Read);
|
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
||||||
public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
|
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class JournalHeader
|
public class JournalHeader
|
||||||
|
|
|
@ -4,7 +4,7 @@ using System.IO;
|
||||||
|
|
||||||
namespace LibHac.IO.Save
|
namespace LibHac.IO.Save
|
||||||
{
|
{
|
||||||
public class RemapStorage : Storage
|
public class RemapStorage : StorageBase
|
||||||
{
|
{
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private IStorage HeaderStorage { get; }
|
private IStorage HeaderStorage { get; }
|
||||||
|
@ -102,9 +102,9 @@ namespace LibHac.IO.Save
|
||||||
BaseStorage.Flush();
|
BaseStorage.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage GetBaseStorage() => BaseStorage.WithAccess(FileAccess.Read);
|
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
||||||
public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
|
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
||||||
public IStorage GetMapEntryStorage() => MapEntryStorage.WithAccess(FileAccess.Read);
|
public IStorage GetMapEntryStorage() => MapEntryStorage.AsReadOnly();
|
||||||
|
|
||||||
private static RemapSegment[] InitSegments(RemapHeader header, MapEntry[] mapEntries)
|
private static RemapSegment[] InitSegments(RemapHeader header, MapEntry[] mapEntries)
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,8 +152,8 @@ namespace LibHac.IO.Save
|
||||||
throw new System.NotImplementedException();
|
throw new System.NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage GetBaseStorage() => BaseStorage.WithAccess(FileAccess.Read);
|
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
||||||
public IStorage GetHeaderStorage() => HeaderStorage.WithAccess(FileAccess.Read);
|
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
||||||
|
|
||||||
private void ReadFileInfo()
|
private void ReadFileInfo()
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class SectorStorage : Storage
|
public class SectorStorage : StorageBase
|
||||||
{
|
{
|
||||||
protected IStorage BaseStorage { get; }
|
protected IStorage BaseStorage { get; }
|
||||||
|
|
||||||
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
62
src/LibHac/IO/StorageBase.cs
Normal file
62
src/LibHac/IO/StorageBase.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public static class StorageExtensions
|
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)
|
if (storage.Length == -1)
|
||||||
{
|
{
|
||||||
|
@ -16,33 +16,29 @@ namespace LibHac.IO
|
||||||
return storage.Slice(start, storage.Length - start);
|
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);
|
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);
|
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) => new StorageStream(storage, FileAccess.ReadWrite, true);
|
||||||
public static Stream AsStream(this IStorage storage, bool keepOpen) => new StorageStream(storage, keepOpen);
|
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)
|
public static void CopyTo(this IStorage input, IStorage output, IProgressReport progress = null)
|
||||||
{
|
{
|
||||||
|
@ -96,7 +92,7 @@ namespace LibHac.IO
|
||||||
while (remaining > 0)
|
while (remaining > 0)
|
||||||
{
|
{
|
||||||
int toWrite = (int) Math.Min(buffer.Length, remaining);
|
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);
|
output.Write(buffer, 0, toWrite);
|
||||||
remaining -= 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 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;
|
if (stream == null) return null;
|
||||||
return new StreamStorage(stream, true);
|
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;
|
if (stream == null) return null;
|
||||||
return new StreamStorage(stream, keepOpen);
|
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;
|
if (stream == null) return null;
|
||||||
return new StreamStorage(stream, true).Slice(start);
|
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;
|
if (stream == null) return null;
|
||||||
return new StreamStorage(stream, true).Slice(start, length);
|
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;
|
if (stream == null) return null;
|
||||||
return new StreamStorage(stream, keepOpen).Slice(start, length);
|
return new StreamStorage(stream, keepOpen).Slice(start, length);
|
||||||
|
|
|
@ -8,17 +8,20 @@ namespace LibHac.IO
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private bool LeaveOpen { get; }
|
private bool LeaveOpen { get; }
|
||||||
|
|
||||||
public StorageStream(IStorage baseStorage, bool leaveOpen)
|
public StorageStream(IStorage baseStorage, FileAccess access, bool leaveOpen)
|
||||||
{
|
{
|
||||||
BaseStorage = baseStorage;
|
BaseStorage = baseStorage;
|
||||||
LeaveOpen = leaveOpen;
|
LeaveOpen = leaveOpen;
|
||||||
Length = baseStorage.Length;
|
Length = baseStorage.Length;
|
||||||
|
|
||||||
|
CanRead = access.HasFlag(FileAccess.Read);
|
||||||
|
CanWrite = access.HasFlag(FileAccess.Write);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
{
|
{
|
||||||
int toRead = (int) Math.Min(count, Length - Position);
|
int toRead = (int) Math.Min(count, Length - Position);
|
||||||
BaseStorage.Read(buffer, Position, toRead, offset);
|
BaseStorage.Read(buffer.AsSpan(offset, count), Position);
|
||||||
|
|
||||||
Position += toRead;
|
Position += toRead;
|
||||||
return toRead;
|
return toRead;
|
||||||
|
@ -26,7 +29,7 @@ namespace LibHac.IO
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
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;
|
Position += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,9 +61,9 @@ namespace LibHac.IO
|
||||||
throw new NotImplementedException();
|
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 CanSeek => true;
|
||||||
public override bool CanWrite => (BaseStorage as Storage)?.CanWrite ?? true;
|
public override bool CanWrite { get; }
|
||||||
public override long Length { get; }
|
public override long Length { get; }
|
||||||
public override long Position { get; set; }
|
public override long Position { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ using System.Buffers;
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class StreamStorage : Storage
|
public class StreamStorage : StorageBase
|
||||||
{
|
{
|
||||||
private Stream BaseStream { get; }
|
private Stream BaseStream { get; }
|
||||||
private object Locker { get; } = new object();
|
private object Locker { get; } = new object();
|
||||||
|
@ -20,24 +20,6 @@ namespace LibHac.IO
|
||||||
if (!leaveOpen) ToDispose.Add(BaseStream);
|
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)
|
protected override void ReadImpl(Span<byte> destination, long offset)
|
||||||
{
|
{
|
||||||
#if STREAM_SPAN
|
#if STREAM_SPAN
|
||||||
|
@ -54,9 +36,17 @@ namespace LibHac.IO
|
||||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(destination.Length);
|
byte[] buffer = ArrayPool<byte>.Shared.Rent(destination.Length);
|
||||||
try
|
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); }
|
finally { ArrayPool<byte>.Shared.Return(buffer); }
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,7 +57,11 @@ namespace LibHac.IO
|
||||||
#if STREAM_SPAN
|
#if STREAM_SPAN
|
||||||
lock (Locker)
|
lock (Locker)
|
||||||
{
|
{
|
||||||
BaseStream.Position = offset;
|
if (BaseStream.Position != offset)
|
||||||
|
{
|
||||||
|
BaseStream.Position = offset;
|
||||||
|
}
|
||||||
|
|
||||||
BaseStream.Write(source);
|
BaseStream.Write(source);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -75,7 +69,16 @@ namespace LibHac.IO
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
source.CopyTo(buffer);
|
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); }
|
finally { ArrayPool<byte>.Shared.Return(buffer); }
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3,11 +3,12 @@ using System.IO;
|
||||||
|
|
||||||
namespace LibHac.IO
|
namespace LibHac.IO
|
||||||
{
|
{
|
||||||
public class SubStorage : Storage
|
public class SubStorage : StorageBase
|
||||||
{
|
{
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private long Offset { get; }
|
private long Offset { get; }
|
||||||
public override long Length { get; }
|
public override long Length { get; }
|
||||||
|
private FileAccess Access { get; } = FileAccess.ReadWrite;
|
||||||
|
|
||||||
public SubStorage(IStorage baseStorage, long offset, long length)
|
public SubStorage(IStorage baseStorage, long offset, long length)
|
||||||
{
|
{
|
||||||
|
@ -16,6 +17,13 @@ namespace LibHac.IO
|
||||||
Length = length;
|
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)
|
public SubStorage(IStorage baseStorage, long offset, long length, bool leaveOpen)
|
||||||
: this(baseStorage, offset, length)
|
: this(baseStorage, offset, length)
|
||||||
{
|
{
|
||||||
|
@ -30,11 +38,13 @@ namespace LibHac.IO
|
||||||
|
|
||||||
protected override void ReadImpl(Span<byte> destination, long offset)
|
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);
|
BaseStorage.Read(destination, offset + Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void WriteImpl(ReadOnlySpan<byte> source, long 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);
|
BaseStorage.Write(source, offset + Offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,13 +52,5 @@ namespace LibHac.IO
|
||||||
{
|
{
|
||||||
BaseStorage.Flush();
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ namespace LibHac
|
||||||
/// <returns>The <see cref="IStorage"/> that provides access to the entire raw NCA file.</returns>
|
/// <returns>The <see cref="IStorage"/> that provides access to the entire raw NCA file.</returns>
|
||||||
public IStorage GetStorage()
|
public IStorage GetStorage()
|
||||||
{
|
{
|
||||||
return BaseStorage.WithAccess(FileAccess.Read);
|
return BaseStorage.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanOpenSection(int index)
|
public bool CanOpenSection(int index)
|
||||||
|
|
|
@ -46,8 +46,7 @@ namespace NandReaderGui.ViewModel
|
||||||
{
|
{
|
||||||
DiskInfo disk = SelectedDisk;
|
DiskInfo disk = SelectedDisk;
|
||||||
var storage = new CachedStorage(new DeviceStream(disk.PhysicalName, disk.Length).AsStorage(), disk.SectorSize * 100, 4, true);
|
var storage = new CachedStorage(new DeviceStream(disk.PhysicalName, disk.Length).AsStorage(), disk.SectorSize * 100, 4, true);
|
||||||
storage.SetReadOnly();
|
Stream stream = storage.AsStream(FileAccess.Read);
|
||||||
Stream stream = storage.AsStream();
|
|
||||||
|
|
||||||
Keyset keyset = OpenKeyset();
|
Keyset keyset = OpenKeyset();
|
||||||
var nand = new Nand(stream, keyset);
|
var nand = new Nand(stream, keyset);
|
||||||
|
|
Loading…
Reference in a new issue