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;
 }
Example #3
0
        /*
         * 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());
        }