Add code for printing save FAT chains

This commit is contained in:
Alex Barney 2019-03-08 19:18:38 -06:00
parent 474e1e031e
commit 7bb99ff926
5 changed files with 106 additions and 5 deletions

View file

@ -16,7 +16,7 @@ namespace LibHac.IO.Save
if (!BeginIteration(initialBlock)) if (!BeginIteration(initialBlock))
{ {
throw new ArgumentException($"Attempted to start FAT iteration from an invalid block. ({initialBlock}"); throw new ArgumentException($"Attempted to start FAT iteration from an invalid block. ({initialBlock})");
} }
} }
@ -24,9 +24,9 @@ namespace LibHac.IO.Save
{ {
AllocationTableEntry tableEntry = Fat.Entries[initialBlock + 1]; AllocationTableEntry tableEntry = Fat.Entries[initialBlock + 1];
if (!tableEntry.IsListStart()) if (!tableEntry.IsListStart() && initialBlock != -1)
{ {
return false; return false;
} }
if (tableEntry.IsSingleBlockSegment()) if (tableEntry.IsSingleBlockSegment())

View file

@ -152,6 +152,7 @@ namespace LibHac.IO.Save
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly(); public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly(); public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
public SaveFileEntry GetFileEntry(string path) => FileDictionary[path];
private void ReadFileInfo() private void ReadFileInfo()
{ {

View file

@ -0,0 +1,17 @@
using System.Collections.Generic;
namespace LibHac.IO.Save
{
public static class SaveExtensions
{
public static IEnumerable<(int block, int length)> DumpChain(this AllocationTable table, int startBlock)
{
var iterator = new AllocationTableIterator(table, startBlock);
do
{
yield return (iterator.PhysicalBlock, iterator.CurrentSegmentSize);
} while (iterator.MoveNext());
}
}
}

View file

@ -34,9 +34,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net46' "> <ItemGroup Condition=" '$(TargetFramework)' == 'net46' ">
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Include="System.Memory" Version="4.5.2" />
<PackageReference Include="System.Buffers" Version="4.5.0" /> <PackageReference Include="System.Buffers" Version="4.5.0" />
<PackageReference Include="System.Memory" Version="4.5.2" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' "> <ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">

View file

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -151,6 +152,87 @@ namespace hactoolnet
} }
ctx.Logger.LogMessage(save.Print()); ctx.Logger.LogMessage(save.Print());
//ctx.Logger.LogMessage(PrintFatLayout(save));
}
}
// ReSharper disable once UnusedMember.Local
private static string PrintFatLayout(this SaveDataFileSystem save)
{
var sb = new StringBuilder();
foreach (DirectoryEntry entry in save.EnumerateEntries().Where(x => x.Type == DirectoryEntryType.File))
{
SaveFileEntry saveEntry = save.SaveDataFileSystemCore.GetFileEntry(entry.FullPath);
if (saveEntry.BlockIndex < 0) continue;
IEnumerable<(int block, int length)> chain = save.SaveDataFileSystemCore.AllocationTable.DumpChain(saveEntry.BlockIndex);
sb.AppendLine(entry.FullPath);
sb.AppendLine(PrintBlockChain(chain));
}
sb.AppendLine("Directory Table");
sb.AppendLine(PrintBlockChain(save.SaveDataFileSystemCore.AllocationTable.DumpChain(0)));
sb.AppendLine("File Table");
sb.AppendLine(PrintBlockChain(save.SaveDataFileSystemCore.AllocationTable.DumpChain(1)));
sb.AppendLine("Free blocks");
sb.AppendLine(PrintBlockChain(save.SaveDataFileSystemCore.AllocationTable.DumpChain(-1)));
return sb.ToString();
}
private static string PrintBlockChain(IEnumerable<(int block, int length)> chain)
{
var sb = new StringBuilder();
int segmentCount = 0;
int segmentStart = -1;
int segmentEnd = -1;
foreach ((int block, int length) in chain)
{
if (segmentStart == -1)
{
segmentStart = block;
segmentEnd = block + length - 1;
continue;
}
if (block == segmentEnd + 1)
{
segmentEnd += length;
continue;
}
PrintSegment();
segmentStart = block;
segmentEnd = block + length - 1;
}
PrintSegment();
return sb.ToString();
void PrintSegment()
{
if (segmentCount > 0) sb.Append(", ");
if (segmentStart == segmentEnd)
{
sb.Append(segmentStart);
}
else
{
sb.Append($"{segmentStart}-{segmentEnd}");
}
segmentCount++;
segmentStart = -1;
segmentEnd = -1;
} }
} }