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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<string, FileEntry> 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<string, FileEntry> dictionary = new Dictionary<string, FileEntry>();
|
||||
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++)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue