mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Use SharedStreams with savefile reading. Fixes #4
This commit is contained in:
parent
26bf0876cb
commit
80cf0b43fb
5 changed files with 89 additions and 97 deletions
|
@ -437,31 +437,26 @@ namespace hactoolnet
|
||||||
var dir = ctx.Options.DebugOutDir;
|
var dir = ctx.Options.DebugOutDir;
|
||||||
Directory.CreateDirectory(dir);
|
Directory.CreateDirectory(dir);
|
||||||
|
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L0_0_DuplexL1A"), save.DuplexL1A);
|
File.WriteAllBytes(Path.Combine(dir, "L1_0_MasterHashA"), save.Header.MasterHashA);
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L0_1_DuplexL1B"), save.DuplexL1B);
|
File.WriteAllBytes(Path.Combine(dir, "L1_1_MasterHashB"), save.Header.MasterHashB);
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L0_2_DuplexDataA"), save.DuplexDataA);
|
File.WriteAllBytes(Path.Combine(dir, "L1_2_DuplexMasterA"), save.Header.DuplexMasterA);
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L0_3_DuplexDataB"), save.DuplexDataB);
|
File.WriteAllBytes(Path.Combine(dir, "L1_3_DuplexMasterB"), save.Header.DuplexMasterB);
|
||||||
|
save.DuplexL1A.WriteAllBytes(Path.Combine(dir, "L0_0_DuplexL1A"), ctx.Logger);
|
||||||
|
save.DuplexL1B.WriteAllBytes(Path.Combine(dir, "L0_1_DuplexL1B"), ctx.Logger);
|
||||||
|
save.DuplexDataA.WriteAllBytes(Path.Combine(dir, "L0_2_DuplexDataA"), ctx.Logger);
|
||||||
|
save.DuplexDataB.WriteAllBytes(Path.Combine(dir, "L0_3_DuplexDataB"), ctx.Logger);
|
||||||
|
save.JournalData.WriteAllBytes(Path.Combine(dir, "L0_4_JournalData"), ctx.Logger);
|
||||||
|
|
||||||
save.FileRemap.Position = layout.JournalDataOffset;
|
save.JournalTable.WriteAllBytes(Path.Combine(dir, "L1_0_JournalTable"), ctx.Logger);
|
||||||
using (var outFile = new FileStream(Path.Combine(dir, "L0_4_JournalData"), FileMode.Create, FileAccess.Write))
|
save.JournalBitmapUpdatedPhysical.WriteAllBytes(Path.Combine(dir, "L1_1_JournalBitmapUpdatedPhysical"), ctx.Logger);
|
||||||
{
|
save.JournalBitmapUpdatedVirtual.WriteAllBytes(Path.Combine(dir, "L1_2_JournalBitmapUpdatedVirtual"), ctx.Logger);
|
||||||
save.FileRemap.CopyStream(outFile, layout.JournalDataSizeB + layout.SizeReservedArea);
|
save.JournalBitmapUnassigned.WriteAllBytes(Path.Combine(dir, "L1_3_JournalBitmapUnassigned"), ctx.Logger);
|
||||||
}
|
save.JournalLayer1Hash.WriteAllBytes(Path.Combine(dir, "L1_4_Layer1Hash"), ctx.Logger);
|
||||||
|
save.JournalLayer2Hash.WriteAllBytes(Path.Combine(dir, "L1_5_Layer2Hash"), ctx.Logger);
|
||||||
|
save.JournalLayer3Hash.WriteAllBytes(Path.Combine(dir, "L1_6_Layer3Hash"), ctx.Logger);
|
||||||
|
save.JournalFat.WriteAllBytes(Path.Combine(dir, "L1_7_FAT"), ctx.Logger);
|
||||||
|
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L1_0_JournalTable"), save.JournalTable);
|
save.JournalStreamSource.CreateStream().WriteAllBytes(Path.Combine(dir, "L2_0_SaveData"), ctx.Logger);
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L1_1_JournalBitmapUpdatedPhysical"), save.JournalBitmapUpdatedPhysical);
|
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L1_2_JournalBitmapUpdatedVirtual"), save.JournalBitmapUpdatedVirtual);
|
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L1_3_JournalBitmapUnassigned"), save.JournalBitmapUnassigned);
|
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L1_4_Layer1Hash"), save.JournalLayer1Hash);
|
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L1_5_Layer2Hash"), save.JournalLayer2Hash);
|
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L1_6_Layer3Hash"), save.JournalLayer3Hash);
|
|
||||||
File.WriteAllBytes(Path.Combine(dir, "L1_7_FAT"), save.JournalFat);
|
|
||||||
|
|
||||||
save.JournalStream.Position = 0;
|
|
||||||
using (var outFile = new FileStream(Path.Combine(dir, "L2_0_SaveData"), FileMode.Create, FileAccess.Write))
|
|
||||||
{
|
|
||||||
save.JournalStream.CopyStream(outFile, save.JournalStream.Length);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,11 @@ namespace libhac.Savefile
|
||||||
public MapEntry[] FileMapEntries { get; set; }
|
public MapEntry[] FileMapEntries { get; set; }
|
||||||
public MapEntry[] MetaMapEntries { get; set; }
|
public MapEntry[] MetaMapEntries { get; set; }
|
||||||
|
|
||||||
|
public byte[] MasterHashA { get; }
|
||||||
|
public byte[] MasterHashB { get; }
|
||||||
|
public byte[] DuplexMasterA { get; }
|
||||||
|
public byte[] DuplexMasterB { get; }
|
||||||
|
|
||||||
public byte[] Data { get; }
|
public byte[] Data { get; }
|
||||||
|
|
||||||
public Header(BinaryReader reader, IProgressReport logger = null)
|
public Header(BinaryReader reader, IProgressReport logger = null)
|
||||||
|
@ -40,6 +45,16 @@ namespace libhac.Savefile
|
||||||
reader.BaseStream.Position = 0x690;
|
reader.BaseStream.Position = 0x690;
|
||||||
MetaRemap = new RemapHeader(reader);
|
MetaRemap = new RemapHeader(reader);
|
||||||
|
|
||||||
|
reader.BaseStream.Position = Layout.MasterHashOffset0;
|
||||||
|
MasterHashA = reader.ReadBytes((int) Layout.MasterHashSize);
|
||||||
|
reader.BaseStream.Position = Layout.MasterHashOffset1;
|
||||||
|
MasterHashB = reader.ReadBytes((int) Layout.MasterHashSize);
|
||||||
|
|
||||||
|
reader.BaseStream.Position = Layout.L1BitmapOffset0;
|
||||||
|
DuplexMasterA = reader.ReadBytes((int) Layout.L1BitmapSize);
|
||||||
|
reader.BaseStream.Position = Layout.L1BitmapOffset1;
|
||||||
|
DuplexMasterB = reader.ReadBytes((int) Layout.L1BitmapSize);
|
||||||
|
|
||||||
reader.BaseStream.Position = Layout.FileMapEntryOffset;
|
reader.BaseStream.Position = Layout.FileMapEntryOffset;
|
||||||
FileMapEntries = new MapEntry[FileRemap.MapEntryCount];
|
FileMapEntries = new MapEntry[FileRemap.MapEntryCount];
|
||||||
for (int i = 0; i < FileRemap.MapEntryCount; i++)
|
for (int i = 0; i < FileRemap.MapEntryCount; i++)
|
||||||
|
|
|
@ -81,13 +81,9 @@ namespace libhac.Savefile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MappingEntry[] ReadMappingEntries(byte[] mapTable, byte[] bitmapUpdatedPhysical,
|
public static MappingEntry[] ReadMappingEntries(Stream mapTable, int count)
|
||||||
byte[] bitmapUpdatedVirtual, byte[] bitmapUnassigned, int count)
|
|
||||||
{
|
{
|
||||||
var physicalBits = new BitReader(bitmapUpdatedPhysical);
|
var tableReader = new BinaryReader(mapTable);
|
||||||
var virtualBits = new BitReader(bitmapUpdatedVirtual);
|
|
||||||
var unassignedBits = new BitReader(bitmapUnassigned);
|
|
||||||
var tableReader = new BinaryReader(new MemoryStream(mapTable));
|
|
||||||
var map = new MappingEntry[count];
|
var map = new MappingEntry[count];
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
|
@ -95,10 +91,7 @@ namespace libhac.Savefile
|
||||||
var entry = new MappingEntry
|
var entry = new MappingEntry
|
||||||
{
|
{
|
||||||
VirtualIndex = i,
|
VirtualIndex = i,
|
||||||
PhysicalIndex = tableReader.ReadInt32() & 0x7FFFFFFF,
|
PhysicalIndex = tableReader.ReadInt32() & 0x7FFFFFFF
|
||||||
//UpdatedPhysical = physicalBits.ReadBool(),
|
|
||||||
//UpdatedVirtual = virtualBits.ReadBool(),
|
|
||||||
//Unassigned = unassignedBits.ReadBool()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
map[i] = entry;
|
map[i] = entry;
|
||||||
|
|
|
@ -9,31 +9,33 @@ namespace libhac.Savefile
|
||||||
public class Savefile
|
public class Savefile
|
||||||
{
|
{
|
||||||
public Header Header { get; }
|
public Header Header { get; }
|
||||||
public RemapStream FileRemap { get; }
|
private RemapStream FileRemap { get; }
|
||||||
public RemapStream MetaRemap { get; }
|
public SharedStreamSource FileRemapSource { get; }
|
||||||
private Stream FileStream { get; }
|
private RemapStream MetaRemap { get; }
|
||||||
public JournalStream JournalStream { get; }
|
public SharedStreamSource MetaRemapSource { get; }
|
||||||
|
private JournalStream JournalStream { get; }
|
||||||
|
public SharedStreamSource JournalStreamSource { get; }
|
||||||
|
|
||||||
public byte[] DuplexL1A { get; }
|
public Stream DuplexL1A { get; }
|
||||||
public byte[] DuplexL1B { get; }
|
public Stream DuplexL1B { get; }
|
||||||
public byte[] DuplexDataA { get; }
|
public Stream DuplexDataA { get; }
|
||||||
public byte[] DuplexDataB { get; }
|
public Stream DuplexDataB { get; }
|
||||||
|
public Stream JournalData { get; }
|
||||||
|
|
||||||
public byte[] JournalTable { get; }
|
public Stream JournalTable { get; }
|
||||||
public byte[] JournalBitmapUpdatedPhysical { get; }
|
public Stream JournalBitmapUpdatedPhysical { get; }
|
||||||
public byte[] JournalBitmapUpdatedVirtual { get; }
|
public Stream JournalBitmapUpdatedVirtual { get; }
|
||||||
public byte[] JournalBitmapUnassigned { get; }
|
public Stream JournalBitmapUnassigned { get; }
|
||||||
public byte[] JournalLayer1Hash { get; }
|
public Stream JournalLayer1Hash { get; }
|
||||||
public byte[] JournalLayer2Hash { get; }
|
public Stream JournalLayer2Hash { get; }
|
||||||
public byte[] JournalLayer3Hash { get; }
|
public Stream JournalLayer3Hash { get; }
|
||||||
public byte[] JournalFat { get; }
|
public Stream JournalFat { get; }
|
||||||
|
|
||||||
public FileEntry[] Files { get; private set; }
|
public FileEntry[] Files { get; private set; }
|
||||||
private Dictionary<string, FileEntry> FileDict { get; }
|
private Dictionary<string, FileEntry> FileDict { get; }
|
||||||
|
|
||||||
public Savefile(Stream file, IProgressReport logger = null)
|
public Savefile(Stream file, IProgressReport logger = null)
|
||||||
{
|
{
|
||||||
FileStream = file;
|
|
||||||
using (var reader = new BinaryReader(file, Encoding.Default, true))
|
using (var reader = new BinaryReader(file, Encoding.Default, true))
|
||||||
{
|
{
|
||||||
Header = new Header(reader, logger);
|
Header = new Header(reader, logger);
|
||||||
|
@ -42,56 +44,33 @@ namespace libhac.Savefile
|
||||||
new SubStream(file, layout.FileMapDataOffset, layout.FileMapDataSize),
|
new SubStream(file, layout.FileMapDataOffset, layout.FileMapDataSize),
|
||||||
Header.FileMapEntries, Header.FileRemap.MapSegmentCount);
|
Header.FileMapEntries, Header.FileRemap.MapSegmentCount);
|
||||||
|
|
||||||
DuplexL1A = new byte[layout.DuplexL1Size];
|
FileRemapSource = new SharedStreamSource(FileRemap);
|
||||||
DuplexL1B = new byte[layout.DuplexL1Size];
|
|
||||||
DuplexDataA = new byte[layout.DuplexDataSize];
|
|
||||||
DuplexDataB = new byte[layout.DuplexDataSize];
|
|
||||||
|
|
||||||
FileRemap.Position = layout.DuplexL1OffsetA;
|
DuplexL1A = FileRemapSource.CreateStream(layout.DuplexL1OffsetA, layout.DuplexL1Size);
|
||||||
FileRemap.Read(DuplexL1A, 0, DuplexL1A.Length);
|
DuplexL1B = FileRemapSource.CreateStream(layout.DuplexL1OffsetB, layout.DuplexL1Size);
|
||||||
FileRemap.Position = layout.DuplexL1OffsetB;
|
DuplexDataA = FileRemapSource.CreateStream(layout.DuplexDataOffsetA, layout.DuplexDataSize);
|
||||||
FileRemap.Read(DuplexL1B, 0, DuplexL1B.Length);
|
DuplexDataB = FileRemapSource.CreateStream(layout.DuplexDataOffsetB, layout.DuplexDataSize);
|
||||||
FileRemap.Position = layout.DuplexDataOffsetA;
|
JournalData = FileRemapSource.CreateStream(layout.JournalDataOffset, layout.JournalDataSizeB + layout.SizeReservedArea);
|
||||||
FileRemap.Read(DuplexDataA, 0, DuplexDataA.Length);
|
|
||||||
FileRemap.Position = layout.DuplexDataOffsetB;
|
|
||||||
FileRemap.Read(DuplexDataB, 0, DuplexDataB.Length);
|
|
||||||
|
|
||||||
var duplexDataOffset = layout.DuplexIndex == 0 ? layout.DuplexDataOffsetA : layout.DuplexDataOffsetB;
|
var duplexData = layout.DuplexIndex == 0 ? DuplexDataA : DuplexDataB;
|
||||||
var duplexData = new SubStream(FileRemap, duplexDataOffset, layout.DuplexDataSize);
|
|
||||||
MetaRemap = new RemapStream(duplexData, Header.MetaMapEntries, Header.MetaRemap.MapSegmentCount);
|
MetaRemap = new RemapStream(duplexData, Header.MetaMapEntries, Header.MetaRemap.MapSegmentCount);
|
||||||
|
MetaRemapSource = new SharedStreamSource(MetaRemap);
|
||||||
|
|
||||||
JournalTable = new byte[layout.JournalTableSize];
|
JournalTable = MetaRemapSource.CreateStream(layout.JournalTableOffset, layout.JournalTableSize);
|
||||||
JournalBitmapUpdatedPhysical = new byte[layout.JournalBitmapUpdatedPhysicalSize];
|
JournalBitmapUpdatedPhysical = MetaRemapSource.CreateStream(layout.JournalBitmapUpdatedPhysicalOffset, layout.JournalBitmapUpdatedPhysicalSize);
|
||||||
JournalBitmapUpdatedVirtual = new byte[layout.JournalBitmapUpdatedVirtualSize];
|
JournalBitmapUpdatedVirtual = MetaRemapSource.CreateStream(layout.JournalBitmapUpdatedVirtualOffset, layout.JournalBitmapUpdatedVirtualSize);
|
||||||
JournalBitmapUnassigned = new byte[layout.JournalBitmapUnassignedSize];
|
JournalBitmapUnassigned = MetaRemapSource.CreateStream(layout.JournalBitmapUnassignedOffset, layout.JournalBitmapUnassignedSize);
|
||||||
JournalLayer1Hash = new byte[layout.Layer1HashSize];
|
JournalLayer1Hash = MetaRemapSource.CreateStream(layout.Layer1HashOffset, layout.Layer1HashSize);
|
||||||
JournalLayer2Hash = new byte[layout.Layer2HashSize];
|
JournalLayer2Hash = MetaRemapSource.CreateStream(layout.Layer2HashOffset, layout.Layer2HashSize);
|
||||||
JournalLayer3Hash = new byte[layout.Layer3HashSize];
|
JournalLayer3Hash = MetaRemapSource.CreateStream(layout.Layer3HashOffset, layout.Layer3HashSize);
|
||||||
JournalFat = new byte[layout.Field150];
|
JournalFat = MetaRemapSource.CreateStream(layout.Field148, layout.Field150);
|
||||||
|
|
||||||
MetaRemap.Position = layout.JournalTableOffset;
|
var journalMap = JournalStream.ReadMappingEntries(JournalTable, Header.Journal.MappingEntryCount);
|
||||||
MetaRemap.Read(JournalTable, 0, JournalTable.Length);
|
|
||||||
MetaRemap.Position = layout.JournalBitmapUpdatedPhysicalOffset;
|
|
||||||
MetaRemap.Read(JournalBitmapUpdatedPhysical, 0, JournalBitmapUpdatedPhysical.Length);
|
|
||||||
MetaRemap.Position = layout.JournalBitmapUpdatedVirtualOffset;
|
|
||||||
MetaRemap.Read(JournalBitmapUpdatedVirtual, 0, JournalBitmapUpdatedVirtual.Length);
|
|
||||||
MetaRemap.Position = layout.JournalBitmapUnassignedOffset;
|
|
||||||
MetaRemap.Read(JournalBitmapUnassigned, 0, JournalBitmapUnassigned.Length);
|
|
||||||
MetaRemap.Position = layout.Layer1HashOffset;
|
|
||||||
MetaRemap.Read(JournalLayer1Hash, 0, JournalLayer1Hash.Length);
|
|
||||||
MetaRemap.Position = layout.Layer2HashOffset;
|
|
||||||
MetaRemap.Read(JournalLayer2Hash, 0, JournalLayer2Hash.Length);
|
|
||||||
MetaRemap.Position = layout.Layer3HashOffset;
|
|
||||||
MetaRemap.Read(JournalLayer3Hash, 0, JournalLayer3Hash.Length);
|
|
||||||
MetaRemap.Position = layout.Field148;
|
|
||||||
MetaRemap.Read(JournalFat, 0, JournalFat.Length);
|
|
||||||
|
|
||||||
var journalMap = JournalStream.ReadMappingEntries(JournalTable, JournalBitmapUpdatedPhysical,
|
var journalData = FileRemapSource.CreateStream(layout.JournalDataOffset,
|
||||||
JournalBitmapUpdatedVirtual, JournalBitmapUnassigned, Header.Journal.MappingEntryCount);
|
|
||||||
|
|
||||||
var journalData = new SubStream(FileRemap, layout.JournalDataOffset,
|
|
||||||
layout.JournalDataSizeB + layout.SizeReservedArea);
|
layout.JournalDataSizeB + layout.SizeReservedArea);
|
||||||
JournalStream = new JournalStream(journalData, journalMap, (int)Header.Journal.BlockSize);
|
JournalStream = new JournalStream(journalData, journalMap, (int)Header.Journal.BlockSize);
|
||||||
|
JournalStreamSource = new SharedStreamSource(JournalStream);
|
||||||
ReadFileInfo();
|
ReadFileInfo();
|
||||||
Dictionary<string, FileEntry> dictionary = new Dictionary<string, FileEntry>();
|
Dictionary<string, FileEntry> dictionary = new Dictionary<string, FileEntry>();
|
||||||
foreach (FileEntry entry in Files)
|
foreach (FileEntry entry in Files)
|
||||||
|
@ -115,7 +94,7 @@ namespace libhac.Savefile
|
||||||
|
|
||||||
public Stream OpenFile(FileEntry file)
|
public Stream OpenFile(FileEntry file)
|
||||||
{
|
{
|
||||||
return new SubStream(JournalStream, file.Offset, file.Size);
|
return JournalStreamSource.CreateStream(file.Offset, file.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool FileExists(string filename) => FileDict.ContainsKey(filename);
|
public bool FileExists(string filename) => FileDict.ContainsKey(filename);
|
||||||
|
@ -128,12 +107,12 @@ namespace libhac.Savefile
|
||||||
|
|
||||||
FileEntry[] dirEntries;
|
FileEntry[] dirEntries;
|
||||||
FileEntry[] fileEntries;
|
FileEntry[] fileEntries;
|
||||||
using (var reader = new BinaryReader(JournalStream, Encoding.Default, true))
|
using (var reader = new BinaryReader(JournalStreamSource.CreateStream(), Encoding.Default, true))
|
||||||
{
|
{
|
||||||
JournalStream.Position = dirOffset;
|
reader.BaseStream.Position = dirOffset;
|
||||||
dirEntries = ReadFileEntries(reader);
|
dirEntries = ReadFileEntries(reader);
|
||||||
|
|
||||||
JournalStream.Position = fileOffset;
|
reader.BaseStream.Position = fileOffset;
|
||||||
fileEntries = ReadFileEntries(reader);
|
fileEntries = ReadFileEntries(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +140,7 @@ namespace libhac.Savefile
|
||||||
private FileEntry[] ReadFileEntries(BinaryReader reader)
|
private FileEntry[] ReadFileEntries(BinaryReader reader)
|
||||||
{
|
{
|
||||||
var count = reader.ReadInt32();
|
var count = reader.ReadInt32();
|
||||||
JournalStream.Position -= 4;
|
reader.BaseStream.Position -= 4;
|
||||||
|
|
||||||
var entries = new FileEntry[count];
|
var entries = new FileEntry[count];
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
|
|
|
@ -78,6 +78,16 @@ namespace libhac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void WriteAllBytes(this Stream input, string filename, IProgressReport progress = null)
|
||||||
|
{
|
||||||
|
input.Position = 0;
|
||||||
|
|
||||||
|
using (var outFile = new FileStream(filename, FileMode.Create, FileAccess.Write))
|
||||||
|
{
|
||||||
|
input.CopyStream(outFile, input.Length, progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string ReadAsciiZ(this BinaryReader reader, int maxLength = int.MaxValue)
|
public static string ReadAsciiZ(this BinaryReader reader, int maxLength = int.MaxValue)
|
||||||
{
|
{
|
||||||
var start = reader.BaseStream.Position;
|
var start = reader.BaseStream.Position;
|
||||||
|
|
Loading…
Reference in a new issue