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; } } }
/** * Reads the next symbol from input. The symbol is encoded using the * huffman tree. * @param input the input source. * @return the next symbol, or -1 if not enough input is available. */ public int getSymbol(StreamManipulator input) { int lookahead, symbol; if ((lookahead = input.peekBits(9)) >= 0) { if ((symbol = tree[lookahead]) >= 0) { input.dropBits(symbol & 15); return symbol >> 4; } int subtree = -(symbol >> 4); int bitlen = symbol & 15; if ((lookahead = input.peekBits(bitlen)) >= 0) { symbol = tree[subtree | (lookahead >> 9)]; input.dropBits(symbol & 15); return symbol >> 4; } else { int bits = input.getAvailableBits(); lookahead = input.peekBits(bits); symbol = tree[subtree | (lookahead >> 9)]; if ((symbol & 15) <= bits) { input.dropBits(symbol & 15); return symbol >> 4; } else return -1; } } else { int bits = input.getAvailableBits(); lookahead = input.peekBits(bits); symbol = tree[lookahead]; if (symbol >= 0 && (symbol & 15) <= bits) { input.dropBits(symbol & 15); return symbol >> 4; } else return -1; } }