You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
8.2 KiB
294 lines
8.2 KiB
/*
|
|
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package java.util.zip;
|
|
|
|
import java.io.FilterInputStream;
|
|
import java.io.InputStream;
|
|
import java.io.IOException;
|
|
|
|
/**
|
|
* Implements an input stream filter for compressing data in the "deflate"
|
|
* compression format.
|
|
*
|
|
* @since 1.6
|
|
* @author David R Tribble (david@tribble.com)
|
|
*
|
|
* @see DeflaterOutputStream
|
|
* @see InflaterOutputStream
|
|
* @see InflaterInputStream
|
|
*/
|
|
|
|
public class DeflaterInputStream extends FilterInputStream {
|
|
/** Compressor for this stream. */
|
|
protected final Deflater def;
|
|
|
|
/** Input buffer for reading compressed data. */
|
|
protected final byte[] buf;
|
|
|
|
/** Temporary read buffer. */
|
|
private byte[] rbuf = new byte[1];
|
|
|
|
/** Default compressor is used. */
|
|
private boolean usesDefaultDeflater = false;
|
|
|
|
/** End of the underlying input stream has been reached. */
|
|
private boolean reachEOF = false;
|
|
|
|
/**
|
|
* Check to make sure that this stream has not been closed.
|
|
*/
|
|
private void ensureOpen() throws IOException {
|
|
if (in == null) {
|
|
throw new IOException("Stream closed");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a new input stream with a default compressor and buffer
|
|
* size.
|
|
*
|
|
* @param in input stream to read the uncompressed data to
|
|
* @throws NullPointerException if {@code in} is null
|
|
*/
|
|
public DeflaterInputStream(InputStream in) {
|
|
this(in, new Deflater());
|
|
usesDefaultDeflater = true;
|
|
}
|
|
|
|
/**
|
|
* Creates 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
|
|
* @throws NullPointerException if {@code in} or {@code defl} is null
|
|
*/
|
|
public DeflaterInputStream(InputStream in, Deflater defl) {
|
|
this(in, defl, 512);
|
|
}
|
|
|
|
/**
|
|
* Creates 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 IllegalArgumentException if {@code bufLen <= 0}
|
|
* @throws NullPointerException if {@code in} or {@code defl} is null
|
|
*/
|
|
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];
|
|
}
|
|
|
|
/**
|
|
* Closes this input stream and its underlying input stream, discarding
|
|
* any pending uncompressed data.
|
|
*
|
|
* @throws IOException if an I/O error occurs
|
|
*/
|
|
public void close() throws IOException {
|
|
if (in != null) {
|
|
try {
|
|
// Clean up
|
|
if (usesDefaultDeflater) {
|
|
def.end();
|
|
}
|
|
|
|
in.close();
|
|
} finally {
|
|
in = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reads a single byte of compressed data from the input stream.
|
|
* This method 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 if an I/O error occurs or if this stream is
|
|
* already closed
|
|
*/
|
|
public int read() throws IOException {
|
|
// Read a single byte of compressed data
|
|
int len = read(rbuf, 0, 1);
|
|
if (len <= 0)
|
|
return -1;
|
|
return (rbuf[0] & 0xFF);
|
|
}
|
|
|
|
/**
|
|
* Reads compressed data into a byte array.
|
|
* This method will block until some input can be read and compressed.
|
|
*
|
|
* @param b buffer into which the data is read
|
|
* @param off starting offset of the data within {@code b}
|
|
* @param len maximum number of compressed bytes to read into {@code b}
|
|
* @return the actual number of bytes read, or -1 if the end of the
|
|
* uncompressed input stream is reached
|
|
* @throws IndexOutOfBoundsException if {@code len > b.length - off}
|
|
* @throws IOException if an I/O error occurs or if this input stream is
|
|
* already closed
|
|
*/
|
|
public int read(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 0;
|
|
}
|
|
|
|
// Read and compress (deflate) input data bytes
|
|
int cnt = 0;
|
|
while (len > 0 && !def.finished()) {
|
|
int n;
|
|
|
|
// Read data from the input stream
|
|
if (def.needsInput()) {
|
|
n = in.read(buf, 0, buf.length);
|
|
if (n < 0) {
|
|
// End of the input stream reached
|
|
def.finish();
|
|
} else if (n > 0) {
|
|
def.setInput(buf, 0, n);
|
|
}
|
|
}
|
|
|
|
// Compress the input data, filling the read buffer
|
|
n = def.deflate(b, off, len);
|
|
cnt += n;
|
|
off += n;
|
|
len -= n;
|
|
}
|
|
if (cnt == 0 && def.finished()) {
|
|
reachEOF = true;
|
|
cnt = -1;
|
|
}
|
|
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* Skips over and discards data from the input stream.
|
|
* This method may block until the specified number of bytes are read and
|
|
* skipped. <em>Note:</em> While {@code n} is given as a {@code long},
|
|
* the maximum number of bytes which can be skipped is
|
|
* {@code Integer.MAX_VALUE}.
|
|
*
|
|
* @param n number of bytes to be skipped
|
|
* @return the actual number of bytes skipped
|
|
* @throws IOException if an I/O error occurs or if this stream is
|
|
* already closed
|
|
*/
|
|
public long skip(long n) throws IOException {
|
|
if (n < 0) {
|
|
throw new IllegalArgumentException("negative skip length");
|
|
}
|
|
ensureOpen();
|
|
|
|
// Skip bytes by repeatedly decompressing small blocks
|
|
if (rbuf.length < 512)
|
|
rbuf = new byte[512];
|
|
|
|
int total = (int)Math.min(n, Integer.MAX_VALUE);
|
|
long cnt = 0;
|
|
while (total > 0) {
|
|
// Read a small block of uncompressed bytes
|
|
int len = read(rbuf, 0, (total <= rbuf.length ? total : rbuf.length));
|
|
|
|
if (len < 0) {
|
|
break;
|
|
}
|
|
cnt += len;
|
|
total -= len;
|
|
}
|
|
return cnt;
|
|
}
|
|
|
|
/**
|
|
* 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 zero after the end of the underlying input stream has been
|
|
* reached, otherwise always returns 1
|
|
* @throws IOException if an I/O error occurs or if this stream is
|
|
* already closed
|
|
*/
|
|
public int available() throws IOException {
|
|
ensureOpen();
|
|
if (reachEOF) {
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/**
|
|
* Always returns {@code false} because this input stream does not support
|
|
* the {@link #mark mark()} and {@link #reset reset()} methods.
|
|
*
|
|
* @return false, always
|
|
*/
|
|
public boolean markSupported() {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* <i>This operation is not supported</i>.
|
|
*
|
|
* @param limit maximum bytes that can be read before invalidating the position marker
|
|
*/
|
|
public void mark(int limit) {
|
|
// Operation not supported
|
|
}
|
|
|
|
/**
|
|
* <i>This operation is not supported</i>.
|
|
*
|
|
* @throws IOException always thrown
|
|
*/
|
|
public void reset() throws IOException {
|
|
throw new IOException("mark/reset not supported");
|
|
}
|
|
}
|