From 80cf0b43fbeaae2024aa93fbcea30f0653717190 Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 24 Aug 2018 17:59:45 -0500 Subject: [PATCH] Use SharedStreams with savefile reading. Fixes #4 --- hactoolnet/Program.cs | 41 ++++++-------- libhac/Savefile/Header.cs | 15 +++++ libhac/Savefile/Journal.cs | 13 +---- libhac/Savefile/Savefile.cs | 107 +++++++++++++++--------------------- libhac/Util.cs | 10 ++++ 5 files changed, 89 insertions(+), 97 deletions(-) diff --git a/hactoolnet/Program.cs b/hactoolnet/Program.cs index e3e87ce5..9f9b0661 100644 --- a/hactoolnet/Program.cs +++ b/hactoolnet/Program.cs @@ -437,31 +437,26 @@ namespace hactoolnet var dir = ctx.Options.DebugOutDir; Directory.CreateDirectory(dir); - File.WriteAllBytes(Path.Combine(dir, "L0_0_DuplexL1A"), save.DuplexL1A); - File.WriteAllBytes(Path.Combine(dir, "L0_1_DuplexL1B"), save.DuplexL1B); - File.WriteAllBytes(Path.Combine(dir, "L0_2_DuplexDataA"), save.DuplexDataA); - File.WriteAllBytes(Path.Combine(dir, "L0_3_DuplexDataB"), save.DuplexDataB); + File.WriteAllBytes(Path.Combine(dir, "L1_0_MasterHashA"), save.Header.MasterHashA); + File.WriteAllBytes(Path.Combine(dir, "L1_1_MasterHashB"), save.Header.MasterHashB); + File.WriteAllBytes(Path.Combine(dir, "L1_2_DuplexMasterA"), save.Header.DuplexMasterA); + 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; - using (var outFile = new FileStream(Path.Combine(dir, "L0_4_JournalData"), FileMode.Create, FileAccess.Write)) - { - save.FileRemap.CopyStream(outFile, layout.JournalDataSizeB + layout.SizeReservedArea); - } + save.JournalTable.WriteAllBytes(Path.Combine(dir, "L1_0_JournalTable"), ctx.Logger); + save.JournalBitmapUpdatedPhysical.WriteAllBytes(Path.Combine(dir, "L1_1_JournalBitmapUpdatedPhysical"), ctx.Logger); + save.JournalBitmapUpdatedVirtual.WriteAllBytes(Path.Combine(dir, "L1_2_JournalBitmapUpdatedVirtual"), ctx.Logger); + 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); - 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); - } + save.JournalStreamSource.CreateStream().WriteAllBytes(Path.Combine(dir, "L2_0_SaveData"), ctx.Logger); } } } diff --git a/libhac/Savefile/Header.cs b/libhac/Savefile/Header.cs index 98761ab6..26b638d0 100644 --- a/libhac/Savefile/Header.cs +++ b/libhac/Savefile/Header.cs @@ -16,6 +16,11 @@ namespace libhac.Savefile public MapEntry[] FileMapEntries { 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 Header(BinaryReader reader, IProgressReport logger = null) @@ -40,6 +45,16 @@ namespace libhac.Savefile reader.BaseStream.Position = 0x690; 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; FileMapEntries = new MapEntry[FileRemap.MapEntryCount]; for (int i = 0; i < FileRemap.MapEntryCount; i++) diff --git a/libhac/Savefile/Journal.cs b/libhac/Savefile/Journal.cs index a68359e7..e31cdbaa 100644 --- a/libhac/Savefile/Journal.cs +++ b/libhac/Savefile/Journal.cs @@ -81,13 +81,9 @@ namespace libhac.Savefile } } - public static MappingEntry[] ReadMappingEntries(byte[] mapTable, byte[] bitmapUpdatedPhysical, - byte[] bitmapUpdatedVirtual, byte[] bitmapUnassigned, int count) + public static MappingEntry[] ReadMappingEntries(Stream mapTable, int count) { - var physicalBits = new BitReader(bitmapUpdatedPhysical); - var virtualBits = new BitReader(bitmapUpdatedVirtual); - var unassignedBits = new BitReader(bitmapUnassigned); - var tableReader = new BinaryReader(new MemoryStream(mapTable)); + var tableReader = new BinaryReader(mapTable); var map = new MappingEntry[count]; for (int i = 0; i < count; i++) @@ -95,10 +91,7 @@ namespace libhac.Savefile var entry = new MappingEntry { VirtualIndex = i, - PhysicalIndex = tableReader.ReadInt32() & 0x7FFFFFFF, - //UpdatedPhysical = physicalBits.ReadBool(), - //UpdatedVirtual = virtualBits.ReadBool(), - //Unassigned = unassignedBits.ReadBool() + PhysicalIndex = tableReader.ReadInt32() & 0x7FFFFFFF }; map[i] = entry; diff --git a/libhac/Savefile/Savefile.cs b/libhac/Savefile/Savefile.cs index 43ecc1e1..448c018b 100644 --- a/libhac/Savefile/Savefile.cs +++ b/libhac/Savefile/Savefile.cs @@ -9,31 +9,33 @@ namespace libhac.Savefile public class Savefile { public Header Header { get; } - public RemapStream FileRemap { get; } - public RemapStream MetaRemap { get; } - private Stream FileStream { get; } - public JournalStream JournalStream { get; } + private RemapStream FileRemap { get; } + public SharedStreamSource FileRemapSource { get; } + private RemapStream MetaRemap { get; } + public SharedStreamSource MetaRemapSource { get; } + private JournalStream JournalStream { get; } + public SharedStreamSource JournalStreamSource { get; } - public byte[] DuplexL1A { get; } - public byte[] DuplexL1B { get; } - public byte[] DuplexDataA { get; } - public byte[] DuplexDataB { get; } + public Stream DuplexL1A { get; } + public Stream DuplexL1B { get; } + public Stream DuplexDataA { get; } + public Stream DuplexDataB { get; } + public Stream JournalData { get; } - public byte[] JournalTable { get; } - public byte[] JournalBitmapUpdatedPhysical { get; } - public byte[] JournalBitmapUpdatedVirtual { get; } - public byte[] JournalBitmapUnassigned { get; } - public byte[] JournalLayer1Hash { get; } - public byte[] JournalLayer2Hash { get; } - public byte[] JournalLayer3Hash { get; } - public byte[] JournalFat { get; } + public Stream JournalTable { get; } + public Stream JournalBitmapUpdatedPhysical { get; } + public Stream JournalBitmapUpdatedVirtual { get; } + public Stream JournalBitmapUnassigned { get; } + public Stream JournalLayer1Hash { get; } + public Stream JournalLayer2Hash { get; } + public Stream JournalLayer3Hash { get; } + public Stream JournalFat { get; } public FileEntry[] Files { get; private set; } private Dictionary FileDict { get; } public Savefile(Stream file, IProgressReport logger = null) { - FileStream = file; using (var reader = new BinaryReader(file, Encoding.Default, true)) { Header = new Header(reader, logger); @@ -42,56 +44,33 @@ namespace libhac.Savefile new SubStream(file, layout.FileMapDataOffset, layout.FileMapDataSize), Header.FileMapEntries, Header.FileRemap.MapSegmentCount); - DuplexL1A = new byte[layout.DuplexL1Size]; - DuplexL1B = new byte[layout.DuplexL1Size]; - DuplexDataA = new byte[layout.DuplexDataSize]; - DuplexDataB = new byte[layout.DuplexDataSize]; + FileRemapSource = new SharedStreamSource(FileRemap); - FileRemap.Position = layout.DuplexL1OffsetA; - FileRemap.Read(DuplexL1A, 0, DuplexL1A.Length); - FileRemap.Position = layout.DuplexL1OffsetB; - FileRemap.Read(DuplexL1B, 0, DuplexL1B.Length); - FileRemap.Position = layout.DuplexDataOffsetA; - FileRemap.Read(DuplexDataA, 0, DuplexDataA.Length); - FileRemap.Position = layout.DuplexDataOffsetB; - FileRemap.Read(DuplexDataB, 0, DuplexDataB.Length); + DuplexL1A = FileRemapSource.CreateStream(layout.DuplexL1OffsetA, layout.DuplexL1Size); + DuplexL1B = FileRemapSource.CreateStream(layout.DuplexL1OffsetB, layout.DuplexL1Size); + DuplexDataA = FileRemapSource.CreateStream(layout.DuplexDataOffsetA, layout.DuplexDataSize); + DuplexDataB = FileRemapSource.CreateStream(layout.DuplexDataOffsetB, layout.DuplexDataSize); + JournalData = FileRemapSource.CreateStream(layout.JournalDataOffset, layout.JournalDataSizeB + layout.SizeReservedArea); - var duplexDataOffset = layout.DuplexIndex == 0 ? layout.DuplexDataOffsetA : layout.DuplexDataOffsetB; - var duplexData = new SubStream(FileRemap, duplexDataOffset, layout.DuplexDataSize); + var duplexData = layout.DuplexIndex == 0 ? DuplexDataA : DuplexDataB; MetaRemap = new RemapStream(duplexData, Header.MetaMapEntries, Header.MetaRemap.MapSegmentCount); + MetaRemapSource = new SharedStreamSource(MetaRemap); - JournalTable = new byte[layout.JournalTableSize]; - JournalBitmapUpdatedPhysical = new byte[layout.JournalBitmapUpdatedPhysicalSize]; - JournalBitmapUpdatedVirtual = new byte[layout.JournalBitmapUpdatedVirtualSize]; - JournalBitmapUnassigned = new byte[layout.JournalBitmapUnassignedSize]; - JournalLayer1Hash = new byte[layout.Layer1HashSize]; - JournalLayer2Hash = new byte[layout.Layer2HashSize]; - JournalLayer3Hash = new byte[layout.Layer3HashSize]; - JournalFat = new byte[layout.Field150]; + JournalTable = MetaRemapSource.CreateStream(layout.JournalTableOffset, layout.JournalTableSize); + JournalBitmapUpdatedPhysical = MetaRemapSource.CreateStream(layout.JournalBitmapUpdatedPhysicalOffset, layout.JournalBitmapUpdatedPhysicalSize); + JournalBitmapUpdatedVirtual = MetaRemapSource.CreateStream(layout.JournalBitmapUpdatedVirtualOffset, layout.JournalBitmapUpdatedVirtualSize); + JournalBitmapUnassigned = MetaRemapSource.CreateStream(layout.JournalBitmapUnassignedOffset, layout.JournalBitmapUnassignedSize); + JournalLayer1Hash = MetaRemapSource.CreateStream(layout.Layer1HashOffset, layout.Layer1HashSize); + JournalLayer2Hash = MetaRemapSource.CreateStream(layout.Layer2HashOffset, layout.Layer2HashSize); + JournalLayer3Hash = MetaRemapSource.CreateStream(layout.Layer3HashOffset, layout.Layer3HashSize); + JournalFat = MetaRemapSource.CreateStream(layout.Field148, layout.Field150); - MetaRemap.Position = layout.JournalTableOffset; - 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, Header.Journal.MappingEntryCount); - var journalMap = JournalStream.ReadMappingEntries(JournalTable, JournalBitmapUpdatedPhysical, - JournalBitmapUpdatedVirtual, JournalBitmapUnassigned, Header.Journal.MappingEntryCount); - - var journalData = new SubStream(FileRemap, layout.JournalDataOffset, + var journalData = FileRemapSource.CreateStream(layout.JournalDataOffset, layout.JournalDataSizeB + layout.SizeReservedArea); JournalStream = new JournalStream(journalData, journalMap, (int)Header.Journal.BlockSize); + JournalStreamSource = new SharedStreamSource(JournalStream); ReadFileInfo(); Dictionary dictionary = new Dictionary(); foreach (FileEntry entry in Files) @@ -115,7 +94,7 @@ namespace libhac.Savefile 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); @@ -128,12 +107,12 @@ namespace libhac.Savefile FileEntry[] dirEntries; 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); - JournalStream.Position = fileOffset; + reader.BaseStream.Position = fileOffset; fileEntries = ReadFileEntries(reader); } @@ -161,7 +140,7 @@ namespace libhac.Savefile private FileEntry[] ReadFileEntries(BinaryReader reader) { var count = reader.ReadInt32(); - JournalStream.Position -= 4; + reader.BaseStream.Position -= 4; var entries = new FileEntry[count]; for (int i = 0; i < count; i++) diff --git a/libhac/Util.cs b/libhac/Util.cs index 12ad805e..9cefc139 100644 --- a/libhac/Util.cs +++ b/libhac/Util.cs @@ -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) { var start = reader.BaseStream.Position;