1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2018, 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.annotation.optimization.ReachabilitySensitive; 30 import dalvik.system.CloseGuard; 31 import java.lang.ref.Cleaner.Cleanable; 32 import java.lang.ref.Reference; 33 import java.nio.ByteBuffer; 34 import java.nio.ReadOnlyBufferException; 35 import java.util.Objects; 36 37 import jdk.internal.ref.CleanerFactory; 38 import sun.nio.ch.DirectBuffer; 39 40 /** 41 * This class provides support for general purpose decompression using the 42 * popular ZLIB compression library. The ZLIB compression library was 43 * initially developed as part of the PNG graphics standard and is not 44 * protected by patents. It is fully described in the specifications at 45 * the <a href="package-summary.html#package-description">java.util.zip 46 * package description</a>. 47 * <p> 48 * This class inflates sequences of ZLIB compressed bytes. The input byte 49 * sequence is provided in either byte array or byte buffer, via one of the 50 * {@code setInput()} methods. The output byte sequence is written to the 51 * output byte array or byte buffer passed to the {@code deflate()} methods. 52 * <p> 53 * The following code fragment demonstrates a trivial compression 54 * and decompression of a string using {@code Deflater} and 55 * {@code Inflater}. 56 * 57 * <blockquote><pre> 58 * try { 59 * // Encode a String into bytes 60 * String inputString = "blahblahblah\u20AC\u20AC"; 61 * byte[] input = inputString.getBytes("UTF-8"); 62 * 63 * // Compress the bytes 64 * byte[] output = new byte[100]; 65 * Deflater compresser = new Deflater(); 66 * compresser.setInput(input); 67 * compresser.finish(); 68 * int compressedDataLength = compresser.deflate(output); 69 * 70 * // Decompress the bytes 71 * Inflater decompresser = new Inflater(); 72 * decompresser.setInput(output, 0, compressedDataLength); 73 * byte[] result = new byte[100]; 74 * int resultLength = decompresser.inflate(result); 75 * decompresser.end(); 76 * 77 * // Decode the bytes into a String 78 * String outputString = new String(result, 0, resultLength, "UTF-8"); 79 * } catch (java.io.UnsupportedEncodingException ex) { 80 * // handle 81 * } catch (java.util.zip.DataFormatException ex) { 82 * // handle 83 * } 84 * </pre></blockquote> 85 * 86 * @apiNote 87 * To release resources used by this {@code Inflater}, the {@link #end()} method 88 * should be called explicitly. Subclasses are responsible for the cleanup of resources 89 * acquired by the subclass. Subclasses that override {@link #finalize()} in order 90 * to perform cleanup should be modified to use alternative cleanup mechanisms such 91 * as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method. 92 * 93 * @see Deflater 94 * @author David Connelly 95 * @since 1.1 96 * 97 */ 98 99 public class Inflater { 100 101 private final InflaterZStreamRef zsRef; 102 private ByteBuffer input = ZipUtils.defaultBuf; 103 private byte[] inputArray; 104 private int inputPos, inputLim; 105 private boolean finished; 106 private boolean needDict; 107 private long bytesRead; 108 private long bytesWritten; 109 110 // Android-added: CloseGuard support. 111 @ReachabilitySensitive 112 private final CloseGuard guard = CloseGuard.get(); 113 114 /* 115 * These fields are used as an "out" parameter from JNI when a 116 * DataFormatException is thrown during the inflate operation. 117 */ 118 private int inputConsumed; 119 private int outputConsumed; 120 121 // Android-removed: initIDs handled in register method. 122 /* 123 static { 124 ZipUtils.loadLibrary(); 125 initIDs(); 126 } 127 */ 128 129 /** 130 * Creates a new decompressor. If the parameter 'nowrap' is true then 131 * the ZLIB header and checksum fields will not be used. This provides 132 * compatibility with the compression format used by both GZIP and PKZIP. 133 * <p> 134 * Note: When using the 'nowrap' option it is also necessary to provide 135 * an extra "dummy" byte as input. This is required by the ZLIB native 136 * library in order to support certain optimizations. 137 * 138 * @param nowrap if true then support GZIP compatible compression 139 */ Inflater(boolean nowrap)140 public Inflater(boolean nowrap) { 141 this.zsRef = new InflaterZStreamRef(this, init(nowrap)); 142 // Android-added: CloseGuard support. 143 guard.open("end"); 144 } 145 146 /** 147 * Creates a new decompressor. 148 */ Inflater()149 public Inflater() { 150 this(false); 151 } 152 153 /** 154 * Sets input data for decompression. 155 * <p> 156 * One of the {@code setInput()} methods should be called whenever 157 * {@code needsInput()} returns true indicating that more input data 158 * is required. 159 * 160 * @param input the input data bytes 161 * @param off the start offset of the input data 162 * @param len the length of the input data 163 * @see Inflater#needsInput 164 */ setInput(byte[] input, int off, int len)165 public void setInput(byte[] input, int off, int len) { 166 if (off < 0 || len < 0 || off > input.length - len) { 167 throw new ArrayIndexOutOfBoundsException(); 168 } 169 synchronized (zsRef) { 170 this.input = null; 171 this.inputArray = input; 172 this.inputPos = off; 173 this.inputLim = off + len; 174 } 175 } 176 177 /** 178 * Sets input data for decompression. 179 * <p> 180 * One of the {@code setInput()} methods should be called whenever 181 * {@code needsInput()} returns true indicating that more input data 182 * is required. 183 * 184 * @param input the input data bytes 185 * @see Inflater#needsInput 186 */ setInput(byte[] input)187 public void setInput(byte[] input) { 188 setInput(input, 0, input.length); 189 } 190 191 /** 192 * Sets input data for decompression. 193 * <p> 194 * One of the {@code setInput()} methods should be called whenever 195 * {@code needsInput()} returns true indicating that more input data 196 * is required. 197 * <p> 198 * The given buffer's position will be advanced as inflate 199 * operations are performed, up to the buffer's limit. 200 * The input buffer may be modified (refilled) between inflate 201 * operations; doing so is equivalent to creating a new buffer 202 * and setting it with this method. 203 * <p> 204 * Modifying the input buffer's contents, position, or limit 205 * concurrently with an inflate operation will result in 206 * undefined behavior, which may include incorrect operation 207 * results or operation failure. 208 * 209 * @param input the input data bytes 210 * @see Inflater#needsInput 211 * @since 11 212 */ setInput(ByteBuffer input)213 public void setInput(ByteBuffer input) { 214 Objects.requireNonNull(input); 215 synchronized (zsRef) { 216 this.input = input; 217 this.inputArray = null; 218 } 219 } 220 221 /** 222 * Sets the preset dictionary to the given array of bytes. Should be 223 * called when inflate() returns 0 and needsDictionary() returns true 224 * indicating that a preset dictionary is required. The method getAdler() 225 * can be used to get the Adler-32 value of the dictionary needed. 226 * @param dictionary the dictionary data bytes 227 * @param off the start offset of the data 228 * @param len the length of the data 229 * @see Inflater#needsDictionary 230 * @see Inflater#getAdler 231 */ setDictionary(byte[] dictionary, int off, int len)232 public void setDictionary(byte[] dictionary, int off, int len) { 233 if (off < 0 || len < 0 || off > dictionary.length - len) { 234 throw new ArrayIndexOutOfBoundsException(); 235 } 236 synchronized (zsRef) { 237 ensureOpen(); 238 setDictionary(zsRef.address(), dictionary, off, len); 239 needDict = false; 240 } 241 } 242 243 /** 244 * Sets the preset dictionary to the given array of bytes. Should be 245 * called when inflate() returns 0 and needsDictionary() returns true 246 * indicating that a preset dictionary is required. The method getAdler() 247 * can be used to get the Adler-32 value of the dictionary needed. 248 * @param dictionary the dictionary data bytes 249 * @see Inflater#needsDictionary 250 * @see Inflater#getAdler 251 */ setDictionary(byte[] dictionary)252 public void setDictionary(byte[] dictionary) { 253 setDictionary(dictionary, 0, dictionary.length); 254 } 255 256 /** 257 * Sets the preset dictionary to the bytes in the given buffer. Should be 258 * called when inflate() returns 0 and needsDictionary() returns true 259 * indicating that a preset dictionary is required. The method getAdler() 260 * can be used to get the Adler-32 value of the dictionary needed. 261 * <p> 262 * The bytes in given byte buffer will be fully consumed by this method. On 263 * return, its position will equal its limit. 264 * 265 * @param dictionary the dictionary data bytes 266 * @see Inflater#needsDictionary 267 * @see Inflater#getAdler 268 * @since 11 269 */ setDictionary(ByteBuffer dictionary)270 public void setDictionary(ByteBuffer dictionary) { 271 synchronized (zsRef) { 272 int position = dictionary.position(); 273 int remaining = Math.max(dictionary.limit() - position, 0); 274 ensureOpen(); 275 if (dictionary.isDirect()) { 276 long address = ((DirectBuffer) dictionary).address(); 277 try { 278 setDictionaryBuffer(zsRef.address(), address + position, remaining); 279 } finally { 280 Reference.reachabilityFence(dictionary); 281 } 282 } else { 283 byte[] array = ZipUtils.getBufferArray(dictionary); 284 int offset = ZipUtils.getBufferOffset(dictionary); 285 setDictionary(zsRef.address(), array, offset + position, remaining); 286 } 287 dictionary.position(position + remaining); 288 needDict = false; 289 } 290 } 291 292 /** 293 * Returns the total number of bytes remaining in the input buffer. 294 * This can be used to find out what bytes still remain in the input 295 * buffer after decompression has finished. 296 * @return the total number of bytes remaining in the input buffer 297 */ getRemaining()298 public int getRemaining() { 299 synchronized (zsRef) { 300 ByteBuffer input = this.input; 301 return input == null ? inputLim - inputPos : input.remaining(); 302 } 303 } 304 305 /** 306 * Returns true if no data remains in the input buffer. This can 307 * be used to determine if one of the {@code setInput()} methods should be 308 * called in order to provide more input. 309 * 310 * @return true if no data remains in the input buffer 311 */ needsInput()312 public boolean needsInput() { 313 synchronized (zsRef) { 314 ByteBuffer input = this.input; 315 return input == null ? inputLim == inputPos : ! input.hasRemaining(); 316 } 317 } 318 319 /** 320 * Returns true if a preset dictionary is needed for decompression. 321 * @return true if a preset dictionary is needed for decompression 322 * @see Inflater#setDictionary 323 */ needsDictionary()324 public boolean needsDictionary() { 325 synchronized (zsRef) { 326 return needDict; 327 } 328 } 329 330 /** 331 * Returns true if the end of the compressed data stream has been 332 * reached. 333 * @return true if the end of the compressed data stream has been 334 * reached 335 */ finished()336 public boolean finished() { 337 synchronized (zsRef) { 338 return finished; 339 } 340 } 341 342 /** 343 * Uncompresses bytes into specified buffer. Returns actual number 344 * of bytes uncompressed. A return value of 0 indicates that 345 * needsInput() or needsDictionary() should be called in order to 346 * determine if more input data or a preset dictionary is required. 347 * In the latter case, getAdler() can be used to get the Adler-32 348 * value of the dictionary required. 349 * <p> 350 * If the {@link #setInput(ByteBuffer)} method was called to provide a buffer 351 * for input, the input buffer's position will be advanced by the number of bytes 352 * consumed by this operation, even in the event that a {@link DataFormatException} 353 * is thrown. 354 * <p> 355 * The {@linkplain #getRemaining() remaining byte count} will be reduced by 356 * the number of consumed input bytes. If the {@link #setInput(ByteBuffer)} 357 * method was called to provide a buffer for input, the input buffer's position 358 * will be advanced the number of consumed bytes. 359 * <p> 360 * These byte totals, as well as 361 * the {@linkplain #getBytesRead() total bytes read} 362 * and the {@linkplain #getBytesWritten() total bytes written} 363 * values, will be updated even in the event that a {@link DataFormatException} 364 * is thrown to reflect the amount of data consumed and produced before the 365 * exception occurred. 366 * 367 * @param output the buffer for the uncompressed data 368 * @param off the start offset of the data 369 * @param len the maximum number of uncompressed bytes 370 * @return the actual number of uncompressed bytes 371 * @throws DataFormatException if the compressed data format is invalid 372 * @see Inflater#needsInput 373 * @see Inflater#needsDictionary 374 */ inflate(byte[] output, int off, int len)375 public int inflate(byte[] output, int off, int len) 376 throws DataFormatException 377 { 378 if (off < 0 || len < 0 || off > output.length - len) { 379 throw new ArrayIndexOutOfBoundsException(); 380 } 381 synchronized (zsRef) { 382 ensureOpen(); 383 ByteBuffer input = this.input; 384 long result; 385 int inputPos; 386 try { 387 if (input == null) { 388 inputPos = this.inputPos; 389 try { 390 result = inflateBytesBytes(zsRef.address(), 391 inputArray, inputPos, inputLim - inputPos, 392 output, off, len); 393 } catch (DataFormatException e) { 394 this.inputPos = inputPos + inputConsumed; 395 throw e; 396 } 397 } else { 398 inputPos = input.position(); 399 try { 400 int inputRem = Math.max(input.limit() - inputPos, 0); 401 if (input.isDirect()) { 402 try { 403 long inputAddress = ((DirectBuffer) input).address(); 404 result = inflateBufferBytes(zsRef.address(), 405 inputAddress + inputPos, inputRem, 406 output, off, len); 407 } finally { 408 Reference.reachabilityFence(input); 409 } 410 } else { 411 byte[] inputArray = ZipUtils.getBufferArray(input); 412 int inputOffset = ZipUtils.getBufferOffset(input); 413 result = inflateBytesBytes(zsRef.address(), 414 inputArray, inputOffset + inputPos, inputRem, 415 output, off, len); 416 } 417 } catch (DataFormatException e) { 418 input.position(inputPos + inputConsumed); 419 throw e; 420 } 421 } 422 } catch (DataFormatException e) { 423 bytesRead += inputConsumed; 424 inputConsumed = 0; 425 int written = outputConsumed; 426 bytesWritten += written; 427 outputConsumed = 0; 428 throw e; 429 } 430 int read = (int) (result & 0x7fff_ffffL); 431 int written = (int) (result >>> 31 & 0x7fff_ffffL); 432 if ((result >>> 62 & 1) != 0) { 433 finished = true; 434 } 435 if ((result >>> 63 & 1) != 0) { 436 needDict = true; 437 } 438 if (input != null) { 439 input.position(inputPos + read); 440 } else { 441 this.inputPos = inputPos + read; 442 } 443 bytesWritten += written; 444 bytesRead += read; 445 return written; 446 } 447 } 448 449 /** 450 * Uncompresses bytes into specified buffer. Returns actual number 451 * of bytes uncompressed. A return value of 0 indicates that 452 * needsInput() or needsDictionary() should be called in order to 453 * determine if more input data or a preset dictionary is required. 454 * In the latter case, getAdler() can be used to get the Adler-32 455 * value of the dictionary required. 456 * <p> 457 * The {@linkplain #getRemaining() remaining byte count} will be reduced by 458 * the number of consumed input bytes. If the {@link #setInput(ByteBuffer)} 459 * method was called to provide a buffer for input, the input buffer's position 460 * will be advanced the number of consumed bytes. 461 * <p> 462 * These byte totals, as well as 463 * the {@linkplain #getBytesRead() total bytes read} 464 * and the {@linkplain #getBytesWritten() total bytes written} 465 * values, will be updated even in the event that a {@link DataFormatException} 466 * is thrown to reflect the amount of data consumed and produced before the 467 * exception occurred. 468 * 469 * @param output the buffer for the uncompressed data 470 * @return the actual number of uncompressed bytes 471 * @throws DataFormatException if the compressed data format is invalid 472 * @see Inflater#needsInput 473 * @see Inflater#needsDictionary 474 */ inflate(byte[] output)475 public int inflate(byte[] output) throws DataFormatException { 476 return inflate(output, 0, output.length); 477 } 478 479 /** 480 * Uncompresses bytes into specified buffer. Returns actual number 481 * of bytes uncompressed. A return value of 0 indicates that 482 * needsInput() or needsDictionary() should be called in order to 483 * determine if more input data or a preset dictionary is required. 484 * In the latter case, getAdler() can be used to get the Adler-32 485 * value of the dictionary required. 486 * <p> 487 * On success, the position of the given {@code output} byte buffer will be 488 * advanced by as many bytes as were produced by the operation, which is equal 489 * to the number returned by this method. Note that the position of the 490 * {@code output} buffer will be advanced even in the event that a 491 * {@link DataFormatException} is thrown. 492 * <p> 493 * The {@linkplain #getRemaining() remaining byte count} will be reduced by 494 * the number of consumed input bytes. If the {@link #setInput(ByteBuffer)} 495 * method was called to provide a buffer for input, the input buffer's position 496 * will be advanced the number of consumed bytes. 497 * <p> 498 * These byte totals, as well as 499 * the {@linkplain #getBytesRead() total bytes read} 500 * and the {@linkplain #getBytesWritten() total bytes written} 501 * values, will be updated even in the event that a {@link DataFormatException} 502 * is thrown to reflect the amount of data consumed and produced before the 503 * exception occurred. 504 * 505 * @param output the buffer for the uncompressed data 506 * @return the actual number of uncompressed bytes 507 * @throws DataFormatException if the compressed data format is invalid 508 * @throws ReadOnlyBufferException if the given output buffer is read-only 509 * @see Inflater#needsInput 510 * @see Inflater#needsDictionary 511 * @since 11 512 */ inflate(ByteBuffer output)513 public int inflate(ByteBuffer output) throws DataFormatException { 514 if (output.isReadOnly()) { 515 throw new ReadOnlyBufferException(); 516 } 517 synchronized (zsRef) { 518 ensureOpen(); 519 ByteBuffer input = this.input; 520 long result; 521 int inputPos; 522 int outputPos = output.position(); 523 int outputRem = Math.max(output.limit() - outputPos, 0); 524 try { 525 if (input == null) { 526 inputPos = this.inputPos; 527 try { 528 if (output.isDirect()) { 529 long outputAddress = ((DirectBuffer) output).address(); 530 try { 531 result = inflateBytesBuffer(zsRef.address(), 532 inputArray, inputPos, inputLim - inputPos, 533 outputAddress + outputPos, outputRem); 534 } finally { 535 Reference.reachabilityFence(output); 536 } 537 } else { 538 byte[] outputArray = ZipUtils.getBufferArray(output); 539 int outputOffset = ZipUtils.getBufferOffset(output); 540 result = inflateBytesBytes(zsRef.address(), 541 inputArray, inputPos, inputLim - inputPos, 542 outputArray, outputOffset + outputPos, outputRem); 543 } 544 } catch (DataFormatException e) { 545 this.inputPos = inputPos + inputConsumed; 546 throw e; 547 } 548 } else { 549 inputPos = input.position(); 550 int inputRem = Math.max(input.limit() - inputPos, 0); 551 try { 552 if (input.isDirect()) { 553 long inputAddress = ((DirectBuffer) input).address(); 554 try { 555 if (output.isDirect()) { 556 long outputAddress = ((DirectBuffer) output).address(); 557 try { 558 result = inflateBufferBuffer(zsRef.address(), 559 inputAddress + inputPos, inputRem, 560 outputAddress + outputPos, outputRem); 561 } finally { 562 Reference.reachabilityFence(output); 563 } 564 } else { 565 byte[] outputArray = ZipUtils.getBufferArray(output); 566 int outputOffset = ZipUtils.getBufferOffset(output); 567 result = inflateBufferBytes(zsRef.address(), 568 inputAddress + inputPos, inputRem, 569 outputArray, outputOffset + outputPos, outputRem); 570 } 571 } finally { 572 Reference.reachabilityFence(input); 573 } 574 } else { 575 byte[] inputArray = ZipUtils.getBufferArray(input); 576 int inputOffset = ZipUtils.getBufferOffset(input); 577 if (output.isDirect()) { 578 long outputAddress = ((DirectBuffer) output).address(); 579 try { 580 result = inflateBytesBuffer(zsRef.address(), 581 inputArray, inputOffset + inputPos, inputRem, 582 outputAddress + outputPos, outputRem); 583 } finally { 584 Reference.reachabilityFence(output); 585 } 586 } else { 587 byte[] outputArray = ZipUtils.getBufferArray(output); 588 int outputOffset = ZipUtils.getBufferOffset(output); 589 result = inflateBytesBytes(zsRef.address(), 590 inputArray, inputOffset + inputPos, inputRem, 591 outputArray, outputOffset + outputPos, outputRem); 592 } 593 } 594 } catch (DataFormatException e) { 595 input.position(inputPos + inputConsumed); 596 throw e; 597 } 598 } 599 } catch (DataFormatException e) { 600 bytesRead += inputConsumed; 601 inputConsumed = 0; 602 int written = outputConsumed; 603 output.position(outputPos + written); 604 bytesWritten += written; 605 outputConsumed = 0; 606 throw e; 607 } 608 int read = (int) (result & 0x7fff_ffffL); 609 int written = (int) (result >>> 31 & 0x7fff_ffffL); 610 if ((result >>> 62 & 1) != 0) { 611 finished = true; 612 } 613 if ((result >>> 63 & 1) != 0) { 614 needDict = true; 615 } 616 if (input != null) { 617 input.position(inputPos + read); 618 } else { 619 this.inputPos = inputPos + read; 620 } 621 // Note: this method call also serves to keep the byteBuffer ref alive 622 output.position(outputPos + written); 623 bytesWritten += written; 624 bytesRead += read; 625 return written; 626 } 627 } 628 629 /** 630 * Returns the ADLER-32 value of the uncompressed data. 631 * @return the ADLER-32 value of the uncompressed data 632 */ getAdler()633 public int getAdler() { 634 synchronized (zsRef) { 635 ensureOpen(); 636 return getAdler(zsRef.address()); 637 } 638 } 639 640 /** 641 * Returns the total number of compressed bytes input so far. 642 * 643 * <p>Since the number of bytes may be greater than 644 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now 645 * the preferred means of obtaining this information.</p> 646 * 647 * @return the total number of compressed bytes input so far 648 */ getTotalIn()649 public int getTotalIn() { 650 return (int) getBytesRead(); 651 } 652 653 /** 654 * Returns the total number of compressed bytes input so far. 655 * 656 * @return the total (non-negative) number of compressed bytes input so far 657 * @since 1.5 658 */ getBytesRead()659 public long getBytesRead() { 660 synchronized (zsRef) { 661 ensureOpen(); 662 return bytesRead; 663 } 664 } 665 666 /** 667 * Returns the total number of uncompressed bytes output so far. 668 * 669 * <p>Since the number of bytes may be greater than 670 * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now 671 * the preferred means of obtaining this information.</p> 672 * 673 * @return the total number of uncompressed bytes output so far 674 */ getTotalOut()675 public int getTotalOut() { 676 return (int) getBytesWritten(); 677 } 678 679 /** 680 * Returns the total number of uncompressed bytes output so far. 681 * 682 * @return the total (non-negative) number of uncompressed bytes output so far 683 * @since 1.5 684 */ getBytesWritten()685 public long getBytesWritten() { 686 synchronized (zsRef) { 687 ensureOpen(); 688 return bytesWritten; 689 } 690 } 691 692 /** 693 * Resets inflater so that a new set of input data can be processed. 694 */ reset()695 public void reset() { 696 synchronized (zsRef) { 697 ensureOpen(); 698 reset(zsRef.address()); 699 // Android-added: CloseGuard support. 700 guard.close(); 701 input = ZipUtils.defaultBuf; 702 inputArray = null; 703 finished = false; 704 needDict = false; 705 bytesRead = bytesWritten = 0; 706 } 707 } 708 709 /** 710 * Closes the decompressor and discards any unprocessed input. 711 * 712 * This method should be called when the decompressor is no longer 713 * being used. Once this method is called, the behavior of the 714 * Inflater object is undefined. 715 */ end()716 public void end() { 717 synchronized (zsRef) { 718 zsRef.clean(); 719 // Android-added: CloseGuard support. 720 guard.close(); 721 input = ZipUtils.defaultBuf; 722 inputArray = null; 723 } 724 } 725 726 ensureOpen()727 private void ensureOpen () { 728 assert Thread.holdsLock(zsRef); 729 if (zsRef.address() == 0) 730 throw new NullPointerException("Inflater has been closed"); 731 } 732 733 // Android-changed: initIDs handled in register method. 734 // private native static void initIDs(); init(boolean nowrap)735 private static native long init(boolean nowrap); setDictionary(long addr, byte[] b, int off, int len)736 private static native void setDictionary(long addr, byte[] b, int off, 737 int len); setDictionaryBuffer(long addr, long bufAddress, int len)738 private static native void setDictionaryBuffer(long addr, long bufAddress, int len); inflateBytesBytes(long addr, byte[] inputArray, int inputOff, int inputLen, byte[] outputArray, int outputOff, int outputLen)739 private native long inflateBytesBytes(long addr, 740 byte[] inputArray, int inputOff, int inputLen, 741 byte[] outputArray, int outputOff, int outputLen) throws DataFormatException; inflateBytesBuffer(long addr, byte[] inputArray, int inputOff, int inputLen, long outputAddress, int outputLen)742 private native long inflateBytesBuffer(long addr, 743 byte[] inputArray, int inputOff, int inputLen, 744 long outputAddress, int outputLen) throws DataFormatException; inflateBufferBytes(long addr, long inputAddress, int inputLen, byte[] outputArray, int outputOff, int outputLen)745 private native long inflateBufferBytes(long addr, 746 long inputAddress, int inputLen, 747 byte[] outputArray, int outputOff, int outputLen) throws DataFormatException; inflateBufferBuffer(long addr, long inputAddress, int inputLen, long outputAddress, int outputLen)748 private native long inflateBufferBuffer(long addr, 749 long inputAddress, int inputLen, 750 long outputAddress, int outputLen) throws DataFormatException; getAdler(long addr)751 private static native int getAdler(long addr); reset(long addr)752 private static native void reset(long addr); end(long addr)753 private static native void end(long addr); 754 755 /** 756 * A reference to the native zlib's z_stream structure. It also 757 * serves as the "cleaner" to clean up the native resource when 758 * the Inflater is ended, closed or cleaned. 759 */ 760 static class InflaterZStreamRef implements Runnable { 761 762 private long address; 763 private final Cleanable cleanable; 764 InflaterZStreamRef(Inflater owner, long addr)765 private InflaterZStreamRef(Inflater owner, long addr) { 766 this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null; 767 this.address = addr; 768 } 769 address()770 long address() { 771 return address; 772 } 773 clean()774 void clean() { 775 cleanable.clean(); 776 } 777 run()778 public synchronized void run() { 779 long addr = address; 780 address = 0; 781 if (addr != 0) { 782 end(addr); 783 } 784 } 785 786 } 787 } 788