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