Ejemplo n.º 1
0
        // Format of the dynamic block header:
        //      5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286)
        //      5 Bits: HDIST, # of Distance codes - 1        (1 - 32)
        //      4 Bits: HCLEN, # of Code Length codes - 4     (4 - 19)
        //
        //      (HCLEN + 4) x 3 bits: code lengths for the code length
        //          alphabet given just above, in the order: 16, 17, 18,
        //          0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
        //
        //          These code lengths are interpreted as 3-bit integers
        //          (0-7); as above, a code length of 0 means the
        //          corresponding symbol (literal/length or distance code
        //          length) is not used.
        //
        //      HLIT + 257 code lengths for the literal/length alphabet,
        //          encoded using the code length Huffman code
        //
        //       HDIST + 1 code lengths for the distance alphabet,
        //          encoded using the code length Huffman code
        //
        // The code length repeat codes can cross from HLIT + 257 to the
        // HDIST + 1 code lengths.  In other words, all code lengths form
        // a single sequence of HLIT + HDIST + 258 values.
        private bool DecodeDynamicBlockHeader()
        {
            switch (state)
            {
            case InflaterState.ReadingNumLitCodes:
                literalLengthCodeCount = input.GetBits(5);
                if (literalLengthCodeCount < 0)
                {
                    return(false);
                }
                literalLengthCodeCount += 257;
                state = InflaterState.ReadingNumDistCodes;
                goto case InflaterState.ReadingNumDistCodes;

            case InflaterState.ReadingNumDistCodes:
                distanceCodeCount = input.GetBits(5);
                if (distanceCodeCount < 0)
                {
                    return(false);
                }
                distanceCodeCount += 1;
                state              = InflaterState.ReadingNumCodeLengthCodes;
                goto case InflaterState.ReadingNumCodeLengthCodes;

            case InflaterState.ReadingNumCodeLengthCodes:
                codeLengthCodeCount = input.GetBits(4);
                if (codeLengthCodeCount < 0)
                {
                    return(false);
                }
                codeLengthCodeCount += 4;
                loopCounter          = 0;
                state = InflaterState.ReadingCodeLengthCodes;
                goto case InflaterState.ReadingCodeLengthCodes;

            case InflaterState.ReadingCodeLengthCodes:
                while (loopCounter < codeLengthCodeCount)
                {
                    int bits = input.GetBits(3);
                    if (bits < 0)
                    {
                        return(false);
                    }
                    codeLengthTreeCodeLength[codeOrder[loopCounter]] = (byte)bits;
                    ++loopCounter;
                }

                for (int i = codeLengthCodeCount; i < codeOrder.Length; i++)
                {
                    codeLengthTreeCodeLength[codeOrder[i]] = 0;
                }

                // create huffman tree for code length
                codeLengthTree = new HuffmanTree(codeLengthTreeCodeLength);
                codeArraySize  = literalLengthCodeCount + distanceCodeCount;
                loopCounter    = 0;      // reset loop count

                state = InflaterState.ReadingTreeCodesBefore;
                goto case InflaterState.ReadingTreeCodesBefore;

            case InflaterState.ReadingTreeCodesBefore:
            case InflaterState.ReadingTreeCodesAfter:
                while (loopCounter < codeArraySize)
                {
                    if (state == InflaterState.ReadingTreeCodesBefore)
                    {
                        if ((lengthCode = codeLengthTree.GetNextSymbol(input)) < 0)
                        {
                            return(false);
                        }
                    }

                    // The alphabet for code lengths is as follows:
                    //  0 - 15: Represent code lengths of 0 - 15
                    //  16: Copy the previous code length 3 - 6 times.
                    //  The next 2 bits indicate repeat length
                    //         (0 = 3, ... , 3 = 6)
                    //      Example:  Codes 8, 16 (+2 bits 11),
                    //                16 (+2 bits 10) will expand to
                    //                12 code lengths of 8 (1 + 6 + 5)
                    //  17: Repeat a code length of 0 for 3 - 10 times.
                    //    (3 bits of length)
                    //  18: Repeat a code length of 0 for 11 - 138 times
                    //    (7 bits of length)
                    if (lengthCode <= 15)
                    {
                        codeList[loopCounter++] = (byte)lengthCode;
                    }
                    else
                    {
                        if (!input.EnsureBitsAvailable(7))
                        {     // it doesn't matter if we require more bits here
                            state = InflaterState.ReadingTreeCodesAfter;
                            return(false);
                        }

                        int repeatCount;
                        if (lengthCode == 16)
                        {
                            if (loopCounter == 0)
                            {              // can't have "prev code" on first code
                                throw new InvalidDataException();
                            }

                            byte previousCode = codeList[loopCounter - 1];
                            repeatCount = input.GetBits(2) + 3;

                            if (loopCounter + repeatCount > codeArraySize)
                            {
                                throw new InvalidDataException();
                            }

                            for (int j = 0; j < repeatCount; j++)
                            {
                                codeList[loopCounter++] = previousCode;
                            }
                        }
                        else if (lengthCode == 17)
                        {
                            repeatCount = input.GetBits(3) + 3;

                            if (loopCounter + repeatCount > codeArraySize)
                            {
                                throw new InvalidDataException();
                            }

                            for (int j = 0; j < repeatCount; j++)
                            {
                                codeList[loopCounter++] = 0;
                            }
                        }
                        else
                        {     // code == 18
                            repeatCount = input.GetBits(7) + 11;

                            if (loopCounter + repeatCount > codeArraySize)
                            {
                                throw new InvalidDataException();
                            }

                            for (int j = 0; j < repeatCount; j++)
                            {
                                codeList[loopCounter++] = 0;
                            }
                        }
                    }
                    state = InflaterState.ReadingTreeCodesBefore;     // we want to read the next code.
                }
                break;

            default:
                Debug.Assert(false, "check why we are here!");
                throw new InvalidDataException("UnknownState");
            }

            byte[] literalTreeCodeLength  = new byte[HuffmanTree.MaxLiteralTreeElements];
            byte[] distanceTreeCodeLength = new byte[HuffmanTree.MaxDistTreeElements];

            // Create literal and distance tables
            Array.Copy(codeList, literalTreeCodeLength, literalLengthCodeCount);
            Array.Copy(codeList, literalLengthCodeCount, distanceTreeCodeLength, 0, distanceCodeCount);

            // Make sure there is an end-of-block code, otherwise how could we ever end?
            if (literalTreeCodeLength[HuffmanTree.EndOfBlockCode] == 0)
            {
                throw new InvalidDataException();
            }

            literalLengthTree = new HuffmanTree(literalTreeCodeLength);
            distanceTree      = new HuffmanTree(distanceTreeCodeLength);
            state             = InflaterState.DecodeTop;
            return(true);
        }
Ejemplo n.º 2
0
        private bool DecodeBlock(out bool end_of_block_code_seen)
        {
            end_of_block_code_seen = false;

            int freeBytes = output.FreeBytes;   // it is a little bit faster than frequently accessing the property

            while (freeBytes > 258)
            {
                // 258 means we can safely do decoding since maximum repeat length is 258

                int symbol;
                switch (state)
                {
                case InflaterState.DecodeTop:
                    // decode an element from the literal tree

                    // TODO: optimize this!!!
                    symbol = literalLengthTree.GetNextSymbol(input);
                    if (symbol < 0)
                    {              // running out of input
                        return(false);
                    }

                    if (symbol < 256)
                    {            // literal
                        output.Write((byte)symbol);
                        --freeBytes;
                    }
                    else if (symbol == 256)
                    {     // end of block
                        end_of_block_code_seen = true;
                        Debug.WriteLineIf(CompressionTracingSwitch.Informational, "End of Block", "Compression");
                        // Reset state
                        state = InflaterState.ReadingBFinal;
                        return(true);              // ***********
                    }
                    else
                    {                     // length/distance pair
                        symbol -= 257;    // length code started at 257
                        if (symbol < 8)
                        {
                            symbol   += 3;     // match length = 3,4,5,6,7,8,9,10
                            extraBits = 0;
                        }
                        else if (symbol == 28)
                        {                    // extra bits for code 285 is 0
                            symbol    = 258; // code 285 means length 258
                            extraBits = 0;
                        }
                        else
                        {
                            if (symbol < 0 || symbol >= extraLengthBits.Length)
                            {
                                throw new InvalidDataException("GenericInvalidData");
                            }
                            extraBits = extraLengthBits[symbol];
                            Debug.Assert(extraBits != 0, "We handle other cases seperately!");
                        }
                        length = symbol;
                        goto case InflaterState.HaveInitialLength;
                    }
                    break;

                case InflaterState.HaveInitialLength:
                    if (extraBits > 0)
                    {
                        state = InflaterState.HaveInitialLength;
                        int bits = input.GetBits(extraBits);
                        if (bits < 0)
                        {
                            return(false);
                        }

                        if (length < 0 || length >= lengthBase.Length)
                        {
                            throw new InvalidDataException("GenericInvalidData");
                        }
                        length = lengthBase[length] + bits;
                    }
                    state = InflaterState.HaveFullLength;
                    goto case InflaterState.HaveFullLength;

                case InflaterState.HaveFullLength:
                    if (blockType == BlockType.Dynamic)
                    {
                        distanceCode = distanceTree.GetNextSymbol(input);
                    }
                    else
                    {       // get distance code directly for static block
                        distanceCode = input.GetBits(5);
                        if (distanceCode >= 0)
                        {
                            distanceCode = staticDistanceTreeTable[distanceCode];
                        }
                    }

                    if (distanceCode < 0)
                    {     // running out input
                        return(false);
                    }

                    state = InflaterState.HaveDistCode;
                    goto case InflaterState.HaveDistCode;

                case InflaterState.HaveDistCode:
                    // To avoid a table lookup we note that for distanceCode >= 2,
                    // extra_bits = (distanceCode-2) >> 1
                    int offset;
                    if (distanceCode > 3)
                    {
                        extraBits = (distanceCode - 2) >> 1;
                        int bits = input.GetBits(extraBits);
                        if (bits < 0)
                        {
                            return(false);
                        }
                        offset = distanceBasePosition[distanceCode] + bits;
                    }
                    else
                    {
                        offset = distanceCode + 1;
                    }

                    Debug.Assert(freeBytes >= 258, "following operation is not safe!");
                    output.WriteLengthDistance(length, offset);
                    freeBytes -= length;
                    state      = InflaterState.DecodeTop;
                    break;

                default:
                    Debug.Assert(false, "check why we are here!");
                    throw new InvalidDataException("UnknownState");
                }
            }

            return(true);
        }