1 /* 2 * Copyright (c) 1996, 2011, 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 /** 29 * This class provides support for general purpose decompression using the 30 * popular ZLIB compression library. The ZLIB compression library was 31 * initially developed as part of the PNG graphics standard and is not 32 * protected by patents. It is fully described in the specifications at 33 * the <a href="package-summary.html#package_description">java.util.zip 34 * package description</a>. 35 * 36 * <p>The following code fragment demonstrates a trivial compression 37 * and decompression of a string using <tt>Deflater</tt> and 38 * <tt>Inflater</tt>. 39 * 40 * <blockquote><pre> 41 * try { 42 * // Encode a String into bytes 43 * String inputString = "blahblahblah\u20AC\u20AC"; 44 * byte[] input = inputString.getBytes("UTF-8"); 45 * 46 * // Compress the bytes 47 * byte[] output = new byte[100]; 48 * Deflater compresser = new Deflater(); 49 * compresser.setInput(input); 50 * compresser.finish(); 51 * int compressedDataLength = compresser.deflate(output); 52 * 53 * // Decompress the bytes 54 * Inflater decompresser = new Inflater(); 55 * decompresser.setInput(output, 0, compressedDataLength); 56 * byte[] result = new byte[100]; 57 * int resultLength = decompresser.inflate(result); 58 * decompresser.end(); 59 * 60 * // Decode the bytes into a String 61 * String outputString = new String(result, 0, resultLength, "UTF-8"); 62 * } catch(java.io.UnsupportedEncodingException ex) { 63 * // handle 64 * } catch (java.util.zip.DataFormatException ex) { 65 * // handle 66 * } 67 * </pre></blockquote> 68 * 69 * @see Deflater 70 * @author David Connelly 71 * 72 */ 73 public 74 class Inflater { 75 76 private final ZStreamRef zsRef; 77 private byte[] buf = defaultBuf; 78 private int off, len; 79 private boolean finished; 80 private boolean needDict; 81 82 private static final byte[] defaultBuf = new byte[0]; 83 84 static { 85 /* Zip library is loaded from System.initializeSystemClass */ 86 initIDs(); 87 } 88 89 /** 90 * Creates a new decompressor. If the parameter 'nowrap' is true then 91 * the ZLIB header and checksum fields will not be used. This provides 92 * compatibility with the compression format used by both GZIP and PKZIP. 93 * <p> 94 * Note: When using the 'nowrap' option it is also necessary to provide 95 * an extra "dummy" byte as input. This is required by the ZLIB native 96 * library in order to support certain optimizations. 97 * 98 * @param nowrap if true then support GZIP compatible compression 99 */ 100 public Inflater(boolean nowrap) { 101 zsRef = new ZStreamRef(init(nowrap)); 102 } 103 104 /** 105 * Creates a new decompressor. 106 */ 107 public Inflater() { 108 this(false); 109 } 110 111 /** 112 * Sets input data for decompression. Should be called whenever 113 * needsInput() returns true indicating that more input data is 114 * required. 115 * @param b the input data bytes 116 * @param off the start offset of the input data 117 * @param len the length of the input data 118 * @see Inflater#needsInput 119 */ 120 public void setInput(byte[] b, int off, int len) { 121 if (b == null) { 122 throw new NullPointerException(); 123 } 124 if (off < 0 || len < 0 || off > b.length - len) { 125 throw new ArrayIndexOutOfBoundsException(); 126 } 127 synchronized (zsRef) { 128 this.buf = b; 129 this.off = off; 130 this.len = len; 131 } 132 } 133 134 /** 135 * Sets input data for decompression. Should be called whenever 136 * needsInput() returns true indicating that more input data is 137 * required. 138 * @param b the input data bytes 139 * @see Inflater#needsInput 140 */ 141 public void setInput(byte[] b) { 142 setInput(b, 0, b.length); 143 } 144 145 /** 146 * Sets the preset dictionary to the given array of bytes. Should be 147 * called when inflate() returns 0 and needsDictionary() returns true 148 * indicating that a preset dictionary is required. The method getAdler() 149 * can be used to get the Adler-32 value of the dictionary needed. 150 * @param b the dictionary data bytes 151 * @param off the start offset of the data 152 * @param len the length of the data 153 * @see Inflater#needsDictionary 154 * @see Inflater#getAdler 155 */ 156 public void setDictionary(byte[] b, int off, int len) { 157 if (b == null) { 158 throw new NullPointerException(); 159 } 160 if (off < 0 || len < 0 || off > b.length - len) { 161 throw new ArrayIndexOutOfBoundsException(); 162 } 163 synchronized (zsRef) { 164 ensureOpen(); 165 setDictionary(zsRef.address(), b, off, len); 166 needDict = false; 167 } 168 } 169 170 /** 171 * Sets the preset dictionary to the given array of bytes. Should be 172 * called when inflate() returns 0 and needsDictionary() returns true 173 * indicating that a preset dictionary is required. The method getAdler() 174 * can be used to get the Adler-32 value of the dictionary needed. 175 * @param b the dictionary data bytes 176 * @see Inflater#needsDictionary 177 * @see Inflater#getAdler 178 */ 179 public void setDictionary(byte[] b) { 180 setDictionary(b, 0, b.length); 181 } 182 183 /** 184 * Returns the total number of bytes remaining in the input buffer. 185 * This can be used to find out what bytes still remain in the input 186 * buffer after decompression has finished. 187 * @return the total number of bytes remaining in the input buffer 188 */ 189 public int getRemaining() { 190 synchronized (zsRef) { 191 return len; 192 } 193 } 194 195 /** 196 * Returns true if no data remains in the input buffer. This can 197 * be used to determine if #setInput should be called in order 198 * to provide more input. 199 * @return true if no data remains in the input buffer 200 */ 201 public boolean needsInput() { 202 synchronized (zsRef) { 203 return len <= 0; 204 } 205 } 206 207 /** 208 * Returns true if a preset dictionary is needed for decompression. 209 * @return true if a preset dictionary is needed for decompression 210 * @see Inflater#setDictionary 211 */ 212 public boolean needsDictionary() { 213 synchronized (zsRef) { 214 return needDict; 215 } 216 } 217 218 /** 219 * Returns true if the end of the compressed data stream has been 220 * reached. 221 * @return true if the end of the compressed data stream has been 222 * reached 223 */ 224 public boolean finished() { 225 synchronized (zsRef) { 226 return finished; 227 } 228 } 229 230 /** 231 * Uncompresses bytes into specified buffer. Returns actual number 232 * of bytes uncompressed. A return value of 0 indicates that 233 * needsInput() or needsDictionary() should be called in order to 234 * determine if more input data or a preset dictionary is required. 235 * In the latter case, getAdler() can be used to get the Adler-32 236 * value of the dictionary required. 237 * @param b the buffer for the uncompressed data 238 * @param off the start offset of the data 239 * @param len the maximum number of uncompressed bytes 240 * @return the actual number of uncompressed bytes 241 * @exception DataFormatException if the compressed data format is invalid 242 * @see Inflater#needsInput 243 * @see Inflater#needsDictionary 244 */ 245 public int inflate(byte[] b, int off, int len) 246 throws DataFormatException 247 { 248 if (b == null) { 249 throw new NullPointerException(); 250 } 251 if (off < 0 || len < 0 || off > b.length - len) { 252 throw new ArrayIndexOutOfBoundsException(); 253 } 254 synchronized (zsRef) { 255 ensureOpen(); 256 return inflateBytes(zsRef.address(), b, off, len); 257 } 258 } 259 260 /** 261 * Uncompresses bytes into specified buffer. Returns actual number 262 * of bytes uncompressed. A return value of 0 indicates that 263 * needsInput() or needsDictionary() should be called in order to 264 * determine if more input data or a preset dictionary is required. 265 * In the latter case, getAdler() can be used to get the Adler-32 266 * value of the dictionary required. 267 * @param b the buffer for the uncompressed data 268 * @return the actual number of uncompressed bytes 269 * @exception DataFormatException if the compressed data format is invalid 270 * @see Inflater#needsInput 271 * @see Inflater#needsDictionary 272 */ 273 public int inflate(byte[] b) throws DataFormatException { 274 return inflate(b, 0, b.length); 275 } 276 277 /** 278 * Returns the ADLER-32 value of the uncompressed data. 279 * @return the ADLER-32 value of the uncompressed data 280 */ 281 public int getAdler() { 282 synchronized (zsRef) { 283 ensureOpen(); 284 return getAdler(zsRef.address()); 285 } 286 } 287 288 /** 289 * Returns the total number of compressed bytes input so far. 290 * 291 * <p>Since the number of bytes may be greater than 292 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now 293 * the preferred means of obtaining this information.</p> 294 * 295 * @return the total number of compressed bytes input so far 296 */ 297 public int getTotalIn() { 298 return (int) getBytesRead(); 299 } 300 301 /** 302 * Returns the total number of compressed bytes input so far.</p> 303 * 304 * @return the total (non-negative) number of compressed bytes input so far 305 * @since 1.5 306 */ 307 public long getBytesRead() { 308 synchronized (zsRef) { 309 ensureOpen(); 310 return getBytesRead(zsRef.address()); 311 } 312 } 313 314 /** 315 * Returns the total number of uncompressed bytes output so far. 316 * 317 * <p>Since the number of bytes may be greater than 318 * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now 319 * the preferred means of obtaining this information.</p> 320 * 321 * @return the total number of uncompressed bytes output so far 322 */ 323 public int getTotalOut() { 324 return (int) getBytesWritten(); 325 } 326 327 /** 328 * Returns the total number of uncompressed bytes output so far.</p> 329 * 330 * @return the total (non-negative) number of uncompressed bytes output so far 331 * @since 1.5 332 */ 333 public long getBytesWritten() { 334 synchronized (zsRef) { 335 ensureOpen(); 336 return getBytesWritten(zsRef.address()); 337 } 338 } 339 340 /** 341 * Resets inflater so that a new set of input data can be processed. 342 */ 343 public void reset() { 344 synchronized (zsRef) { 345 ensureOpen(); 346 reset(zsRef.address()); 347 buf = defaultBuf; 348 finished = false; 349 needDict = false; 350 off = len = 0; 351 } 352 } 353 354 /** 355 * Closes the decompressor and discards any unprocessed input. 356 * This method should be called when the decompressor is no longer 357 * being used, but will also be called automatically by the finalize() 358 * method. Once this method is called, the behavior of the Inflater 359 * object is undefined. 360 */ 361 public void end() { 362 synchronized (zsRef) { 363 long addr = zsRef.address(); 364 zsRef.clear(); 365 if (addr != 0) { 366 end(addr); 367 buf = null; 368 } 369 } 370 } 371 372 /** 373 * Closes the decompressor when garbage is collected. 374 */ 375 protected void finalize() { 376 end(); 377 } 378 379 private void ensureOpen () { 380 assert Thread.holdsLock(zsRef); 381 if (zsRef.address() == 0) 382 throw new NullPointerException("Inflater has been closed"); 383 } 384 385 boolean ended() { 386 synchronized (zsRef) { 387 return zsRef.address() == 0; 388 } 389 } 390 391 private native static void initIDs(); 392 private native static long init(boolean nowrap); 393 private native static void setDictionary(long addr, byte[] b, int off, 394 int len); 395 private native int inflateBytes(long addr, byte[] b, int off, int len) 396 throws DataFormatException; 397 private native static int getAdler(long addr); 398 private native static long getBytesRead(long addr); 399 private native static long getBytesWritten(long addr); 400 private native static void reset(long addr); 401 private native static void end(long addr); 402 }