public void LoadTlkData(string fileName)
{
path = fileName;
name = Path.GetFileNameWithoutExtension(fileName);
/* **************** STEP ONE ****************
* -- load TLK file header --
*
* reading first 28 (4 * 7) bytes
*/
Stream fs = File.OpenRead(fileName);
BinaryReader 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 */
long pos = r.BaseStream.Position;
r.BaseStream.Seek(pos + (Header.MaleEntryCount + Header.FemaleEntryCount) * 8, SeekOrigin.Begin);
CharacterTree = new List<HuffmanNode>();
for (int i = 0; i < Header.treeNodeCount; i++)
CharacterTree.Add(new HuffmanNode(r));
/* **************** STEP THREE ****************
* -- read all of coded data into memory --
*/
byte[] 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 */
Dictionary<int, string> rawStrings = new Dictionary<int, string>();
int offset = 0;
// int maxOffset = 0;
while (offset < Bits.Length)
{
int key = offset;
// if (key > maxOffset)
// maxOffset = key;
/* read the string and update 'offset' variable to store NEXT string offset */
string 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 List<TLKStringRef>();
for (int i = 0; i < Header.MaleEntryCount + Header.FemaleEntryCount; i++)
{
TLKStringRef sref = new TLKStringRef(r);
sref.position = i;
if (sref.BitOffset >= 0)
{
if (!rawStrings.ContainsKey(sref.BitOffset))
{
int tmpOffset = sref.BitOffset;
string 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.Data = partString;
}
else
{
sref.Data = rawStrings[sref.BitOffset];
}
}
StringRefs.Add(sref);
}
r.Close();
}