1 /* 2 * Copyright (c) 1996, 2017, 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 jdk.internal.ref.CleanerFactory; 30 31 /** 32 * This class provides support for general purpose decompression using the 33 * popular ZLIB compression library. The ZLIB compression library was 34 * initially developed as part of the PNG graphics standard and is not 35 * protected by patents. It is fully described in the specifications at 36 * the <a href="package-summary.html#package.description">java.util.zip 37 * package description</a>. 38 * 39 * <p>The following code fragment demonstrates a trivial compression 40 * and decompression of a string using {@code Deflater} and 41 * {@code Inflater}. 42 * 43 * <blockquote><pre> 44 * try { 45 * // Encode a String into bytes 46 * String inputString = "blahblahblah\u20AC\u20AC"; 47 * byte[] input = inputString.getBytes("UTF-8"); 48 * 49 * // Compress the bytes 50 * byte[] output = new byte[100]; 51 * Deflater compresser = new Deflater(); 52 * compresser.setInput(input); 53 * compresser.finish(); 54 * int compressedDataLength = compresser.deflate(output); 55 * 56 * // Decompress the bytes 57 * Inflater decompresser = new Inflater(); 58 * decompresser.setInput(output, 0, compressedDataLength); 59 * byte[] result = new byte[100]; 60 * int resultLength = decompresser.inflate(result); 61 * decompresser.end(); 62 * 63 * // Decode the bytes into a String 64 * String outputString = new String(result, 0, resultLength, "UTF-8"); 65 * } catch(java.io.UnsupportedEncodingException ex) { 66 * // handle 67 * } catch (java.util.zip.DataFormatException ex) { 68 * // handle 69 * } 70 * </pre></blockquote> 71 * 72 * @apiNote 73 * To release resources used by this {@code Inflater}, the {@link #end()} method 74 * should be called explicitly. Subclasses are responsible for the cleanup of resources 75 * acquired by the subclass. Subclasses that override {@link #finalize()} in order 76 * to perform cleanup should be modified to use alternative cleanup mechanisms such 77 * as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method. 78 * 79 * @implSpec 80 * If this {@code Inflater} has been subclassed and the {@code end} method has been 81 * overridden, the {@code end} method will be called by the finalization when the 82 * inflater is unreachable. But the subclasses should not depend on this specific 83 * implementation; the finalization is not reliable and the {@code finalize} method 84 * is deprecated to be removed. 85 * 86 * @see Deflater 87 * @author David Connelly 88 * @since 1.1 89 * 90 */ 91 92 public class Inflater { 93 94 private final InflaterZStreamRef zsRef; 95 private byte[] buf = defaultBuf; 96 private int off, len; 97 private boolean finished; 98 private boolean needDict; 99 private long bytesRead; 100 private long bytesWritten; 101 102 private static final byte[] defaultBuf = new byte[0]; 103 104 static { 105 ZipUtils.loadLibrary(); 106 initIDs(); 107 } 108 109 /** 110 * Creates a new decompressor. If the parameter 'nowrap' is true then 111 * the ZLIB header and checksum fields will not be used. This provides 112 * compatibility with the compression format used by both GZIP and PKZIP. 113 * <p> 114 * Note: When using the 'nowrap' option it is also necessary to provide 115 * an extra "dummy" byte as input. This is required by the ZLIB native 116 * library in order to support certain optimizations. 117 * 118 * @param nowrap if true then support GZIP compatible compression 119 */ 120 public Inflater(boolean nowrap) { 121 this.zsRef = InflaterZStreamRef.get(this, init(nowrap)); 122 } 123 124 /** 125 * Creates a new decompressor. 126 */ 127 public Inflater() { 128 this(false); 129 } 130 131 /** 132 * Sets input data for decompression. Should be called whenever 133 * needsInput() returns true indicating that more input data is 134 * required. 135 * @param b the input data bytes 136 * @param off the start offset of the input data 137 * @param len the length of the input data 138 * @see Inflater#needsInput 139 */ 140 public void setInput(byte[] b, int off, int len) { 141 if (b == null) { 142 throw new NullPointerException(); 143 } 144 if (off < 0 || len < 0 || off > b.length - len) { 145 throw new ArrayIndexOutOfBoundsException(); 146 } 147 synchronized (zsRef) { 148 this.buf = b; 149 this.off = off; 150 this.len = len; 151 } 152 } 153 154 /** 155 * Sets input data for decompression. Should be called whenever 156 * needsInput() returns true indicating that more input data is 157 * required. 158 * @param b the input data bytes 159 * @see Inflater#needsInput 160 */ 161 public void setInput(byte[] b) { 162 setInput(b, 0, b.length); 163 } 164 165 /** 166 * Sets the preset dictionary to the given array of bytes. Should be 167 * called when inflate() returns 0 and needsDictionary() returns true 168 * indicating that a preset dictionary is required. The method getAdler() 169 * can be used to get the Adler-32 value of the dictionary needed. 170 * @param b the dictionary data bytes 171 * @param off the start offset of the data 172 * @param len the length of the data 173 * @see Inflater#needsDictionary 174 * @see Inflater#getAdler 175 */ 176 public void setDictionary(byte[] b, int off, int len) { 177 if (b == null) { 178 throw new NullPointerException(); 179 } 180 if (off < 0 || len < 0 || off > b.length - len) { 181 throw new ArrayIndexOutOfBoundsException(); 182 } 183 synchronized (zsRef) { 184 ensureOpen(); 185 setDictionary(zsRef.address(), b, off, len); 186 needDict = false; 187 } 188 } 189 190 /** 191 * Sets the preset dictionary to the given array of bytes. Should be 192 * called when inflate() returns 0 and needsDictionary() returns true 193 * indicating that a preset dictionary is required. The method getAdler() 194 * can be used to get the Adler-32 value of the dictionary needed. 195 * @param b the dictionary data bytes 196 * @see Inflater#needsDictionary 197 * @see Inflater#getAdler 198 */ 199 public void setDictionary(byte[] b) { 200 setDictionary(b, 0, b.length); 201 } 202 203 /** 204 * Returns the total number of bytes remaining in the input buffer. 205 * This can be used to find out what bytes still remain in the input 206 * buffer after decompression has finished. 207 * @return the total number of bytes remaining in the input buffer 208 */ 209 public int getRemaining() { 210 synchronized (zsRef) { 211 return len; 212 } 213 } 214 215 /** 216 * Returns true if no data remains in the input buffer. This can 217 * be used to determine if #setInput should be called in order 218 * to provide more input. 219 * @return true if no data remains in the input buffer 220 */ 221 public boolean needsInput() { 222 synchronized (zsRef) { 223 return len <= 0; 224 } 225 } 226 227 /** 228 * Returns true if a preset dictionary is needed for decompression. 229 * @return true if a preset dictionary is needed for decompression 230 * @see Inflater#setDictionary 231 */ 232 public boolean needsDictionary() { 233 synchronized (zsRef) { 234 return needDict; 235 } 236 } 237 238 /** 239 * Returns true if the end of the compressed data stream has been 240 * reached. 241 * @return true if the end of the compressed data stream has been 242 * reached 243 */ 244 public boolean finished() { 245 synchronized (zsRef) { 246 return finished; 247 } 248 } 249 250 /** 251 * Uncompresses bytes into specified buffer. Returns actual number 252 * of bytes uncompressed. A return value of 0 indicates that 253 * needsInput() or needsDictionary() should be called in order to 254 * determine if more input data or a preset dictionary is required. 255 * In the latter case, getAdler() can be used to get the Adler-32 256 * value of the dictionary required. 257 * @param b the buffer for the uncompressed data 258 * @param off the start offset of the data 259 * @param len the maximum number of uncompressed bytes 260 * @return the actual number of uncompressed bytes 261 * @exception DataFormatException if the compressed data format is invalid 262 * @see Inflater#needsInput 263 * @see Inflater#needsDictionary 264 */ 265 public int inflate(byte[] b, int off, int len) 266 throws DataFormatException 267 { 268 if (b == null) { 269 throw new NullPointerException(); 270 } 271 if (off < 0 || len < 0 || off > b.length - len) { 272 throw new ArrayIndexOutOfBoundsException(); 273 } 274 synchronized (zsRef) { 275 ensureOpen(); 276 int thisLen = this.len; 277 int n = inflateBytes(zsRef.address(), b, off, len); 278 bytesWritten += n; 279 bytesRead += (thisLen - this.len); 280 return n; 281 } 282 } 283 284 /** 285 * Uncompresses bytes into specified buffer. Returns actual number 286 * of bytes uncompressed. A return value of 0 indicates that 287 * needsInput() or needsDictionary() should be called in order to 288 * determine if more input data or a preset dictionary is required. 289 * In the latter case, getAdler() can be used to get the Adler-32 290 * value of the dictionary required. 291 * @param b the buffer for the uncompressed data 292 * @return the actual number of uncompressed bytes 293 * @exception DataFormatException if the compressed data format is invalid 294 * @see Inflater#needsInput 295 * @see Inflater#needsDictionary 296 */ 297 public int inflate(byte[] b) throws DataFormatException { 298 return inflate(b, 0, b.length); 299 } 300 301 /** 302 * Returns the ADLER-32 value of the uncompressed data. 303 * @return the ADLER-32 value of the uncompressed data 304 */ 305 public int getAdler() { 306 synchronized (zsRef) { 307 ensureOpen(); 308 return getAdler(zsRef.address()); 309 } 310 } 311 312 /** 313 * Returns the total number of compressed bytes input so far. 314 * 315 * <p>Since the number of bytes may be greater than 316 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now 317 * the preferred means of obtaining this information.</p> 318 * 319 * @return the total number of compressed bytes input so far 320 */ 321 public int getTotalIn() { 322 return (int) getBytesRead(); 323 } 324 325 /** 326 * Returns the total number of compressed bytes input so far. 327 * 328 * @return the total (non-negative) number of compressed bytes input so far 329 * @since 1.5 330 */ 331 public long getBytesRead() { 332 synchronized (zsRef) { 333 ensureOpen(); 334 return bytesRead; 335 } 336 } 337 338 /** 339 * Returns the total number of uncompressed bytes output so far. 340 * 341 * <p>Since the number of bytes may be greater than 342 * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now 343 * the preferred means of obtaining this information.</p> 344 * 345 * @return the total number of uncompressed bytes output so far 346 */ 347 public int getTotalOut() { 348 return (int) getBytesWritten(); 349 } 350 351 /** 352 * Returns the total number of uncompressed bytes output so far. 353 * 354 * @return the total (non-negative) number of uncompressed bytes output so far 355 * @since 1.5 356 */ 357 public long getBytesWritten() { 358 synchronized (zsRef) { 359 ensureOpen(); 360 return bytesWritten; 361 } 362 } 363 364 /** 365 * Resets inflater so that a new set of input data can be processed. 366 */ 367 public void reset() { 368 synchronized (zsRef) { 369 ensureOpen(); 370 reset(zsRef.address()); 371 buf = defaultBuf; 372 finished = false; 373 needDict = false; 374 off = len = 0; 375 bytesRead = bytesWritten = 0; 376 } 377 } 378 379 /** 380 * Closes the decompressor and discards any unprocessed input. 381 * 382 * This method should be called when the decompressor is no longer 383 * being used. Once this method is called, the behavior of the 384 * Inflater object is undefined. 385 */ 386 public void end() { 387 synchronized (zsRef) { 388 zsRef.clean(); 389 buf = null; 390 } 391 } 392 393 /** 394 * Closes the decompressor when garbage is collected. 395 * 396 * @implSpec 397 * If this {@code Inflater} has been subclassed and the {@code end} method 398 * has been overridden, the {@code end} method will be called when the 399 * inflater is unreachable. 400 * 401 * @deprecated The {@code finalize} method has been deprecated and will be 402 * removed. It is implemented as a no-op. Subclasses that override 403 * {@code finalize} in order to perform cleanup should be modified to use 404 * alternative cleanup mechanisms and remove the overriding {@code finalize} 405 * method. The recommended cleanup for compressor is to explicitly call 406 * {@code end} method when it is no longer in use. If the {@code end} is 407 * not invoked explicitly the resource of the compressor will be released 408 * when the instance becomes unreachable, 409 */ 410 @Deprecated(since="9", forRemoval=true) 411 protected void finalize() {} 412 413 private void ensureOpen () { 414 assert Thread.holdsLock(zsRef); 415 if (zsRef.address() == 0) 416 throw new NullPointerException("Inflater has been closed"); 417 } 418 419 boolean ended() { 420 synchronized (zsRef) { 421 return zsRef.address() == 0; 422 } 423 } 424 425 private static native void initIDs(); 426 private static native long init(boolean nowrap); 427 private static native void setDictionary(long addr, byte[] b, int off, 428 int len); 429 private native int inflateBytes(long addr, byte[] b, int off, int len) 430 throws DataFormatException; 431 private static native int getAdler(long addr); 432 private static native void reset(long addr); 433 private static native void end(long addr); 434 435 /** 436 * A reference to the native zlib's z_stream structure. It also 437 * serves as the "cleaner" to clean up the native resource when 438 * the Inflater is ended, closed or cleaned. 439 */ 440 static class InflaterZStreamRef implements Runnable { 441 442 private long address; 443 private final Cleanable cleanable; 444 445 private InflaterZStreamRef(Inflater owner, long addr) { 446 this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null; 447 this.address = addr; 448 } 449 450 long address() { 451 return address; 452 } 453 454 void clean() { 455 cleanable.clean(); 456 } 457 458 public synchronized void run() { 459 long addr = address; 460 address = 0; 461 if (addr != 0) { 462 end(addr); 463 } 464 } 465 466 /* 467 * If {@code Inflater} has been subclassed and the {@code end} method is 468 * overridden, uses {@code finalizer} mechanism for resource cleanup. So 469 * {@code end} method can be called when the {@code Inflater} is unreachable. 470 * This mechanism will be removed when the {@code finalize} method is 471 * removed from {@code Inflater}. 472 */ 473 static InflaterZStreamRef get(Inflater owner, long addr) { 474 Class<?> clz = owner.getClass(); 475 while (clz != Inflater.class) { 476 try { 477 clz.getDeclaredMethod("end"); 478 return new FinalizableZStreamRef(owner, addr); 479 } catch (NoSuchMethodException nsme) {} 480 clz = clz.getSuperclass(); 481 } 482 return new InflaterZStreamRef(owner, addr); 483 } 484 485 private static class FinalizableZStreamRef extends InflaterZStreamRef { 486 final Inflater owner; 487 488 FinalizableZStreamRef(Inflater owner, long addr) { 489 super(null, addr); 490 this.owner = owner; 491 } 492 493 @Override 494 void clean() { 495 run(); 496 } 497 498 @Override 499 @SuppressWarnings("deprecation") 500 protected void finalize() { 501 owner.end(); 502 } 503 } 504 } 505 }