using System; using System.Collections; using System.Collections.Generic; using NW4RTools.Models; namespace NW4RTools { public class BrresWriter { public static byte[] WriteFile(ResFile file) { return new BrresWriter().Save(file); } private ResFile File; private ILogger Debug; private SortedDictionary OffsetMap; private OutputStream Output; private BrresWriter() { Debug = new ConsoleLogger(); OffsetMap = new SortedDictionary(); } private byte[] Save(ResFile file) { Output = new OutputStream(ByteEndian.BigEndian); File = file; using (var c = Debug.Push("Offset Calculation")) CalculateRoot(); Output.WriteBytes(StringTableData.GetBuffer()); return Output.GetBuffer(); } // OK, here's how I'm going to code this: kinda like how BrawlLib works, first I'll calculate the size of // each written element, and use that to build up a list of offsets. Then, I'll actually write out the data. // This code will also handle building the string table. #region Offset/String Table Calculation private int CurrentPos; private void CalculateRoot() { // Where it all starts! InitialiseStringTable(); // First up: BRRES header CurrentPos = 0x10; // First block, and ResDict CurrentPos += 8; CurrentPos += GetSizeForResDict(File); // Now do each ResDict in the File foreach (object dict in File.Values) { CurrentPos += GetSizeForResDict(dict as ResDict); } // OK, so that's done. Process each type foreach (var name in File.Keys) { AddString(name); switch (name) { case "3DModels(NW4R)": // do that stuff break; default: Debug.Send("[[ UNIMPLEMENTED {0} ]]", name); break; } } // ... and done with that. Build the string table and go! CalculateStringTable(); } private int GetSizeForResDict(ResDict dict) { return 8 + ((dict.Count + 1) * 0x10); } #endregion #region String Table Handling // Contains the strings while they're being pulled from the ResFile data private List StringTable; // Once every string used in the .brres is found, CalculateStringTable() is called, which // writes the table to an OutputStream and saves every offset private Dictionary StringTableOffsets; private OutputStream StringTableData; // Called at the start of the process private void InitialiseStringTable() { StringTable = new List(); } private void AddString(string str) { if (!StringTable.Contains(str)) { StringTable.Add(str); } } private void CalculateStringTable() { StringTable.Sort(); StringTableOffsets = new Dictionary(); StringTableData = new OutputStream(ByteEndian.BigEndian); foreach (var s in StringTable) { // Add 4 because the Names are referenced by the string data, and not by the ResName struct itself StringTableOffsets[s] = StringTableData.Position + 4; StringTableData.WriteName(s); } } #endregion } }