Home | History | Annotate | Download | only in zip
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package java.util.zip;
     19 
     20 import dalvik.system.CloseGuard;
     21 import java.io.FileDescriptor;
     22 import java.util.Arrays;
     23 
     24 /**
     25  * This class decompresses data that was compressed using the <i>DEFLATE</i>
     26  * algorithm (see <a href="http://www.gzip.org/algorithm.txt">specification</a>).
     27  *
     28  * <p>It is usually more convenient to use {@link InflaterInputStream}.
     29  *
     30  * <p>To decompress an in-memory {@code byte[]} to another in-memory {@code byte[]} manually:
     31  * <pre>
     32  *     byte[] compressedBytes = ...
     33  *     int decompressedByteCount = ... // From your format's metadata.
     34  *     Inflater inflater = new Inflater();
     35  *     inflater.setInput(compressedBytes, 0, compressedBytes.length);
     36  *     byte[] decompressedBytes = new byte[decompressedByteCount];
     37  *     if (inflater.inflate(decompressedBytes) != decompressedByteCount) {
     38  *         throw new AssertionError();
     39  *     }
     40  *     inflater.end();
     41  * </pre>
     42  * <p>In situations where you don't have all the input in one array (or have so much
     43  * input that you want to feed it to the inflater in chunks), it's possible to call
     44  * {@link #setInput} repeatedly, but you're much better off using {@link InflaterInputStream}
     45  * to handle all this for you.
     46  *
     47  * <p>If you don't know how big the decompressed data will be, you can call {@link #inflate}
     48  * repeatedly on a temporary buffer, copying the bytes to a {@link java.io.ByteArrayOutputStream},
     49  * but this is probably another sign you'd be better off using {@link InflaterInputStream}.
     50  */
     51 public class Inflater {
     52 
     53     private int inLength;
     54 
     55     private int inRead; // Set by inflateImpl.
     56     private boolean finished; // Set by inflateImpl.
     57     private boolean needsDictionary; // Set by inflateImpl.
     58 
     59     private long streamHandle = -1;
     60 
     61     private final CloseGuard guard = CloseGuard.get();
     62 
     63     /**
     64      * This constructor creates an inflater that expects a header from the input
     65      * stream. Use {@link #Inflater(boolean)} if the input comes without a ZLIB
     66      * header.
     67      */
     68     public Inflater() {
     69         this(false);
     70     }
     71 
     72     /**
     73      * This constructor allows to create an inflater that expects no header from
     74      * the input stream.
     75      *
     76      * @param noHeader
     77      *            {@code true} indicates that no ZLIB header comes with the
     78      *            input.
     79      */
     80     public Inflater(boolean noHeader) {
     81         streamHandle = createStream(noHeader);
     82         guard.open("end");
     83     }
     84 
     85     private native long createStream(boolean noHeader1);
     86 
     87     /**
     88      * Releases resources associated with this {@code Inflater}. Any unused
     89      * input or output is discarded. This method should be called explicitly in
     90      * order to free native resources as soon as possible. After {@code end()} is
     91      * called, other methods will typically throw {@code IllegalStateException}.
     92      */
     93     public synchronized void end() {
     94         guard.close();
     95         if (streamHandle != -1) {
     96             endImpl(streamHandle);
     97             inRead = 0;
     98             inLength = 0;
     99             streamHandle = -1;
    100         }
    101     }
    102 
    103     private native void endImpl(long handle);
    104 
    105     @Override protected void finalize() {
    106         try {
    107             if (guard != null) {
    108                 guard.warnIfOpen();
    109             }
    110             end();
    111         } finally {
    112             try {
    113                 super.finalize();
    114             } catch (Throwable t) {
    115                 throw new AssertionError(t);
    116             }
    117         }
    118     }
    119 
    120     /**
    121      * Indicates if the {@code Inflater} has inflated the entire deflated
    122      * stream. If deflated bytes remain and {@link #needsInput} returns {@code
    123      * true} this method will return {@code false}. This method should be
    124      * called after all deflated input is supplied to the {@code Inflater}.
    125      *
    126      * @return {@code true} if all input has been inflated, {@code false}
    127      *         otherwise.
    128      */
    129     public synchronized boolean finished() {
    130         return finished;
    131     }
    132 
    133     /**
    134      * Returns the {@link Adler32} checksum of the bytes inflated so far, or the
    135      * checksum of the preset dictionary if {@link #needsDictionary} returns true.
    136      */
    137     public synchronized int getAdler() {
    138         checkOpen();
    139         return getAdlerImpl(streamHandle);
    140     }
    141 
    142     private native int getAdlerImpl(long handle);
    143 
    144     /**
    145      * Returns the total number of bytes read by the {@code Inflater}. This
    146      * method is the same as {@link #getTotalIn} except that it returns a
    147      * {@code long} value instead of an integer.
    148      */
    149     public synchronized long getBytesRead() {
    150         checkOpen();
    151         return getTotalInImpl(streamHandle);
    152     }
    153 
    154     /**
    155      * Returns a the total number of bytes written by this {@code Inflater}. This
    156      * method is the same as {@code getTotalOut} except it returns a
    157      * {@code long} value instead of an integer.
    158      */
    159     public synchronized long getBytesWritten() {
    160         checkOpen();
    161         return getTotalOutImpl(streamHandle);
    162     }
    163 
    164     /**
    165      * Returns the number of bytes of current input remaining to be read by this
    166      * inflater.
    167      */
    168     public synchronized int getRemaining() {
    169         return inLength - inRead;
    170     }
    171 
    172     /**
    173      * Returns the total number of bytes of input read by this {@code Inflater}. This
    174      * method is limited to 32 bits; use {@link #getBytesRead} instead.
    175      */
    176     public synchronized int getTotalIn() {
    177         checkOpen();
    178         return (int) Math.min(getTotalInImpl(streamHandle), (long) Integer.MAX_VALUE);
    179     }
    180 
    181     private native long getTotalInImpl(long handle);
    182 
    183     /**
    184      * Returns the total number of bytes written to the output buffer by this {@code
    185      * Inflater}. The method is limited to 32 bits; use {@link #getBytesWritten} instead.
    186      */
    187     public synchronized int getTotalOut() {
    188         checkOpen();
    189         return (int) Math.min(getTotalOutImpl(streamHandle), (long) Integer.MAX_VALUE);
    190     }
    191 
    192     private native long getTotalOutImpl(long handle);
    193 
    194     /**
    195      * Inflates bytes from the current input and stores them in {@code buf}.
    196      *
    197      * @param buf
    198      *            the buffer where decompressed data bytes are written.
    199      * @return the number of bytes inflated.
    200      * @throws DataFormatException
    201      *             if the underlying stream is corrupted or was not compressed
    202      *             using a {@code Deflater}.
    203      */
    204     public int inflate(byte[] buf) throws DataFormatException {
    205         return inflate(buf, 0, buf.length);
    206     }
    207 
    208     /**
    209      * Inflates up to {@code byteCount} bytes from the current input and stores them in
    210      * {@code buf} starting at {@code offset}.
    211      *
    212      * @throws DataFormatException
    213      *             if the underlying stream is corrupted or was not compressed
    214      *             using a {@code Deflater}.
    215      * @return the number of bytes inflated.
    216      */
    217     public synchronized int inflate(byte[] buf, int offset, int byteCount) throws DataFormatException {
    218         Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
    219 
    220         checkOpen();
    221 
    222         if (needsInput()) {
    223             return 0;
    224         }
    225 
    226         boolean neededDict = needsDictionary;
    227         needsDictionary = false;
    228         int result = inflateImpl(buf, offset, byteCount, streamHandle);
    229         if (needsDictionary && neededDict) {
    230             throw new DataFormatException("Needs dictionary");
    231         }
    232         return result;
    233     }
    234 
    235     private native int inflateImpl(byte[] buf, int offset, int byteCount, long handle);
    236 
    237     /**
    238      * Returns true if the input bytes were compressed with a preset
    239      * dictionary. This method should be called if the first call to {@link #inflate} returns 0,
    240      * to determine whether a dictionary is required. If so, {@link #setDictionary}
    241      * should be called with the appropriate dictionary before calling {@code
    242      * inflate} again. Use {@link #getAdler} to determine which dictionary is required.
    243      */
    244     public synchronized boolean needsDictionary() {
    245         return needsDictionary;
    246     }
    247 
    248     /**
    249      * Returns true if {@link #setInput} must be called before inflation can continue.
    250      */
    251     public synchronized boolean needsInput() {
    252         return inRead == inLength;
    253     }
    254 
    255     /**
    256      * Resets this {@code Inflater}. Should be called prior to inflating a new
    257      * set of data.
    258      */
    259     public synchronized void reset() {
    260         checkOpen();
    261         finished = false;
    262         needsDictionary = false;
    263         inLength = inRead = 0;
    264         resetImpl(streamHandle);
    265     }
    266 
    267     private native void resetImpl(long handle);
    268 
    269     /**
    270      * Sets the preset dictionary to be used for inflation to {@code dictionary}.
    271      * See {@link #needsDictionary} for details.
    272      */
    273     public synchronized void setDictionary(byte[] dictionary) {
    274         setDictionary(dictionary, 0, dictionary.length);
    275     }
    276 
    277     /**
    278      * Sets the preset dictionary to be used for inflation to a subsequence of {@code dictionary}
    279      * starting at {@code offset} and continuing for {@code byteCount} bytes. See {@link
    280      * #needsDictionary} for details.
    281      */
    282     public synchronized void setDictionary(byte[] dictionary, int offset, int byteCount) {
    283         checkOpen();
    284         Arrays.checkOffsetAndCount(dictionary.length, offset, byteCount);
    285         setDictionaryImpl(dictionary, offset, byteCount, streamHandle);
    286     }
    287 
    288     private native void setDictionaryImpl(byte[] dictionary, int offset, int byteCount, long handle);
    289 
    290     /**
    291      * Sets the current input to to be decompressed. This method should only be
    292      * called if {@link #needsInput} returns {@code true}.
    293      */
    294     public synchronized void setInput(byte[] buf) {
    295         setInput(buf, 0, buf.length);
    296     }
    297 
    298     /**
    299      * Sets the current input to to be decompressed. This method should only be
    300      * called if {@link #needsInput} returns {@code true}.
    301      */
    302     public synchronized void setInput(byte[] buf, int offset, int byteCount) {
    303         checkOpen();
    304         Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
    305         inRead = 0;
    306         inLength = byteCount;
    307         setInputImpl(buf, offset, byteCount, streamHandle);
    308     }
    309 
    310     private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle);
    311 
    312     synchronized int setFileInput(FileDescriptor fd, long offset, int byteCount) {
    313         checkOpen();
    314         inRead = 0;
    315         inLength = setFileInputImpl(fd, offset, byteCount, streamHandle);
    316         return inLength;
    317     }
    318 
    319     private native int setFileInputImpl(FileDescriptor fd, long offset, int byteCount, long handle);
    320 
    321     private void checkOpen() {
    322         if (streamHandle == -1) {
    323             throw new IllegalStateException("attempt to use Inflater after calling end");
    324         }
    325     }
    326 }
    327