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 // 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; // 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(SR.GetString(SR.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(SR.GetString(SR.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(SR.GetString(SR.UnknownState)); } } return(true); }
// 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. 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(SR.GetString(SR.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); }
// 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. 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(SR.GetString(SR.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; }