public HuffNode(byte symbol) { IsBranch = false; Symbol = symbol; Weight = 1; Left = Right = null; }
public HuffNode(int weight, HuffNode left, HuffNode right) { IsBranch = true; Symbol = 0; Weight = weight; Left = left; Right = right; }
/* * Pack * Encode 1 or more byte streams into a Huffman archive * * List<byte[]> files = List of byte streams (files) */ public static byte[] Pack(List <byte[]> files) { int numFiles = files.Count; // scan files to get symbols and their respective weights List <HuffNode> nodes = new List <HuffNode>(); for (int i = 0; i < files.Count; i++) { for (int j = 0; j < files[i].Length; j++) { if (nodes.Count == 0) { nodes.Add(new HuffNode(files[i][j])); } else { bool nodeFound = false; for (int n = 0; n < nodes.Count; n++) { if (nodes[n].Symbol == files[i][j]) { nodes[n].Weight++; nodeFound = true; break; } } if (!nodeFound) { nodes.Add(new HuffNode(files[i][j])); } } } } // sort the Nodes into a priority queue (in ascending weight order) nodes.Sort((x, y) => x.Weight.CompareTo(y.Weight)); // build tree while (nodes.Count > 1) { HuffNode left = nodes[0]; HuffNode right = nodes[1]; int weight = nodes[0].Weight + nodes[1].Weight; nodes.RemoveRange(0, 2); HuffNode branch = new HuffNode(weight, left, right); int n = 0; while (n < nodes.Count) { if (branch.Weight <= nodes[n].Weight) { break; } n++; } nodes.Insert(n, branch); } // traverse tree and write it, also saving the hash codes for each symbol List <byte> chars = new List <byte>(); List <bool> tree = new List <bool>(); List <HuffCode> huffCodes = new List <HuffCode>(); nodes[0].Traverse(chars, tree, huffCodes, new List <bool>()); // initialise byte stream that will eventually be returned List <byte> stream = new List <byte>(); // write # files stream.Add(0); stream.Add((byte)numFiles); // write # chars stream.Add((byte)(chars.Count >> 8)); stream.Add((byte)chars.Count); // write file headers & prepare data List <bool> data = new List <bool>(); foreach (byte[] file in files) { // write byte offset ushort offset = (ushort)(2 + 2 + (6 * numFiles) + chars.Count + Math.Ceiling(((decimal)tree.Count) / 8) + (data.Count / 8)); byte msb = (byte)(offset >> 8); byte lsb = (byte)(offset & 0x00FF); stream.Add(msb); stream.Add(lsb); // write bit offset lsb = (byte)(data.Count % 8); stream.Add(0); stream.Add(lsb); // write unpacked data length ushort len = (ushort)file.Length; msb = (byte)(len >> 8); lsb = (byte)(len & 0x00FF); stream.Add(msb); stream.Add(lsb); // process each byte in the file and write the packed hash foreach (byte symbol in file) { foreach (HuffCode huffCode in huffCodes) { if (symbol == huffCode.Symbol) { data.AddRange(huffCode.HashString); break; } } } } // write chars stream.AddRange(chars); // write tree stream.AddRange(bitsToBytes(tree)); // write data stream.AddRange(bitsToBytes(data)); return(stream.ToArray()); }