public void Write(Stream stream) { uint filesSize = (uint)FMDX_DATA_PREFIX.Length; foreach (FMDX.File file in this.Files) { filesSize += NumberUtil.Align((uint)file.Data.Length, 0x10); } using (BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8, true)) { long fmdxStartOffset = writer.BaseStream.Position; writer.WriteFixedString(4, FMDX_MAGIC); writer.Write(filesSize); writer.Write((uint)this.Files.Length); writer.Write((uint)1); // Always 1. writer.Write(new byte[68]); // Padding; always observed to be 0. uint offset = FMDX_HEADER_SIZE + (uint)this.Files.Length * FMDX_FILE_HEADER_SIZE + (uint)FMDX_DATA_PREFIX.Length; foreach (FMDX.File file in this.Files) { WriteFile(writer, file, offset, fmdxStartOffset); offset += NumberUtil.Align((uint)file.Data.Length, 0x10); } writer.Write(FMDX_DATA_PREFIX); } }
private void WriteFileSet(Stream stream, FileSet fileSet) { PACKFSHD fileSetHeader = new PACKFSHD(); GENESTRT fileSetNameTable = new GENESTRT(); fileSetHeader.Unknown = 0x10000; fileSetHeader.DataOffset = 0; // Filled in later. foreach (File file in fileSet.Files) { PACKFSHD.FileEntry fileEntry = new PACKFSHD.FileEntry(); fileEntry.NameIndex = fileSetNameTable.AddString(file.Name); fileEntry.Unknown = 0x2; fileEntry.Offset = 0; // Filled in later. fileEntry.UncompressedSize = file.UncompressedSize; fileEntry.CompressedSize = (uint)file.RawData.Length; fileSetHeader.Files.Add(fileEntry); } SectionSet fileSetSections = new SectionSet(); fileSetSections.Add(new ENDILTLE()); fileSetSections.Add(fileSetHeader); fileSetSections.Add(fileSetNameTable); fileSetSections.Add(new GENEEOF()); ulong headersSize; using (MemoryStream sizeTestStream = new MemoryStream()) { SectionIO.WriteAll(sizeTestStream, fileSetSections); headersSize = (ulong)sizeTestStream.Length; } ulong currOffset = NumberUtil.Align(headersSize, 0x10); fileSetHeader.DataOffset = (uint)currOffset - 0x10; // Offset excludes ENDILTLE. foreach (PACKFSHD.FileEntry fileEntry in fileSetHeader.Files) { fileEntry.Offset = currOffset; currOffset = NumberUtil.Align(currOffset + fileEntry.CompressedSize, 0x10); } SectionIO.WriteAll(stream, fileSetSections); foreach (File file in fileSet.Files) { stream.Write(file.RawData); stream.PadTo(0x10); } }
private static void WriteFile(BinaryWriter writer, FMDX.File file, uint offset, long fmdxStartOffset) { writer.WriteFixedString(128, file.Path); writer.Write(offset); writer.Write((uint)file.Data.Length); writer.Write(new byte[8]); // Padding; always observed to be 0. long pos = writer.BaseStream.Position; writer.BaseStream.Seek(fmdxStartOffset + offset, SeekOrigin.Begin); writer.Write(file.Data); uint padding = NumberUtil.Align((uint)file.Data.Length, 0x10) - (uint)file.Data.Length; if (padding > 0) { writer.Write(new byte[padding]); } writer.BaseStream.Seek(pos, SeekOrigin.Begin); }
public void Write(Stream stream) { GENESTRT nameTable = new GENESTRT(); nameTable.Strings.Add(this.Name); PACKHEDR packhedr = new PACKHEDR(); packhedr.Unknown1 = 0x10000; packhedr.NameIndex = 0; packhedr.DataOffset = 0; // Filled in later. packhedr.Unknown3 = 1; packhedr.Hash = new byte[16]; // TODO PACKTOC toc = new PACKTOC(); byte[] fileData; using (MemoryStream fileStream = new MemoryStream()) { this.WriteFiles(fileStream, toc, nameTable); fileData = fileStream.ToArray(); } PACKFSLS fsls = new PACKFSLS(); List <byte[]> fileSetDatas = new List <byte[]>(); uint nameIndex = (uint)nameTable.Strings.Count; foreach (FileSet fileSet in this.FileSets) { byte[] fileSetData; using (MemoryStream fileSetStream = new MemoryStream()) { this.WriteFileSet(fileSetStream, fileSet); fileSetData = fileSetStream.ToArray(); } PACKFSLS.FileSetEntry entry = new PACKFSLS.FileSetEntry(); entry.NameIndex = nameTable.AddString(fileSet.Name); entry.PackageIndex = 0; entry.Offset = 0; // Filled in later. entry.Size = (ulong)fileSetData.Length; entry.Hash = new MD5CryptoServiceProvider().ComputeHash(fileSetData); fsls.FileSets.Add(entry); fileSetDatas.Add(fileSetData); } SectionSet set = new SectionSet(); set.Add(new ENDILTLE()); set.Add(packhedr); set.Add(toc); set.Add(fsls); set.Add(nameTable); set.Add(new GENEEOF()); ulong headersSize; using (MemoryStream sizeTestStream = new MemoryStream()) { SectionIO.WriteAll(sizeTestStream, set); headersSize = (ulong)sizeTestStream.Length; } ulong currOffset = NumberUtil.Align(headersSize, 0x800); packhedr.DataOffset = (uint)currOffset; foreach (PACKTOC.Entry entry in toc.Entries) { if (entry is PACKTOC.UncompressedFileEntry uFileEntry) { uFileEntry.Offset = currOffset; currOffset = NumberUtil.Align(currOffset + uFileEntry.Size, 0x200); } else if (entry is PACKTOC.CompressedFileEntry cFileEntry) { cFileEntry.Offset = currOffset; currOffset = NumberUtil.Align(currOffset + cFileEntry.CompressedSize, 0x200); } } currOffset = NumberUtil.Align(currOffset, 0x800); foreach (PACKFSLS.FileSetEntry fileSetEntry in fsls.FileSets) { fileSetEntry.Offset = currOffset; currOffset = NumberUtil.Align(currOffset + fileSetEntry.Size, 0x800); } SectionIO.WriteAll(stream, set); stream.PadTo(0x800); stream.Write(fileData); foreach (byte[] fileSetData in fileSetDatas) { stream.PadTo(0x800); stream.Write(fileSetData); } }