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