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 SARC(byte[] Data) { EndianBinaryReaderEx er = new EndianBinaryReaderEx(new MemoryStream(Data), Endianness.LittleEndian); try { Header = new SARCHeader(er); SFat = new SFAT(er); SFnt = new SFNT(er); er.BaseStream.Position = Header.FileDataOffset; this.Data = er.ReadBytes((int)(Header.FileSize - Header.FileDataOffset)); } finally { er.Close(); } }
public SARC(Stream inputStream) { EndianBinaryReader er = new EndianBinaryReader(inputStream, Endian.Big); try { Header = new SARCHeader(er); SfatHeader = new SFATHeader(er); SfatNodes = new SFATNode[SfatHeader.NodeCount]; for (int i = 0; i < SfatHeader.NodeCount; i++) { SfatNodes[i] = new SFATNode(er); } // Just skip the SFNT_HEADER because it's useless for now ? er.ReadBytes(8); SfatStringTable = new string[SfatHeader.NodeCount]; for (int i = 0; i < SfatHeader.NodeCount; i++) { // These are padded strings, so skip the null bytes padding them while (er.PeekReadByte() == 0) { er.ReadByte(); } SfatStringTable[i] = Encoding.UTF8.GetString(er.ReadBytesUntil(0)); SfatNodes[i].copied_name = SfatStringTable[i]; } // TODO: Maybe we have to pad here too? SfatDataTable = new byte[SfatHeader.NodeCount][]; for (int i = 0; i < SfatHeader.NodeCount; i++) { uint dataLength = SfatNodes[i].NodeDataEndOffset - SfatNodes[i].NodeDataBeginOffset; SfatDataTable[i] = er.ReadBytesAt(Header.DataOffset + SfatNodes[i].NodeDataBeginOffset, (int)dataLength); SfatNodes[i].copied_data = SfatDataTable[i]; } } finally { er.Close(); } }
public void FromFileSystem(SFSDirectory Root) { Header = new SARCHeader(); SFat = new SFAT(); SFat.NrEntries = (ushort)Root.Files.Count; uint DataStart = 0; foreach (var v in Root.Files) { while ((DataStart % 128) != 0) { DataStart++; } uint hash; if (v.FileName == string.Format("0x{0:X8}", v.FileID)) { hash = (uint)v.FileID; } else { hash = GetHashFromName(v.FileName); } SFat.Entries.Add(new SFAT.SFATEntry() { FileDataStart = DataStart, FileDataEnd = (uint)(DataStart + v.Data.Length), FileNameHash = hash, FileNameOffset = 0 }); DataStart += (uint)v.Data.Length; } Data = new byte[DataStart]; int i = 0; foreach (var v in Root.Files) { Array.Copy(v.Data, 0, Data, SFat.Entries[i].FileDataStart, v.Data.Length); i++; } SFnt = new SFNT(); Header.FileSize = (uint)(0x14 + 0xC + SFat.NrEntries * 0x10 + 0x8); while ((Header.FileSize % 128) != 0) { Header.FileSize++; } Header.FileDataOffset = Header.FileSize; Header.FileSize += (uint)Data.Length; }
public void FromFileSystem(SFSDirectory Root) { Header = new SARCHeader(); SFat = new SFAT(); SFat.NrEntries = (ushort)Root.Files.Count; uint DataStart = 0; Root.Files.Sort(delegate(SFSFile a, SFSFile b) { uint hasha = (uint)a.FileID; uint hashb = (uint)b.FileID; return(hasha.CompareTo(hashb)); }); foreach (var v in Root.Files) { while ((DataStart % 128) != 0) { DataStart++; } uint hash = (uint)v.FileID; SFat.Entries.Add(new SFAT.SFATEntry() { FileDataStart = DataStart, FileDataEnd = (uint)(DataStart + v.Data.Length), FileNameHash = hash, FileNameOffset = 0 }); DataStart += (uint)v.Data.Length; } Data = new byte[DataStart]; int i = 0; foreach (var v in Root.Files) { Array.Copy(v.Data, 0, Data, SFat.Entries[i].FileDataStart, v.Data.Length); i++; } SFnt = new SFNT(); Header.FileSize = (uint)(0x14 + 0xC + SFat.NrEntries * 0x10 + 0x8); while ((Header.FileSize % 128) != 0) { Header.FileSize++; } Header.FileDataOffset = Header.FileSize; Header.FileSize += (uint)Data.Length; }