/// <summary>
 /// BitStringLookup function.
 /// </summary>
 /// <param name="bstr">
 /// BITSTRING to look up.
 /// </param>
 /// <param name="n"></param>
 /// <returns></returns>
 public UInt32 BitStringLookup(ref BITSTRING bstr, UInt32 n)
 {
     if (n == 0)
     {
         return(0);
     }
     else
     {
         return(bstr.mask >> (int)(32 - n));
     }
 }
 /// <summary>
 /// Initializes BitString
 /// </summary>
 /// <param name="bstr">
 /// BITSTRING to initialize.
 /// </param>
 /// <param name="source">
 /// Source array
 /// </param>
 /// <param name="index">
 /// Index value
 /// </param>
 public void BitStringInit(ref BITSTRING bstr, byte[] source, UInt32 index)
 {
     bstr.mask   = BitConverter.ToUInt16(source, (int)index);
     bstr.mask   = bstr.mask << 16;
     index       = index + 2;
     bstr.mask   = bstr.mask + BitConverter.ToUInt16(source, (int)index);
     index       = index + 2;
     bstr.bits   = 32;
     bstr.source = source;
     bstr.index  = index;
 }
        /// <summary>
        /// BitStringSkip function
        /// </summary>
        /// <param name="bstr"></param>
        /// <param name="n"></param>
        public void BitStringSkip(ref BITSTRING bstr, UInt32 n)
        {
            bstr.mask = bstr.mask << (int)n;
            bstr.bits = bstr.bits - (Int32)n;

            if (bstr.bits < 16)
            {
                bstr.mask = bstr.mask + (UInt32)(BitConverter.ToUInt16(bstr.source, (int)bstr.index)
                                                 << (int)(16 - bstr.bits));
                bstr.index = bstr.index + 2;
                bstr.bits  = bstr.bits + 16;
            }
        }
        /// <summary>
        /// PrefixCodeTreeDecodeSymbol method decodes the symbols.
        /// </summary>
        /// <param name="bstr"></param>
        /// <param name="root">
        /// Used to traverse the tree.
        /// </param>
        /// <returns></returns>
        public UInt32 PrefixCodeTreeDecodeSymbol(ref BITSTRING bstr, PrefixCodeNode root)
        {
            UInt32         bit;
            PrefixCodeNode node = root;

            do
            {
                bit = BitStringLookup(ref bstr, 1);
                BitStringSkip(ref bstr, 1);
                node = node.Child[bit];
            } while (node.leaf == false);

            return(node.symbol);
        }
        /// <summary>
        /// This method is called to decompress the compressed data
        /// </summary>
        /// <param name="input">
        /// Compressed Byte Array
        /// </param>
        /// <param name="outputSize">
        /// Uncompressed Output Size
        /// </param>
        /// <param name="outputBuffer">
        /// Decompressed output buffer.
        /// </param>
        public void Decompress(byte[] input, UInt32 outputSize, out byte[] outputBuffer)
        {
            byte[] output = new byte[outputSize];

            UInt32 i         = 0;
            UInt32 stopIndex = i + outputSize;
            UInt32 symbol;
            UInt32 length;
            Int32  offset;

            PrefixCodeNode root = new PrefixCodeNode();

            PrefixCodeNode[] prefixCodeTreeNodes = new PrefixCodeNode[1024];
            for (int count = 0; count < 1024; count++)
            {
                prefixCodeTreeNodes[count] = new PrefixCodeNode();
            }

            BITSTRING bstr = new BITSTRING();

            root = PrefixCodeTreeRebuild(input, ref prefixCodeTreeNodes);

            BitStringInit(ref bstr, input, 256);

            while (i < stopIndex)
            {
                symbol = PrefixCodeTreeDecodeSymbol(ref bstr, root);

                if (symbol < 256)
                {
                    output[i] = (byte)symbol;
                    i++;
                }
                else
                {
                    symbol = symbol - 256;
                    length = symbol & 15;
                    symbol = symbol >> 4;

                    offset = (int)((1 << (int)symbol) + BitStringLookup(ref bstr, symbol));
                    offset = (-1) * offset;

                    if (length == 15)
                    {
                        length     = bstr.source[bstr.index] + (UInt32)15;
                        bstr.index = bstr.index + 1;

                        if (length == 270)
                        {
                            length     = BitConverter.ToUInt16(bstr.source, (int)bstr.index);
                            bstr.index = bstr.index + 2;
                        }
                    }

                    BitStringSkip(ref bstr, symbol);
                    length = length + 3;

                    do
                    {
                        output[i] = output[i + offset];
                        i++;
                        length--;
                    } while (length != 0);
                }
            }

            outputBuffer = output;
        }