/// <summary> /// Default constructor. /// </summary> /// <param name="count">The initial number of entries in the tlk file.</param> public Tlk(int count) { name = string.Empty; header = new TlkHeader(); resRefs = new RawResRef[count]; strings = new string[count]; header.fileType = tlkFile; header.fileVersion = tlkVersion; header.stringCount = count; header.stringOffset = 0; for (int i = 0; i < count; i++) { resRefs[i] = new RawResRef(); resRefs[i].flags = (int) ResRefFlags.None; resRefs[i].offsetToString = 0; resRefs[i].pitchVariance = 0; resRefs[i].soundLength = 0; resRefs[i].soundResRef = string.Empty; resRefs[i].stringSize = 0; resRefs[i].volumeVariance = 0; strings[i] = string.Empty; } }
public void LoadTlkData(string path) { //var huffman = new StaticHuffman<char>(); /* **************** STEP ONE **************** * -- load TLK file header -- * * reading first 28 (4 * 7) bytes */ _path = path; Stream fs = File.OpenRead(path); var r = new BinaryReader(fs); _header = new TlkHeader(r); //DebugTools.PrintHeader(Header); /* **************** STEP TWO **************** * -- read and store Huffman Tree nodes -- */ /* jumping to the beginning of Huffmann Tree stored in TLK file */ var pos = r.BaseStream.Position; r.BaseStream.Seek(pos + (_header.MaleEntryCount + _header.FemaleEntryCount) * 8, SeekOrigin.Begin); _characterTree = new List <HuffmanNode>(); for (var i = 0; i < _header.TreeNodeCount; i++) { _characterTree.Add(new HuffmanNode(r)); } r.BaseStream.Seek(pos + (_header.MaleEntryCount + _header.FemaleEntryCount) * 8, SeekOrigin.Begin); var characterTree = new List <Tuple <int, int> >(); //var queue = new Queue<HuffmanNode<int>>(); //var queue = new Queue<HuffmanNode<int>>(); for (var i = 0; i < _header.TreeNodeCount; i++) { characterTree.Add(new Tuple <int, int>(r.ReadInt32(), r.ReadInt32())); } /*foreach (var tuple in characterTree) * { * var leftNode = new HuffmanNode<int>(tuple.Item1); * var rightNode = new HuffmanNode<int>(tuple.Item2); * var parent = new HuffmanNode<int>(leftNode, rightNode); * * queue.Enqueue(parent); * }*/ //var tree = new HuffmanTree<int>(table); /* **************** STEP THREE **************** * -- read all of coded data into memory -- */ var data = new byte[_header.DataLen]; r.BaseStream.Read(data, 0, data.Length); /* and store it as raw bits for further processing */ _bits = new BitArray(data); /* rewind BinaryReader just after the Header * at the beginning of TLK Entries data */ r.BaseStream.Seek(pos, SeekOrigin.Begin); /* **************** STEP FOUR **************** * -- decode (basing on Huffman Tree) raw bits data into actual strings -- * and store them in a Dictionary<int, string> where: * int: bit offset of the beginning of data (offset starting at 0 and counted for Bits array) * so offset == 0 means the first bit in Bits array * string: actual decoded string */ var rawStrings = new Dictionary <int, string>(); var offset = 0; // int maxOffset = 0; while (offset < _bits.Length) { var key = offset; // if (key > maxOffset) // maxOffset = key; /* read the string and update 'offset' variable to store NEXT string offset */ var s = GetString(ref offset); rawStrings.Add(key, s); } // Console.WriteLine("Max offset = " + maxOffset); /* **************** STEP FIVE **************** * -- bind data to String IDs -- * go through Entries in TLK file and read it's String ID and offset * then check if offset is a key in rawStrings and if it is, then bind data. * Sometimes there's no such key, in that case, our String ID is probably a substring * of another String present in rawStrings. */ //StringRefs = new XmlTlkStrings(); MaleStringRefs = new List <TlkString>(); FemaleStringRefs = new List <TlkString>(); for (var i = 0; i < _header.MaleEntryCount /* + _header.FemaleEntryCount*/; i++) { var sref = new TlkString(r, i); if (sref.BitOffset >= 0) { if (!rawStrings.ContainsKey(sref.BitOffset)) { var tmpOffset = sref.BitOffset; var partString = GetString(ref tmpOffset); /* actually, it should store the fullString and subStringOffset, * but as we don't have to use this compression feature, * we will store only the part of string we need */ /* int key = rawStrings.Keys.Last(c => c < sref.BitOffset); * string fullString = rawStrings[key]; * int subStringOffset = fullString.LastIndexOf(partString); * sref.StartOfString = subStringOffset; * sref.Data = fullString; */ sref.Value = partString; } else { sref.Value = rawStrings[sref.BitOffset]; } } if (string.IsNullOrEmpty(sref.Value) || string.IsNullOrWhiteSpace(sref.Value)) { sref.Value = TlkString.EmptyText; } MaleStringRefs.Add(sref); } for (var i = 0; i < _header.FemaleEntryCount; i++) { var sref = new TlkString(r, i); if (sref.BitOffset >= 0) { if (!rawStrings.ContainsKey(sref.BitOffset)) { var tmpOffset = sref.BitOffset; var partString = GetString(ref tmpOffset); /* actually, it should store the fullString and subStringOffset, * but as we don't have to use this compression feature, * we will store only the part of string we need */ /* int key = rawStrings.Keys.Last(c => c < sref.BitOffset); * string fullString = rawStrings[key]; * int subStringOffset = fullString.LastIndexOf(partString); * sref.StartOfString = subStringOffset; * sref.Data = fullString; */ sref.Value = partString; } else { sref.Value = rawStrings[sref.BitOffset]; } } if (string.IsNullOrEmpty(sref.Value) || string.IsNullOrWhiteSpace(sref.Value)) { sref.Value = TlkString.EmptyText; } FemaleStringRefs.Add(sref); } r.Close(); }
/// <summary> /// Private constructor, instances of this class must /// </summary> private Tlk() { header = new TlkHeader(); resRefs = null; strings = null; }
/// <summary> /// Deserializes the header from the given byte array. /// </summary> /// <param name="bytes">The byte array containing the header</param> private void DeserializeHeader(byte[] bytes) { // Alloc a hglobal to store the bytes. IntPtr buffer = Marshal.AllocHGlobal(bytes.Length); try { // Copy the data to unprotected memory, then convert it to a TlkHeader // structure Marshal.Copy(bytes, 0, buffer, bytes.Length); object o = Marshal.PtrToStructure(buffer, typeof(TlkHeader)); header = (TlkHeader) o; } finally { // Free the hglobal before exiting. Marshal.FreeHGlobal(buffer); } }