1 /* 2 * Copyright (c) 1996, 2022, 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 dalvik.annotation.optimization.ReachabilitySensitive; 29 import dalvik.system.CloseGuard; 30 import java.lang.ref.Cleaner.Cleanable; 31 import java.lang.ref.Reference; 32 import java.nio.ByteBuffer; 33 import java.nio.ReadOnlyBufferException; 34 import java.util.Objects; 35 36 import jdk.internal.ref.CleanerFactory; 37 import sun.nio.ch.DirectBuffer; 38 39 /** 40 * This class provides support for general purpose compression using the 41 * popular ZLIB compression library. The ZLIB compression library was 42 * initially developed as part of the PNG graphics standard and is not 43 * protected by patents. It is fully described in the specifications at 44 * the <a href="package-summary.html#package-description">java.util.zip 45 * package description</a>. 46 * <p> 47 * This class deflates sequences of bytes into ZLIB compressed data format. 48 * The input byte sequence is provided in either byte array or byte buffer, 49 * via one of the {@code setInput()} methods. The output byte sequence is 50 * written to the output byte array or byte buffer passed to the 51 * {@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"; 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 * compresser.end(); 70 * 71 * // Decompress the bytes 72 * Inflater decompresser = new Inflater(); 73 * decompresser.setInput(output, 0, compressedDataLength); 74 * byte[] result = new byte[100]; 75 * int resultLength = decompresser.inflate(result); 76 * decompresser.end(); 77 * 78 * // Decode the bytes into a String 79 * String outputString = new String(result, 0, resultLength, "UTF-8"); 80 * } catch (java.io.UnsupportedEncodingException ex) { 81 * // handle 82 * } catch (java.util.zip.DataFormatException ex) { 83 * // handle 84 * } 85 * </pre></blockquote> 86 * 87 * @apiNote 88 * To release resources used by this {@code Deflater}, the {@link #end()} method 89 * should be called explicitly. Subclasses are responsible for the cleanup of resources 90 * acquired by the subclass. Subclasses that override {@link #finalize()} in order 91 * to perform cleanup should be modified to use alternative cleanup mechanisms such 92 * as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method. 93 * 94 * @see Inflater 95 * @author David Connelly 96 * @since 1.1 97 */ 98 99 public class Deflater { 100 101 private final DeflaterZStreamRef zsRef; 102 private ByteBuffer input = ZipUtils.defaultBuf; 103 private byte[] inputArray; 104 private int inputPos, inputLim; 105 private int level, strategy; 106 private boolean setParams; 107 private boolean finish, finished; 108 private long bytesRead; 109 private long bytesWritten; 110 111 // Android-added: CloseGuard support. 112 @ReachabilitySensitive 113 private final CloseGuard guard = CloseGuard.get(); 114 115 /** 116 * Compression method for the deflate algorithm (the only one currently 117 * supported). 118 */ 119 public static final int DEFLATED = 8; 120 121 /** 122 * Compression level for no compression. 123 */ 124 public static final int NO_COMPRESSION = 0; 125 126 /** 127 * Compression level for fastest compression. 128 */ 129 public static final int BEST_SPEED = 1; 130 131 /** 132 * Compression level for best compression. 133 */ 134 public static final int BEST_COMPRESSION = 9; 135 136 /** 137 * Default compression level. 138 */ 139 public static final int DEFAULT_COMPRESSION = -1; 140 141 /** 142 * Compression strategy best used for data consisting mostly of small 143 * values with a somewhat random distribution. Forces more Huffman coding 144 * and less string matching. 145 */ 146 public static final int FILTERED = 1; 147 148 /** 149 * Compression strategy for Huffman coding only. 150 */ 151 public static final int HUFFMAN_ONLY = 2; 152 153 /** 154 * Default compression strategy. 155 */ 156 public static final int DEFAULT_STRATEGY = 0; 157 158 /** 159 * Compression flush mode used to achieve best compression result. 160 * 161 * @see Deflater#deflate(byte[], int, int, int) 162 * @since 1.7 163 */ 164 public static final int NO_FLUSH = 0; 165 166 /** 167 * Compression flush mode used to flush out all pending output; may 168 * degrade compression for some compression algorithms. 169 * 170 * @see Deflater#deflate(byte[], int, int, int) 171 * @since 1.7 172 */ 173 public static final int SYNC_FLUSH = 2; 174 175 /** 176 * Compression flush mode used to flush out all pending output and 177 * reset the deflater. Using this mode too often can seriously degrade 178 * compression. 179 * 180 * @see Deflater#deflate(byte[], int, int, int) 181 * @since 1.7 182 */ 183 public static final int FULL_FLUSH = 3; 184 185 /** 186 * Flush mode to use at the end of output. Can only be provided by the 187 * user by way of {@link #finish()}. 188 */ 189 private static final int FINISH = 4; 190 191 // Android-removed: initIDs handled in register method. 192 /* 193 static { 194 ZipUtils.loadLibrary(); 195 } 196 */ 197 198 /** 199 * Creates a new compressor using the specified compression level. 200 * If 'nowrap' is true then the ZLIB header and checksum fields will 201 * not be used in order to support the compression format used in 202 * both GZIP and PKZIP. 203 * @param level the compression level (0-9) 204 * @param nowrap if true then use GZIP compatible compression 205 */ Deflater(int level, boolean nowrap)206 public Deflater(int level, boolean nowrap) { 207 this.level = level; 208 this.strategy = DEFAULT_STRATEGY; 209 this.zsRef = new DeflaterZStreamRef(this, 210 init(level, DEFAULT_STRATEGY, nowrap)); 211 // Android-added: CloseGuard support. 212 guard.open("end"); 213 } 214 215 /** 216 * Creates a new compressor using the specified compression level. 217 * Compressed data will be generated in ZLIB format. 218 * @param level the compression level (0-9) 219 */ Deflater(int level)220 public Deflater(int level) { 221 this(level, false); 222 } 223 224 /** 225 * Creates a new compressor with the default compression level. 226 * Compressed data will be generated in ZLIB format. 227 */ Deflater()228 public Deflater() { 229 this(DEFAULT_COMPRESSION, false); 230 } 231 232 /** 233 * Sets input data for compression. 234 * <p> 235 * One of the {@code setInput()} methods should be called whenever 236 * {@code needsInput()} returns true indicating that more input data 237 * is required. 238 * @param input the input data bytes 239 * @param off the start offset of the data 240 * @param len the length of the data 241 * @see Deflater#needsInput 242 */ setInput(byte[] input, int off, int len)243 public void setInput(byte[] input, int off, int len) { 244 if (off < 0 || len < 0 || off > input.length - len) { 245 throw new ArrayIndexOutOfBoundsException(); 246 } 247 synchronized (zsRef) { 248 this.input = null; 249 this.inputArray = input; 250 this.inputPos = off; 251 this.inputLim = off + len; 252 } 253 } 254 255 /** 256 * Sets input data for compression. 257 * <p> 258 * One of the {@code setInput()} methods should be called whenever 259 * {@code needsInput()} returns true indicating that more input data 260 * is required. 261 * @param input the input data bytes 262 * @see Deflater#needsInput 263 */ setInput(byte[] input)264 public void setInput(byte[] input) { 265 setInput(input, 0, input.length); 266 } 267 268 /** 269 * Sets input data for compression. 270 * <p> 271 * One of the {@code setInput()} methods should be called whenever 272 * {@code needsInput()} returns true indicating that more input data 273 * is required. 274 * <p> 275 * The given buffer's position will be advanced as deflate 276 * operations are performed, up to the buffer's limit. 277 * The input buffer may be modified (refilled) between deflate 278 * operations; doing so is equivalent to creating a new buffer 279 * and setting it with this method. 280 * <p> 281 * Modifying the input buffer's contents, position, or limit 282 * concurrently with an deflate operation will result in 283 * undefined behavior, which may include incorrect operation 284 * results or operation failure. 285 * 286 * @param input the input data bytes 287 * @see Deflater#needsInput 288 * @since 11 289 */ setInput(ByteBuffer input)290 public void setInput(ByteBuffer input) { 291 Objects.requireNonNull(input); 292 synchronized (zsRef) { 293 this.input = input; 294 this.inputArray = null; 295 } 296 } 297 298 /** 299 * Sets preset dictionary for compression. A preset dictionary is used 300 * when the history buffer can be predetermined. When the data is later 301 * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called 302 * in order to get the Adler-32 value of the dictionary required for 303 * decompression. 304 * @param dictionary the dictionary data bytes 305 * @param off the start offset of the data 306 * @param len the length of the data 307 * @see Inflater#inflate 308 * @see Inflater#getAdler 309 */ setDictionary(byte[] dictionary, int off, int len)310 public void setDictionary(byte[] dictionary, int off, int len) { 311 if (off < 0 || len < 0 || off > dictionary.length - len) { 312 throw new ArrayIndexOutOfBoundsException(); 313 } 314 synchronized (zsRef) { 315 ensureOpen(); 316 setDictionary(zsRef.address(), dictionary, off, len); 317 } 318 } 319 320 /** 321 * Sets preset dictionary for compression. A preset dictionary is used 322 * when the history buffer can be predetermined. When the data is later 323 * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called 324 * in order to get the Adler-32 value of the dictionary required for 325 * decompression. 326 * @param dictionary the dictionary data bytes 327 * @see Inflater#inflate 328 * @see Inflater#getAdler 329 */ setDictionary(byte[] dictionary)330 public void setDictionary(byte[] dictionary) { 331 setDictionary(dictionary, 0, dictionary.length); 332 } 333 334 /** 335 * Sets preset dictionary for compression. A preset dictionary is used 336 * when the history buffer can be predetermined. When the data is later 337 * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called 338 * in order to get the Adler-32 value of the dictionary required for 339 * decompression. 340 * <p> 341 * The bytes in given byte buffer will be fully consumed by this method. On 342 * return, its position will equal its limit. 343 * 344 * @param dictionary the dictionary data bytes 345 * @see Inflater#inflate 346 * @see Inflater#getAdler 347 */ setDictionary(ByteBuffer dictionary)348 public void setDictionary(ByteBuffer dictionary) { 349 synchronized (zsRef) { 350 int position = dictionary.position(); 351 int remaining = Math.max(dictionary.limit() - position, 0); 352 ensureOpen(); 353 if (dictionary.isDirect()) { 354 long address = ((DirectBuffer) dictionary).address(); 355 try { 356 setDictionaryBuffer(zsRef.address(), address + position, remaining); 357 } finally { 358 Reference.reachabilityFence(dictionary); 359 } 360 } else { 361 byte[] array = ZipUtils.getBufferArray(dictionary); 362 int offset = ZipUtils.getBufferOffset(dictionary); 363 setDictionary(zsRef.address(), array, offset + position, remaining); 364 } 365 dictionary.position(position + remaining); 366 } 367 } 368 369 /** 370 * Sets the compression strategy to the specified value. 371 * 372 * <p> If the compression strategy is changed, the next invocation 373 * of {@code deflate} will compress the input available so far with 374 * the old strategy (and may be flushed); the new strategy will take 375 * effect only after that invocation. 376 * 377 * @param strategy the new compression strategy 378 * @throws IllegalArgumentException if the compression strategy is 379 * invalid 380 */ setStrategy(int strategy)381 public void setStrategy(int strategy) { 382 switch (strategy) { 383 case DEFAULT_STRATEGY: 384 case FILTERED: 385 case HUFFMAN_ONLY: 386 break; 387 default: 388 throw new IllegalArgumentException(); 389 } 390 synchronized (zsRef) { 391 if (this.strategy != strategy) { 392 this.strategy = strategy; 393 setParams = true; 394 } 395 } 396 } 397 398 /** 399 * Sets the compression level to the specified value. 400 * 401 * <p> If the compression level is changed, the next invocation 402 * of {@code deflate} will compress the input available so far 403 * with the old level (and may be flushed); the new level will 404 * take effect only after that invocation. 405 * 406 * @param level the new compression level (0-9) 407 * @throws IllegalArgumentException if the compression level is invalid 408 */ setLevel(int level)409 public void setLevel(int level) { 410 if ((level < 0 || level > 9) && level != DEFAULT_COMPRESSION) { 411 throw new IllegalArgumentException("invalid compression level"); 412 } 413 synchronized (zsRef) { 414 if (this.level != level) { 415 this.level = level; 416 setParams = true; 417 } 418 } 419 } 420 421 /** 422 * Returns true if no data remains in the input buffer. This can 423 * be used to determine if one of the {@code setInput()} methods should be 424 * called in order to provide more input. 425 * 426 * @return true if the input data buffer is empty and setInput() 427 * should be called in order to provide more input 428 */ needsInput()429 public boolean needsInput() { 430 synchronized (zsRef) { 431 ByteBuffer input = this.input; 432 return input == null ? inputLim == inputPos : ! input.hasRemaining(); 433 } 434 } 435 436 /** 437 * When called, indicates that compression should end with the current 438 * contents of the input buffer. 439 */ finish()440 public void finish() { 441 synchronized (zsRef) { 442 finish = true; 443 } 444 } 445 446 /** 447 * Returns true if the end of the compressed data output stream has 448 * been reached. 449 * @return true if the end of the compressed data output stream has 450 * been reached 451 */ finished()452 public boolean finished() { 453 synchronized (zsRef) { 454 return finished; 455 } 456 } 457 458 /** 459 * Compresses the input data and fills specified buffer with compressed 460 * data. Returns actual number of bytes of compressed data. A return value 461 * of 0 indicates that {@link #needsInput() needsInput} should be called 462 * in order to determine if more input data is required. 463 * 464 * <p>This method uses {@link #NO_FLUSH} as its compression flush mode. 465 * An invocation of this method of the form {@code deflater.deflate(b, off, len)} 466 * yields the same result as the invocation of 467 * {@code deflater.deflate(b, off, len, Deflater.NO_FLUSH)}. 468 * 469 * @param output the buffer for the compressed data 470 * @param off the start offset of the data 471 * @param len the maximum number of bytes of compressed data 472 * @return the actual number of bytes of compressed data written to the 473 * output buffer 474 */ deflate(byte[] output, int off, int len)475 public int deflate(byte[] output, int off, int len) { 476 return deflate(output, off, len, NO_FLUSH); 477 } 478 479 /** 480 * Compresses the input data and fills specified buffer with compressed 481 * data. Returns actual number of bytes of compressed data. A return value 482 * of 0 indicates that {@link #needsInput() needsInput} should be called 483 * in order to determine if more input data is required. 484 * 485 * <p>This method uses {@link #NO_FLUSH} as its compression flush mode. 486 * An invocation of this method of the form {@code deflater.deflate(b)} 487 * yields the same result as the invocation of 488 * {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}. 489 * 490 * @param output the buffer for the compressed data 491 * @return the actual number of bytes of compressed data written to the 492 * output buffer 493 */ deflate(byte[] output)494 public int deflate(byte[] output) { 495 return deflate(output, 0, output.length, NO_FLUSH); 496 } 497 498 /** 499 * Compresses the input data and fills specified buffer with compressed 500 * data. Returns actual number of bytes of compressed data. A return value 501 * of 0 indicates that {@link #needsInput() needsInput} should be called 502 * in order to determine if more input data is required. 503 * 504 * <p>This method uses {@link #NO_FLUSH} as its compression flush mode. 505 * An invocation of this method of the form {@code deflater.deflate(output)} 506 * yields the same result as the invocation of 507 * {@code deflater.deflate(output, Deflater.NO_FLUSH)}. 508 * 509 * @param output the buffer for the compressed data 510 * @return the actual number of bytes of compressed data written to the 511 * output buffer 512 * @since 11 513 */ deflate(ByteBuffer output)514 public int deflate(ByteBuffer output) { 515 return deflate(output, NO_FLUSH); 516 } 517 518 /** 519 * Compresses the input data and fills the specified buffer with compressed 520 * data. Returns actual number of bytes of data compressed. 521 * 522 * <p>Compression flush mode is one of the following three modes: 523 * 524 * <ul> 525 * <li>{@link #NO_FLUSH}: allows the deflater to decide how much data 526 * to accumulate, before producing output, in order to achieve the best 527 * compression (should be used in normal use scenario). A return value 528 * of 0 in this flush mode indicates that {@link #needsInput()} should 529 * be called in order to determine if more input data is required. 530 * 531 * <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed, 532 * to the specified output buffer, so that an inflater that works on 533 * compressed data can get all input data available so far (In particular 534 * the {@link #needsInput()} returns {@code true} after this invocation 535 * if enough output space is provided). Flushing with {@link #SYNC_FLUSH} 536 * may degrade compression for some compression algorithms and so it 537 * should be used only when necessary. 538 * 539 * <li>{@link #FULL_FLUSH}: all pending output is flushed out as with 540 * {@link #SYNC_FLUSH}. The compression state is reset so that the inflater 541 * that works on the compressed output data can restart from this point 542 * if previous compressed data has been damaged or if random access is 543 * desired. Using {@link #FULL_FLUSH} too often can seriously degrade 544 * compression. 545 * </ul> 546 * 547 * <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if 548 * the return value is {@code len}, the space available in output 549 * buffer {@code b}, this method should be invoked again with the same 550 * {@code flush} parameter and more output space. Make sure that 551 * {@code len} is greater than 6 to avoid flush marker (5 bytes) being 552 * repeatedly output to the output buffer every time this method is 553 * invoked. 554 * 555 * <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer 556 * for input, the input buffer's position will be advanced by the number of bytes 557 * consumed by this operation. 558 * 559 * @param output the buffer for the compressed data 560 * @param off the start offset of the data 561 * @param len the maximum number of bytes of compressed data 562 * @param flush the compression flush mode 563 * @return the actual number of bytes of compressed data written to 564 * the output buffer 565 * 566 * @throws IllegalArgumentException if the flush mode is invalid 567 * @since 1.7 568 */ deflate(byte[] output, int off, int len, int flush)569 public int deflate(byte[] output, int off, int len, int flush) { 570 if (off < 0 || len < 0 || off > output.length - len) { 571 throw new ArrayIndexOutOfBoundsException(); 572 } 573 if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) { 574 throw new IllegalArgumentException(); 575 } 576 synchronized (zsRef) { 577 ensureOpen(); 578 579 ByteBuffer input = this.input; 580 if (finish) { 581 // disregard given flush mode in this case 582 flush = FINISH; 583 } 584 int params; 585 if (setParams) { 586 // bit 0: true to set params 587 // bit 1-2: strategy (0, 1, or 2) 588 // bit 3-31: level (0..9 or -1) 589 params = 1 | strategy << 1 | level << 3; 590 } else { 591 params = 0; 592 } 593 int inputPos; 594 long result; 595 if (input == null) { 596 inputPos = this.inputPos; 597 result = deflateBytesBytes(zsRef.address(), 598 inputArray, inputPos, inputLim - inputPos, 599 output, off, len, 600 flush, params); 601 } else { 602 inputPos = input.position(); 603 int inputRem = Math.max(input.limit() - inputPos, 0); 604 if (input.isDirect()) { 605 try { 606 long inputAddress = ((DirectBuffer) input).address(); 607 result = deflateBufferBytes(zsRef.address(), 608 inputAddress + inputPos, inputRem, 609 output, off, len, 610 flush, params); 611 } finally { 612 Reference.reachabilityFence(input); 613 } 614 } else { 615 byte[] inputArray = ZipUtils.getBufferArray(input); 616 int inputOffset = ZipUtils.getBufferOffset(input); 617 result = deflateBytesBytes(zsRef.address(), 618 inputArray, inputOffset + inputPos, inputRem, 619 output, off, len, 620 flush, params); 621 } 622 } 623 int read = (int) (result & 0x7fff_ffffL); 624 int written = (int) (result >>> 31 & 0x7fff_ffffL); 625 if ((result >>> 62 & 1) != 0) { 626 finished = true; 627 } 628 if (params != 0 && (result >>> 63 & 1) == 0) { 629 setParams = false; 630 } 631 if (input != null) { 632 input.position(inputPos + read); 633 } else { 634 this.inputPos = inputPos + read; 635 } 636 bytesWritten += written; 637 bytesRead += read; 638 return written; 639 } 640 } 641 642 /** 643 * Compresses the input data and fills the specified buffer with compressed 644 * data. Returns actual number of bytes of data compressed. 645 * 646 * <p>Compression flush mode is one of the following three modes: 647 * 648 * <ul> 649 * <li>{@link #NO_FLUSH}: allows the deflater to decide how much data 650 * to accumulate, before producing output, in order to achieve the best 651 * compression (should be used in normal use scenario). A return value 652 * of 0 in this flush mode indicates that {@link #needsInput()} should 653 * be called in order to determine if more input data is required. 654 * 655 * <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed, 656 * to the specified output buffer, so that an inflater that works on 657 * compressed data can get all input data available so far (In particular 658 * the {@link #needsInput()} returns {@code true} after this invocation 659 * if enough output space is provided). Flushing with {@link #SYNC_FLUSH} 660 * may degrade compression for some compression algorithms and so it 661 * should be used only when necessary. 662 * 663 * <li>{@link #FULL_FLUSH}: all pending output is flushed out as with 664 * {@link #SYNC_FLUSH}. The compression state is reset so that the inflater 665 * that works on the compressed output data can restart from this point 666 * if previous compressed data has been damaged or if random access is 667 * desired. Using {@link #FULL_FLUSH} too often can seriously degrade 668 * compression. 669 * </ul> 670 * 671 * <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if 672 * the return value is equal to the {@linkplain ByteBuffer#remaining() remaining space} 673 * of the buffer, this method should be invoked again with the same 674 * {@code flush} parameter and more output space. Make sure that 675 * the buffer has at least 6 bytes of remaining space to avoid the 676 * flush marker (5 bytes) being repeatedly output to the output buffer 677 * every time this method is invoked. 678 * 679 * <p>On success, the position of the given {@code output} byte buffer will be 680 * advanced by as many bytes as were produced by the operation, which is equal 681 * to the number returned by this method. 682 * 683 * <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer 684 * for input, the input buffer's position will be advanced by the number of bytes 685 * consumed by this operation. 686 * 687 * @param output the buffer for the compressed data 688 * @param flush the compression flush mode 689 * @return the actual number of bytes of compressed data written to 690 * the output buffer 691 * 692 * @throws IllegalArgumentException if the flush mode is invalid 693 * @since 11 694 */ deflate(ByteBuffer output, int flush)695 public int deflate(ByteBuffer output, int flush) { 696 if (output.isReadOnly()) { 697 throw new ReadOnlyBufferException(); 698 } 699 if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) { 700 throw new IllegalArgumentException(); 701 } 702 synchronized (zsRef) { 703 ensureOpen(); 704 705 ByteBuffer input = this.input; 706 if (finish) { 707 // disregard given flush mode in this case 708 flush = FINISH; 709 } 710 int params; 711 if (setParams) { 712 // bit 0: true to set params 713 // bit 1-2: strategy (0, 1, or 2) 714 // bit 3-31: level (0..9 or -1) 715 params = 1 | strategy << 1 | level << 3; 716 } else { 717 params = 0; 718 } 719 int outputPos = output.position(); 720 int outputRem = Math.max(output.limit() - outputPos, 0); 721 int inputPos; 722 long result; 723 if (input == null) { 724 inputPos = this.inputPos; 725 if (output.isDirect()) { 726 long outputAddress = ((DirectBuffer) output).address(); 727 try { 728 result = deflateBytesBuffer(zsRef.address(), 729 inputArray, inputPos, inputLim - inputPos, 730 outputAddress + outputPos, outputRem, 731 flush, params); 732 } finally { 733 Reference.reachabilityFence(output); 734 } 735 } else { 736 byte[] outputArray = ZipUtils.getBufferArray(output); 737 int outputOffset = ZipUtils.getBufferOffset(output); 738 result = deflateBytesBytes(zsRef.address(), 739 inputArray, inputPos, inputLim - inputPos, 740 outputArray, outputOffset + outputPos, outputRem, 741 flush, params); 742 } 743 } else { 744 inputPos = input.position(); 745 int inputRem = Math.max(input.limit() - inputPos, 0); 746 if (input.isDirect()) { 747 long inputAddress = ((DirectBuffer) input).address(); 748 try { 749 if (output.isDirect()) { 750 long outputAddress = outputPos + ((DirectBuffer) output).address(); 751 try { 752 result = deflateBufferBuffer(zsRef.address(), 753 inputAddress + inputPos, inputRem, 754 outputAddress, outputRem, 755 flush, params); 756 } finally { 757 Reference.reachabilityFence(output); 758 } 759 } else { 760 byte[] outputArray = ZipUtils.getBufferArray(output); 761 int outputOffset = ZipUtils.getBufferOffset(output); 762 result = deflateBufferBytes(zsRef.address(), 763 inputAddress + inputPos, inputRem, 764 outputArray, outputOffset + outputPos, outputRem, 765 flush, params); 766 } 767 } finally { 768 Reference.reachabilityFence(input); 769 } 770 } else { 771 byte[] inputArray = ZipUtils.getBufferArray(input); 772 int inputOffset = ZipUtils.getBufferOffset(input); 773 if (output.isDirect()) { 774 long outputAddress = ((DirectBuffer) output).address(); 775 try { 776 result = deflateBytesBuffer(zsRef.address(), 777 inputArray, inputOffset + inputPos, inputRem, 778 outputAddress + outputPos, outputRem, 779 flush, params); 780 } finally { 781 Reference.reachabilityFence(output); 782 } 783 } else { 784 byte[] outputArray = ZipUtils.getBufferArray(output); 785 int outputOffset = ZipUtils.getBufferOffset(output); 786 result = deflateBytesBytes(zsRef.address(), 787 inputArray, inputOffset + inputPos, inputRem, 788 outputArray, outputOffset + outputPos, outputRem, 789 flush, params); 790 } 791 } 792 } 793 int read = (int) (result & 0x7fff_ffffL); 794 int written = (int) (result >>> 31 & 0x7fff_ffffL); 795 if ((result >>> 62 & 1) != 0) { 796 finished = true; 797 } 798 if (params != 0 && (result >>> 63 & 1) == 0) { 799 setParams = false; 800 } 801 if (input != null) { 802 input.position(inputPos + read); 803 } else { 804 this.inputPos = inputPos + read; 805 } 806 output.position(outputPos + written); 807 bytesWritten += written; 808 bytesRead += read; 809 return written; 810 } 811 } 812 813 /** 814 * Returns the ADLER-32 value of the uncompressed data. 815 * @return the ADLER-32 value of the uncompressed data 816 */ getAdler()817 public int getAdler() { 818 synchronized (zsRef) { 819 ensureOpen(); 820 return getAdler(zsRef.address()); 821 } 822 } 823 824 /** 825 * Returns the total number of uncompressed bytes input so far. 826 * 827 * <p>Since the number of bytes may be greater than 828 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now 829 * the preferred means of obtaining this information.</p> 830 * 831 * @return the total number of uncompressed bytes input so far 832 */ getTotalIn()833 public int getTotalIn() { 834 return (int) getBytesRead(); 835 } 836 837 /** 838 * Returns the total number of uncompressed bytes input so far. 839 * 840 * @return the total (non-negative) number of uncompressed bytes input so far 841 * @since 1.5 842 */ getBytesRead()843 public long getBytesRead() { 844 synchronized (zsRef) { 845 ensureOpen(); 846 return bytesRead; 847 } 848 } 849 850 /** 851 * Returns the total number of compressed bytes output so far. 852 * 853 * <p>Since the number of bytes may be greater than 854 * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now 855 * the preferred means of obtaining this information.</p> 856 * 857 * @return the total number of compressed bytes output so far 858 */ getTotalOut()859 public int getTotalOut() { 860 return (int) getBytesWritten(); 861 } 862 863 /** 864 * Returns the total number of compressed bytes output so far. 865 * 866 * @return the total (non-negative) number of compressed bytes output so far 867 * @since 1.5 868 */ getBytesWritten()869 public long getBytesWritten() { 870 synchronized (zsRef) { 871 ensureOpen(); 872 return bytesWritten; 873 } 874 } 875 876 /** 877 * Resets deflater so that a new set of input data can be processed. 878 * Keeps current compression level and strategy settings. 879 */ reset()880 public void reset() { 881 synchronized (zsRef) { 882 ensureOpen(); 883 reset(zsRef.address()); 884 finish = false; 885 finished = false; 886 input = ZipUtils.defaultBuf; 887 inputArray = null; 888 bytesRead = bytesWritten = 0; 889 } 890 } 891 892 /** 893 * Closes the compressor and discards any unprocessed input. 894 * 895 * This method should be called when the compressor is no longer 896 * being used. Once this method is called, the behavior of the 897 * Deflater object is undefined. 898 */ end()899 public void end() { 900 synchronized (zsRef) { 901 zsRef.clean(); 902 // Android-added: CloseGuard support. 903 if (guard != null) { 904 guard.close(); 905 } 906 input = ZipUtils.defaultBuf; 907 } 908 } 909 ensureOpen()910 private void ensureOpen() { 911 assert Thread.holdsLock(zsRef); 912 if (zsRef.address() == 0) 913 throw new NullPointerException("Deflater has been closed"); 914 } 915 916 /** 917 * Returns the value of 'finish' flag. 918 * 'finish' will be set to true if def.finish() method is called. 919 */ shouldFinish()920 boolean shouldFinish() { 921 synchronized (zsRef) { 922 return finish; 923 } 924 } 925 init(int level, int strategy, boolean nowrap)926 private static native long init(int level, int strategy, boolean nowrap); setDictionary(long addr, byte[] b, int off, int len)927 private static native void setDictionary(long addr, byte[] b, int off, 928 int len); setDictionaryBuffer(long addr, long bufAddress, int len)929 private static native void setDictionaryBuffer(long addr, long bufAddress, int len); deflateBytesBytes(long addr, byte[] inputArray, int inputOff, int inputLen, byte[] outputArray, int outputOff, int outputLen, int flush, int params)930 private native long deflateBytesBytes(long addr, 931 byte[] inputArray, int inputOff, int inputLen, 932 byte[] outputArray, int outputOff, int outputLen, 933 int flush, int params); deflateBytesBuffer(long addr, byte[] inputArray, int inputOff, int inputLen, long outputAddress, int outputLen, int flush, int params)934 private native long deflateBytesBuffer(long addr, 935 byte[] inputArray, int inputOff, int inputLen, 936 long outputAddress, int outputLen, 937 int flush, int params); deflateBufferBytes(long addr, long inputAddress, int inputLen, byte[] outputArray, int outputOff, int outputLen, int flush, int params)938 private native long deflateBufferBytes(long addr, 939 long inputAddress, int inputLen, 940 byte[] outputArray, int outputOff, int outputLen, 941 int flush, int params); deflateBufferBuffer(long addr, long inputAddress, int inputLen, long outputAddress, int outputLen, int flush, int params)942 private native long deflateBufferBuffer(long addr, 943 long inputAddress, int inputLen, 944 long outputAddress, int outputLen, 945 int flush, int params); getAdler(long addr)946 private static native int getAdler(long addr); reset(long addr)947 private static native void reset(long addr); end(long addr)948 private static native void end(long addr); 949 950 /** 951 * A reference to the native zlib's z_stream structure. It also 952 * serves as the "cleaner" to clean up the native resource when 953 * the Deflater is ended, closed or cleaned. 954 */ 955 static class DeflaterZStreamRef implements Runnable { 956 957 private long address; 958 private final Cleanable cleanable; 959 DeflaterZStreamRef(Deflater owner, long addr)960 private DeflaterZStreamRef(Deflater owner, long addr) { 961 this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null; 962 this.address = addr; 963 } 964 address()965 long address() { 966 return address; 967 } 968 clean()969 void clean() { 970 cleanable.clean(); 971 } 972 run()973 public synchronized void run() { 974 long addr = address; 975 address = 0; 976 if (addr != 0) { 977 end(addr); 978 } 979 } 980 981 } 982 } 983