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 offset of the next byte to read in the underlying buffer.
    174      *
    175      * For internal use only.
    176      */
    177     synchronized int getCurrentOffset() {
    178         return inRead;
    179     }
    180 
    181     /**
    182      * Returns the total number of bytes of input read by this {@code Inflater}. This
    183      * method is limited to 32 bits; use {@link #getBytesRead} instead.
    184      */
    185     public synchronized int getTotalIn() {
    186         checkOpen();
    187         return (int) Math.min(getTotalInImpl(streamHandle), (long) Integer.MAX_VALUE);
    188     }
    189 
    190     private native long getTotalInImpl(long handle);
    191 
    192     /**
    193      * Returns the total number of bytes written to the output buffer by this {@code
    194      * Inflater}. The method is limited to 32 bits; use {@link #getBytesWritten} instead.
    195      */
    196     public synchronized int getTotalOut() {
    197         checkOpen();
    198         return (int) Math.min(getTotalOutImpl(streamHandle), (long) Integer.MAX_VALUE);
    199     }
    200 
    201     private native long getTotalOutImpl(long handle);
    202 
    203     /**
    204      * Inflates bytes from the current input and stores them in {@code buf}.
    205      *
    206      * @param buf
    207      *            the buffer where decompressed data bytes are written.
    208      * @return the number of bytes inflated.
    209      * @throws DataFormatException
    210      *             if the underlying stream is corrupted or was not compressed
    211      *             using a {@code Deflater}.
    212      */
    213     public int inflate(byte[] buf) throws DataFormatException {
    214         return inflate(buf, 0, buf.length);
    215     }
    216 
    217     /**
    218      * Inflates up to {@code byteCount} bytes from the current input and stores them in
    219      * {@code buf} starting at {@code offset}.
    220      *
    221      * @throws DataFormatException
    222      *             if the underlying stream is corrupted or was not compressed
    223      *             using a {@code Deflater}.
    224      * @return the number of bytes inflated.
    225      */
    226     public synchronized int inflate(byte[] buf, int offset, int byteCount) throws DataFormatException {
    227         Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
    228 
    229         checkOpen();
    230 
    231         if (needsInput()) {
    232             return 0;
    233         }
    234 
    235         boolean neededDict = needsDictionary;
    236         needsDictionary = false;
    237         int result = inflateImpl(buf, offset, byteCount, streamHandle);
    238         if (needsDictionary && neededDict) {
    239             throw new DataFormatException("Needs dictionary");
    240         }
    241         return result;
    242     }
    243 
    244     private native int inflateImpl(byte[] buf, int offset, int byteCount, long handle);
    245 
    246     /**
    247      * Returns true if the input bytes were compressed with a preset
    248      * dictionary. This method should be called if the first call to {@link #inflate} returns 0,
    249      * to determine whether a dictionary is required. If so, {@link #setDictionary}
    250      * should be called with the appropriate dictionary before calling {@code
    251      * inflate} again. Use {@link #getAdler} to determine which dictionary is required.
    252      */
    253     public synchronized boolean needsDictionary() {
    254         return needsDictionary;
    255     }
    256 
    257     /**
    258      * Returns true if {@link #setInput} must be called before inflation can continue.
    259      */
    260     public synchronized boolean needsInput() {
    261         return inRead == inLength;
    262     }
    263 
    264     /**
    265      * Resets this {@code Inflater}. Should be called prior to inflating a new
    266      * set of data.
    267      */
    268     public synchronized void reset() {
    269         checkOpen();
    270         finished = false;
    271         needsDictionary = false;
    272         inLength = inRead = 0;
    273         resetImpl(streamHandle);
    274     }
    275 
    276     private native void resetImpl(long handle);
    277 
    278     /**
    279      * Sets the preset dictionary to be used for inflation to {@code dictionary}.
    280      * See {@link #needsDictionary} for details.
    281      */
    282     public synchronized void setDictionary(byte[] dictionary) {
    283         setDictionary(dictionary, 0, dictionary.length);
    284     }
    285 
    286     /**
    287      * Sets the preset dictionary to be used for inflation to a subsequence of {@code dictionary}
    288      * starting at {@code offset} and continuing for {@code byteCount} bytes. See {@link
    289      * #needsDictionary} for details.
    290      */
    291     public synchronized void setDictionary(byte[] dictionary, int offset, int byteCount) {
    292         checkOpen();
    293         Arrays.checkOffsetAndCount(dictionary.length, offset, byteCount);
    294         setDictionaryImpl(dictionary, offset, byteCount, streamHandle);
    295     }
    296 
    297     private native void setDictionaryImpl(byte[] dictionary, int offset, int byteCount, long handle);
    298 
    299     /**
    300      * Sets the current input to to be decompressed. This method should only be
    301      * called if {@link #needsInput} returns {@code true}.
    302      */
    303     public synchronized void setInput(byte[] buf) {
    304         setInput(buf, 0, buf.length);
    305     }
    306 
    307     /**
    308      * Sets the current input to to be decompressed. This method should only be
    309      * called if {@link #needsInput} returns {@code true}.
    310      */
    311     public synchronized void setInput(byte[] buf, int offset, int byteCount) {
    312         checkOpen();
    313         Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
    314         inRead = 0;
    315         inLength = byteCount;
    316         setInputImpl(buf, offset, byteCount, streamHandle);
    317     }
    318 
    319     private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle);
    320 
    321     synchronized int setFileInput(FileDescriptor fd, long offset, int byteCount) {
    322         checkOpen();
    323         inRead = 0;
    324         inLength = setFileInputImpl(fd, offset, byteCount, streamHandle);
    325         return inLength;
    326     }
    327 
    328     private native int setFileInputImpl(FileDescriptor fd, long offset, int byteCount, long handle);
    329 
    330     private void checkOpen() {
    331         if (streamHandle == -1) {
    332             throw new IllegalStateException("attempt to use Inflater after calling end");
    333         }
    334     }
    335 }
    336