Move some logic to AllocationTable

This commit is contained in:
Alex Barney 2019-04-03 16:55:14 -05:00
parent 6112e35eb2
commit d7dd540b21
2 changed files with 77 additions and 58 deletions

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -13,6 +14,9 @@ namespace LibHac.IO.Save
public AllocationTableHeader Header { get; } public AllocationTableHeader Header { get; }
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
public AllocationTable(IStorage storage, IStorage header) public AllocationTable(IStorage storage, IStorage header)
{ {
BaseStorage = storage; BaseStorage = storage;
@ -20,20 +24,68 @@ namespace LibHac.IO.Save
Header = new AllocationTableHeader(HeaderStorage); Header = new AllocationTableHeader(HeaderStorage);
} }
public void ReadEntry(int index, out AllocationTableEntry entry) public void ReadEntry(int blockIndex, out int next, out int previous, out int length)
{
int entryIndex = BlockToEntryIndex(blockIndex);
Span<AllocationTableEntry> entries = stackalloc AllocationTableEntry[2];
ReadEntries(entryIndex, entries);
if (entries[0].IsSingleBlockSegment())
{
length = 1;
}
else
{
length = entries[1].Next - entryIndex;
}
if (entries[0].IsListEnd())
{
next = -1;
}
else
{
next = EntryIndexToBlock(entries[0].Next & 0x7FFFFFFF);
}
if (entries[0].IsListStart())
{
previous = -1;
}
else
{
previous = EntryIndexToBlock(entries[0].Prev & 0x7FFFFFFF);
}
}
private void ReadEntries(int entryIndex, Span<AllocationTableEntry> entries)
{
Debug.Assert(entries.Length >= 2);
bool isLastBlock = entryIndex == BlockToEntryIndex(Header.AllocationTableBlockCount) - 1;
int entriesToRead = isLastBlock ? 1 : 2;
int offset = entryIndex * EntrySize;
Span<byte> buffer = MemoryMarshal.Cast<AllocationTableEntry, byte>(entries.Slice(0, entriesToRead));
BaseStorage.Read(buffer, offset);
}
private void ReadEntry(int entryIndex, out AllocationTableEntry entry)
{ {
Span<byte> bytes = stackalloc byte[EntrySize]; Span<byte> bytes = stackalloc byte[EntrySize];
int offset = index * EntrySize; int offset = entryIndex * EntrySize;
BaseStorage.Read(bytes, offset); BaseStorage.Read(bytes, offset);
entry = GetEntryFromBytes(bytes); entry = GetEntryFromBytes(bytes);
} }
public void WriteEntry(int index, ref AllocationTableEntry entry) private void WriteEntry(int entryIndex, ref AllocationTableEntry entry)
{ {
Span<byte> bytes = stackalloc byte[EntrySize]; Span<byte> bytes = stackalloc byte[EntrySize];
int offset = index * EntrySize; int offset = entryIndex * EntrySize;
ref AllocationTableEntry newEntry = ref GetEntryFromBytes(bytes); ref AllocationTableEntry newEntry = ref GetEntryFromBytes(bytes);
newEntry = entry; newEntry = entry;
@ -41,13 +93,13 @@ namespace LibHac.IO.Save
BaseStorage.Write(bytes, offset); BaseStorage.Write(bytes, offset);
} }
private ref AllocationTableEntry GetEntryFromBytes(Span<byte> entry) private static ref AllocationTableEntry GetEntryFromBytes(Span<byte> entry)
{ {
return ref MemoryMarshal.Cast<byte, AllocationTableEntry>(entry)[0]; return ref MemoryMarshal.Cast<byte, AllocationTableEntry>(entry)[0];
} }
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); private static int EntryIndexToBlock(int entryIndex) => entryIndex - 1;
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); private static int BlockToEntryIndex(int blockIndex) => blockIndex + 1;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
@ -81,7 +133,7 @@ namespace LibHac.IO.Save
{ {
public long BlockSize { get; } public long BlockSize { get; }
public long AllocationTableOffset { get; } public long AllocationTableOffset { get; }
public long AllocationTableBlockCount { get; } public int AllocationTableBlockCount { get; }
public long DataOffset { get; } public long DataOffset { get; }
public long DataBlockCount { get; } public long DataBlockCount { get; }
public int DirectoryTableBlock { get; } public int DirectoryTableBlock { get; }

View file

@ -8,7 +8,11 @@ namespace LibHac.IO.Save
public int VirtualBlock { get; private set; } public int VirtualBlock { get; private set; }
public int PhysicalBlock { get; private set; } public int PhysicalBlock { get; private set; }
public int CurrentSegmentSize { get; private set; } public int CurrentSegmentSize => _currentSegmentSize;
private int _nextBlock;
private int _prevBlock;
private int _currentSegmentSize;
public AllocationTableIterator(AllocationTable table, int initialBlock) public AllocationTableIterator(AllocationTable table, int initialBlock)
{ {
@ -22,71 +26,34 @@ namespace LibHac.IO.Save
public bool BeginIteration(int initialBlock) public bool BeginIteration(int initialBlock)
{ {
Fat.ReadEntry(initialBlock + 1, out AllocationTableEntry tableEntry);
if (!tableEntry.IsListStart() && initialBlock != -1)
{
return false;
}
if (tableEntry.IsSingleBlockSegment())
{
CurrentSegmentSize = 1;
}
else
{
Fat.ReadEntry(initialBlock + 2, out AllocationTableEntry lengthEntry);
CurrentSegmentSize = lengthEntry.Next - initialBlock;
}
PhysicalBlock = initialBlock; PhysicalBlock = initialBlock;
Fat.ReadEntry(initialBlock, out _nextBlock, out _prevBlock, out _currentSegmentSize);
return true; return _prevBlock == -1;
} }
public bool MoveNext() public bool MoveNext()
{ {
Fat.ReadEntry(PhysicalBlock + 1, out AllocationTableEntry currentEntry); if (_nextBlock == -1) return false;
if (currentEntry.IsListEnd()) return false;
int newBlock = currentEntry.Next & 0x7FFFFFFF;
Fat.ReadEntry(newBlock, out AllocationTableEntry newEntry); VirtualBlock += _currentSegmentSize;
VirtualBlock += CurrentSegmentSize; PhysicalBlock = _nextBlock;
if (newEntry.IsSingleBlockSegment()) Fat.ReadEntry(_nextBlock, out _nextBlock, out _prevBlock, out _currentSegmentSize);
{
CurrentSegmentSize = 1;
}
else
{
Fat.ReadEntry(newBlock + 1, out AllocationTableEntry lengthEntry);
CurrentSegmentSize = lengthEntry.Next - (newBlock - 1);
}
PhysicalBlock = newBlock - 1;
return true; return true;
} }
public bool MovePrevious() public bool MovePrevious()
{ {
Fat.ReadEntry(PhysicalBlock + 1, out AllocationTableEntry currentEntry); if (_prevBlock == -1) return false;
if (currentEntry.IsListStart()) return false;
int newBlock = currentEntry.Prev & 0x7FFFFFFF;
Fat.ReadEntry(newBlock, out AllocationTableEntry newEntry); PhysicalBlock = _prevBlock;
if (newEntry.IsSingleBlockSegment()) Fat.ReadEntry(_prevBlock, out _nextBlock, out _prevBlock, out _currentSegmentSize);
{
CurrentSegmentSize = 1;
}
else
{
Fat.ReadEntry(newBlock + 1, out AllocationTableEntry lengthEntry);
CurrentSegmentSize = lengthEntry.Next - (newBlock - 1);
}
VirtualBlock -= CurrentSegmentSize; VirtualBlock -= _currentSegmentSize;
PhysicalBlock = newBlock - 1;
return true; return true;
} }