diff --git a/botw-toolset/IO/SARC/SARC.cs b/botw-toolset/IO/SARC/SARC.cs index 4d84835..299085a 100644 --- a/botw-toolset/IO/SARC/SARC.cs +++ b/botw-toolset/IO/SARC/SARC.cs @@ -37,15 +37,15 @@ namespace BOTWToolset.IO.SARC public byte[][] Files; /// - /// Gets a from a data stream. + /// Gets a from an array of bytes. /// - /// Data stream to get info from. + /// Array of bytes to get info from. /// with the stream's data. - public static SARC FromBytes(Stream stream) + public static SARC FromBytes(byte[] bytes) { SARC s = new SARC(); - using (var r = new BinaryReaderBig(stream)) + using (var r = new BinaryReaderBig(new MemoryStream(bytes))) { //SARC header s.Magic = new string(r.ReadChars(4)); @@ -159,26 +159,69 @@ namespace BOTWToolset.IO.SARC return s; } - public static SARC ReadFile(string file) - { - if (File.Exists(file)) - { - return FromBytes(File.Open(file, FileMode.Open)); - } - else - { - throw new FileNotFoundException("Cannot find SARC file to read."); - } - } - - public static byte[] GetBytes(SARC sarc) + /// + /// Gets an array of bytes from a . + /// + /// to convert to bytes. + /// byte[] containg the data. + public static byte[] ToBytes(SARC sarc) { // TODO: Make this an actual function List bytes = new List(); + // SARC header + bytes.AddRange(new byte[] { 0x53, 0x41, 0x52, 0x43 }); // SARC magic header + bytes.AddRange(new byte[] { 0x00, 0x14 }); // Header length, always 0x14 + bytes.AddRange(new byte[] { 0xFE, 0xFF }); // 0xFEFF - big endian, 0xFFFE - little endian + bytes.AddRange(BitConverter.GetBytes(sarc.FileSize).Reverse()); // File size of the entire SARC, including headers + bytes.AddRange(BitConverter.GetBytes(sarc.DataOffset).Reverse()); // Beginning of data offset + bytes.AddRange(new byte[] { 0x01, 0x00 }); // Version number, always 0x0100 + bytes.AddRange(new byte[] { 0x00, 0x00 }); // Reserved + + // SFAT header + bytes.AddRange(new byte[] { 0x53, 0x46, 0x41, 0x54 }); // SFAT magic header + bytes.AddRange(new byte[] { 0x00, 0x0C }); // Header length, always 0xC + bytes.AddRange(BitConverter.GetBytes(sarc.SFAT.NodeCount).Reverse()); + bytes.AddRange(new byte[] { 0x00, 0x00, 0x00, 0x65 }); // Hash key, always 0x65 + + // SFAT node structures + foreach (SFATNode node in sarc.SFAT.Nodes) + { + bytes.AddRange(BitConverter.GetBytes(node.FileNameHash).Reverse()); + bytes.AddRange(BitConverter.GetBytes(node.FileAttributes).Reverse()); + bytes.AddRange(BitConverter.GetBytes(node.NodeFileDataBegin).Reverse()); + bytes.AddRange(BitConverter.GetBytes(node.NodeFileDataEnd).Reverse()); + } + + // SFNT header + bytes.AddRange(new byte[] { 0x53, 0x46, 0x4E, 0x54 }); // SFNT magic header + bytes.AddRange(new byte[] { 0x00, 0x08 }); // Header length, always 0x8 + bytes.AddRange(new byte[] { 0x00, 0x00 }); // Reserved + + foreach (var filename in sarc.SFNT.FileNames) + { + var extra = filename.Length % 4; // Number of characters not in a 4-byte-aligned segment + + for (int i = 0; i < filename.Length + (4 - extra); i++) + { + if (i < filename.Length) // If this is a valid char + bytes.Add((byte)filename[i]); + else // If not, add null + bytes.Add(0x00); + } + } + + foreach (var file_bytes in sarc.Files) + bytes.AddRange(file_bytes); + return bytes.ToArray(); } + /// + /// Writes a 's unpackaged files to a folder. + /// + /// to get file data from. + /// Folder to write the unpackaged files to. public static void WriteFiles(SARC sarc, string folder) { //TODO: Finish this function @@ -191,10 +234,8 @@ namespace BOTWToolset.IO.SARC // Get combined path (folder + file name) var file_path = Path.Combine(folder, file_name); - using (var r = new BinaryWriterBig(File.OpenWrite(file_path), System.Text.Encoding.UTF8)) - { - - } + // Write bytes to file + File.WriteAllBytes(file_path, files[i]); } } }