Example #1
0
  /**
   * 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 boolean decodeHuffman() throws DataFormatException {
    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 (ArrayIndexOutOfBoundsException ex) {
            throw new DataFormatException("Illegal rep length code");
          }
          /* fall through */
        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 */
        case DECODE_HUFFMAN_DIST:
          symbol = distTree.getSymbol(input);
          if (symbol < 0) return false;
          try {
            repDist = CPDIST[symbol];
            neededBits = CPDEXT[symbol];
          } catch (ArrayIndexOutOfBoundsException ex) {
            throw new DataFormatException("Illegal rep dist code");
          }
          /* fall through */
        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 IllegalStateException();
      }
    }
    return true;
  }
  public boolean decode(final StreamManipulator input) throws DataFormatException {
    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 */
        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 */
        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 */
        case BLLENS:
          while (ptr < blnum) {
            final 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 */
        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 DataFormatException();
              }
            }
            repSymbol = symbol - 16;
            mode = REPS;
          }
          /* fall through */

        case REPS:
          {
            final 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 DataFormatException();
            }
            while (count-- > 0) {
              litdistLens[ptr++] = lastLen;
            }

            if (ptr == num) {
              /* Finished */
              return true;
            }
          }
          mode = LENS;
          continue decode_loop;
      }
    }
  }