• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package java.util.zip;
28 
29 import java.io.FilterInputStream;
30 import java.io.InputStream;
31 import java.io.IOException;
32 
33 /**
34  * Implements an input stream filter for compressing data in the "deflate"
35  * compression format.
36  *
37  * @since       1.6
38  * @author      David R Tribble (david@tribble.com)
39  *
40  * @see DeflaterOutputStream
41  * @see InflaterOutputStream
42  * @see InflaterInputStream
43  */
44 
45 public class DeflaterInputStream extends FilterInputStream {
46     /** Compressor for this stream. */
47     protected final Deflater def;
48 
49     /** Input buffer for reading compressed data. */
50     protected final byte[] buf;
51 
52     /** Temporary read buffer. */
53     private byte[] rbuf = new byte[1];
54 
55     /** Default compressor is used. */
56     private boolean usesDefaultDeflater = false;
57 
58     /** End of the underlying input stream has been reached. */
59     private boolean reachEOF = false;
60 
61     /**
62      * Check to make sure that this stream has not been closed.
63      */
ensureOpen()64     private void ensureOpen() throws IOException {
65         if (in == null) {
66             throw new IOException("Stream closed");
67         }
68     }
69 
70     /**
71      * Creates a new input stream with a default compressor and buffer
72      * size.
73      *
74      * @param in input stream to read the uncompressed data to
75      * @throws NullPointerException if {@code in} is null
76      */
DeflaterInputStream(InputStream in)77     public DeflaterInputStream(InputStream in) {
78         this(in, new Deflater());
79         usesDefaultDeflater = true;
80     }
81 
82     /**
83      * Creates a new input stream with the specified compressor and a
84      * default buffer size.
85      *
86      * @param in input stream to read the uncompressed data to
87      * @param defl compressor ("deflater") for this stream
88      * @throws NullPointerException if {@code in} or {@code defl} is null
89      */
DeflaterInputStream(InputStream in, Deflater defl)90     public DeflaterInputStream(InputStream in, Deflater defl) {
91         this(in, defl, 512);
92     }
93 
94     /**
95      * Creates a new input stream with the specified compressor and buffer
96      * size.
97      *
98      * @param in input stream to read the uncompressed data to
99      * @param defl compressor ("deflater") for this stream
100      * @param bufLen compression buffer size
101      * @throws IllegalArgumentException if {@code bufLen} is <= 0
102      * @throws NullPointerException if {@code in} or {@code defl} is null
103      */
DeflaterInputStream(InputStream in, Deflater defl, int bufLen)104     public DeflaterInputStream(InputStream in, Deflater defl, int bufLen) {
105         super(in);
106 
107         // Sanity checks
108         if (in == null)
109             throw new NullPointerException("Null input");
110         if (defl == null)
111             throw new NullPointerException("Null deflater");
112         if (bufLen < 1)
113             throw new IllegalArgumentException("Buffer size < 1");
114 
115         // Initialize
116         def = defl;
117         buf = new byte[bufLen];
118     }
119 
120     /**
121      * Closes this input stream and its underlying input stream, discarding
122      * any pending uncompressed data.
123      *
124      * @throws IOException if an I/O error occurs
125      */
close()126     public void close() throws IOException {
127         if (in != null) {
128             try {
129                 // Clean up
130                 if (usesDefaultDeflater) {
131                     def.end();
132                 }
133 
134                 in.close();
135             } finally {
136                 in = null;
137             }
138         }
139     }
140 
141     /**
142      * Reads a single byte of compressed data from the input stream.
143      * This method will block until some input can be read and compressed.
144      *
145      * @return a single byte of compressed data, or -1 if the end of the
146      * uncompressed input stream is reached
147      * @throws IOException if an I/O error occurs or if this stream is
148      * already closed
149      */
read()150     public int read() throws IOException {
151         // Read a single byte of compressed data
152         int len = read(rbuf, 0, 1);
153         if (len <= 0)
154             return -1;
155         return (rbuf[0] & 0xFF);
156     }
157 
158     /**
159      * Reads compressed data into a byte array.
160      * This method will block until some input can be read and compressed.
161      *
162      * @param b buffer into which the data is read
163      * @param off starting offset of the data within {@code b}
164      * @param len maximum number of compressed bytes to read into {@code b}
165      * @return the actual number of bytes read, or -1 if the end of the
166      * uncompressed input stream is reached
167      * @throws IndexOutOfBoundsException  if {@code len} > {@code b.length -
168      * off}
169      * @throws IOException if an I/O error occurs or if this input stream is
170      * already closed
171      */
read(byte[] b, int off, int len)172     public int read(byte[] b, int off, int len) throws IOException {
173         // Sanity checks
174         ensureOpen();
175         if (b == null) {
176             throw new NullPointerException("Null buffer for read");
177         } else if (off < 0 || len < 0 || len > b.length - off) {
178             throw new IndexOutOfBoundsException();
179         } else if (len == 0) {
180             return 0;
181         }
182 
183         // Read and compress (deflate) input data bytes
184         int cnt = 0;
185         while (len > 0 && !def.finished()) {
186             int n;
187 
188             // Read data from the input stream
189             if (def.needsInput()) {
190                 n = in.read(buf, 0, buf.length);
191                 if (n < 0) {
192                     // End of the input stream reached
193                     def.finish();
194                 } else if (n > 0) {
195                     def.setInput(buf, 0, n);
196                 }
197             }
198 
199             // Compress the input data, filling the read buffer
200             n = def.deflate(b, off, len);
201             cnt += n;
202             off += n;
203             len -= n;
204         }
205 
206         // Android changed : set reachEOF eagerly (not just when the number of bytes is zero).
207         // so that available is more accurate.
208         if (def.finished()) {
209             reachEOF =true;
210             if (cnt == 0) {
211                 cnt = -1;
212             }
213         }
214 
215         return cnt;
216     }
217 
218     /**
219      * Skips over and discards data from the input stream.
220      * This method may block until the specified number of bytes are read and
221      * skipped. <em>Note:</em> While {@code n} is given as a {@code long},
222      * the maximum number of bytes which can be skipped is
223      * {@code Integer.MAX_VALUE}.
224      *
225      * @param n number of bytes to be skipped
226      * @return the actual number of bytes skipped
227      * @throws IOException if an I/O error occurs or if this stream is
228      * already closed
229      */
skip(long n)230     public long skip(long n) throws IOException {
231         if (n < 0) {
232             throw new IllegalArgumentException("negative skip length");
233         }
234         ensureOpen();
235 
236         // Skip bytes by repeatedly decompressing small blocks
237         if (rbuf.length < 512)
238             rbuf = new byte[512];
239 
240         int total = (int)Math.min(n, Integer.MAX_VALUE);
241         long cnt = 0;
242         while (total > 0) {
243             // Read a small block of uncompressed bytes
244             int len = read(rbuf, 0, (total <= rbuf.length ? total : rbuf.length));
245 
246             if (len < 0) {
247                 break;
248             }
249             cnt += len;
250             total -= len;
251         }
252         return cnt;
253     }
254 
255     /**
256      * Returns 0 after EOF has been reached, otherwise always return 1.
257      * <p>
258      * Programs should not count on this method to return the actual number
259      * of bytes that could be read without blocking
260      * @return zero after the end of the underlying input stream has been
261      * reached, otherwise always returns 1
262      * @throws IOException if an I/O error occurs or if this stream is
263      * already closed
264      */
available()265     public int available() throws IOException {
266         ensureOpen();
267         if (reachEOF) {
268             return 0;
269         }
270         return 1;
271     }
272 
273     /**
274      * Always returns {@code false} because this input stream does not support
275      * the {@link #mark mark()} and {@link #reset reset()} methods.
276      *
277      * @return false, always
278      */
markSupported()279     public boolean markSupported() {
280         return false;
281     }
282 
283     /**
284      * <i>This operation is not supported</i>.
285      *
286      * @param limit maximum bytes that can be read before invalidating the position marker
287      */
mark(int limit)288     public void mark(int limit) {
289         // Operation not supported
290     }
291 
292     /**
293      * <i>This operation is not supported</i>.
294      *
295      * @throws IOException always thrown
296      */
reset()297     public void reset() throws IOException {
298         throw new IOException("mark/reset not supported");
299     }
300 }
301