< prev index next >

src/java.base/share/classes/java/util/zip/Inflater.java

Print this page




   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 {@code Deflater} and
  38  * {@code Inflater}.
  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];


  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  * @since 1.1
  72  *
  73  */
  74 public
  75 class Inflater {
  76 
  77     private final ZStreamRef zsRef;
  78     private byte[] buf = defaultBuf;
  79     private int off, len;
  80     private boolean finished;
  81     private boolean needDict;
  82     private long bytesRead;
  83     private long bytesWritten;
  84 
  85     private static final byte[] defaultBuf = new byte[0];
  86 
  87     static {
  88         ZipUtils.loadLibrary();
  89         initIDs();
  90     }
  91 
  92     /**
  93      * Creates a new decompressor. If the parameter 'nowrap' is true then
  94      * the ZLIB header and checksum fields will not be used. This provides
  95      * compatibility with the compression format used by both GZIP and PKZIP.
  96      * <p>
  97      * Note: When using the 'nowrap' option it is also necessary to provide
  98      * an extra "dummy" byte as input. This is required by the ZLIB native
  99      * library in order to support certain optimizations.
 100      *
 101      * @param nowrap if true then support GZIP compatible compression
 102      */
 103     public Inflater(boolean nowrap) {
 104         zsRef = new ZStreamRef(init(nowrap));


 105     }
 106 
 107     /**
 108      * Creates a new decompressor.
 109      */
 110     public Inflater() {
 111         this(false);
 112     }
 113 
 114     /**
 115      * Sets input data for decompression. Should be called whenever
 116      * needsInput() returns true indicating that more input data is
 117      * required.
 118      * @param b the input data bytes
 119      * @param off the start offset of the input data
 120      * @param len the length of the input data
 121      * @see Inflater#needsInput
 122      */
 123     public void setInput(byte[] b, int off, int len) {
 124         if (b == null) {


 148     /**
 149      * Sets the preset dictionary to the given array of bytes. Should be
 150      * called when inflate() returns 0 and needsDictionary() returns true
 151      * indicating that a preset dictionary is required. The method getAdler()
 152      * can be used to get the Adler-32 value of the dictionary needed.
 153      * @param b the dictionary data bytes
 154      * @param off the start offset of the data
 155      * @param len the length of the data
 156      * @see Inflater#needsDictionary
 157      * @see Inflater#getAdler
 158      */
 159     public void setDictionary(byte[] b, int off, int len) {
 160         if (b == null) {
 161             throw new NullPointerException();
 162         }
 163         if (off < 0 || len < 0 || off > b.length - len) {
 164             throw new ArrayIndexOutOfBoundsException();
 165         }
 166         synchronized (zsRef) {
 167             ensureOpen();
 168             setDictionary(zsRef.address(), b, off, len);

 169             needDict = false;
 170         }
 171     }
 172 
 173     /**
 174      * Sets the preset dictionary to the given array of bytes. Should be
 175      * called when inflate() returns 0 and needsDictionary() returns true
 176      * indicating that a preset dictionary is required. The method getAdler()
 177      * can be used to get the Adler-32 value of the dictionary needed.
 178      * @param b the dictionary data bytes
 179      * @see Inflater#needsDictionary
 180      * @see Inflater#getAdler
 181      */
 182     public void setDictionary(byte[] b) {
 183         setDictionary(b, 0, b.length);
 184     }
 185 
 186     /**
 187      * Returns the total number of bytes remaining in the input buffer.
 188      * This can be used to find out what bytes still remain in the input


 240      * @param b the buffer for the uncompressed data
 241      * @param off the start offset of the data
 242      * @param len the maximum number of uncompressed bytes
 243      * @return the actual number of uncompressed bytes
 244      * @exception DataFormatException if the compressed data format is invalid
 245      * @see Inflater#needsInput
 246      * @see Inflater#needsDictionary
 247      */
 248     public int inflate(byte[] b, int off, int len)
 249         throws DataFormatException
 250     {
 251         if (b == null) {
 252             throw new NullPointerException();
 253         }
 254         if (off < 0 || len < 0 || off > b.length - len) {
 255             throw new ArrayIndexOutOfBoundsException();
 256         }
 257         synchronized (zsRef) {
 258             ensureOpen();
 259             int thisLen = this.len;
 260             int n = inflateBytes(zsRef.address(), b, off, len);

 261             bytesWritten += n;
 262             bytesRead += (thisLen - this.len);
 263             return n;
 264         }
 265     }
 266 
 267     /**
 268      * Uncompresses bytes into specified buffer. Returns actual number
 269      * of bytes uncompressed. A return value of 0 indicates that
 270      * needsInput() or needsDictionary() should be called in order to
 271      * determine if more input data or a preset dictionary is required.
 272      * In the latter case, getAdler() can be used to get the Adler-32
 273      * value of the dictionary required.
 274      * @param b the buffer for the uncompressed data
 275      * @return the actual number of uncompressed bytes
 276      * @exception DataFormatException if the compressed data format is invalid
 277      * @see Inflater#needsInput
 278      * @see Inflater#needsDictionary
 279      */
 280     public int inflate(byte[] b) throws DataFormatException {
 281         return inflate(b, 0, b.length);
 282     }
 283 
 284     /**
 285      * Returns the ADLER-32 value of the uncompressed data.
 286      * @return the ADLER-32 value of the uncompressed data
 287      */
 288     public int getAdler() {
 289         synchronized (zsRef) {
 290             ensureOpen();
 291             return getAdler(zsRef.address());


 292         }
 293     }
 294 
 295     /**
 296      * Returns the total number of compressed bytes input so far.
 297      *
 298      * <p>Since the number of bytes may be greater than
 299      * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
 300      * the preferred means of obtaining this information.</p>
 301      *
 302      * @return the total number of compressed bytes input so far
 303      */
 304     public int getTotalIn() {
 305         return (int) getBytesRead();
 306     }
 307 
 308     /**
 309      * Returns the total number of compressed bytes input so far.
 310      *
 311      * @return the total (non-negative) number of compressed bytes input so far


 333 
 334     /**
 335      * Returns the total number of uncompressed bytes output so far.
 336      *
 337      * @return the total (non-negative) number of uncompressed bytes output so far
 338      * @since 1.5
 339      */
 340     public long getBytesWritten() {
 341         synchronized (zsRef) {
 342             ensureOpen();
 343             return bytesWritten;
 344         }
 345     }
 346 
 347     /**
 348      * Resets inflater so that a new set of input data can be processed.
 349      */
 350     public void reset() {
 351         synchronized (zsRef) {
 352             ensureOpen();
 353             reset(zsRef.address());

 354             buf = defaultBuf;
 355             finished = false;
 356             needDict = false;
 357             off = len = 0;
 358             bytesRead = bytesWritten = 0;
 359         }
 360     }
 361 
 362     /**
 363      * Closes the decompressor and discards any unprocessed input.

 364      * This method should be called when the decompressor is no longer
 365      * being used, but will also be called automatically by the finalize()
 366      * method. Once this method is called, the behavior of the Inflater
 367      * object is undefined.
 368      */
 369     public void end() {
 370         synchronized (zsRef) {
 371             long addr = zsRef.address();
 372             zsRef.clear();
 373             if (addr != 0) {
 374                 end(addr);
 375                 buf = null;
 376             }
 377         }
 378     }
 379 
 380     /**
 381      * Closes the decompressor when garbage is collected.
 382      *
 383      * @deprecated The {@code finalize} method has been deprecated.
 384      *     Subclasses that override {@code finalize} in order to perform cleanup
 385      *     should be modified to use alternative cleanup mechanisms and
 386      *     to remove the overriding {@code finalize} method.
 387      *     When overriding the {@code finalize} method, its implementation must explicitly
 388      *     ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
 389      *     See the specification for {@link Object#finalize()} for further
 390      *     information about migration options.
 391      */
 392     @Deprecated(since="9")
 393     protected void finalize() {
 394         end();
 395     }
 396 
 397     private void ensureOpen () {
 398         assert Thread.holdsLock(zsRef);
 399         if (zsRef.address() == 0)


 400             throw new NullPointerException("Inflater has been closed");
 401     }
 402 
 403     boolean ended() {
 404         synchronized (zsRef) {
 405             return zsRef.address() == 0;
 406         }
 407     }
 408 
 409     private static native void initIDs();
 410     private static native long init(boolean nowrap);
 411     private static native void setDictionary(long addr, byte[] b, int off,
 412                                              int len);
 413     private native int inflateBytes(long addr, byte[] b, int off, int len)
 414             throws DataFormatException;
 415     private static native int getAdler(long addr);
 416     private static native void reset(long addr);
 417     private static native void end(long addr);
 418 }


   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 jdk.internal.ref.CleanerFactory;
  29 
  30 import java.lang.ref.Cleaner;
  31 import java.lang.ref.Reference;
  32 
  33 /**
  34  * This class provides support for general purpose decompression using the
  35  * popular ZLIB compression library. The ZLIB compression library was
  36  * initially developed as part of the PNG graphics standard and is not
  37  * protected by patents. It is fully described in the specifications at
  38  * the <a href="package-summary.html#package.description">java.util.zip
  39  * package description</a>.
  40  *
  41  * <p>The following code fragment demonstrates a trivial compression
  42  * and decompression of a string using {@code Deflater} and
  43  * {@code Inflater}.
  44  *
  45  * <blockquote><pre>
  46  * try {
  47  *     // Encode a String into bytes
  48  *     String inputString = "blahblahblah\u20AC\u20AC";
  49  *     byte[] input = inputString.getBytes("UTF-8");
  50  *
  51  *     // Compress the bytes
  52  *     byte[] output = new byte[100];


  54  *     compresser.setInput(input);
  55  *     compresser.finish();
  56  *     int compressedDataLength = compresser.deflate(output);
  57  *
  58  *     // Decompress the bytes
  59  *     Inflater decompresser = new Inflater();
  60  *     decompresser.setInput(output, 0, compressedDataLength);
  61  *     byte[] result = new byte[100];
  62  *     int resultLength = decompresser.inflate(result);
  63  *     decompresser.end();
  64  *
  65  *     // Decode the bytes into a String
  66  *     String outputString = new String(result, 0, resultLength, "UTF-8");
  67  * } catch(java.io.UnsupportedEncodingException ex) {
  68  *     // handle
  69  * } catch (java.util.zip.DataFormatException ex) {
  70  *     // handle
  71  * }
  72  * </pre></blockquote>
  73  *
  74  * <p>
  75  * @apiNote
  76  * In earlier versions the {@link Object#finalize} method was overridden and
  77  * specified to call the {@code end} method to close the {@code inflater} and
  78  * release the resource when the instance becomes unreachable.
  79  * The {@code finalize} method is no longer defined. The recommended cleanup
  80  * for decompressor is to explicitly call {@code end} method when it is no
  81  * longer in use.
  82  *
  83  * @implNote
  84  * The resource of the decompressor will be released when the instance becomes
  85  * phantom-reachable, if the {@code end} is not invoked explicitly.
  86  * <p>
  87  *
  88  * @see         Deflater
  89  * @author      David Connelly
  90  * @since 1.1
  91  *
  92  */
  93 public
  94 class Inflater {
  95 
  96     private final Cleaner.LongCleanableResource zsRef;
  97     private byte[] buf = defaultBuf;
  98     private int off, len;
  99     private boolean finished;
 100     private boolean needDict;
 101     private long bytesRead;
 102     private long bytesWritten;
 103 
 104     private static final byte[] defaultBuf = new byte[0];
 105 
 106     static {
 107         ZipUtils.loadLibrary();
 108         initIDs();
 109     }
 110 
 111     /**
 112      * Creates a new decompressor. If the parameter 'nowrap' is true then
 113      * the ZLIB header and checksum fields will not be used. This provides
 114      * compatibility with the compression format used by both GZIP and PKZIP.
 115      * <p>
 116      * Note: When using the 'nowrap' option it is also necessary to provide
 117      * an extra "dummy" byte as input. This is required by the ZLIB native
 118      * library in order to support certain optimizations.
 119      *
 120      * @param nowrap if true then support GZIP compatible compression
 121      */
 122     public Inflater(boolean nowrap) {
 123         this.zsRef = CleanerFactory
 124             .cleaner()
 125             .createLongResource(this, () -> init(nowrap), Inflater::end);
 126     }
 127 
 128     /**
 129      * Creates a new decompressor.
 130      */
 131     public Inflater() {
 132         this(false);
 133     }
 134 
 135     /**
 136      * Sets input data for decompression. Should be called whenever
 137      * needsInput() returns true indicating that more input data is
 138      * required.
 139      * @param b the input data bytes
 140      * @param off the start offset of the input data
 141      * @param len the length of the input data
 142      * @see Inflater#needsInput
 143      */
 144     public void setInput(byte[] b, int off, int len) {
 145         if (b == null) {


 169     /**
 170      * Sets the preset dictionary to the given array of bytes. Should be
 171      * called when inflate() returns 0 and needsDictionary() returns true
 172      * indicating that a preset dictionary is required. The method getAdler()
 173      * can be used to get the Adler-32 value of the dictionary needed.
 174      * @param b the dictionary data bytes
 175      * @param off the start offset of the data
 176      * @param len the length of the data
 177      * @see Inflater#needsDictionary
 178      * @see Inflater#getAdler
 179      */
 180     public void setDictionary(byte[] b, int off, int len) {
 181         if (b == null) {
 182             throw new NullPointerException();
 183         }
 184         if (off < 0 || len < 0 || off > b.length - len) {
 185             throw new ArrayIndexOutOfBoundsException();
 186         }
 187         synchronized (zsRef) {
 188             ensureOpen();
 189             setDictionary(zsRef.value(), b, off, len);
 190             Reference.reachabilityFence(this);
 191             needDict = false;
 192         }
 193     }
 194 
 195     /**
 196      * Sets the preset dictionary to the given array of bytes. Should be
 197      * called when inflate() returns 0 and needsDictionary() returns true
 198      * indicating that a preset dictionary is required. The method getAdler()
 199      * can be used to get the Adler-32 value of the dictionary needed.
 200      * @param b the dictionary data bytes
 201      * @see Inflater#needsDictionary
 202      * @see Inflater#getAdler
 203      */
 204     public void setDictionary(byte[] b) {
 205         setDictionary(b, 0, b.length);
 206     }
 207 
 208     /**
 209      * Returns the total number of bytes remaining in the input buffer.
 210      * This can be used to find out what bytes still remain in the input


 262      * @param b the buffer for the uncompressed data
 263      * @param off the start offset of the data
 264      * @param len the maximum number of uncompressed bytes
 265      * @return the actual number of uncompressed bytes
 266      * @exception DataFormatException if the compressed data format is invalid
 267      * @see Inflater#needsInput
 268      * @see Inflater#needsDictionary
 269      */
 270     public int inflate(byte[] b, int off, int len)
 271         throws DataFormatException
 272     {
 273         if (b == null) {
 274             throw new NullPointerException();
 275         }
 276         if (off < 0 || len < 0 || off > b.length - len) {
 277             throw new ArrayIndexOutOfBoundsException();
 278         }
 279         synchronized (zsRef) {
 280             ensureOpen();
 281             int thisLen = this.len;
 282             int n = inflateBytes(zsRef.value(), b, off, len);
 283             Reference.reachabilityFence(this);
 284             bytesWritten += n;
 285             bytesRead += (thisLen - this.len);
 286             return n;
 287         }
 288     }
 289 
 290     /**
 291      * Uncompresses bytes into specified buffer. Returns actual number
 292      * of bytes uncompressed. A return value of 0 indicates that
 293      * needsInput() or needsDictionary() should be called in order to
 294      * determine if more input data or a preset dictionary is required.
 295      * In the latter case, getAdler() can be used to get the Adler-32
 296      * value of the dictionary required.
 297      * @param b the buffer for the uncompressed data
 298      * @return the actual number of uncompressed bytes
 299      * @exception DataFormatException if the compressed data format is invalid
 300      * @see Inflater#needsInput
 301      * @see Inflater#needsDictionary
 302      */
 303     public int inflate(byte[] b) throws DataFormatException {
 304         return inflate(b, 0, b.length);
 305     }
 306 
 307     /**
 308      * Returns the ADLER-32 value of the uncompressed data.
 309      * @return the ADLER-32 value of the uncompressed data
 310      */
 311     public int getAdler() {
 312         synchronized (zsRef) {
 313             ensureOpen();
 314             int adler = getAdler(zsRef.value());
 315             Reference.reachabilityFence(this);
 316             return adler;
 317         }
 318     }
 319 
 320     /**
 321      * Returns the total number of compressed bytes input so far.
 322      *
 323      * <p>Since the number of bytes may be greater than
 324      * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
 325      * the preferred means of obtaining this information.</p>
 326      *
 327      * @return the total number of compressed bytes input so far
 328      */
 329     public int getTotalIn() {
 330         return (int) getBytesRead();
 331     }
 332 
 333     /**
 334      * Returns the total number of compressed bytes input so far.
 335      *
 336      * @return the total (non-negative) number of compressed bytes input so far


 358 
 359     /**
 360      * Returns the total number of uncompressed bytes output so far.
 361      *
 362      * @return the total (non-negative) number of uncompressed bytes output so far
 363      * @since 1.5
 364      */
 365     public long getBytesWritten() {
 366         synchronized (zsRef) {
 367             ensureOpen();
 368             return bytesWritten;
 369         }
 370     }
 371 
 372     /**
 373      * Resets inflater so that a new set of input data can be processed.
 374      */
 375     public void reset() {
 376         synchronized (zsRef) {
 377             ensureOpen();
 378             reset(zsRef.value());
 379             Reference.reachabilityFence(this);
 380             buf = defaultBuf;
 381             finished = false;
 382             needDict = false;
 383             off = len = 0;
 384             bytesRead = bytesWritten = 0;
 385         }
 386     }
 387 
 388     /**
 389      * Closes the decompressor and discards any unprocessed input.
 390      *
 391      * This method should be called when the decompressor is no longer
 392      * being used. Once this method is called, the behavior of the
 393      * Inflater object is undefined.

 394      */
 395     public void end() {
 396         synchronized (zsRef) {
 397             zsRef.clean();



 398             buf = null;
 399         }
 400     }


















 401 
 402     private void ensureOpen () {
 403         assert Thread.holdsLock(zsRef);
 404         try {
 405             zsRef.value();
 406         } catch (IllegalStateException e) {
 407             throw new NullPointerException("Inflater has been closed");





 408         }
 409     }
 410 
 411     private static native void initIDs();
 412     private static native long init(boolean nowrap);
 413     private static native void setDictionary(long addr, byte[] b, int off,
 414                                              int len);
 415     private native int inflateBytes(long addr, byte[] b, int off, int len)
 416             throws DataFormatException;
 417     private static native int getAdler(long addr);
 418     private static native void reset(long addr);
 419     private static native void end(long addr);
 420 }
< prev index next >