/**
   * Flushes this output stream, forcing any pending buffered output bytes to be written.
   *
   * @throws IOException if an I/O error occurs or this stream is already closed
   */
  public void flush() throws IOException {
    ensureOpen();

    // Finish decompressing and writing pending output data
    if (!inf.finished()) {
      try {
        while (!inf.finished() && !inf.needsInput()) {
          int n;

          // Decompress pending output data
          n = inf.inflate(buf, 0, buf.length);
          if (n < 1) {
            break;
          }

          // Write the uncompressed output data block
          out.write(buf, 0, n);
        }
        super.flush();
      } catch (DataFormatException ex) {
        // Improperly formatted compressed (ZIP) data
        String msg = ex.getMessage();
        if (msg == null) {
          msg = "Invalid ZLIB data format";
        }
        throw new ZipException(msg);
      }
    }
  }
 /**
  * Reads uncompressed data into an array of bytes. If <code>len</code> is not zero, the method
  * will block until some input can be decompressed; otherwise, no bytes are read and <code>0
  * </code> is returned.
  *
  * @param b the buffer into which the data is read
  * @param off the start offset in the destination array <code>b</code>
  * @param len the maximum number of bytes read
  * @return the actual number of bytes read, or -1 if the end of the compressed input is reached or
  *     a preset dictionary is needed
  * @exception NullPointerException If <code>b</code> is <code>null</code>.
  * @exception IndexOutOfBoundsException If <code>off</code> is negative, <code>len</code> is
  *     negative, or <code>len</code> is greater than <code>b.length - off</code>
  * @exception ZipException if a ZIP format error has occurred
  * @exception IOException if an I/O error has occurred
  */
 public int read(byte[] b, int off, int len) throws IOException {
   ensureOpen();
   if (b == null) {
     throw new NullPointerException();
   } else if (off < 0 || len < 0 || len > b.length - off) {
     throw new IndexOutOfBoundsException();
   } else if (len == 0) {
     return 0;
   }
   try {
     int n;
     while ((n = inf.inflate(b, off, len)) == 0) {
       if (inf.finished() || inf.needsDictionary()) {
         reachEOF = true;
         return -1;
       }
       if (inf.needsInput()) {
         fill();
       }
     }
     return n;
   } catch (DataFormatException e) {
     String s = e.getMessage();
     throw new ZipException(s != null ? s : "Invalid ZLIB data format");
   }
 }
예제 #3
0
  @Override
  public TransformationResult getMoreData(byte opCode, boolean fin, int rsv, ByteBuffer dest)
      throws IOException {
    // Control frames are never compressed and may appear in the middle of
    // a WebSocket method. Pass them straight through.
    if (Util.isControl(opCode)) {
      return next.getMoreData(opCode, fin, rsv, dest);
    }

    if (!Util.isContinuation(opCode)) {
      // First frame in new message
      skipDecompression = (rsv & RSV_BITMASK) == 0;
    }

    // Pass uncompressed frames straight through.
    if (skipDecompression) {
      return next.getMoreData(opCode, fin, rsv, dest);
    }

    int written;
    boolean usedEomBytes = false;

    while (dest.remaining() > 0) {
      // Space available in destination. Try and fill it.
      try {
        written =
            inflater.inflate(dest.array(), dest.arrayOffset() + dest.position(), dest.remaining());
      } catch (DataFormatException e) {
        throw new IOException(sm.getString("perMessageDeflate.deflateFailed"), e);
      }
      dest.position(dest.position() + written);

      if (inflater.needsInput() && !usedEomBytes) {
        if (dest.hasRemaining()) {
          readBuffer.clear();
          TransformationResult nextResult =
              next.getMoreData(opCode, fin, (rsv ^ RSV_BITMASK), readBuffer);
          inflater.setInput(readBuffer.array(), readBuffer.arrayOffset(), readBuffer.position());
          if (TransformationResult.UNDERFLOW.equals(nextResult)) {
            return nextResult;
          } else if (TransformationResult.END_OF_FRAME.equals(nextResult)
              && readBuffer.position() == 0) {
            if (fin) {
              inflater.setInput(EOM_BYTES);
              usedEomBytes = true;
            } else {
              return TransformationResult.END_OF_FRAME;
            }
          }
        }
      } else if (written == 0) {
        if (fin && (isServer && !clientContextTakeover || !isServer && !serverContextTakeover)) {
          inflater.reset();
        }
        return TransformationResult.END_OF_FRAME;
      }
    }

    return TransformationResult.OVERFLOW;
  }
예제 #4
0
  /**
   * @param compressed_size or use null if not known
   * @param uncompressed_size or use null if not known
   * @return uncompressed ByteArrayOutputStream
   * @throws IOException
   * @throws DataFormatException
   */
  private ByteArrayOutputStream unCompress(Integer compressed_size, Integer uncompressed_size)
      throws IOException, DataFormatException {
    byte[] uncompressed_data = null;
    byte[] input_data = null;
    ByteArrayOutputStream ret = new ByteArrayOutputStream();
    Inflater decompresser = new Inflater(false);
    long first_seek = fileChannel.position();
    Boolean uncompressing = true;
    while (uncompressing) {
      if (decompresser.needsInput()) {
        input_data = new byte[(compressed_size != null) ? compressed_size.intValue() : 1024];
        fileChannel.read(ByteBuffer.wrap(input_data));
        decompresser.setInput(input_data, 0, input_data.length);
      }
      uncompressed_data =
          new byte
              [(uncompressed_size != null)
                  ? uncompressed_size.intValue()
                  : (input_data.length * 4)];
      decompresser.inflate(uncompressed_data);
      int op = (int) (decompresser.getBytesWritten() - (long) ret.size());
      if (op > 0) ret.write(uncompressed_data, 0, op);

      if (decompresser.finished()) uncompressing = false;
    }
    fileChannel.position(
        (first_seek + decompresser.getBytesRead())); // move file pointer to start of next stream
    decompresser.end();
    return ret;
  }
  /**
   * Writes an array of bytes to the uncompressed output stream.
   *
   * @param b buffer containing compressed data to decompress and write to the output stream
   * @param off starting offset of the compressed data within {@code b}
   * @param len number of bytes to decompress from {@code b}
   * @throws IndexOutOfBoundsException if {@code off < 0}, or if {@code len < 0}, or if {@code len >
   *     b.length - off}
   * @throws IOException if an I/O error occurs or this stream is already closed
   * @throws NullPointerException if {@code b} is null
   * @throws ZipException if a compression (ZIP) format error occurs
   */
  public void write(byte[] b, int off, int len) throws IOException {
    // Sanity checks
    ensureOpen();
    if (b == null) {
      throw new NullPointerException("Null buffer for read");
    } else if (off < 0 || len < 0 || len > b.length - off) {
      throw new IndexOutOfBoundsException();
    } else if (len == 0) {
      return;
    }

    // Write uncompressed data to the output stream
    try {
      for (; ; ) {
        int n;

        // Fill the decompressor buffer with output data
        if (inf.needsInput()) {
          int part;

          if (len < 1) {
            break;
          }

          part = (len < 512 ? len : 512);
          inf.setInput(b, off, part);
          off += part;
          len -= part;
        }

        // Decompress and write blocks of output data
        do {
          n = inf.inflate(buf, 0, buf.length);
          if (n > 0) {
            out.write(buf, 0, n);
          }
        } while (n > 0);

        // Check the decompressor
        if (inf.finished()) {
          break;
        }
        if (inf.needsDictionary()) {
          throw new ZipException("ZLIB dictionary missing");
        }
      }
    } catch (DataFormatException ex) {
      // Improperly formatted compressed (ZIP) data
      String msg = ex.getMessage();
      if (msg == null) {
        msg = "Invalid ZLIB data format";
      }
      throw new ZipException(msg);
    }
  }
예제 #6
0
  /**
   * Reads from the compressed stream and stores the resulting uncompressed data into the byte
   * array.
   *
   * @return number of bytes read, or -1 upon EOF
   */
  public int read(byte[] b, int off, int len) throws IOException {
    if (len <= 0 || off < 0 || off + len > b.length) return 0;

    if (_eof) return -1;

    // Read from uncompressed stream
    if (!_isGzip) return _in.read(b, off, len);

    try {
      int sublen;
      int length = 0;
      while (length < len) {
        if (_inflater.needsInput()) {
          _readBufferSize = _in.read(_readBuffer, 0, _readBuffer.length);
          if (_readBufferSize < 0) break;

          _inflater.setInput(_readBuffer, 0, _readBufferSize);
        }

        sublen = _inflater.inflate(b, off + length, len - length);

        _crc.update(b, off + length, sublen);
        _inputSize += sublen;
        _totalInputSize += sublen;

        length += sublen;

        // Unread gzip trailer and possibly beginning of appended gzip data.
        if (_inflater.finished()) {
          int remaining = _inflater.getRemaining();
          _in.unread(_readBuffer, _readBufferSize - remaining, remaining);

          readTrailer();

          int secondPart = read(b, off + length, len - length);

          return secondPart > 0 ? length + secondPart : length;
        }
      }

      return length;
    } catch (DataFormatException e) {
      throw new IOException(e.getMessage());
    }
  }
예제 #7
0
  int inflate(Inflater inf, long pos, byte[] dstbuf, int dstoff) throws DataFormatException {
    int ptr = (int) (pos - start);
    int in = Math.min(INFLATE_STRIDE, block.length - ptr);
    if (dstoff < dstbuf.length) in = Math.min(in, dstbuf.length - dstoff);
    inf.setInput(block, ptr, in);

    for (; ; ) {
      int out = inf.inflate(dstbuf, dstoff, dstbuf.length - dstoff);
      if (out == 0) {
        if (inf.needsInput()) {
          ptr += in;
          in = Math.min(INFLATE_STRIDE, block.length - ptr);
          if (in == 0) return dstoff;
          inf.setInput(block, ptr, in);
          continue;
        }
        return dstoff;
      }
      dstoff += out;
    }
  }
예제 #8
0
  /*
   * feed inflater more bytes in order to get some
   * decompressed output.
   * returns number of bytes actually got
   */
  private int doRead(byte[] buf, int offset, int len) throws DataFormatException, IOException {
    int read = 0;
    int n = 0;
    byte[] inputBuffer = new byte[len];

    while (len > 0) {
      n = inflater.inflate(buf, offset, len);
      if (n == 0) {
        if (inflater.finished()) {
          break;
        } else if (inflater.needsInput()) {
          // feeding
          int m = input.read(inputBuffer);

          if (m == -1) {
            // it shouldn't be here, throw exception
            throw new DataFormatException("Input is over while inflater still expecting data");
          } else {
            // feed the data in
            inflater.setInput(inputBuffer, 0, m);
            n = inflater.inflate(buf, offset, len);
            if (n > 0) {
              read += n;
              offset += n;
              len -= n;
            }
          }
        } else {
          // it shouldn't be here, throw
          throw new DataFormatException("Inflater is neither finished nor needing input.");
        }
      } else {
        read += n;
        offset += n;
        len -= n;
      }
    }
    return read;
  }
예제 #9
0
  @Override
  public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
    try {
      ByteBufferList transformed = new ByteBufferList();
      ByteBuffer output = ByteBuffer.allocate(bb.remaining() * 2);
      int totalInflated = 0;
      int totalRead = 0;
      while (bb.size() > 0) {
        ByteBuffer b = bb.remove();
        if (b.hasRemaining()) {
          totalRead = +b.remaining();
          mInflater.setInput(b.array(), b.arrayOffset() + b.position(), b.remaining());
          do {
            int inflated =
                mInflater.inflate(
                    output.array(), output.arrayOffset() + output.position(), output.remaining());
            totalInflated += inflated;
            output.position(output.position() + inflated);
            if (!output.hasRemaining()) {
              output.limit(output.position());
              output.position(0);
              transformed.add(output);
              Assert.assertNotSame(totalRead, 0);
              int newSize = output.capacity() * 2;
              output = ByteBuffer.allocate(newSize);
            }
          } while (!mInflater.needsInput() && !mInflater.finished());
        }
      }
      output.limit(output.position());
      output.position(0);
      transformed.add(output);

      Util.emitAllData(this, transformed);
    } catch (Exception ex) {
      report(ex);
    }
  }
예제 #10
0
 public boolean needsInput() {
   return inflater.needsInput();
 }
예제 #11
0
  /**
   * {@inheritDoc}
   *
   * <p>If the decoding did not produce any output, for example because it consumed gzip header or
   * trailer bytes, it returns a buffer with zero capacity.
   *
   * <p>This method never returns null.
   *
   * <p>The given {@code buffer}'s position will be modified to reflect the bytes consumed during
   * the decoding.
   *
   * <p>The decoding may be finished without consuming the buffer completely if the buffer contains
   * gzip bytes plus other bytes (either plain or gzipped).
   */
  @Override
  public ByteBuffer decode(ByteBuffer buffer) {
    try {
      while (buffer.hasRemaining()) {
        byte currByte = buffer.get();
        switch (state) {
          case INITIAL:
            {
              buffer.position(buffer.position() - 1);
              state = State.ID;
              break;
            }
          case ID:
            {
              value += (currByte & 0xFF) << 8 * size;
              ++size;
              if (size == 2) {
                if (value != 0x8B1F) throw new ZipException("Invalid gzip bytes");
                state = State.CM;
              }
              break;
            }
          case CM:
            {
              if ((currByte & 0xFF) != 0x08)
                throw new ZipException("Invalid gzip compression method");
              state = State.FLG;
              break;
            }
          case FLG:
            {
              flags = currByte;
              state = State.MTIME;
              size = 0;
              value = 0;
              break;
            }
          case MTIME:
            {
              // Skip the 4 MTIME bytes
              ++size;
              if (size == 4) state = State.XFL;
              break;
            }
          case XFL:
            {
              // Skip XFL
              state = State.OS;
              break;
            }
          case OS:
            {
              // Skip OS
              state = State.FLAGS;
              break;
            }
          case FLAGS:
            {
              buffer.position(buffer.position() - 1);
              if ((flags & 0x04) == 0x04) {
                state = State.EXTRA_LENGTH;
                size = 0;
                value = 0;
              } else if ((flags & 0x08) == 0x08) state = State.NAME;
              else if ((flags & 0x10) == 0x10) state = State.COMMENT;
              else if ((flags & 0x2) == 0x2) {
                state = State.HCRC;
                size = 0;
                value = 0;
              } else state = State.DATA;
              break;
            }
          case EXTRA_LENGTH:
            {
              value += (currByte & 0xFF) << 8 * size;
              ++size;
              if (size == 2) state = State.EXTRA;
              break;
            }
          case EXTRA:
            {
              // Skip EXTRA bytes
              --value;
              if (value == 0) {
                // Clear the EXTRA flag and loop on the flags
                flags &= ~0x04;
                state = State.FLAGS;
              }
              break;
            }
          case NAME:
            {
              // Skip NAME bytes
              if (currByte == 0) {
                // Clear the NAME flag and loop on the flags
                flags &= ~0x08;
                state = State.FLAGS;
              }
              break;
            }
          case COMMENT:
            {
              // Skip COMMENT bytes
              if (currByte == 0) {
                // Clear the COMMENT flag and loop on the flags
                flags &= ~0x10;
                state = State.FLAGS;
              }
              break;
            }
          case HCRC:
            {
              // Skip HCRC
              ++size;
              if (size == 2) {
                // Clear the HCRC flag and loop on the flags
                flags &= ~0x02;
                state = State.FLAGS;
              }
              break;
            }
          case DATA:
            {
              buffer.position(buffer.position() - 1);
              while (true) {
                int decoded = inflate(bytes);
                if (decoded == 0) {
                  if (inflater.needsInput()) {
                    if (buffer.hasRemaining()) {
                      byte[] input = new byte[buffer.remaining()];
                      buffer.get(input);
                      inflater.setInput(input);
                    } else {
                      if (output != null) {
                        ByteBuffer result = ByteBuffer.wrap(output);
                        output = null;
                        return result;
                      }
                      break;
                    }
                  } else if (inflater.finished()) {
                    int remaining = inflater.getRemaining();
                    buffer.position(buffer.limit() - remaining);
                    state = State.CRC;
                    size = 0;
                    value = 0;
                    break;
                  } else {
                    throw new ZipException("Invalid inflater state");
                  }
                } else {
                  if (output == null) {
                    // Save the inflated bytes and loop to see if we have finished
                    output = Arrays.copyOf(bytes, decoded);
                  } else {
                    // Accumulate inflated bytes and loop to see if we have finished
                    byte[] newOutput = Arrays.copyOf(output, output.length + decoded);
                    System.arraycopy(bytes, 0, newOutput, output.length, decoded);
                    output = newOutput;
                  }
                }
              }
              break;
            }
          case CRC:
            {
              value += (currByte & 0xFF) << 8 * size;
              ++size;
              if (size == 4) {
                // From RFC 1952, compliant decoders need not to verify the CRC
                state = State.ISIZE;
                size = 0;
                value = 0;
              }
              break;
            }
          case ISIZE:
            {
              value += (currByte & 0xFF) << 8 * size;
              ++size;
              if (size == 4) {
                if (value != inflater.getBytesWritten())
                  throw new ZipException("Invalid input size");

                ByteBuffer result =
                    output == null ? BufferUtil.EMPTY_BUFFER : ByteBuffer.wrap(output);
                reset();
                return result;
              }
              break;
            }
          default:
            throw new ZipException();
        }
      }
      return BufferUtil.EMPTY_BUFFER;
    } catch (ZipException x) {
      throw new RuntimeException(x);
    }
  }
  /**
   * Returns the non-null InputStream that should be returned to by all requests to {@link
   * #getContent()}.
   *
   * @return a non-null InputStream
   * @throws IOException if there was a problem
   */
  @Override
  InputStream decorate(final InputStream wrapped) throws IOException {
    /*
     * A zlib stream will have a header.
     *
     * CMF | FLG [| DICTID ] | ...compressed data | ADLER32 |
     *
     * * CMF is one byte.
     *
     * * FLG is one byte.
     *
     * * DICTID is four bytes, and only present if FLG.FDICT is set.
     *
     * Sniff the content. Does it look like a zlib stream, with a CMF, etc? c.f. RFC1950,
     * section 2.2. http://tools.ietf.org/html/rfc1950#page-4
     *
     * We need to see if it looks like a proper zlib stream, or whether it is just a deflate
     * stream. RFC2616 calls zlib streams deflate. Confusing, isn't it? That's why some servers
     * implement deflate Content-Encoding using deflate streams, rather than zlib streams.
     *
     * We could start looking at the bytes, but to be honest, someone else has already read
     * the RFCs and implemented that for us. So we'll just use the JDK libraries and exception
     * handling to do this. If that proves slow, then we could potentially change this to check
     * the first byte - does it look like a CMF? What about the second byte - does it look like
     * a FLG, etc.
     */

    /* We read a small buffer to sniff the content. */
    final byte[] peeked = new byte[6];

    final PushbackInputStream pushback = new PushbackInputStream(wrapped, peeked.length);

    final int headerLength = pushback.read(peeked);

    if (headerLength == -1) {
      throw new IOException("Unable to read the response");
    }

    /* We try to read the first uncompressed byte. */
    final byte[] dummy = new byte[1];

    final Inflater inf = new Inflater();

    try {
      int n;
      while ((n = inf.inflate(dummy)) == 0) {
        if (inf.finished()) {

          /* Not expecting this, so fail loudly. */
          throw new IOException("Unable to read the response");
        }

        if (inf.needsDictionary()) {

          /* Need dictionary - then it must be zlib stream with DICTID part? */
          break;
        }

        if (inf.needsInput()) {
          inf.setInput(peeked);
        }
      }

      if (n == -1) {
        throw new IOException("Unable to read the response");
      }

      /*
       * We read something without a problem, so it's a valid zlib stream. Just need to reset
       * and return an unused InputStream now.
       */
      pushback.unread(peeked, 0, headerLength);
      return new DeflateStream(pushback, new Inflater());
    } catch (final DataFormatException e) {

      /* Presume that it's an RFC1951 deflate stream rather than RFC1950 zlib stream and try
       * again. */
      pushback.unread(peeked, 0, headerLength);
      return new DeflateStream(pushback, new Inflater(true));
    } finally {
      inf.end();
    }
  }