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