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