1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2006, 2021, 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, in != null ? new Deflater() : null); 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 <= 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 > b.length - off} 168 * @throws IOException if an I/O error occurs or if this input stream is 169 * already closed 170 */ read(byte[] b, int off, int len)171 public int read(byte[] b, int off, int len) throws IOException { 172 // Sanity checks 173 ensureOpen(); 174 if (b == null) { 175 throw new NullPointerException("Null buffer for read"); 176 } else if (off < 0 || len < 0 || len > b.length - off) { 177 throw new IndexOutOfBoundsException(); 178 } else if (len == 0) { 179 return 0; 180 } 181 182 // Read and compress (deflate) input data bytes 183 int cnt = 0; 184 while (len > 0 && !def.finished()) { 185 int n; 186 187 // Read data from the input stream 188 if (def.needsInput()) { 189 n = in.read(buf, 0, buf.length); 190 if (n < 0) { 191 // End of the input stream reached 192 def.finish(); 193 } else if (n > 0) { 194 def.setInput(buf, 0, n); 195 } 196 } 197 198 // Compress the input data, filling the read buffer 199 n = def.deflate(b, off, len); 200 cnt += n; 201 off += n; 202 len -= n; 203 } 204 // BEGIN Android-changed: Return more accurate value from available(). 205 // Set reachEOF eagerly when the Deflater has finished, and not just when the number of 206 // bytes is zero so that available is more accurate. 207 // See http://b/111589691 208 /* 209 if (cnt == 0 && def.finished()) { 210 reachEOF = true; 211 cnt = -1; 212 } 213 */ 214 if (def.finished()) { 215 reachEOF = true; 216 if (cnt == 0) { 217 cnt = -1; 218 } 219 } 220 // END Android-changed: Return more accurate value from available(). 221 222 return cnt; 223 } 224 225 /** 226 * Skips over and discards data from the input stream. 227 * This method may block until the specified number of bytes are read and 228 * skipped. <em>Note:</em> While {@code n} is given as a {@code long}, 229 * the maximum number of bytes which can be skipped is 230 * {@code Integer.MAX_VALUE}. 231 * 232 * @param n number of bytes to be skipped 233 * @return the actual number of bytes skipped 234 * @throws IOException if an I/O error occurs or if this stream is 235 * already closed 236 */ skip(long n)237 public long skip(long n) throws IOException { 238 if (n < 0) { 239 throw new IllegalArgumentException("negative skip length"); 240 } 241 ensureOpen(); 242 243 // Skip bytes by repeatedly decompressing small blocks 244 if (rbuf.length < 512) 245 rbuf = new byte[512]; 246 247 int total = (int)Math.min(n, Integer.MAX_VALUE); 248 long cnt = 0; 249 while (total > 0) { 250 // Read a small block of uncompressed bytes 251 int len = read(rbuf, 0, (total <= rbuf.length ? total : rbuf.length)); 252 253 if (len < 0) { 254 break; 255 } 256 cnt += len; 257 total -= len; 258 } 259 return cnt; 260 } 261 262 /** 263 * Returns 0 after EOF has been reached, otherwise always return 1. 264 * <p> 265 * Programs should not count on this method to return the actual number 266 * of bytes that could be read without blocking 267 * @return zero after the end of the underlying input stream has been 268 * reached, otherwise always returns 1 269 * @throws IOException if an I/O error occurs or if this stream is 270 * already closed 271 */ available()272 public int available() throws IOException { 273 ensureOpen(); 274 if (reachEOF) { 275 return 0; 276 } 277 return 1; 278 } 279 280 /** 281 * Always returns {@code false} because this input stream does not support 282 * the {@link #mark mark()} and {@link #reset reset()} methods. 283 * 284 * @return false, always 285 */ markSupported()286 public boolean markSupported() { 287 return false; 288 } 289 290 /** 291 * <i>This operation is not supported</i>. 292 * 293 * @param limit maximum bytes that can be read before invalidating the position marker 294 */ mark(int limit)295 public void mark(int limit) { 296 // Operation not supported 297 } 298 299 /** 300 * <i>This operation is not supported</i>. 301 * 302 * @throws IOException always thrown 303 */ reset()304 public void reset() throws IOException { 305 throw new IOException("mark/reset not supported"); 306 } 307 } 308