mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Move some logic to AllocationTable
This commit is contained in:
parent
6112e35eb2
commit
d7dd540b21
2 changed files with 77 additions and 58 deletions
|
@ -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; }
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue