public static string Decode(Pair[] tree, BitArray data, int offset, int maxLength) { var sb = new StringBuilder(); var start = tree.Length - 1; while (true) { var node = start; do { node = data[offset] == false ? tree[node].Left : tree[node].Right; offset++; } while (node >= 0); var c = (ushort) (-1 - node); if (c == 0) { break; } sb.Append((char) c); if (sb.Length >= maxLength) { break; } } return sb.ToString(); }
public Pair[] GetPairs() { var pairs = new List<Pair>(); var mapping = new Dictionary<Node, Pair>(); var queue = new Queue<Node>(); queue.Enqueue(_root); var root = new Pair(); mapping.Add(_root, root); while (queue.Count > 0) { var node = queue.Dequeue(); var pair = mapping[node]; if (node.Left == null && node.Right == null) { throw new InvalidOperationException(); } // ReSharper disable PossibleNullReferenceException if (node.Left.Left == null && // ReSharper restore PossibleNullReferenceException node.Left.Right == null) { pair.Left = -1 - node.Left.Symbol; } else { var left = new Pair(); mapping.Add(node.Left, left); pairs.Add(left); queue.Enqueue(node.Left); pair.Left = pairs.IndexOf(left); } if (node.Right.Left == null && node.Right.Right == null) { pair.Right = -1 - node.Right.Symbol; } else { var right = new Pair(); mapping.Add(node.Right, right); pairs.Add(right); queue.Enqueue(node.Right); pair.Right = pairs.IndexOf(right); } } pairs.Add(root); return pairs.ToArray(); }
public void Deserialize(Stream input) { var magic = input.ReadUInt32(); if (magic != 0x666D726D && magic.Swap() != 0x666D726D) { throw new FormatException(); } var endian = magic == 0x666D726D ? ByteOrder.LittleEndian : ByteOrder.BigEndian; var version = input.ReadUInt32(endian); if (version != 1) { throw new FormatException(); } Version = version; input.ReadInt32(endian); var maxValueLength = input.ReadInt32(endian); var stringTableSize = input.ReadUInt32(endian); var huffmanSize = input.ReadUInt32(endian); var indexSize = input.ReadUInt32(endian); var dataSize = input.ReadUInt32(endian); var strings = new List<KeyValuePair<uint, string>>(); using (var data = input.ReadToMemoryStream(stringTableSize)) { var localStringTableSize = data.ReadUInt32(endian); if (localStringTableSize != stringTableSize) { throw new FormatException(); } var count = data.ReadUInt32(endian); var offsets = new List<KeyValuePair<uint, uint>>(); for (uint i = 0; i < count; i++) { var hash = data.ReadUInt32(endian); var offset = data.ReadUInt32(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.ReadUInt16(endian); var text = data.ReadString(length, Encoding.UTF8); if (text.HashCrc32() != hash) { throw new InvalidOperationException(); } strings.Add(new KeyValuePair<uint, string>(hash, text)); } } Pair[] huffmanTree; using (var data = input.ReadToMemoryStream(huffmanSize)) { var count = data.ReadUInt16(endian); huffmanTree = new Pair[count]; for (ushort i = 0; i < count; i++) { var left = data.ReadInt32(endian); var right = data.ReadInt32(endian); huffmanTree[i] = new Pair(left, right); } } using (var index = input.ReadToMemoryStream(indexSize)) { var totalBits = input.ReadInt32(endian); var data = input.ReadBytes(dataSize); var bitArray = new BitArray(data) { Length = totalBits }; var files = new List<KeyValuePair<string, uint>>(); var fileCount = index.ReadUInt16(endian); for (ushort i = 0; i < fileCount; i++) { var nameIndex = index.ReadUInt16(endian); var name = strings[nameIndex].Value; var offset = index.ReadUInt32(endian); files.Add(new KeyValuePair<string, uint>(name, offset)); } foreach (var fileInfo in files.OrderBy(f => f.Key)) { var file = new FileEntry { Name = fileInfo.Key }; index.Seek(fileInfo.Value, SeekOrigin.Begin); var sectionCount = index.ReadUInt16(endian); var sections = new List<KeyValuePair<string, uint>>(); for (ushort i = 0; i < sectionCount; i++) { var nameIndex = index.ReadUInt16(endian); var name = strings[nameIndex].Value; var offset = index.ReadUInt32(endian); sections.Add(new KeyValuePair<string, uint>(name, offset)); } foreach (var sectionInfo in sections.OrderBy(s => s.Key)) { var section = new Dictionary<string, List<PropertyValue>>(); index.Seek(fileInfo.Value + sectionInfo.Value, SeekOrigin.Begin); var valueCount = index.ReadUInt16(endian); var values = new List<KeyValuePair<string, uint>>(); for (ushort i = 0; i < valueCount; i++) { var nameIndex = index.ReadUInt16(endian); var name = strings[nameIndex].Value; var offset = index.ReadUInt32(endian); values.Add(new KeyValuePair<string, uint>(name, offset)); } foreach (var valueInfo in values.OrderBy(v => v.Key)) { var value = new List<PropertyValue>(); index.Seek(fileInfo.Value + sectionInfo.Value + valueInfo.Value, SeekOrigin.Begin); var itemCount = index.ReadUInt16(endian); for (ushort i = 0; i < itemCount; i++) { var offset = index.ReadInt32(endian); var type = (offset & 0xE0000000) >> 29; switch (type) { case 1: { value.Add(new PropertyValue(1, null)); break; } case 0: case 2: case 3: case 4: { offset &= 0x1fffffff; var text = Decoder.Decode(huffmanTree, bitArray, offset, maxValueLength); value.Add(new PropertyValue((int) type, text)); break; } default: { throw new NotImplementedException(); } } } section.Add(valueInfo.Key, value); } file.Sections.Add(sectionInfo.Key, section); } Files.Add(file); } } ByteOrder = endian; }