Blast.Blast.DecompressStream C# (CSharp) Method

DecompressStream() private method

Decode PKWare Compression Library stream. Format notes: - First byte is 0 if literals are uncoded or 1 if they are coded. Second byte is 4, 5, or 6 for the number of extra bits in the distance code. This is the base-2 logarithm of the dictionary size minus six. - Compressed data is a combination of literals and length/distance pairs terminated by an end code. Literals are either Huffman coded or uncoded bytes. A length/distance pair is a coded length followed by a coded distance to represent a string that occurs earlier in the uncompressed data that occurs again at the current location. - A bit preceding a literal or length/distance pair indicates which comes next, 0 for literals, 1 for length/distance. - If literals are uncoded, then the next eight bits are the literal, in the normal bit order in th stream, i.e. no bit-reversal is needed. Similarly, no bit reversal is needed for either the length extra bits or the distance extra bits. - Literal bytes are simply written to the output. A length/distance pair is an instruction to copy previously uncompressed bytes to the output. The copy is from distance bytes back in the output stream, copying for length bytes. - Distances pointing before the beginning of the output data are not permitted. - Overlapped copies, where the length is greater than the distance, are allowed and common. For example, a distance of one and a length of 518 simply copies the last byte 518 times. A distance of four and a length of twelve copies the last four bytes three times. A simple forward copy ignoring whether the length is greater than the distance or not implements this correctly.
private DecompressStream ( ) : void
return void
        private void DecompressStream()
        {
            int codedLiteral; // true if literals are coded
            int dictSize;		   // log2(dictionary size) - 6
            int decodedSymbol;		 // decoded symbol, extra bits for distance
            int copyLength;			// length for copy
            int copyDist;		   // distance for copy
            int copyCount;		   // copy counter

            int fromIndex;

            // read header (start of compressed stream)
            codedLiteral = GetBits(8);
            if (codedLiteral > 1)
            {
                throw new BlastException(BlastException.LiteralFlagMessage);
            }

            dictSize = GetBits(8);

            if (dictSize < 4 || dictSize > 6)
            {
                throw new BlastException(BlastException.DictionarySizeMessage);
            }

            // decode the compressed stream
            try
            {
                // decode literals and length/distance pairs
                do
                {
                    if (GetBits(1) > 0)
                    { // 0 == literal, 1 == length+distance

                        // decode length
                        decodedSymbol = Decode(HuffmanTable.LENGTH_CODE);
                        copyLength = LENGTH_CODE_BASE[decodedSymbol] + GetBits(LENGTH_CODE_EXTRA[decodedSymbol]);

                        if (copyLength == END_OF_STREAM) // sentinel value
                        {
                            // no more for this stream,
                            // stop and flush
                            break;
                        }

                        // decode distance
                        decodedSymbol = copyLength == 2 ? 2 : dictSize;
                        copyDist = Decode(HuffmanTable.DISTANCE_CODE) << decodedSymbol;
                        copyDist += GetBits(decodedSymbol);
                        copyDist++;

                        // malformed input - you can't go back that far
                        if (copyDist > this._outputBufferPos)
                        {
                            throw new BlastException(BlastException.DistanceMessage);
                        }

                        // Copy copyLength bytes from copyDist bytes back.
                        // If copyLength is greater than copyDist, repeatedly
                        // copy copyDist bytes up to a count of copyLength.
                        do
                        {
                            fromIndex = this._outputBufferPos - copyDist;

                            copyCount = copyDist;

                            if (copyCount > copyLength)
                            {
                                copyCount = copyLength;
                            }

                            CopyBufferSection(fromIndex, copyCount);

                            copyLength -= copyCount;

                        } while (copyLength != 0);
                    }
                    else
                    {
                        // get literal and write it
                        decodedSymbol = codedLiteral != 0 ? Decode(HuffmanTable.LITERAL_CODE) : GetBits(8);
                        WriteBuffer((byte)decodedSymbol);
                    }
                } while (true);
            }
            finally
            {
                // write remaining bytes
                FlushOutputBuffer();
                FlushBits();
            }
        }