mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Read directly from save allocation table when requested
This commit is contained in:
parent
90fc0e096c
commit
6112e35eb2
2 changed files with 39 additions and 26 deletions
|
@ -1,13 +1,16 @@
|
||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace LibHac.IO.Save
|
namespace LibHac.IO.Save
|
||||||
{
|
{
|
||||||
public class AllocationTable
|
public class AllocationTable
|
||||||
{
|
{
|
||||||
|
private const int EntrySize = 8;
|
||||||
|
|
||||||
private IStorage BaseStorage { get; }
|
private IStorage BaseStorage { get; }
|
||||||
private IStorage HeaderStorage { get; }
|
private IStorage HeaderStorage { get; }
|
||||||
|
|
||||||
public AllocationTableEntry[] Entries { get; }
|
|
||||||
public AllocationTableHeader Header { get; }
|
public AllocationTableHeader Header { get; }
|
||||||
|
|
||||||
public AllocationTable(IStorage storage, IStorage header)
|
public AllocationTable(IStorage storage, IStorage header)
|
||||||
|
@ -15,33 +18,43 @@ namespace LibHac.IO.Save
|
||||||
BaseStorage = storage;
|
BaseStorage = storage;
|
||||||
HeaderStorage = header;
|
HeaderStorage = header;
|
||||||
Header = new AllocationTableHeader(HeaderStorage);
|
Header = new AllocationTableHeader(HeaderStorage);
|
||||||
|
}
|
||||||
|
|
||||||
Stream tableStream = storage.AsStream();
|
public void ReadEntry(int index, out AllocationTableEntry entry)
|
||||||
|
{
|
||||||
|
Span<byte> bytes = stackalloc byte[EntrySize];
|
||||||
|
int offset = index * EntrySize;
|
||||||
|
|
||||||
// The first entry in the table is reserved. Block 0 is at table index 1
|
BaseStorage.Read(bytes, offset);
|
||||||
int blockCount = (int)(Header.AllocationTableBlockCount) + 1;
|
|
||||||
|
|
||||||
Entries = new AllocationTableEntry[blockCount];
|
entry = GetEntryFromBytes(bytes);
|
||||||
tableStream.Position = 0;
|
}
|
||||||
var reader = new BinaryReader(tableStream);
|
|
||||||
|
|
||||||
for (int i = 0; i < blockCount; i++)
|
public void WriteEntry(int index, ref AllocationTableEntry entry)
|
||||||
{
|
{
|
||||||
int parent = reader.ReadInt32();
|
Span<byte> bytes = stackalloc byte[EntrySize];
|
||||||
int child = reader.ReadInt32();
|
int offset = index * EntrySize;
|
||||||
|
|
||||||
Entries[i] = new AllocationTableEntry { Next = child, Prev = parent };
|
ref AllocationTableEntry newEntry = ref GetEntryFromBytes(bytes);
|
||||||
}
|
newEntry = entry;
|
||||||
|
|
||||||
|
BaseStorage.Write(bytes, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ref AllocationTableEntry GetEntryFromBytes(Span<byte> entry)
|
||||||
|
{
|
||||||
|
return ref MemoryMarshal.Cast<byte, AllocationTableEntry>(entry)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
|
||||||
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AllocationTableEntry
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct AllocationTableEntry
|
||||||
{
|
{
|
||||||
public int Prev { get; set; }
|
public int Prev;
|
||||||
public int Next { get; set; }
|
public int Next;
|
||||||
|
|
||||||
public bool IsListStart()
|
public bool IsListStart()
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,11 +22,11 @@ namespace LibHac.IO.Save
|
||||||
|
|
||||||
public bool BeginIteration(int initialBlock)
|
public bool BeginIteration(int initialBlock)
|
||||||
{
|
{
|
||||||
AllocationTableEntry tableEntry = Fat.Entries[initialBlock + 1];
|
Fat.ReadEntry(initialBlock + 1, out AllocationTableEntry tableEntry);
|
||||||
|
|
||||||
if (!tableEntry.IsListStart() && initialBlock != -1)
|
if (!tableEntry.IsListStart() && initialBlock != -1)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tableEntry.IsSingleBlockSegment())
|
if (tableEntry.IsSingleBlockSegment())
|
||||||
|
@ -35,7 +35,7 @@ namespace LibHac.IO.Save
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AllocationTableEntry lengthEntry = Fat.Entries[initialBlock + 2];
|
Fat.ReadEntry(initialBlock + 2, out AllocationTableEntry lengthEntry);
|
||||||
CurrentSegmentSize = lengthEntry.Next - initialBlock;
|
CurrentSegmentSize = lengthEntry.Next - initialBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,11 +46,11 @@ namespace LibHac.IO.Save
|
||||||
|
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
AllocationTableEntry currentEntry = Fat.Entries[PhysicalBlock + 1];
|
Fat.ReadEntry(PhysicalBlock + 1, out AllocationTableEntry currentEntry);
|
||||||
if (currentEntry.IsListEnd()) return false;
|
if (currentEntry.IsListEnd()) return false;
|
||||||
int newBlock = currentEntry.Next & 0x7FFFFFFF;
|
int newBlock = currentEntry.Next & 0x7FFFFFFF;
|
||||||
|
|
||||||
AllocationTableEntry newEntry = Fat.Entries[newBlock];
|
Fat.ReadEntry(newBlock, out AllocationTableEntry newEntry);
|
||||||
VirtualBlock += CurrentSegmentSize;
|
VirtualBlock += CurrentSegmentSize;
|
||||||
|
|
||||||
if (newEntry.IsSingleBlockSegment())
|
if (newEntry.IsSingleBlockSegment())
|
||||||
|
@ -59,7 +59,7 @@ namespace LibHac.IO.Save
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AllocationTableEntry lengthEntry = Fat.Entries[newBlock + 1];
|
Fat.ReadEntry(newBlock + 1, out AllocationTableEntry lengthEntry);
|
||||||
CurrentSegmentSize = lengthEntry.Next - (newBlock - 1);
|
CurrentSegmentSize = lengthEntry.Next - (newBlock - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,11 +69,11 @@ namespace LibHac.IO.Save
|
||||||
|
|
||||||
public bool MovePrevious()
|
public bool MovePrevious()
|
||||||
{
|
{
|
||||||
AllocationTableEntry currentEntry = Fat.Entries[PhysicalBlock + 1];
|
Fat.ReadEntry(PhysicalBlock + 1, out AllocationTableEntry currentEntry);
|
||||||
if (currentEntry.IsListStart()) return false;
|
if (currentEntry.IsListStart()) return false;
|
||||||
int newBlock = currentEntry.Prev & 0x7FFFFFFF;
|
int newBlock = currentEntry.Prev & 0x7FFFFFFF;
|
||||||
|
|
||||||
AllocationTableEntry newEntry = Fat.Entries[newBlock];
|
Fat.ReadEntry(newBlock, out AllocationTableEntry newEntry);
|
||||||
|
|
||||||
if (newEntry.IsSingleBlockSegment())
|
if (newEntry.IsSingleBlockSegment())
|
||||||
{
|
{
|
||||||
|
@ -81,7 +81,7 @@ namespace LibHac.IO.Save
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AllocationTableEntry lengthEntry = Fat.Entries[newBlock + 1];
|
Fat.ReadEntry(newBlock + 1, out AllocationTableEntry lengthEntry);
|
||||||
CurrentSegmentSize = lengthEntry.Next - (newBlock - 1);
|
CurrentSegmentSize = lengthEntry.Next - (newBlock - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue