001: /*
002: * @(#)InflaterInputStream.java 1.38 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.util.zip;
029:
030: import java.io.FilterInputStream;
031: import java.io.InputStream;
032: import java.io.IOException;
033: import java.io.EOFException;
034:
035: /**
036: * This class implements a stream filter for uncompressing data in the
037: * "deflate" compression format. It is also used as the basis for other
038: * decompression filters, such as GZIPInputStream.
039: * NOTE: <B>java.util.zip.GZIPInputStream</B> is found in J2ME CDC profiles
040: * such as J2ME Foundation Profile.
041: *
042: * @see Inflater
043: * @version 1.28, 02/02/00
044: * @author David Connelly
045: */
046: public class InflaterInputStream extends FilterInputStream {
047: /**
048: * Decompressor for this stream.
049: */
050: protected Inflater inf;
051:
052: /**
053: * Input buffer for decompression.
054: */
055: protected byte[] buf;
056:
057: /**
058: * Length of input buffer.
059: */
060: protected int len;
061:
062: private boolean closed = false;
063: // this flag is set to true after EOF has reached
064: private boolean reachEOF = false;
065:
066: /**
067: * Check to make sure that this stream has not been closed
068: */
069: private void ensureOpen() throws IOException {
070: if (closed) {
071: throw new IOException("Stream closed");
072: }
073: }
074:
075: /**
076: * Creates a new input stream with the specified decompressor and
077: * buffer size.
078: * @param in the input stream
079: * @param inf the decompressor ("inflater")
080: * @param size the input buffer size
081: * @exception IllegalArgumentException if size is <= 0
082: */
083: public InflaterInputStream(InputStream in, Inflater inf, int size) {
084: super (in);
085: if (in == null || inf == null) {
086: throw new NullPointerException();
087: } else if (size <= 0) {
088: throw new IllegalArgumentException("buffer size <= 0");
089: }
090: this .inf = inf;
091: buf = new byte[size];
092: }
093:
094: /**
095: * Creates a new input stream with the specified decompressor and a
096: * default buffer size.
097: * @param in the input stream
098: * @param inf the decompressor ("inflater")
099: */
100: public InflaterInputStream(InputStream in, Inflater inf) {
101: this (in, inf, 512);
102: }
103:
104: boolean usesDefaultInflater = false;
105:
106: /**
107: * Creates a new input stream with a default decompressor and buffer size.
108: * @param in the input stream
109: */
110: public InflaterInputStream(InputStream in) {
111: this (in, new Inflater());
112: usesDefaultInflater = true;
113: }
114:
115: private byte[] singleByteBuf = new byte[1];
116:
117: /**
118: * Reads a byte of uncompressed data. This method will block until
119: * enough input is available for decompression.
120: * @return the byte read, or -1 if end of compressed input is reached
121: * @exception IOException if an I/O error has occurred
122: */
123: public int read() throws IOException {
124: ensureOpen();
125: return read(singleByteBuf, 0, 1) == -1 ? -1
126: : singleByteBuf[0] & 0xff;
127: }
128:
129: /**
130: * Reads uncompressed data into an array of bytes. This method will
131: * block until some input can be decompressed.
132: * @param b the buffer into which the data is read
133: * @param off the start offset of the data
134: * @param len the maximum number of bytes read
135: * @return the actual number of bytes read, or -1 if the end of the
136: * compressed input is reached or a preset dictionary is needed
137: * @exception ZipException if a ZIP format error has occurred
138: * @exception IOException if an I/O error has occurred
139: */
140: public int read(byte[] b, int off, int len) throws IOException {
141: ensureOpen();
142: if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
143: throw new IndexOutOfBoundsException();
144: } else if (len == 0) {
145: return 0;
146: }
147: try {
148: int bytesRead = 0;
149: while (len > 0) {
150: int n = inf.inflate(b, off, len);
151: if (n == 0) {
152: if (inf.finished() || inf.needsDictionary()) {
153: reachEOF = true;
154: if (bytesRead > 0) {
155: return bytesRead;
156: } else {
157: return -1;
158: }
159: }
160: if (inf.needsInput()) {
161: fill();
162: }
163: }
164: bytesRead += n;
165: off += n;
166: len -= n;
167: }
168: return bytesRead;
169: } catch (DataFormatException e) {
170: String s = e.getMessage();
171: throw new ZipException(s != null ? s
172: : "Invalid ZLIB data format");
173: }
174: }
175:
176: /**
177: * Returns 0 after EOF has reached, otherwise always return 1.
178: * <p>
179: * Programs should not count on this method to return the actual number
180: * of bytes that could be read without blocking.
181: *
182: * @return 1 before EOF and 0 after EOF.
183: * @exception IOException if an I/O error occurs.
184: *
185: */
186: public int available() throws IOException {
187: ensureOpen();
188: if (reachEOF) {
189: return 0;
190: } else {
191: return 1;
192: }
193: }
194:
195: private byte[] b = new byte[512];
196:
197: /**
198: * Skips specified number of bytes of uncompressed data.
199: * @param n the number of bytes to skip
200: * @return the actual number of bytes skipped.
201: * @exception IOException if an I/O error has occurred
202: * @exception IllegalArgumentException if n < 0
203: */
204: public long skip(long n) throws IOException {
205: if (n < 0) {
206: throw new IllegalArgumentException("negative skip length");
207: }
208: ensureOpen();
209: int max = (int) Math.min(n, Integer.MAX_VALUE);
210: int total = 0;
211: while (total < max) {
212: int len = max - total;
213: if (len > b.length) {
214: len = b.length;
215: }
216: len = read(b, 0, len);
217: if (len == -1) {
218: reachEOF = true;
219: break;
220: }
221: total += len;
222: }
223: return total;
224: }
225:
226: /**
227: * Closes the input stream.
228: * @exception IOException if an I/O error has occurred
229: */
230: public void close() throws IOException {
231: if (!closed) {
232: if (usesDefaultInflater)
233: inf.end();
234: in.close();
235: closed = true;
236: }
237: }
238:
239: /**
240: * Fills input buffer with more data to decompress.
241: * @exception IOException if an I/O error has occurred
242: */
243: protected void fill() throws IOException {
244: ensureOpen();
245: len = in.read(buf, 0, buf.length);
246: if (len == -1) {
247: throw new EOFException(
248: "Unexpected end of ZLIB input stream");
249: }
250: inf.setInput(buf, 0, len);
251: }
252: }
|