public void Save(Stream output, IList <IArchiveFileInfo> files) { var darcTreeBuilder = new U8TreeBuilder(Encoding.ASCII); darcTreeBuilder.Build(files.Select(x => ("/." + x.FilePath.FullName, x)).ToArray()); var entries = darcTreeBuilder.Entries; var nameStream = darcTreeBuilder.NameStream; var namePosition = _headerSize + entries.Count * _entrySize; var dataOffset = (namePosition + (int)nameStream.Length + 0x1F) & ~0x1F; using var bw = new BinaryWriterX(output, ByteOrder.BigEndian); // Write names bw.BaseStream.Position = namePosition; nameStream.Position = 0; nameStream.CopyTo(bw.BaseStream); bw.WriteAlignment(0x20); // Write files foreach (var(u8Entry, afi) in entries.Where(x => x.Item2 != null)) { bw.WriteAlignment(0x20); var fileOffset = (int)bw.BaseStream.Position; var writtenSize = (afi as ArchiveFileInfo).SaveFileData(bw.BaseStream); u8Entry.offset = fileOffset; u8Entry.size = (int)writtenSize; } // Write entries bw.BaseStream.Position = _headerSize; bw.WriteMultiple(entries.Select(x => x.Item1)); // Write header bw.BaseStream.Position = 0; bw.WriteType(new U8Header { entryDataOffset = _headerSize, entryDataSize = entries.Count * _entrySize + (int)nameStream.Length, dataOffset = dataOffset }); bw.WritePadding(0x10, 0xCC); }
public void Save(Stream output, IList <IArchiveFileInfo> files) { using var bw = new BinaryWriterX(output, ByteOrder.BigEndian); // Get system files var bi2File = files.First(x => x.FilePath.ToRelative() == "sys/bi2.bin"); var appLoaderFile = files.First(x => x.FilePath.ToRelative() == "sys/appldr.bin"); var execFile = files.First(x => x.FilePath.ToRelative() == "sys/main.dol"); // Calculate offsets var bi2Offset = 0x440; var appLoaderOffset = bi2Offset + bi2File.FileSize; var execOffset = appLoaderOffset + ((appLoaderFile.FileSize + 0x1F) & ~0x1F) + 0x20; var fstOffset = (execOffset + execFile.FileSize + 0x1F) & ~0x1F; // Build U8 entry list var treeBuilder = new U8TreeBuilder(Encoding.ASCII); treeBuilder.Build(files.Where(x => !x.FilePath.IsInDirectory("/sys", false)).Select(x => (x.FilePath.FullName, x)).ToArray()); var nameStream = treeBuilder.NameStream; var entries = treeBuilder.Entries; nameStream.Position = 0; // Write names var nameOffset = output.Position = fstOffset + treeBuilder.Entries.Count * Tools.MeasureType(typeof(U8Entry)); nameStream.CopyTo(output); bw.WriteAlignment(0x20); // Write files foreach (var(u8Entry, afi) in entries.Where(x => x.Item2 != null)) { bw.WriteAlignment(0x20); var fileOffset = (int)bw.BaseStream.Position; var writtenSize = (afi as ArchiveFileInfo).SaveFileData(bw.BaseStream); u8Entry.offset = fileOffset; u8Entry.size = (int)writtenSize; } // Write FST output.Position = fstOffset; bw.WriteMultiple(entries.Select(x => x.Item1)); // Write system files output.Position = bi2Offset; (bi2File as ArchiveFileInfo).SaveFileData(output); output.Position = appLoaderOffset; (appLoaderFile as ArchiveFileInfo).SaveFileData(output); output.Position = execOffset; (execFile as ArchiveFileInfo).SaveFileData(output); // Write header _header.execOffset = (int)execOffset; _header.fstOffset = (int)fstOffset; _header.fstSize = (int)(nameStream.Length + (nameOffset - fstOffset)); _header.fstMaxSize = _header.fstSize; output.Position = 0; bw.WriteType(_header); }