InflaterInputStream.java revision f9480f317cddcec859025833b748f096247a40aa
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.util.zip; 19 20import java.io.EOFException; 21import java.io.FilterInputStream; 22import java.io.IOException; 23import java.io.InputStream; 24import java.util.Arrays; 25import libcore.base.Streams; 26 27/** 28 * This class provides an implementation of {@code FilterInputStream} that 29 * decompresses data that was compressed using the <i>DEFLATE</i> algorithm 30 * (see <a href="http://www.gzip.org/algorithm.txt">specification</a>). 31 * Basically it wraps the {@code Inflater} class and takes care of the 32 * buffering. 33 * 34 * @see Inflater 35 * @see DeflaterOutputStream 36 */ 37public class InflaterInputStream extends FilterInputStream { 38 39 /** 40 * The inflater used for this stream. 41 */ 42 protected Inflater inf; 43 44 /** 45 * The input buffer used for decompression. 46 */ 47 protected byte[] buf; 48 49 /** 50 * The length of the buffer. 51 */ 52 protected int len; 53 54 boolean closed; 55 56 /** 57 * True if this stream's last byte has been returned to the user. This 58 * could be because the underlying stream has been exhausted, or if errors 59 * were encountered while inflating that stream. 60 */ 61 boolean eof; 62 63 static final int BUF_SIZE = 512; 64 65 int nativeEndBufSize = 0; // android-only 66 67 /** 68 * This is the most basic constructor. You only need to pass the {@code 69 * InputStream} from which the compressed data is to be read from. Default 70 * settings for the {@code Inflater} and internal buffer are be used. In 71 * particular the Inflater expects a ZLIB header from the input stream. 72 * 73 * @param is 74 * the {@code InputStream} to read data from. 75 */ 76 public InflaterInputStream(InputStream is) { 77 this(is, new Inflater(), BUF_SIZE); 78 } 79 80 /** 81 * This constructor lets you pass a specifically initialized Inflater, 82 * for example one that expects no ZLIB header. 83 * 84 * @param is 85 * the {@code InputStream} to read data from. 86 * @param inflater 87 * the specific {@code Inflater} for decompressing data. 88 */ 89 public InflaterInputStream(InputStream is, Inflater inflater) { 90 this(is, inflater, BUF_SIZE); 91 } 92 93 /** 94 * This constructor lets you specify both the {@code Inflater} as well as 95 * the internal buffer size to be used. 96 * 97 * @param is 98 * the {@code InputStream} to read data from. 99 * @param inflater 100 * the specific {@code Inflater} for decompressing data. 101 * @param bsize 102 * the size to be used for the internal buffer. 103 */ 104 public InflaterInputStream(InputStream is, Inflater inflater, int bsize) { 105 super(is); 106 if (is == null || inflater == null) { 107 throw new NullPointerException(); 108 } 109 if (bsize <= 0) { 110 throw new IllegalArgumentException(); 111 } 112 this.inf = inflater; 113 // BEGIN android-only 114 if (is instanceof ZipFile.RAFStream) { 115 nativeEndBufSize = bsize; 116 } else { 117 buf = new byte[bsize]; 118 } 119 // END android-only 120 } 121 122 /** 123 * Reads a single byte of decompressed data. 124 * 125 * @return the byte read. 126 * @throws IOException 127 * if an error occurs reading the byte. 128 */ 129 @Override 130 public int read() throws IOException { 131 byte[] b = new byte[1]; 132 if (read(b, 0, 1) == -1) { 133 return -1; 134 } 135 return b[0] & 0xff; 136 } 137 138 /** 139 * Reads up to {@code byteCount} bytes of decompressed data and stores it in 140 * {@code buffer} starting at {@code offset}. 141 * 142 * @return Number of uncompressed bytes read 143 */ 144 @Override 145 public int read(byte[] buffer, int offset, int byteCount) throws IOException { 146 checkClosed(); 147 Arrays.checkOffsetAndCount(buffer.length, offset, byteCount); 148 149 if (byteCount == 0) { 150 return 0; 151 } 152 153 if (eof) { 154 return -1; 155 } 156 157 do { 158 if (inf.needsInput()) { 159 fill(); 160 } 161 // Invariant: if reading returns -1 or throws, eof must be true. 162 // It may also be true if the next read() should return -1. 163 try { 164 int result = inf.inflate(buffer, offset, byteCount); 165 eof = inf.finished(); 166 if (result > 0) { 167 return result; 168 } else if (eof) { 169 return -1; 170 } else if (inf.needsDictionary()) { 171 eof = true; 172 return -1; 173 } else if (len == -1) { 174 eof = true; 175 throw new EOFException(); 176 // If result == 0, fill() and try again 177 } 178 } catch (DataFormatException e) { 179 eof = true; 180 if (len == -1) { 181 throw new EOFException(); 182 } 183 throw (IOException) (new IOException().initCause(e)); 184 } 185 } while (true); 186 } 187 188 /** 189 * Fills the input buffer with data to be decompressed. 190 * 191 * @throws IOException 192 * if an {@code IOException} occurs. 193 */ 194 protected void fill() throws IOException { 195 checkClosed(); 196 // BEGIN android-only 197 if (nativeEndBufSize > 0) { 198 ZipFile.RAFStream is = (ZipFile.RAFStream)in; 199 synchronized (is.mSharedRaf) { 200 long len = is.mLength - is.mOffset; 201 if (len > nativeEndBufSize) len = nativeEndBufSize; 202 int cnt = inf.setFileInput(is.mSharedRaf.getFD(), is.mOffset, (int)nativeEndBufSize); 203 is.skip(cnt); 204 } 205 } else { 206 if ((len = in.read(buf)) > 0) { 207 inf.setInput(buf, 0, len); 208 } 209 } 210 // END android-only 211 } 212 213 /** 214 * Skips up to {@code byteCount} bytes of uncompressed data. 215 * 216 * @param byteCount the number of bytes to skip. 217 * @return the number of uncompressed bytes skipped. 218 * @throws IllegalArgumentException if {@code byteCount < 0}. 219 * @throws IOException if an error occurs skipping. 220 */ 221 @Override 222 public long skip(long byteCount) throws IOException { 223 if (byteCount < 0) { 224 throw new IllegalArgumentException("byteCount < 0"); 225 } 226 return Streams.skipByReading(this, byteCount); 227 } 228 229 /** 230 * Returns 0 when when this stream has exhausted its input; and 1 otherwise. 231 * A result of 1 does not guarantee that further bytes can be returned, 232 * with or without blocking. 233 * 234 * <p>Although consistent with the RI, this behavior is inconsistent with 235 * {@link InputStream#available()}, and violates the <a 236 * href="http://en.wikipedia.org/wiki/Liskov_substitution_principle">Liskov 237 * Substitution Principle</a>. This method should not be used. 238 * 239 * @return 0 if no further bytes are available. Otherwise returns 1, 240 * which suggests (but does not guarantee) that additional bytes are 241 * available. 242 * @throws IOException if this stream is closed or an error occurs 243 */ 244 @Override 245 public int available() throws IOException { 246 checkClosed(); 247 if (eof) { 248 return 0; 249 } 250 return 1; 251 } 252 253 /** 254 * Closes the input stream. 255 * 256 * @throws IOException 257 * If an error occurs closing the input stream. 258 */ 259 @Override 260 public void close() throws IOException { 261 if (!closed) { 262 inf.end(); 263 closed = true; 264 eof = true; 265 super.close(); 266 } 267 } 268 269 /** 270 * Marks the current position in the stream. This implementation overrides 271 * the super type implementation to do nothing at all. 272 * 273 * @param readlimit 274 * of no use. 275 */ 276 @Override 277 public void mark(int readlimit) { 278 // do nothing 279 } 280 281 /** 282 * Reset the position of the stream to the last marked position. This 283 * implementation overrides the supertype implementation and always throws 284 * an {@link IOException IOException} when called. 285 * 286 * @throws IOException 287 * if the method is called 288 */ 289 @Override 290 public void reset() throws IOException { 291 throw new IOException(); 292 } 293 294 /** 295 * Returns whether the receiver implements {@code mark} semantics. This type 296 * does not support {@code mark()}, so always responds {@code false}. 297 * 298 * @return false, always 299 */ 300 @Override 301 public boolean markSupported() { 302 return false; 303 } 304 305 private void checkClosed() throws IOException { 306 if (closed) { 307 throw new IOException("Stream is closed"); 308 } 309 } 310} 311