/**
   * Deflates the current input block to the given array. It returns the number of bytes compressed,
   * or 0 if either needsInput() or finished() returns true or length is zero.
   *
   * @param output the buffer where to write the compressed data.
   * @param offset the offset into the output array.
   * @param length the maximum number of bytes that may be written.
   * @exception IllegalStateException if end() was called.
   * @exception IndexOutOfBoundsException if offset and/or length don't match the array length.
   */
  public int deflate(byte[] output, int offset, int length) {
    int origLength = length;

    if (state == CLOSED_STATE) throw new IllegalStateException("Deflater closed");

    if (state < BUSY_STATE) {
      /* output header */
      int header = (DEFLATED + ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;
      int level_flags = (level - 1) >> 1;
      if (level_flags < 0 || level_flags > 3) level_flags = 3;
      header |= level_flags << 6;
      if ((state & IS_SETDICT) != 0)
        /* Dictionary was set */
        header |= DeflaterConstants.PRESET_DICT;
      header += 31 - (header % 31);

      pending.writeShortMSB(header);
      if ((state & IS_SETDICT) != 0) {
        int chksum = engine.getAdler();
        engine.resetAdler();
        pending.writeShortMSB(chksum >> 16);
        pending.writeShortMSB(chksum & 0xffff);
      }

      state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));
    }

    for (; ; ) {
      int count = pending.flush(output, offset, length);
      offset += count;
      totalOut += count;
      length -= count;
      if (length == 0 || state == FINISHED_STATE) break;

      if (!engine.deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) {
        if (state == BUSY_STATE)
          /* We need more input now */
          return origLength - length;
        else if (state == FLUSHING_STATE) {
          if (level != NO_COMPRESSION) {
            /* We have to supply some lookahead.  8 bit lookahead
             * are needed by the zlib inflater, and we must fill
             * the next byte, so that all bits are flushed.
             */
            int neededbits = 8 + ((-pending.getBitCount()) & 7);
            while (neededbits > 0) {
              /* write a static tree block consisting solely of
               * an EOF:
               */
              pending.writeBits(2, 10);
              neededbits -= 10;
            }
          }
          state = BUSY_STATE;
        } else if (state == FINISHING_STATE) {
          pending.alignToByte();
          /* We have completed the stream */
          if (!noHeader) {
            int adler = engine.getAdler();
            pending.writeShortMSB(adler >> 16);
            pending.writeShortMSB(adler & 0xffff);
          }
          state = FINISHED_STATE;
        }
      }
    }

    return origLength - length;
  }
 /** Gets the current adler checksum of the data that was processed so far. */
 public int getAdler() {
   return engine.getAdler();
 }