mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add joining allocation table lists
This commit is contained in:
parent
d7dd540b21
commit
c89b8be887
1 changed files with 124 additions and 3 deletions
|
@ -59,6 +59,47 @@ namespace LibHac.IO.Save
|
|||
}
|
||||
}
|
||||
|
||||
public void Join(int frontListBlockIndex, int backListBlockIndex)
|
||||
{
|
||||
int frontEntryIndex = BlockToEntryIndex(frontListBlockIndex);
|
||||
int backEntryIndex = BlockToEntryIndex(backListBlockIndex);
|
||||
|
||||
int frontTailIndex = GetListTail(frontEntryIndex);
|
||||
|
||||
AllocationTableEntry frontTail = ReadEntry(frontTailIndex);
|
||||
AllocationTableEntry backHead = ReadEntry(backEntryIndex);
|
||||
|
||||
frontTail.SetNext(backEntryIndex);
|
||||
backHead.SetPrev(frontTailIndex);
|
||||
|
||||
WriteEntry(frontTailIndex, frontTail);
|
||||
WriteEntry(backEntryIndex, backHead);
|
||||
}
|
||||
|
||||
public int GetListLength(int blockIndex)
|
||||
{
|
||||
int index = blockIndex;
|
||||
int totalLength = 0;
|
||||
|
||||
int tableSize = Header.AllocationTableBlockCount;
|
||||
int nodesIterated = 0;
|
||||
|
||||
while (index != -1)
|
||||
{
|
||||
ReadEntry(index, out index, out int _, out int length);
|
||||
|
||||
totalLength += length;
|
||||
nodesIterated++;
|
||||
|
||||
if (nodesIterated > tableSize)
|
||||
{
|
||||
throw new InvalidDataException("Cycle detected in allocation table.");
|
||||
}
|
||||
}
|
||||
|
||||
return totalLength;
|
||||
}
|
||||
|
||||
private void ReadEntries(int entryIndex, Span<AllocationTableEntry> entries)
|
||||
{
|
||||
Debug.Assert(entries.Length >= 2);
|
||||
|
@ -72,17 +113,17 @@ namespace LibHac.IO.Save
|
|||
BaseStorage.Read(buffer, offset);
|
||||
}
|
||||
|
||||
private void ReadEntry(int entryIndex, out AllocationTableEntry entry)
|
||||
private AllocationTableEntry ReadEntry(int entryIndex)
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[EntrySize];
|
||||
int offset = entryIndex * EntrySize;
|
||||
|
||||
BaseStorage.Read(bytes, offset);
|
||||
|
||||
entry = GetEntryFromBytes(bytes);
|
||||
return GetEntryFromBytes(bytes);
|
||||
}
|
||||
|
||||
private void WriteEntry(int entryIndex, ref AllocationTableEntry entry)
|
||||
private void WriteEntry(int entryIndex, AllocationTableEntry entry)
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[EntrySize];
|
||||
int offset = entryIndex * EntrySize;
|
||||
|
@ -93,6 +134,52 @@ namespace LibHac.IO.Save
|
|||
BaseStorage.Write(bytes, offset);
|
||||
}
|
||||
|
||||
private int GetListHead(int entryIndex)
|
||||
{
|
||||
int headIndex = entryIndex;
|
||||
int tableSize = Header.AllocationTableBlockCount;
|
||||
int nodesTraversed = 0;
|
||||
|
||||
AllocationTableEntry entry = ReadEntry(entryIndex);
|
||||
|
||||
while (!entry.IsListStart())
|
||||
{
|
||||
nodesTraversed++;
|
||||
headIndex = entry.Prev & 0x7FFFFFFF;
|
||||
entry = ReadEntry(headIndex);
|
||||
|
||||
if (nodesTraversed > tableSize)
|
||||
{
|
||||
throw new InvalidDataException("Cycle detected in allocation table.");
|
||||
}
|
||||
}
|
||||
|
||||
return headIndex;
|
||||
}
|
||||
|
||||
private int GetListTail(int entryIndex)
|
||||
{
|
||||
int tailIndex = entryIndex;
|
||||
int tableSize = Header.AllocationTableBlockCount;
|
||||
int nodesTraversed = 0;
|
||||
|
||||
AllocationTableEntry entry = ReadEntry(entryIndex);
|
||||
|
||||
while (!entry.IsListEnd())
|
||||
{
|
||||
nodesTraversed++;
|
||||
tailIndex = entry.Next & 0x7FFFFFFF;
|
||||
entry = ReadEntry(tailIndex);
|
||||
|
||||
if (nodesTraversed > tableSize)
|
||||
{
|
||||
throw new InvalidDataException("Cycle detected in allocation table.");
|
||||
}
|
||||
}
|
||||
|
||||
return tailIndex;
|
||||
}
|
||||
|
||||
private static ref AllocationTableEntry GetEntryFromBytes(Span<byte> entry)
|
||||
{
|
||||
return ref MemoryMarshal.Cast<byte, AllocationTableEntry>(entry)[0];
|
||||
|
@ -123,10 +210,44 @@ namespace LibHac.IO.Save
|
|||
return Next < 0;
|
||||
}
|
||||
|
||||
public void MakeMultiBlockSegment()
|
||||
{
|
||||
Next |= unchecked((int)0x80000000);
|
||||
}
|
||||
|
||||
public void MakeSingleBlockSegment()
|
||||
{
|
||||
Next &= 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
public bool IsSingleBlockSegment()
|
||||
{
|
||||
return Next >= 0;
|
||||
}
|
||||
|
||||
public void MakeListStart()
|
||||
{
|
||||
Prev = int.MinValue;
|
||||
}
|
||||
|
||||
public void MakeRangeEntry()
|
||||
{
|
||||
Prev |= unchecked((int)0x80000000);
|
||||
}
|
||||
|
||||
public void SetNext(int value)
|
||||
{
|
||||
Debug.Assert(value >= 0);
|
||||
|
||||
Next = Next & unchecked((int)0x80000000) | value;
|
||||
}
|
||||
|
||||
public void SetPrev(int value)
|
||||
{
|
||||
Debug.Assert(value >= 0);
|
||||
|
||||
Prev = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class AllocationTableHeader
|
||||
|
|
Loading…
Reference in a new issue