static InflaterHuffmanTree() { try { byte[] codeLengths = new byte[288]; int i = 0; while (i < 144) codeLengths[i++] = 8; while (i < 256) codeLengths[i++] = 9; while (i < 280) codeLengths[i++] = 7; while (i < 288) codeLengths[i++] = 8; defLitLenTree = new InflaterHuffmanTree(codeLengths); codeLengths = new byte[32]; i = 0; while (i < 32) codeLengths[i++] = 5; defDistTree = new InflaterHuffmanTree(codeLengths); } catch (System.Exception ex) { throw new System.Exception("InflaterHuffmanTree: static tree length illegal"); } }
public bool decode(StreamManipulator input) { decode_loop: for (; ; ) { switch (mode) { case LNUM: lnum = input.peekBits(5); if (lnum < 0) return false; lnum += 257; input.dropBits(5); // System.err.println("LNUM: "+lnum); mode = DNUM; /* fall through */ goto case DNUM; case DNUM: dnum = input.peekBits(5); if (dnum < 0) return false; dnum++; input.dropBits(5); // System.err.println("DNUM: "+dnum); num = lnum + dnum; litdistLens = new byte[num]; mode = BLNUM; /* fall through */ goto case BLNUM; case BLNUM: blnum = input.peekBits(4); if (blnum < 0) return false; blnum += 4; input.dropBits(4); blLens = new byte[19]; ptr = 0; // System.err.println("BLNUM: "+blnum); mode = BLLENS; /* fall through */ goto case BLLENS; case BLLENS: while (ptr < blnum) { int len = input.peekBits(3); if (len < 0) return false; input.dropBits(3); // System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len); blLens[BL_ORDER[ptr]] = (byte)len; ptr++; } blTree = new InflaterHuffmanTree(blLens); blLens = null; ptr = 0; mode = LENS; /* fall through */ goto case LENS; case LENS: { int symbol; while (((symbol = blTree.getSymbol(input)) & ~15) == 0) { /* Normal case: symbol in [0..15] */ // System.err.println("litdistLens["+ptr+"]: "+symbol); litdistLens[ptr++] = lastLen = (byte)symbol; if (ptr == num) { /* Finished */ return true; } } /* need more input ? */ if (symbol < 0) return false; /* otherwise repeat code */ if (symbol >= 17) { /* repeat zero */ // System.err.println("repeating zero"); lastLen = 0; } else { if (ptr == 0) throw new System.Exception(); } repSymbol = symbol - 16; mode = REPS; } /* fall through */ goto case REPS; case REPS: { int bits = repBits[repSymbol]; int count = input.peekBits(bits); if (count < 0) return false; input.dropBits(bits); count += repMin[repSymbol]; // System.err.println("litdistLens repeated: "+count); if (ptr + count > num) throw new System.Exception(); while (count-- > 0) litdistLens[ptr++] = lastLen; if (ptr == num) { /* Finished */ return true; } } mode = LENS; goto decode_loop; } } }
/** * Decodes the deflated stream. * @return false if more input is needed, or if finished. * @exception DataFormatException if deflated stream is invalid. */ private bool decode() { switch (mode) { case DECODE_HEADER: return decodeHeader(); case DECODE_DICT: return decodeDict(); case DECODE_CHKSUM: return decodeChksum(); case DECODE_BLOCKS: if (isLastBlock) { if (nowrap) { mode = FINISHED; return false; } else { input.skipToByteBoundary(); neededBits = 32; mode = DECODE_CHKSUM; return true; } } int type = input.peekBits(3); if (type < 0) return false; input.dropBits(3); if ((type & 1) != 0) isLastBlock = true; switch (type >> 1) { case DeflaterConstants.STORED_BLOCK: input.skipToByteBoundary(); mode = DECODE_STORED_LEN1; break; case DeflaterConstants.STATIC_TREES: litlenTree = InflaterHuffmanTree.defLitLenTree; distTree = InflaterHuffmanTree.defDistTree; mode = DECODE_HUFFMAN; break; case DeflaterConstants.DYN_TREES: dynHeader = new InflaterDynHeader(); mode = DECODE_DYN_HEADER; break; default: throw new System.Exception("Unknown block type " + type); } return true; case DECODE_STORED_LEN1: { if ((uncomprLen = input.peekBits(16)) < 0) return false; input.dropBits(16); mode = DECODE_STORED_LEN2; } /* fall through */ goto case DECODE_STORED_LEN2; case DECODE_STORED_LEN2: { int nlen = input.peekBits(16); if (nlen < 0) return false; input.dropBits(16); if (nlen != (uncomprLen ^ 0xffff)) throw new System.Exception("broken uncompressed block"); mode = DECODE_STORED; } /* fall through */ goto case DECODE_STORED; case DECODE_STORED: { int more = outputWindow.copyStored(input, uncomprLen); uncomprLen -= more; if (uncomprLen == 0) { mode = DECODE_BLOCKS; return true; } return !input.needsInput(); } //goto case DECODE_DYN_HEADER; case DECODE_DYN_HEADER: if (!dynHeader.decode(input)) return false; litlenTree = dynHeader.buildLitLenTree(); distTree = dynHeader.buildDistTree(); mode = DECODE_HUFFMAN; /* fall through */ goto case DECODE_HUFFMAN; case DECODE_HUFFMAN: case DECODE_HUFFMAN_LENBITS: case DECODE_HUFFMAN_DIST: case DECODE_HUFFMAN_DISTBITS: return decodeHuffman(); case FINISHED: return false; default: throw new System.Exception(); } }
/** * Decodes the huffman encoded symbols in the input stream. * @return false if more input is needed, true if output window is * full or the current block ends. * @exception DataFormatException if deflated stream is invalid. */ private bool decodeHuffman() { int free = outputWindow.getFreeSpace(); while (free >= 258) { int symbol; switch (mode) { case DECODE_HUFFMAN: /* This is the inner loop so it is optimized a bit */ while (((symbol = litlenTree.getSymbol(input)) & ~0xff) == 0) { outputWindow.write(symbol); if (--free < 258) return true; } if (symbol < 257) { if (symbol < 0) return false; else { /* symbol == 256: end of block */ distTree = null; litlenTree = null; mode = DECODE_BLOCKS; return true; } } try { repLength = CPLENS[symbol - 257]; neededBits = CPLEXT[symbol - 257]; } catch (System.Exception ex) { throw new System.Exception("Illegal rep length code"); } /* fall through */ goto case DECODE_HUFFMAN_LENBITS; case DECODE_HUFFMAN_LENBITS: if (neededBits > 0) { mode = DECODE_HUFFMAN_LENBITS; int i = input.peekBits(neededBits); if (i < 0) return false; input.dropBits(neededBits); repLength += i; } mode = DECODE_HUFFMAN_DIST; /* fall through */ goto case DECODE_HUFFMAN_DIST; case DECODE_HUFFMAN_DIST: symbol = distTree.getSymbol(input); if (symbol < 0) return false; try { repDist = CPDIST[symbol]; neededBits = CPDEXT[symbol]; } catch (IndexOutOfRangeException ex) { throw new System.Exception("Illegal rep dist code"); } /* fall through */ goto case DECODE_HUFFMAN_DISTBITS; case DECODE_HUFFMAN_DISTBITS: if (neededBits > 0) { mode = DECODE_HUFFMAN_DISTBITS; int i = input.peekBits(neededBits); if (i < 0) return false; input.dropBits(neededBits); repDist += i; } outputWindow.repeat(repLength, repDist); free -= repLength; mode = DECODE_HUFFMAN; break; default: throw new System.Exception(); } } return true; }
/** * Resets the inflater so that a new stream can be decompressed. All * pending input and output will be discarded. */ public void reset() { mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; totalIn = totalOut = 0; input.reset(); outputWindow.reset(); dynHeader = null; litlenTree = null; distTree = null; isLastBlock = false; adler.reset(); }
/** * Frees all objects allocated by the inflater. There's no reason * to call this, since you can just rely on garbage collection (even * for the Sun implementation). Exists only for compatibility * with Sun's JDK, where the compressor allocates native memory. * If you call any method (even reset) afterwards the behaviour is * <i>undefined</i>. */ public void end() { outputWindow = null; input = null; dynHeader = null; litlenTree = null; distTree = null; adler = null; }