Home | History | Annotate | Download | only in zip
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
      4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      5  *
      6  * This code is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License version 2 only, as
      8  * published by the Free Software Foundation.  Oracle designates this
      9  * particular file as subject to the "Classpath" exception as provided
     10  * by Oracle in the LICENSE file that accompanied this code.
     11  *
     12  * This code is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     15  * version 2 for more details (a copy is included in the LICENSE file that
     16  * accompanied this code).
     17  *
     18  * You should have received a copy of the GNU General Public License version
     19  * 2 along with this work; if not, write to the Free Software Foundation,
     20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     21  *
     22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     23  * or visit www.oracle.com if you need additional information or have any
     24  * questions.
     25  */
     26 
     27 package java.util.zip;
     28 
     29 import dalvik.system.CloseGuard;
     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 <tt>Deflater</tt> and
     41  * <tt>Inflater</tt>.
     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  * @see         Deflater
     73  * @author      David Connelly
     74  *
     75  */
     76 public
     77 class Inflater {
     78 
     79     private final ZStreamRef zsRef;
     80     private byte[] buf = defaultBuf;
     81     private int off, len;
     82     private boolean finished;
     83     private boolean needDict;
     84     private long bytesRead;
     85     private long bytesWritten;
     86 
     87     // Android-changed: added CloseGuard instance
     88     private final CloseGuard guard = CloseGuard.get();
     89 
     90     private static final byte[] defaultBuf = new byte[0];
     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         // Android-changed: added close guard
    106         guard.open("end");
    107     }
    108 
    109     /**
    110      * Creates a new decompressor.
    111      */
    112     public Inflater() {
    113         this(false);
    114     }
    115 
    116     /**
    117      * Sets input data for decompression. Should be called whenever
    118      * needsInput() returns true indicating that more input data is
    119      * required.
    120      * @param b the input data bytes
    121      * @param off the start offset of the input data
    122      * @param len the length of the input data
    123      * @see Inflater#needsInput
    124      */
    125     public void setInput(byte[] b, int off, int len) {
    126         if (b == null) {
    127             throw new NullPointerException();
    128         }
    129         if (off < 0 || len < 0 || off > b.length - len) {
    130             throw new ArrayIndexOutOfBoundsException();
    131         }
    132         synchronized (zsRef) {
    133             this.buf = b;
    134             this.off = off;
    135             this.len = len;
    136         }
    137     }
    138 
    139     /**
    140      * Sets input data for decompression. Should be called whenever
    141      * needsInput() returns true indicating that more input data is
    142      * required.
    143      * @param b the input data bytes
    144      * @see Inflater#needsInput
    145      */
    146     public void setInput(byte[] b) {
    147         setInput(b, 0, b.length);
    148     }
    149 
    150     /**
    151      * Sets the preset dictionary to the given array of bytes. Should be
    152      * called when inflate() returns 0 and needsDictionary() returns true
    153      * indicating that a preset dictionary is required. The method getAdler()
    154      * can be used to get the Adler-32 value of the dictionary needed.
    155      * @param b the dictionary data bytes
    156      * @param off the start offset of the data
    157      * @param len the length of the data
    158      * @see Inflater#needsDictionary
    159      * @see Inflater#getAdler
    160      */
    161     public void setDictionary(byte[] b, int off, int len) {
    162         if (b == null) {
    163             throw new NullPointerException();
    164         }
    165         if (off < 0 || len < 0 || off > b.length - len) {
    166             throw new ArrayIndexOutOfBoundsException();
    167         }
    168         synchronized (zsRef) {
    169             ensureOpen();
    170             setDictionary(zsRef.address(), b, off, len);
    171             needDict = false;
    172         }
    173     }
    174 
    175     /**
    176      * Sets the preset dictionary to the given array of bytes. Should be
    177      * called when inflate() returns 0 and needsDictionary() returns true
    178      * indicating that a preset dictionary is required. The method getAdler()
    179      * can be used to get the Adler-32 value of the dictionary needed.
    180      * @param b the dictionary data bytes
    181      * @see Inflater#needsDictionary
    182      * @see Inflater#getAdler
    183      */
    184     public void setDictionary(byte[] b) {
    185         setDictionary(b, 0, b.length);
    186     }
    187 
    188     /**
    189      * Returns the total number of bytes remaining in the input buffer.
    190      * This can be used to find out what bytes still remain in the input
    191      * buffer after decompression has finished.
    192      * @return the total number of bytes remaining in the input buffer
    193      */
    194     public int getRemaining() {
    195         synchronized (zsRef) {
    196             return len;
    197         }
    198     }
    199 
    200     /**
    201      * Returns true if no data remains in the input buffer. This can
    202      * be used to determine if #setInput should be called in order
    203      * to provide more input.
    204      * @return true if no data remains in the input buffer
    205      */
    206     public boolean needsInput() {
    207         synchronized (zsRef) {
    208             return len <= 0;
    209         }
    210     }
    211 
    212     /**
    213      * Returns true if a preset dictionary is needed for decompression.
    214      * @return true if a preset dictionary is needed for decompression
    215      * @see Inflater#setDictionary
    216      */
    217     public boolean needsDictionary() {
    218         synchronized (zsRef) {
    219             return needDict;
    220         }
    221     }
    222 
    223     /**
    224      * Returns true if the end of the compressed data stream has been
    225      * reached.
    226      * @return true if the end of the compressed data stream has been
    227      * reached
    228      */
    229     public boolean finished() {
    230         synchronized (zsRef) {
    231             return finished;
    232         }
    233     }
    234 
    235     /**
    236      * Uncompresses bytes into specified buffer. Returns actual number
    237      * of bytes uncompressed. A return value of 0 indicates that
    238      * needsInput() or needsDictionary() should be called in order to
    239      * determine if more input data or a preset dictionary is required.
    240      * In the latter case, getAdler() can be used to get the Adler-32
    241      * value of the dictionary required.
    242      * @param b the buffer for the uncompressed data
    243      * @param off the start offset of the data
    244      * @param len the maximum number of uncompressed bytes
    245      * @return the actual number of uncompressed bytes
    246      * @exception DataFormatException if the compressed data format is invalid
    247      * @see Inflater#needsInput
    248      * @see Inflater#needsDictionary
    249      */
    250     public int inflate(byte[] b, int off, int len)
    251         throws DataFormatException
    252     {
    253         if (b == null) {
    254             throw new NullPointerException();
    255         }
    256         if (off < 0 || len < 0 || off > b.length - len) {
    257             throw new ArrayIndexOutOfBoundsException();
    258         }
    259         synchronized (zsRef) {
    260             ensureOpen();
    261             int thisLen = this.len;
    262             int n = inflateBytes(zsRef.address(), b, off, len);
    263             bytesWritten += n;
    264             bytesRead += (thisLen - this.len);
    265             return n;
    266         }
    267     }
    268 
    269     /**
    270      * Uncompresses bytes into specified buffer. Returns actual number
    271      * of bytes uncompressed. A return value of 0 indicates that
    272      * needsInput() or needsDictionary() should be called in order to
    273      * determine if more input data or a preset dictionary is required.
    274      * In the latter case, getAdler() can be used to get the Adler-32
    275      * value of the dictionary required.
    276      * @param b the buffer for the uncompressed data
    277      * @return the actual number of uncompressed bytes
    278      * @exception DataFormatException if the compressed data format is invalid
    279      * @see Inflater#needsInput
    280      * @see Inflater#needsDictionary
    281      */
    282     public int inflate(byte[] b) throws DataFormatException {
    283         return inflate(b, 0, b.length);
    284     }
    285 
    286     /**
    287      * Returns the ADLER-32 value of the uncompressed data.
    288      * @return the ADLER-32 value of the uncompressed data
    289      */
    290     public int getAdler() {
    291         synchronized (zsRef) {
    292             ensureOpen();
    293             return getAdler(zsRef.address());
    294         }
    295     }
    296 
    297     /**
    298      * Returns the total number of compressed bytes input so far.
    299      *
    300      * <p>Since the number of bytes may be greater than
    301      * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
    302      * the preferred means of obtaining this information.</p>
    303      *
    304      * @return the total number of compressed bytes input so far
    305      */
    306     public int getTotalIn() {
    307         return (int) getBytesRead();
    308     }
    309 
    310     /**
    311      * Returns the total number of compressed bytes input so far.
    312      *
    313      * @return the total (non-negative) number of compressed bytes input so far
    314      * @since 1.5
    315      */
    316     public long getBytesRead() {
    317         synchronized (zsRef) {
    318             ensureOpen();
    319             return bytesRead;
    320         }
    321     }
    322 
    323     /**
    324      * Returns the total number of uncompressed bytes output so far.
    325      *
    326      * <p>Since the number of bytes may be greater than
    327      * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
    328      * the preferred means of obtaining this information.</p>
    329      *
    330      * @return the total number of uncompressed bytes output so far
    331      */
    332     public int getTotalOut() {
    333         return (int) getBytesWritten();
    334     }
    335 
    336     /**
    337      * Returns the total number of uncompressed bytes output so far.
    338      *
    339      * @return the total (non-negative) number of uncompressed bytes output so far
    340      * @since 1.5
    341      */
    342     public long getBytesWritten() {
    343         synchronized (zsRef) {
    344             ensureOpen();
    345             return bytesWritten;
    346         }
    347     }
    348 
    349     /**
    350      * Resets inflater so that a new set of input data can be processed.
    351      */
    352     public void reset() {
    353         synchronized (zsRef) {
    354             ensureOpen();
    355             reset(zsRef.address());
    356             buf = defaultBuf;
    357             finished = false;
    358             needDict = false;
    359             off = len = 0;
    360             bytesRead = bytesWritten = 0;
    361         }
    362     }
    363 
    364     /**
    365      * Closes the decompressor and discards any unprocessed input.
    366      * This method should be called when the decompressor is no longer
    367      * being used, but will also be called automatically by the finalize()
    368      * method. Once this method is called, the behavior of the Inflater
    369      * object is undefined.
    370      */
    371     public void end() {
    372         synchronized (zsRef) {
    373             guard.close();
    374 
    375             long addr = zsRef.address();
    376             zsRef.clear();
    377             if (addr != 0) {
    378                 end(addr);
    379                 buf = null;
    380             }
    381         }
    382     }
    383 
    384     /**
    385      * Closes the decompressor when garbage is collected.
    386      */
    387     protected void finalize() {
    388         // Android-changed: added close guard
    389         if (guard != null) {
    390             guard.warnIfOpen();
    391         }
    392 
    393         end();
    394     }
    395 
    396     private void ensureOpen () {
    397         assert Thread.holdsLock(zsRef);
    398         // Android-changed: Throw IllegalStateException instead of a NullPointerException.
    399         if (zsRef.address() == 0)
    400             throw new IllegalStateException("Inflater has been closed");
    401     }
    402 
    403     boolean ended() {
    404         synchronized (zsRef) {
    405             return zsRef.address() == 0;
    406         }
    407     }
    408 
    409     // Android-changed: initIDs handled in register method.
    410     // private native static void initIDs();
    411     private native static long init(boolean nowrap);
    412     private native static void setDictionary(long addr, byte[] b, int off,
    413                                              int len);
    414     private native int inflateBytes(long addr, byte[] b, int off, int len)
    415             throws DataFormatException;
    416     private native static int getAdler(long addr);
    417     private native static void reset(long addr);
    418     private native static void end(long addr);
    419 }
    420