Rebasing the Inflater support on jzlib which, unlike GNU ClassPath, has correct implementation of Huffman code. Making the implementation more easily testable by turning Inflater and ZipInputStream into pure delegates. Current implementation is going to need proper long support.
2 * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
26 package java.util.zip;
28 import java.io.FilterInputStream;
29 import java.io.InputStream;
30 import java.io.IOException;
31 import java.io.EOFException;
34 * This class implements a stream filter for uncompressing data in the
35 * "deflate" compression format. It is also used as the basis for other
36 * decompression filters, such as GZIPInputStream.
39 * @author David Connelly
42 class InflaterInputStream extends FilterInputStream {
44 * Decompressor for this stream.
46 protected Inflater inf;
49 * Input buffer for decompression.
54 * Length of input buffer.
58 private boolean closed = false;
59 // this flag is set to true after EOF has reached
60 private boolean reachEOF = false;
63 * Check to make sure that this stream has not been closed
65 private void ensureOpen() throws IOException {
67 throw new IOException("Stream closed");
73 * Creates a new input stream with the specified decompressor and
75 * @param in the input stream
76 * @param inf the decompressor ("inflater")
77 * @param size the input buffer size
78 * @exception IllegalArgumentException if size is <= 0
80 public InflaterInputStream(InputStream in, Inflater inf, int size) {
82 if (in == null || inf == null) {
83 throw new NullPointerException();
84 } else if (size <= 0) {
85 throw new IllegalArgumentException("buffer size <= 0");
92 * Creates a new input stream with the specified decompressor and a
93 * default buffer size.
94 * @param in the input stream
95 * @param inf the decompressor ("inflater")
97 public InflaterInputStream(InputStream in, Inflater inf) {
101 boolean usesDefaultInflater = false;
104 * Creates a new input stream with a default decompressor and buffer size.
105 * @param in the input stream
107 public InflaterInputStream(InputStream in) {
108 this(in, new Inflater());
109 usesDefaultInflater = true;
112 private byte[] singleByteBuf = new byte[1];
115 * Reads a byte of uncompressed data. This method will block until
116 * enough input is available for decompression.
117 * @return the byte read, or -1 if end of compressed input is reached
118 * @exception IOException if an I/O error has occurred
120 public int read() throws IOException {
122 return read(singleByteBuf, 0, 1) == -1 ? -1 : singleByteBuf[0] & 0xff;
126 * Reads uncompressed data into an array of bytes. If <code>len</code> is not
127 * zero, the method will block until some input can be decompressed; otherwise,
128 * no bytes are read and <code>0</code> is returned.
129 * @param b the buffer into which the data is read
130 * @param off the start offset in the destination array <code>b</code>
131 * @param len the maximum number of bytes read
132 * @return the actual number of bytes read, or -1 if the end of the
133 * compressed input is reached or a preset dictionary is needed
134 * @exception NullPointerException If <code>b</code> is <code>null</code>.
135 * @exception IndexOutOfBoundsException If <code>off</code> is negative,
136 * <code>len</code> is negative, or <code>len</code> is greater than
137 * <code>b.length - off</code>
138 * @exception ZipException if a ZIP format error has occurred
139 * @exception IOException if an I/O error has occurred
141 public int read(byte[] b, int off, int len) throws IOException {
144 throw new NullPointerException();
145 } else if (off < 0 || len < 0 || len > b.length - off) {
146 throw new IndexOutOfBoundsException();
147 } else if (len == 0) {
152 while ((n = inf.inflate(b, off, len)) == 0) {
153 if (inf.finished() || inf.needsDictionary()) {
157 if (inf.needsInput()) {
162 } catch (DataFormatException e) {
163 String s = e.getMessage();
164 throw new ZipException(s != null ? s : "Invalid ZLIB data format");
169 * Returns 0 after EOF has been reached, otherwise always return 1.
171 * Programs should not count on this method to return the actual number
172 * of bytes that could be read without blocking.
174 * @return 1 before EOF and 0 after EOF.
175 * @exception IOException if an I/O error occurs.
178 public int available() throws IOException {
187 private byte[] b = new byte[512];
190 * Skips specified number of bytes of uncompressed data.
191 * @param n the number of bytes to skip
192 * @return the actual number of bytes skipped.
193 * @exception IOException if an I/O error has occurred
194 * @exception IllegalArgumentException if n < 0
196 public long skip(long n) throws IOException {
198 throw new IllegalArgumentException("negative skip length");
201 int max = (int)Math.min(n, Integer.MAX_VALUE);
203 while (total < max) {
204 int len = max - total;
205 if (len > b.length) {
208 len = read(b, 0, len);
219 * Closes this input stream and releases any system resources associated
221 * @exception IOException if an I/O error has occurred
223 public void close() throws IOException {
225 if (usesDefaultInflater)
233 * Fills input buffer with more data to decompress.
234 * @exception IOException if an I/O error has occurred
236 protected void fill() throws IOException {
238 len = in.read(buf, 0, buf.length);
240 throw new EOFException("Unexpected end of ZLIB input stream");
242 inf.setInput(buf, 0, len);
246 * Tests if this input stream supports the <code>mark</code> and
247 * <code>reset</code> methods. The <code>markSupported</code>
248 * method of <code>InflaterInputStream</code> returns
249 * <code>false</code>.
251 * @return a <code>boolean</code> indicating if this stream type supports
252 * the <code>mark</code> and <code>reset</code> methods.
253 * @see java.io.InputStream#mark(int)
254 * @see java.io.InputStream#reset()
256 public boolean markSupported() {
261 * Marks the current position in this input stream.
263 * <p> The <code>mark</code> method of <code>InflaterInputStream</code>
266 * @param readlimit the maximum limit of bytes that can be read before
267 * the mark position becomes invalid.
268 * @see java.io.InputStream#reset()
270 public synchronized void mark(int readlimit) {
274 * Repositions this stream to the position at the time the
275 * <code>mark</code> method was last called on this input stream.
277 * <p> The method <code>reset</code> for class
278 * <code>InflaterInputStream</code> does nothing except throw an
279 * <code>IOException</code>.
281 * @exception IOException if this method is invoked.
282 * @see java.io.InputStream#mark(int)
283 * @see java.io.IOException
285 public synchronized void reset() throws IOException {
286 throw new IOException("mark/reset not supported");