public void Save(Stream output, bool leaveOpen = false) { using (var bw = new BinaryWriterX(output, leaveOpen, byteOrder)) { //Header.dataOffset = Files.Aggregate( // 0x14 + 0xC + 0x8 + Files.Sum(afi => usesSFNT ? ((afi.FileName.Length + 4) & ~3) + 0x10 : 0x10), // (n, file) => Support.Pad(n, file.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU)); // SFAT Header bw.BaseStream.Position = 0x14; bw.WriteStruct(new SFATHeader { hashMultiplier = (int)hashMultiplier, nodeCount = (short)Files.Count }); // SFAT List + nameList var nameOffset = 0; var dataOffset = 0; var sfatEntry = new SFATEntry(); foreach (var afi in Files) { dataOffset = Support.Pad(dataOffset, afi.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU); // BXLIM Alignment Reading if (afi.FileName.EndsWith("lim")) { using (var br = new BinaryReaderX(afi.FileData, true, byteOrder)) { br.BaseStream.Position = br.BaseStream.Length - 0x28; var type = br.PeekString(); var alignment = 0; if (type == "FLIM") { br.BaseStream.Position = br.BaseStream.Length - 0x8; alignment = br.ReadInt16(); } else if (type == "CLIM") { br.BaseStream.Position = br.BaseStream.Length - 0x6; alignment = br.ReadInt16(); } dataOffset = (sfatEntry.dataEnd + alignment - 1) & -alignment; } } var fileLen = (int)afi.FileData.Length; sfatEntry = new SFATEntry { nameHash = usesSFNT ? SimpleHash.Create(afi.FileName, hashMultiplier) : Convert.ToUInt32(afi.FileName.Substring(2, 8), 16), SFNTOffsetFlag = (uint)(((usesSFNT ? 0x100 : 0) << 16) | (usesSFNT ? nameOffset / 4 : 0)), dataStart = dataOffset, dataEnd = dataOffset + fileLen }; bw.WriteStruct(sfatEntry); nameOffset = (nameOffset + afi.FileName.Length + 4) & ~3; dataOffset = sfatEntry.dataEnd; } // SFNT bw.WriteStruct(SFNTHeader); if (usesSFNT) { foreach (var afi in Files) { bw.WriteASCII(afi.FileName + "\0"); bw.BaseStream.Position = (bw.BaseStream.Position + 3) & ~3; } } // Files bw.WriteAlignment(Header.dataOffset); foreach (var afi in Files) { var alignment = Support.Pad((int)bw.BaseStream.Length, afi.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU); // BXLIM Alignment Reading if (afi.FileName.EndsWith("lim")) { using (var br = new BinaryReaderX(afi.FileData, true, byteOrder)) { br.BaseStream.Position = br.BaseStream.Length - 0x28; var type = br.PeekString(); if (type == "FLIM") { br.BaseStream.Position = br.BaseStream.Length - 0x8; alignment = br.ReadInt16(); } else if (type == "CLIM") { br.BaseStream.Position = br.BaseStream.Length - 0x6; alignment = br.ReadInt16(); } } } bw.WriteAlignment(alignment); afi.FileData.CopyTo(bw.BaseStream); } // Header bw.BaseStream.Position = 0; Header.fileSize = (int)bw.BaseStream.Length; bw.WriteStruct(Header); } }
public void Save(Stream output, bool leaveOpen = false) { using (var bw = new BinaryWriterX(output, leaveOpen, byteOrder)) { //Create SARCHeader var header = new SARCHeader { byteOrder = byteOrder, dataOffset = Files.Aggregate( 0x14 + 0xc + 0x8 + Files.Sum(afi => usesSFNT ? ((afi.FileName.Length + 4) & ~3) + 0x10 : 0x10), (n, file) => Support.Pad(n, file.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU)) }; //SFATHeader bw.BaseStream.Position = 0x14; bw.WriteStruct(new SFATHeader { hashMultiplier = (int)hashMultiplier, nodeCount = (short)Files.Count }); //SFAT List + nameList int nameOffset = 0; int dataOffset = 0; foreach (var afi in Files) { dataOffset = Support.Pad(dataOffset, afi.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU); var fileLen = (int)afi.FileData.Length; var sfatEntry = new SFATEntry { nameHash = usesSFNT ? SimpleHash.Create(afi.FileName, hashMultiplier) : Convert.ToUInt32(afi.FileName.Substring(2, 8), 16), SFNTOffsetFlag = (uint)(((usesSFNT ? 0x100 : 0) << 16) | (usesSFNT ? nameOffset / 4 : 0)), dataStart = dataOffset, dataEnd = dataOffset + fileLen }; bw.WriteStruct(sfatEntry); nameOffset = (nameOffset + afi.FileName.Length + 4) & ~3; dataOffset = sfatEntry.dataEnd; } //SFNT bw.WriteStruct(new SFNTHeader()); if (usesSFNT) { foreach (var afi in Files) { bw.WriteASCII(afi.FileName + "\0"); bw.BaseStream.Position = (bw.BaseStream.Position + 3) & ~3; } } //FileData bw.WriteAlignment(header.dataOffset); foreach (var afi in Files) { bw.WriteAlignment(Support.Pad((int)bw.BaseStream.Length, afi.FileName, (byteOrder == ByteOrder.LittleEndian) ? System.CTR : System.WiiU)); //(unusual) padding scheme through filenames afi.FileData.CopyTo(bw.BaseStream); } bw.BaseStream.Position = 0; header.fileSize = (int)bw.BaseStream.Length; bw.WriteStruct(header); } }