public void Deserialize(Stream input)
{
var magic = input.ReadValueU32(Endian.Little);
if (magic != 0x666D726D && // fmrm
magic.Swap() != 0x666D726D)
{
throw new FormatException();
}
var endian = magic == 0x666D726D ? Endian.Little : Endian.Big;
var version = input.ReadValueU32(endian);
if (version != 1)
{
throw new FormatException();
}
this.Version = version;
/*var maxKeyLength =*/ input.ReadValueS32(endian);
var maxValueLength = input.ReadValueS32(endian);
var stringTableSize = input.ReadValueU32(endian);
var huffmanSize = input.ReadValueU32(endian);
var indexSize = input.ReadValueU32(endian);
var dataSize = input.ReadValueU32(endian);
var strings = new List<KeyValuePair<uint, string>>();
using (var data = input.ReadToMemoryStream(stringTableSize))
{
var localStringTableSize = data.ReadValueU32(endian);
if (localStringTableSize != stringTableSize)
{
throw new FormatException();
}
var count = data.ReadValueU32(endian);
var offsets = new List<KeyValuePair<uint, uint>>();
for (uint i = 0; i < count; i++)
{
var hash = data.ReadValueU32(endian);
var offset = data.ReadValueU32(endian);
offsets.Add(new KeyValuePair<uint, uint>(hash, offset));
}
foreach (var kv in offsets)
{
var hash = kv.Key;
var offset = kv.Value;
data.Seek(8 + offset, SeekOrigin.Begin);
var length = data.ReadValueU16(endian);
var text = data.ReadString(length, Encoding.UTF8);
if (text.HashCrc32() != hash)
{
throw new InvalidOperationException();
}
strings.Add(new KeyValuePair<uint, string>(hash, text));
}
}
Huffman.Pair[] huffmanTree;
using (var data = input.ReadToMemoryStream(huffmanSize))
{
var count = data.ReadValueU16(endian);
huffmanTree = new Huffman.Pair[count];
for (ushort i = 0; i < count; i++)
{
var left = data.ReadValueS32(endian);
var right = data.ReadValueS32(endian);
huffmanTree[i] = new Huffman.Pair(left, right);
}
}
using (var index = input.ReadToMemoryStream(indexSize))
{
var totalBits = input.ReadValueS32(endian);
var data = input.ReadBytes(dataSize);
var bitArray = new BitArray(data) { Length = totalBits };
var files = new List<KeyValuePair<string, uint>>();
var fileCount = index.ReadValueU16(endian);
for (ushort i = 0; i < fileCount; i++)
{
var nameIndex = index.ReadValueU16(endian);
var name = strings[nameIndex].Value;
var offset = index.ReadValueU32(endian);
files.Add(new KeyValuePair<string, uint>(name, offset));
}
foreach (var fileInfo in files.OrderBy(f => f.Key))
{
var file = new Coalesced.File() { Name = fileInfo.Key };
index.Seek(fileInfo.Value, SeekOrigin.Begin);
var sectionCount = index.ReadValueU16(endian);
var sections = new List<KeyValuePair<string, uint>>();
for (ushort i = 0; i < sectionCount; i++)
{
var nameIndex = index.ReadValueU16(endian);
var name = strings[nameIndex].Value;
var offset = index.ReadValueU32(endian);
sections.Add(new KeyValuePair<string, uint>(name, offset));
}
foreach (var sectionInfo in sections.OrderBy(s => s.Key))
{
var section = new Dictionary<string, List<Coalesced.Entry>>();
index.Seek(fileInfo.Value + sectionInfo.Value, SeekOrigin.Begin);
var valueCount = index.ReadValueU16(endian);
var values = new List<KeyValuePair<string, uint>>();
for (ushort i = 0; i < valueCount; i++)
{
var nameIndex = index.ReadValueU16(endian);
var name = strings[nameIndex].Value;
var offset = index.ReadValueU32(endian);
values.Add(new KeyValuePair<string, uint>(name, offset));
}
foreach (var valueInfo in values.OrderBy(v => v.Key))
{
var value = new List<Coalesced.Entry>();
index.Seek(fileInfo.Value + sectionInfo.Value + valueInfo.Value, SeekOrigin.Begin);
var itemCount = index.ReadValueU16(endian);
for (ushort i = 0; i < itemCount; i++)
{
var offset = index.ReadValueS32(endian);
var type = (offset & 0xE0000000) >> 29;
if (type == 1)
{
value.Add(new Coalesced.Entry(1, null));
}
else if (type == 0 || type == 2 || type == 3 || type == 4)
{
offset &= 0x1FFFFFFF;
var text = Huffman.Decoder.Decode(
huffmanTree, bitArray, offset, maxValueLength);
value.Add(new Coalesced.Entry(2, text));
}
else
{
throw new NotImplementedException();
}
}
section.Add(valueInfo.Key, value);
}
file.Sections.Add(sectionInfo.Key, section);
}
this.Files.Add(file);
}
}
this.Endian = endian;
}
}