/**
  * 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");
   }
 }
 /**
  * Fills input buffer with more data to decompress.
  *
  * @exception IOException if an I/O error has occurred
  */
 protected void fill() throws IOException {
   ensureOpen();
   len = in.read(buf, 0, buf.length);
   if (len == -1) {
     throw new EOFException("Unexpected end of ZLIB input stream");
   }
   inf.setInput(buf, 0, len);
 }
 /**
  * Returns 0 after EOF has been reached, otherwise always return 1.
  *
  * <p>Programs should not count on this method to return the actual number of bytes that could be
  * read without blocking.
  *
  * @return 1 before EOF and 0 after EOF.
  * @exception IOException if an I/O error occurs.
  */
 public int available() throws IOException {
   ensureOpen();
   if (reachEOF) {
     return 0;
   } else {
     return 1;
   }
 }
 /**
  * Skips specified number of bytes of uncompressed data.
  *
  * @param n the number of bytes to skip
  * @return the actual number of bytes skipped.
  * @exception IOException if an I/O error has occurred
  * @exception IllegalArgumentException if {@code n < 0}
  */
 public long skip(long n) throws IOException {
   if (n < 0) {
     throw new IllegalArgumentException("negative skip length");
   }
   ensureOpen();
   int max = (int) Math.min(n, Integer.MAX_VALUE);
   int total = 0;
   while (total < max) {
     int len = max - total;
     if (len > b.length) {
       len = b.length;
     }
     len = read(b, 0, len);
     if (len == -1) {
       reachEOF = true;
       break;
     }
     total += len;
   }
   return total;
 }
 /**
  * Reads a byte of uncompressed data. This method will block until enough input is available for
  * decompression.
  *
  * @return the byte read, or -1 if end of compressed input is reached
  * @exception IOException if an I/O error has occurred
  */
 public int read() throws IOException {
   ensureOpen();
   return read(singleByteBuf, 0, 1) == -1 ? -1 : Byte.toUnsignedInt(singleByteBuf[0]);
 }