//
package net.sf.zipme;
import java.io.IOException;
import java.io.InputStream;
/**
* This filter stream is used to decompress data compressed in the "deflate"
* format. The "deflate" format is described in RFC 1951.
* This stream may form the basis for other decompression filters, such
* as the <code>GZIPInputStream</code>.
* @author John Leuner
* @author Tom Tromey
* @since 1.1
*/
public class InflaterInputStream extends InputStream {
/**
* This is the subordinate <code>InputStream</code> to which method calls
* are redirected
*/
protected InputStream in;
/**
* Decompressor for this filter
*/
protected Inflater inf;
/**
* Byte array used as a buffer
*/
protected byte[] buf;
/**
* Size of buffer
*/
protected int len;
private byte[] onebytebuffer=new byte[1];
/**
* Create an InflaterInputStream with the default decompresseor
* and a default buffer size.
* @param in the InputStream to read bytes from
*/
public InflaterInputStream( InputStream in){
this(in,new Inflater(),4096);
}
/**
* Create an InflaterInputStream with the specified decompresseor
* and a default buffer size.
* @param in the InputStream to read bytes from
* @param inf the decompressor used to decompress data read from in
*/
public InflaterInputStream( InputStream in, Inflater inf){
this(in,inf,4096);
}
/**
* Create an InflaterInputStream with the specified decompresseor
* and a specified buffer size.
* @param in the InputStream to read bytes from
* @param inf the decompressor used to decompress data read from in
* @param size size of the buffer to use
*/
public InflaterInputStream( InputStream in, Inflater inf, int size){
this.in=in;
if (in == null) throw new NullPointerException("in may not be null");
if (inf == null) throw new NullPointerException("inf may not be null");
if (size < 0) throw new IllegalArgumentException("size may not be negative");
this.inf=inf;
this.buf=new byte[size];
}
/**
* Returns 0 once the end of the stream (EOF) has been reached.
* Otherwise returns 1.
*/
public int available() throws IOException {
if (inf == null) throw new IOException("stream closed");
return inf.finished() ? 0 : 1;
}
/**
* Closes the input stream
*/
public synchronized void close() throws IOException {
if (in != null) in.close();
in=null;
}
/**
* Fills the buffer with more data to decompress.
*/
protected void fill() throws IOException {
if (in == null) throw new ZipException("InflaterInputStream is closed");
len=in.read(buf,0,buf.length);
if (len < 0) throw new ZipException("Deflated stream ends early.");
inf.setInput(buf,0,len);
}
/**
* Reads one byte of decompressed data.
* The byte is in the lower 8 bits of the int.
*/
public int read() throws IOException {
int nread=read(onebytebuffer,0,1);
if (nread > 0) return onebytebuffer[0] & 0xff;
return -1;
}
/**
* Calls the <code>read(byte[], int, int)</code> overloaded method.
* Note that
* this method does not redirect its call directly to a corresponding
* method in <code>in</code>. This allows subclasses to override only the
* three argument version of <code>read</code>.
* @param buf The buffer to read bytes into
* @return The value retured from <code>in.read(byte[], int, int)</code>
* @exception IOException If an error occurs
*/
public int read( byte[] buf) throws IOException {
return read(buf,0,buf.length);
}
/**
* Decompresses data into the byte array
* @param b the array to read and decompress data into
* @param off the offset indicating where the data should be placed
* @param len the number of bytes to decompress
*/
public int read( byte[] b, int off, int len) throws IOException {
if (inf == null) throw new IOException("stream closed");
if (len == 0) return 0;
int count=0;
for (; ; ) {
try {
count=inf.inflate(b,off,len);
}
catch ( DataFormatException dfe) {
throw new ZipException(dfe.getMessage());
}
if (count > 0) return count;
if (inf.needsDictionary() | inf.finished()) return -1;
else if (inf.needsInput()) fill();
else throw new Error("Don't know what to do");
}
}
/**
* Skip specified number of bytes of uncompressed data
* @param n number of bytes to skip
*/
public long skip( long n) throws IOException {
if (inf == null) throw new IOException("stream closed");
if (n < 0) throw new IllegalArgumentException();
if (n == 0) return 0;
int buflen=(int)Math.min(n,2048);
byte[] tmpbuf=new byte[buflen];
long skipped=0L;
while (n > 0L) {
int numread=read(tmpbuf,0,buflen);
if (numread <= 0) break;
n-=numread;
skipped+=numread;
buflen=(int)Math.min(n,2048);
}
return skipped;
}
public boolean markSupported(){
return false;
}
public void mark( int readLimit){
}
public void reset() throws IOException {
throw new IOException("reset not supported");
}
}