public void Save(Stream output, bool leaveOpen = false) { using (var bw = new BinaryWriterX(output, leaveOpen)) { //SARCHeader var header = new SARCHeader { dataOffset = Files.Aggregate(40 + Files.Sum(afi => usesSFNT ? afi.FileName.Length / 4 * 4 + 20 : 16), (n, afi) => Pad(n, afi.FileName)) }; bw.WriteStruct(header); // filesize is added later //SFATHeader bw.WriteStruct(new SFATHeader { nodeCount = (short)Files.Count }); //SFAT List + nameList int nameOffset = 0; int dataOffset = 0; foreach (var afi in Files) { dataOffset = Pad(dataOffset, afi.FileName); var fileLen = (int)afi.FileData.Length; var sfatEntry = new SFATEntry { nameHash = usesSFNT ? SimpleHash.Create(afi.FileName, 0x65) : Convert.ToUInt32(afi.FileName.Substring(2, 8), 16), SFNTOffset = (short)(usesSFNT ? nameOffset : 0), filenameFlags = (short)(usesSFNT ? 0x100 : 0), dataStart = dataOffset, dataEnd = dataOffset + fileLen }; bw.WriteStruct(sfatEntry); nameOffset += afi.FileName.Length / 4 + 1; dataOffset = sfatEntry.dataEnd; } bw.WriteStruct(new SFNTHeader()); if (usesSFNT) { foreach (var afi in Files) { bw.WriteASCII(afi.FileName.PadRight(afi.FileName.Length / 4 * 4 + 4, '\0')); } } bw.WriteAlignment(header.dataOffset); foreach (var afi in Files) { bw.Write(new byte[Pad((int)bw.BaseStream.Length, afi.FileName) - (int)bw.BaseStream.Length]); // padding afi.FileData.CopyTo(bw.BaseStream); } bw.BaseStream.Position = 0; header.fileSize = (int)bw.BaseStream.Length; bw.WriteStruct(header); } }
public Archive(Stream stream) { byte[] header = new byte[4]; stream.Read(header, 0, 4); stream.Seek(-4, SeekOrigin.Current); if (header[0] == 'Y') { archiveFileStream = new Yaz0Stream(stream); } else { archiveFileStream = stream; } using (EndianBinaryReader er = new EndianBinaryReader(archiveFileStream, Encoding.ASCII, true, Endian.Big)) { archiveHeader = new ArchiveHeader(er); sfatHeader = new SFATHeader(er); sfatEntries = new SFATEntry[sfatHeader.NodeCount]; for (int i = 0; i < sfatHeader.NodeCount; i++) { sfatEntries[i] = new SFATEntry(er); } er.Skip(8); // SFNT, 0x00, 0x08, 0x00, 0x00 sfatStringTable = new string[sfatHeader.NodeCount]; for (int i = 0; i < sfatHeader.NodeCount; i++) { // These strings are aligned to 4 bytes. //while (er.PeekReadByte() == 0) // er.ReadByte(); sfatStringTable[i] = Encoding.ASCII.GetString(er.ReadBytesUntil(0)); } } for (int i = 0; i < sfatEntries.Length; i++) { sfatEntries[i].FileName = sfatStringTable[sfatEntries[i].FileNameTableOffset / 4]; } fileDictionary = new Dictionary <string, ArchiveEntry>(sfatEntries.Length); for (int i = 0; i < sfatEntries.Length; i++) { string name = sfatStringTable[sfatEntries[i].FileNameTableOffset / 4]; uint size = sfatEntries[i].DataOffsetEnd - sfatEntries[i].DataOffsetStart; fileDictionary.Add(name, new ArchiveEntry(name, sfatEntries[i].DataOffsetStart + archiveHeader.DataOffset, size, sfatEntries[i].FileType)); } }