/// Bug 4679743: Additional Compressed Streams Requested /// This file is also available at: /// http://david.tribble.com/src/jdk/DeflaterInputStream.java ///--- CUT HERE ---------------------------------------------------------------- /* * @(#)DeflaterInputStream.java 1.1 2005-07-15 * * Copyright ©2005 Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. */ package java.util.zip; // System imports import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; import java.lang.IllegalArgumentException; import java.lang.NullPointerException; import java.lang.String; import java.lang.System; import java.lang.Throwable; // Local imports import java.util.zip.Deflater; /******************************************************************************* * Implements an input stream filter for compressing data in the "deflate" * compression format. * * @version 1.1 2005-07-15 * @since JDK 1.6 * @author David R Tribble (david@tribble.com) * * @see DeflaterOutputStream * @see InflaterOutputStream * @see InflaterInputStream */ public class DeflaterInputStream extends java.io.FilterInputStream { /** Default buffer size (512 bytes). */ private static final int DFL_BUFLEN = 512; /** Compressor for this stream. */ protected Deflater def; /** Input buffer for reading compressed data. */ protected byte[] buf; /** Temporary read buffer. */ private byte[] rbuf = new byte[1]; /** Default compressor is used. */ private boolean isDefault; /** End of the underlying input stream has been reached. */ private boolean eof; /*************************************************************************** * Construct a new input stream with a default compressor and buffer size. * * @param in * Input stream to read the uncompressed data to. */ public DeflaterInputStream(InputStream in) { this(in, new Deflater(), DFL_BUFLEN); isDefault = true; } /*************************************************************************** * Construct a new input stream with the specified compressor and a * default buffer size. * * @param in * Input stream to read the uncompressed data to. * * @param defl * Compressor ("deflater") for this stream. */ public DeflaterInputStream(InputStream in, Deflater defl) { this(in, defl, DFL_BUFLEN); } /*************************************************************************** * Construct a new input stream with the specified compressor and buffer * size. * * @param in * Input stream to read the uncompressed data to. * * @param defl * Compressor ("deflater") for this stream. * * @param bufLen * Compression buffer size. * * @throws NullPointerException (unchecked) * Thrown if in or defl is null. * * @throws IllegalArgumentException (unchecked) * Thrown if bufLen is less than 1. */ public DeflaterInputStream(InputStream in, Deflater defl, int bufLen) { super(in); // Sanity checks if (in == null) throw new NullPointerException("Null input"); if (defl == null) throw new NullPointerException("Null deflater"); if (bufLen < 1) throw new IllegalArgumentException("Buffer size < 1"); // Initialize def = defl; buf = new byte[bufLen]; } /*************************************************************************** * Close this input stream and its underlying input stream, discarding any * pending uncompressed data. * * @throws IOException * Thrown if an I/O error occurs. */ public void close() throws IOException { if (in == null) return; // Clean up if (isDefault) def.end(); def = null; buf = null; in.close(); in = null; } /*************************************************************************** * Read compressed data from the input stream. * This will block until some input can be read and compressed. * * @return * A single byte of compressed data, or -1 if the end of the uncompressed * input stream is reached. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @throws NullPointerException (unchecked) * Thrown if the underlying input stream is closed. */ public int read() throws IOException { int len; // Read a single byte of compressed data len = read(rbuf, 0, 1); if (len <= 0) return -1; return (rbuf[0] & 0xFF); } /*************************************************************************** * Read compressed data from the input stream. * This will block until some input can be read and compressed. * * @param buf * Buffer into which the data is read. * An attempt is made to fill the entire array. * * @return * The actual number of bytes read, or -1 if the end of the uncompressed * input stream is reached. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @throws NullPointerException (unchecked) * Thrown if the underlying input stream is closed. */ public int read(byte[] buf) throws IOException { return read(buf, 0, buf.length); } /*************************************************************************** * Read compressed data from the input stream. * This will block until some input can be read and compressed. * * @param buf * Buffer into which the data is read. * * @param off * Starting offset of the data within buf. * * @param len * Maximum number of compressed bytes to read into buf. * * @return * The actual number of bytes read, or -1 if the end of the uncompressed * input stream is reached. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @throws NullPointerException (unchecked) * Thrown if the underlying input stream is closed. */ public int read(byte[] buf, int off, int len) throws IOException { int cnt; // Sanity checks if (in == null) throw new NullPointerException(); if ((off | len | (off + len)) < 0) throw new IndexOutOfBoundsException(); if ((buf.length - (off + len)) < 0) throw new IndexOutOfBoundsException(); // Read and compress (deflate) input data bytes cnt = 0; while (len > 0 && !def.finished()) { int n; // Read data from the input stream if (def.needsInput() && !eof) { n = in.read(this.buf, 0, this.buf.length); if (n < 0) { // End of the input stream reached def.finish(); eof = true; } else if (n > 0) { def.setInput(this.buf, 0, n); } } // Compress the input data, filling the read buffer n = def.deflate(buf, off, len); cnt += n; off += n; len -= n; } if (cnt == 0 && eof) return -1; return cnt; } /*************************************************************************** * Skip over and discard data from the input stream. * This method may block until the specified number of bytes are read and * skipped. * * @param n * Number of bytes to be skipped. * * @return * The actual number of bytes skipped. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @throws NullPointerException (unchecked) * Thrown if the underlying input stream is closed. */ public long skip(long n) throws IOException { long cnt; // Skip bytes by repeatedly decompressing small blocks if (rbuf.length < 128) rbuf = new byte[128]; cnt = 0; while (n > 0) { int len; // Read a small block of uncompressed bytes len = rbuf.length; len = read(rbuf, 0, (n <= len ? (int) n : len)); if (len < 0) break; cnt += len; n -= len; } return cnt; } /*************************************************************************** * Determine the number of bytes that can be read from this input stream * without blocking. * *
* Programs should not count on this method to return the actual number * of bytes that could be read without blocking. * * @return * Zero after the end of the underlying input stream has been reached, * otherwise always returns 1. * * @throws IOException * Thrown if an I/O (read) error occurs. */ public int available() throws IOException { if (eof || in == null) return 0; return 1; } /*************************************************************************** * Test if this input stream supports the {@link #mark mark()} and * {@link #reset reset()} methods. * These operations are not supported. * * @return * False, always. */ public boolean markSupported() { return false; } /*************************************************************************** * This operation is not supported. * * @param limit * Maximum bytes that can be read before invalidating the position marker. */ public void mark(int limit) { // Operation not supported } /*************************************************************************** * This operation is not supported. * * @throws IOException * Always thrown. */ public void reset() throws IOException { throw new IOException("Mark/reset operation not supported"); } } // End DeflaterInputStream.java