Inflater.java revision 49965c1dc9da104344f4893a05e45795a5740d20
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2011, 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 27package java.util.zip; 28 29import dalvik.system.CloseGuard; 30 31/** 32 * This class provides support for general purpose decompression using the 33 * popular ZLIB compression library. The ZLIB compression library was 34 * initially developed as part of the PNG graphics standard and is not 35 * protected by patents. It is fully described in the specifications at 36 * the <a href="package-summary.html#package_description">java.util.zip 37 * package description</a>. 38 * 39 * <p>The following code fragment demonstrates a trivial compression 40 * and decompression of a string using <tt>Deflater</tt> and 41 * <tt>Inflater</tt>. 42 * 43 * <blockquote><pre> 44 * try { 45 * // Encode a String into bytes 46 * String inputString = "blahblahblah\u20AC\u20AC"; 47 * byte[] input = inputString.getBytes("UTF-8"); 48 * 49 * // Compress the bytes 50 * byte[] output = new byte[100]; 51 * Deflater compresser = new Deflater(); 52 * compresser.setInput(input); 53 * compresser.finish(); 54 * int compressedDataLength = compresser.deflate(output); 55 * 56 * // Decompress the bytes 57 * Inflater decompresser = new Inflater(); 58 * decompresser.setInput(output, 0, compressedDataLength); 59 * byte[] result = new byte[100]; 60 * int resultLength = decompresser.inflate(result); 61 * decompresser.end(); 62 * 63 * // Decode the bytes into a String 64 * String outputString = new String(result, 0, resultLength, "UTF-8"); 65 * } catch(java.io.UnsupportedEncodingException ex) { 66 * // handle 67 * } catch (java.util.zip.DataFormatException ex) { 68 * // handle 69 * } 70 * </pre></blockquote> 71 * 72 * @see Deflater 73 * @author David Connelly 74 * 75 */ 76public 77class Inflater { 78 79 private final ZStreamRef zsRef; 80 private byte[] buf = defaultBuf; 81 private int off, len; 82 private boolean finished; 83 private boolean needDict; 84 private long bytesRead; 85 private long bytesWritten; 86 87 private final CloseGuard guard = CloseGuard.get(); 88 89 private static final byte[] defaultBuf = new byte[0]; 90 91 /** 92 * Creates a new decompressor. If the parameter 'nowrap' is true then 93 * the ZLIB header and checksum fields will not be used. This provides 94 * compatibility with the compression format used by both GZIP and PKZIP. 95 * <p> 96 * Note: When using the 'nowrap' option it is also necessary to provide 97 * an extra "dummy" byte as input. This is required by the ZLIB native 98 * library in order to support certain optimizations. 99 * 100 * @param nowrap if true then support GZIP compatible compression 101 */ 102 public Inflater(boolean nowrap) { 103 zsRef = new ZStreamRef(init(nowrap)); 104 guard.open("end"); 105 } 106 107 /** 108 * Creates a new decompressor. 109 */ 110 public Inflater() { 111 this(false); 112 } 113 114 /** 115 * Sets input data for decompression. Should be called whenever 116 * needsInput() returns true indicating that more input data is 117 * required. 118 * @param b the input data bytes 119 * @param off the start offset of the input data 120 * @param len the length of the input data 121 * @see Inflater#needsInput 122 */ 123 public void setInput(byte[] b, int off, int len) { 124 if (b == null) { 125 throw new NullPointerException(); 126 } 127 if (off < 0 || len < 0 || off > b.length - len) { 128 throw new ArrayIndexOutOfBoundsException(); 129 } 130 synchronized (zsRef) { 131 this.buf = b; 132 this.off = off; 133 this.len = len; 134 } 135 } 136 137 /** 138 * Sets input data for decompression. Should be called whenever 139 * needsInput() returns true indicating that more input data is 140 * required. 141 * @param b the input data bytes 142 * @see Inflater#needsInput 143 */ 144 public void setInput(byte[] b) { 145 setInput(b, 0, b.length); 146 } 147 148 /** 149 * Sets the preset dictionary to the given array of bytes. Should be 150 * called when inflate() returns 0 and needsDictionary() returns true 151 * indicating that a preset dictionary is required. The method getAdler() 152 * can be used to get the Adler-32 value of the dictionary needed. 153 * @param b the dictionary data bytes 154 * @param off the start offset of the data 155 * @param len the length of the data 156 * @see Inflater#needsDictionary 157 * @see Inflater#getAdler 158 */ 159 public void setDictionary(byte[] b, int off, int len) { 160 if (b == null) { 161 throw new NullPointerException(); 162 } 163 if (off < 0 || len < 0 || off > b.length - len) { 164 throw new ArrayIndexOutOfBoundsException(); 165 } 166 synchronized (zsRef) { 167 ensureOpen(); 168 setDictionary(zsRef.address(), b, off, len); 169 needDict = false; 170 } 171 } 172 173 /** 174 * Sets the preset dictionary to the given array of bytes. Should be 175 * called when inflate() returns 0 and needsDictionary() returns true 176 * indicating that a preset dictionary is required. The method getAdler() 177 * can be used to get the Adler-32 value of the dictionary needed. 178 * @param b the dictionary data bytes 179 * @see Inflater#needsDictionary 180 * @see Inflater#getAdler 181 */ 182 public void setDictionary(byte[] b) { 183 setDictionary(b, 0, b.length); 184 } 185 186 /** 187 * Returns the total number of bytes remaining in the input buffer. 188 * This can be used to find out what bytes still remain in the input 189 * buffer after decompression has finished. 190 * @return the total number of bytes remaining in the input buffer 191 */ 192 public int getRemaining() { 193 synchronized (zsRef) { 194 return len; 195 } 196 } 197 198 /** 199 * Returns true if no data remains in the input buffer. This can 200 * be used to determine if #setInput should be called in order 201 * to provide more input. 202 * @return true if no data remains in the input buffer 203 */ 204 public boolean needsInput() { 205 synchronized (zsRef) { 206 return len <= 0; 207 } 208 } 209 210 /** 211 * Returns true if a preset dictionary is needed for decompression. 212 * @return true if a preset dictionary is needed for decompression 213 * @see Inflater#setDictionary 214 */ 215 public boolean needsDictionary() { 216 synchronized (zsRef) { 217 return needDict; 218 } 219 } 220 221 /** 222 * Returns true if the end of the compressed data stream has been 223 * reached. 224 * @return true if the end of the compressed data stream has been 225 * reached 226 */ 227 public boolean finished() { 228 synchronized (zsRef) { 229 return finished; 230 } 231 } 232 233 /** 234 * Uncompresses bytes into specified buffer. Returns actual number 235 * of bytes uncompressed. A return value of 0 indicates that 236 * needsInput() or needsDictionary() should be called in order to 237 * determine if more input data or a preset dictionary is required. 238 * In the latter case, getAdler() can be used to get the Adler-32 239 * value of the dictionary required. 240 * @param b the buffer for the uncompressed data 241 * @param off the start offset of the data 242 * @param len the maximum number of uncompressed bytes 243 * @return the actual number of uncompressed bytes 244 * @exception DataFormatException if the compressed data format is invalid 245 * @see Inflater#needsInput 246 * @see Inflater#needsDictionary 247 */ 248 public int inflate(byte[] b, int off, int len) 249 throws DataFormatException 250 { 251 if (b == null) { 252 throw new NullPointerException(); 253 } 254 if (off < 0 || len < 0 || off > b.length - len) { 255 throw new ArrayIndexOutOfBoundsException(); 256 } 257 synchronized (zsRef) { 258 ensureOpen(); 259 int thisLen = this.len; 260 int n = inflateBytes(zsRef.address(), b, off, len); 261 bytesWritten += n; 262 bytesRead += (thisLen - this.len); 263 return n; 264 } 265 } 266 267 /** 268 * Uncompresses bytes into specified buffer. Returns actual number 269 * of bytes uncompressed. A return value of 0 indicates that 270 * needsInput() or needsDictionary() should be called in order to 271 * determine if more input data or a preset dictionary is required. 272 * In the latter case, getAdler() can be used to get the Adler-32 273 * value of the dictionary required. 274 * @param b the buffer for the uncompressed data 275 * @return the actual number of uncompressed bytes 276 * @exception DataFormatException if the compressed data format is invalid 277 * @see Inflater#needsInput 278 * @see Inflater#needsDictionary 279 */ 280 public int inflate(byte[] b) throws DataFormatException { 281 return inflate(b, 0, b.length); 282 } 283 284 /** 285 * Returns the ADLER-32 value of the uncompressed data. 286 * @return the ADLER-32 value of the uncompressed data 287 */ 288 public int getAdler() { 289 synchronized (zsRef) { 290 ensureOpen(); 291 return getAdler(zsRef.address()); 292 } 293 } 294 295 /** 296 * Returns the total number of compressed bytes input so far. 297 * 298 * <p>Since the number of bytes may be greater than 299 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now 300 * the preferred means of obtaining this information.</p> 301 * 302 * @return the total number of compressed bytes input so far 303 */ 304 public int getTotalIn() { 305 return (int) getBytesRead(); 306 } 307 308 /** 309 * Returns the total number of compressed bytes input so far.</p> 310 * 311 * @return the total (non-negative) number of compressed bytes input so far 312 * @since 1.5 313 */ 314 public long getBytesRead() { 315 synchronized (zsRef) { 316 ensureOpen(); 317 return bytesRead; 318 } 319 } 320 321 /** 322 * Returns the total number of uncompressed bytes output so far. 323 * 324 * <p>Since the number of bytes may be greater than 325 * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now 326 * the preferred means of obtaining this information.</p> 327 * 328 * @return the total number of uncompressed bytes output so far 329 */ 330 public int getTotalOut() { 331 return (int) getBytesWritten(); 332 } 333 334 /** 335 * Returns the total number of uncompressed bytes output so far.</p> 336 * 337 * @return the total (non-negative) number of uncompressed bytes output so far 338 * @since 1.5 339 */ 340 public long getBytesWritten() { 341 synchronized (zsRef) { 342 ensureOpen(); 343 return bytesWritten; 344 } 345 } 346 347 /** 348 * Resets inflater so that a new set of input data can be processed. 349 */ 350 public void reset() { 351 synchronized (zsRef) { 352 ensureOpen(); 353 reset(zsRef.address()); 354 buf = defaultBuf; 355 finished = false; 356 needDict = false; 357 off = len = 0; 358 bytesRead = bytesWritten = 0; 359 } 360 } 361 362 /** 363 * Closes the decompressor and discards any unprocessed input. 364 * This method should be called when the decompressor is no longer 365 * being used, but will also be called automatically by the finalize() 366 * method. Once this method is called, the behavior of the Inflater 367 * object is undefined. 368 */ 369 public void end() { 370 synchronized (zsRef) { 371 guard.close(); 372 373 long addr = zsRef.address(); 374 zsRef.clear(); 375 if (addr != 0) { 376 end(addr); 377 buf = null; 378 } 379 } 380 } 381 382 /** 383 * Closes the decompressor when garbage is collected. 384 */ 385 protected void finalize() { 386 if (guard != null) { 387 guard.warnIfOpen(); 388 } 389 390 end(); 391 } 392 393 private void ensureOpen () { 394 assert Thread.holdsLock(zsRef); 395 // Android changed : Throw IllegalStateException instead of a NullPointerException. 396 if (zsRef.address() == 0) 397 throw new IllegalStateException("Inflater has been closed"); 398 } 399 400 boolean ended() { 401 synchronized (zsRef) { 402 return zsRef.address() == 0; 403 } 404 } 405 406 private native static long init(boolean nowrap); 407 private native static void setDictionary(long addr, byte[] b, int off, 408 int len); 409 private native int inflateBytes(long addr, byte[] b, int off, int len) 410 throws DataFormatException; 411 private native static int getAdler(long addr); 412 private native static void reset(long addr); 413 private native static void end(long addr); 414} 415