diff --git a/src/LibHac/IO/Save/AllocationTableIterator.cs b/src/LibHac/IO/Save/AllocationTableIterator.cs
index 78adec21..e64a6882 100644
--- a/src/LibHac/IO/Save/AllocationTableIterator.cs
+++ b/src/LibHac/IO/Save/AllocationTableIterator.cs
@@ -16,7 +16,7 @@ namespace LibHac.IO.Save
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];
- if (!tableEntry.IsListStart())
+ if (!tableEntry.IsListStart() && initialBlock != -1)
{
- return false;
+ return false;
}
if (tableEntry.IsSingleBlockSegment())
diff --git a/src/LibHac/IO/Save/SaveDataFileSystemCore.cs b/src/LibHac/IO/Save/SaveDataFileSystemCore.cs
index 22a108b3..35a8cdd1 100644
--- a/src/LibHac/IO/Save/SaveDataFileSystemCore.cs
+++ b/src/LibHac/IO/Save/SaveDataFileSystemCore.cs
@@ -152,6 +152,7 @@ namespace LibHac.IO.Save
public IStorage GetBaseStorage() => BaseStorage.AsReadOnly();
public IStorage GetHeaderStorage() => HeaderStorage.AsReadOnly();
+ public SaveFileEntry GetFileEntry(string path) => FileDictionary[path];
private void ReadFileInfo()
{
diff --git a/src/LibHac/IO/Save/SaveExtensions.cs b/src/LibHac/IO/Save/SaveExtensions.cs
new file mode 100644
index 00000000..64d114f8
--- /dev/null
+++ b/src/LibHac/IO/Save/SaveExtensions.cs
@@ -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());
+ }
+ }
+}
diff --git a/src/LibHac/LibHac.csproj b/src/LibHac/LibHac.csproj
index 8f04d210..5e7e8904 100644
--- a/src/LibHac/LibHac.csproj
+++ b/src/LibHac/LibHac.csproj
@@ -34,9 +34,10 @@
-
-
+
+
+
diff --git a/src/hactoolnet/ProcessSave.cs b/src/hactoolnet/ProcessSave.cs
index bd6ed932..a7d70704 100644
--- a/src/hactoolnet/ProcessSave.cs
+++ b/src/hactoolnet/ProcessSave.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
@@ -151,6 +152,87 @@ namespace hactoolnet
}
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;
}
}