//Each block of compressed data begins with 3 header bits
// containing the following data:
// first bit BFINAL
// next 2 bits BTYPE
// Note that the header bits do not necessarily begin on a byte
// boundary, since a block does not necessarily occupy an integral
// number of bytes.
// BFINAL is set if and only if this is the last block of the data
// set.
// BTYPE specifies how the data are compressed, as follows:
// 00 - no compression
// 01 - compressed with fixed Huffman codes
// 10 - compressed with dynamic Huffman codes
// 11 - reserved (error)
// The only difference between the two compressed cases is how the
// Huffman codes for the literal/length and distance alphabets are
// defined.
//
// This function returns true for success (end of block or output window is full,)
// false if we are short of input
//
private bool Decode()
{
bool eob = false;
bool result = false;
if (Finished())
{
return(true);
}
if (using_gzip)
{
if (state == InflaterState.ReadingGZIPHeader)
{
if (!gZipDecoder.ReadGzipHeader())
{
return(false);
}
state = InflaterState.ReadingBFinal;
}
else if (state == InflaterState.StartReadingGZIPFooter || state == InflaterState.ReadingGZIPFooter)
{
if (!gZipDecoder.ReadGzipFooter())
{
return(false);
}
state = InflaterState.VerifyingGZIPFooter;
return(true);
}
}
if (state == InflaterState.ReadingBFinal) // reading bfinal bit
// Need 1 bit
{
if (!input.EnsureBitsAvailable(1))
{
return(false);
}
bfinal = input.GetBits(1);
state = InflaterState.ReadingBType;
}
if (state == InflaterState.ReadingBType)
{
// Need 2 bits
if (!input.EnsureBitsAvailable(2))
{
state = InflaterState.ReadingBType;
return(false);
}
blockType = (BlockType)input.GetBits(2);
if (blockType == BlockType.Dynamic)
{
Debug.WriteLineIf(CompressionTracingSwitch.Informational, "Decoding Dynamic Block", "Compression");
state = InflaterState.ReadingNumLitCodes;
}
else if (blockType == BlockType.Static)
{
Debug.WriteLineIf(CompressionTracingSwitch.Informational, "Decoding Static Block", "Compression");
literalLengthTree = HuffmanTree.StaticLiteralLengthTree;
distanceTree = HuffmanTree.StaticDistanceTree;
state = InflaterState.DecodeTop;
}
else if (blockType == BlockType.Uncompressed)
{
Debug.WriteLineIf(CompressionTracingSwitch.Informational, "Decoding UnCompressed Block", "Compression");
state = InflaterState.UncompressedAligning;
}
else
{
throw new InvalidDataException(SR.GetString(SR.UnknownBlockType));
}
}
if (blockType == BlockType.Dynamic)
{
if (state < InflaterState.DecodeTop) // we are reading the header
{
result = DecodeDynamicBlockHeader();
}
else
{
result = DecodeBlock(out eob); // this can returns true when output is full
}
}
else if (blockType == BlockType.Static)
{
result = DecodeBlock(out eob);
}
else if (blockType == BlockType.Uncompressed)
{
result = DecodeUncompressedBlock(out eob);
}
else
{
throw new InvalidDataException(SR.GetString(SR.UnknownBlockType));
}
//
// If we reached the end of the block and the block we were decoding had
// bfinal=1 (final block)
//
if (eob && (bfinal != 0))
{
if (using_gzip)
{
state = InflaterState.StartReadingGZIPFooter;
}
else
{
state = InflaterState.Done;
}
}
return(result);
}