| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.util.zip; |
| |
| import java.io.FileDescriptor; |
| |
| /** |
| * This class uncompresses data that was compressed using the <i>DEFLATE</i> |
| * algorithm (see <a href="http://www.gzip.org/algorithm.txt">specification</a>). |
| * <p> |
| * Basically this class is part of the API to the stream based ZLIB compression |
| * library and is used as such by {@code InflaterInputStream} and its |
| * descendants. |
| * <p> |
| * The typical usage of a {@code Inflater} outside this package consists of a |
| * specific call to one of its constructors before being passed to an instance |
| * of {@code InflaterInputStream}. |
| * |
| * @see InflaterInputStream |
| * @see Deflater |
| */ |
| public class Inflater { |
| private boolean finished; // Set by the inflateImpl native |
| |
| int inLength; |
| |
| int inRead; |
| |
| private boolean needsDictionary; // Set by the inflateImpl native |
| |
| private long streamHandle = -1; |
| |
| /** |
| * This constructor creates an inflater that expects a header from the input |
| * stream. Use {@code Inflater(boolean)} if the input comes without a ZLIB |
| * header. |
| */ |
| public Inflater() { |
| this(false); |
| } |
| |
| /** |
| * This constructor allows to create an inflater that expects no header from |
| * the input stream. |
| * |
| * @param noHeader |
| * {@code true} indicates that no ZLIB header comes with the |
| * input. |
| */ |
| public Inflater(boolean noHeader) { |
| streamHandle = createStream(noHeader); |
| } |
| |
| private native long createStream(boolean noHeader1); |
| |
| /** |
| * Release any resources associated with this {@code Inflater}. Any unused |
| * input/output is discarded. This is also called by the finalize method. |
| */ |
| public synchronized void end() { |
| if (streamHandle != -1) { |
| endImpl(streamHandle); |
| inRead = 0; |
| inLength = 0; |
| streamHandle = -1; |
| } |
| } |
| |
| private native synchronized void endImpl(long handle); |
| |
| @Override protected void finalize() { |
| try { |
| end(); |
| } finally { |
| try { |
| super.finalize(); |
| } catch (Throwable t) { |
| throw new AssertionError(t); |
| } |
| } |
| } |
| |
| /** |
| * Indicates if the {@code Inflater} has inflated the entire deflated |
| * stream. If deflated bytes remain and {@code needsInput()} returns {@code |
| * true} this method will return {@code false}. This method should be |
| * called after all deflated input is supplied to the {@code Inflater}. |
| * |
| * @return {@code true} if all input has been inflated, {@code false} |
| * otherwise. |
| */ |
| public synchronized boolean finished() { |
| return finished; |
| } |
| |
| /** |
| * Returns the <i>Adler32</i> checksum of either all bytes inflated, or the |
| * checksum of the preset dictionary if one has been supplied. |
| * |
| * @return The <i>Adler32</i> checksum associated with this |
| * {@code Inflater}. |
| */ |
| public synchronized int getAdler() { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| return getAdlerImpl(streamHandle); |
| } |
| |
| private native synchronized int getAdlerImpl(long handle); |
| |
| /** |
| * Returns the total number of bytes read by the {@code Inflater}. This |
| * method performs the same as {@code getTotalIn()} except that it returns a |
| * {@code long} value instead of an integer. |
| * |
| * @return the total number of bytes read. |
| */ |
| public synchronized long getBytesRead() { |
| // Throw NPE here |
| if (streamHandle == -1) { |
| throw new NullPointerException(); |
| } |
| return getTotalInImpl(streamHandle); |
| } |
| |
| /** |
| * Returns a the total number of bytes read by the {@code Inflater}. This |
| * method performs the same as {@code getTotalOut} except it returns a |
| * {@code long} value instead of an integer. |
| * |
| * @return the total bytes written to the output buffer. |
| */ |
| public synchronized long getBytesWritten() { |
| // Throw NPE here |
| if (streamHandle == -1) { |
| throw new NullPointerException(); |
| } |
| return getTotalOutImpl(streamHandle); |
| } |
| |
| /** |
| * Returns the number of bytes of current input remaining to be read by the |
| * inflater. |
| * |
| * @return the number of bytes of unread input. |
| */ |
| public synchronized int getRemaining() { |
| return inLength - inRead; |
| } |
| |
| /** |
| * Returns total number of bytes of input read by the {@code Inflater}. The |
| * result value is limited by {@code Integer.MAX_VALUE}. |
| * |
| * @return the total number of bytes read. |
| */ |
| public synchronized int getTotalIn() { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| long totalIn = getTotalInImpl(streamHandle); |
| return (totalIn <= Integer.MAX_VALUE ? (int) totalIn |
| : Integer.MAX_VALUE); |
| } |
| |
| private synchronized native long getTotalInImpl(long handle); |
| |
| /** |
| * Returns total number of bytes written to the output buffer by the {@code |
| * Inflater}. The result value is limited by {@code Integer.MAX_VALUE}. |
| * |
| * @return the total bytes of output data written. |
| */ |
| public synchronized int getTotalOut() { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| long totalOut = getTotalOutImpl(streamHandle); |
| return (totalOut <= Integer.MAX_VALUE ? (int) totalOut |
| : Integer.MAX_VALUE); |
| } |
| |
| private native synchronized long getTotalOutImpl(long handle); |
| |
| /** |
| * Inflates bytes from current input and stores them in {@code buf}. |
| * |
| * @param buf |
| * the buffer where decompressed data bytes are written. |
| * @return the number of bytes inflated. |
| * @throws DataFormatException |
| * if the underlying stream is corrupted or was not compressed |
| * using a {@code Deflater}. |
| */ |
| public int inflate(byte[] buf) throws DataFormatException { |
| return inflate(buf, 0, buf.length); |
| } |
| |
| /** |
| * Inflates up to n bytes from the current input and stores them in {@code |
| * buf} starting at {@code off}. |
| * |
| * @param buf |
| * the buffer to write inflated bytes to. |
| * @param off |
| * the offset in buffer where to start writing decompressed data. |
| * @param nbytes |
| * the number of inflated bytes to write to {@code buf}. |
| * @throws DataFormatException |
| * if the underlying stream is corrupted or was not compressed |
| * using a {@code Deflater}. |
| * @return the number of bytes inflated. |
| */ |
| public synchronized int inflate(byte[] buf, int off, int nbytes) |
| throws DataFormatException { |
| // avoid int overflow, check null buf |
| if (off > buf.length || nbytes < 0 || off < 0 |
| || buf.length - off < nbytes) { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| |
| if (nbytes == 0) { |
| return 0; |
| } |
| |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| |
| if (needsInput()) { |
| return 0; |
| } |
| |
| boolean neededDict = needsDictionary; |
| needsDictionary = false; |
| int result = inflateImpl(buf, off, nbytes, streamHandle); |
| if (needsDictionary && neededDict) { |
| throw new DataFormatException("Needs dictionary"); |
| } |
| |
| return result; |
| } |
| |
| private native synchronized int inflateImpl(byte[] buf, int off, |
| int nbytes, long handle); |
| |
| /** |
| * Indicates whether the input bytes were compressed with a preset |
| * dictionary. This method should be called prior to {@code inflate()} to |
| * determine whether a dictionary is required. If so {@code setDictionary()} |
| * should be called with the appropriate dictionary prior to calling {@code |
| * inflate()}. |
| * |
| * @return {@code true} if a preset dictionary is required for inflation. |
| * @see #setDictionary(byte[]) |
| * @see #setDictionary(byte[], int, int) |
| */ |
| public synchronized boolean needsDictionary() { |
| return needsDictionary; |
| } |
| |
| /** |
| * Indicates that input has to be passed to the inflater. |
| * |
| * @return {@code true} if {@code setInput} has to be called before |
| * inflation can proceed. |
| * @see #setInput(byte[]) |
| */ |
| public synchronized boolean needsInput() { |
| return inRead == inLength; |
| } |
| |
| /** |
| * Resets the {@code Inflater}. Should be called prior to inflating a new |
| * set of data. |
| */ |
| public synchronized void reset() { |
| if (streamHandle == -1) { |
| throw new NullPointerException(); |
| } |
| finished = false; |
| needsDictionary = false; |
| inLength = inRead = 0; |
| resetImpl(streamHandle); |
| } |
| |
| private native synchronized void resetImpl(long handle); |
| |
| /** |
| * Sets the preset dictionary to be used for inflation to {@code buf}. |
| * {@code needsDictionary()} can be called to determine whether the current |
| * input was deflated using a preset dictionary. |
| * |
| * @param buf |
| * The buffer containing the dictionary bytes. |
| * @see #needsDictionary |
| */ |
| public synchronized void setDictionary(byte[] buf) { |
| setDictionary(buf, 0, buf.length); |
| } |
| |
| /** |
| * Like {@code setDictionary(byte[])}, allowing to define a specific region |
| * inside {@code buf} to be used as a dictionary. |
| * <p> |
| * The dictionary should be set if the {@link #inflate(byte[])} returned |
| * zero bytes inflated and {@link #needsDictionary()} returns |
| * <code>true</code>. |
| * |
| * @param buf |
| * the buffer containing the dictionary data bytes. |
| * @param off |
| * the offset of the data. |
| * @param nbytes |
| * the length of the data. |
| * @see #needsDictionary |
| */ |
| public synchronized void setDictionary(byte[] buf, int off, int nbytes) { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| // avoid int overflow, check null buf |
| if (off <= buf.length && nbytes >= 0 && off >= 0 |
| && buf.length - off >= nbytes) { |
| setDictionaryImpl(buf, off, nbytes, streamHandle); |
| } else { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| } |
| |
| private native synchronized void setDictionaryImpl(byte[] buf, int off, |
| int nbytes, long handle); |
| |
| /** |
| * Sets the current input to to be decrompressed. This method should only be |
| * called if {@code needsInput()} returns {@code true}. |
| * |
| * @param buf |
| * the input buffer. |
| * @see #needsInput |
| */ |
| public synchronized void setInput(byte[] buf) { |
| setInput(buf, 0, buf.length); |
| } |
| |
| /** |
| * Sets the current input to the region of the input buffer starting at |
| * {@code off} and ending at {@code nbytes - 1} where data is written after |
| * decompression. This method should only be called if {@code needsInput()} |
| * returns {@code true}. |
| * |
| * @param buf |
| * the input buffer. |
| * @param off |
| * the offset to read from the input buffer. |
| * @param nbytes |
| * the number of bytes to read. |
| * @see #needsInput |
| */ |
| public synchronized void setInput(byte[] buf, int off, int nbytes) { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| // avoid int overflow, check null buf |
| if (off <= buf.length && nbytes >= 0 && off >= 0 |
| && buf.length - off >= nbytes) { |
| inRead = 0; |
| inLength = nbytes; |
| setInputImpl(buf, off, nbytes, streamHandle); |
| } else { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| } |
| |
| // BEGIN android-only |
| /** |
| * Sets the current input to the region within a file starting at {@code |
| * off} and ending at {@code nbytes - 1}. This method should only be called |
| * if {@code needsInput()} returns {@code true}. |
| * |
| * @param fd |
| * the input file. |
| * @param off |
| * the offset to read from in buffer. |
| * @param nbytes |
| * the number of bytes to read. |
| * @see #needsInput |
| */ |
| synchronized int setFileInput(FileDescriptor fd, long off, int nbytes) { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| inRead = 0; |
| inLength = setFileInputImpl(fd, off, nbytes, streamHandle); |
| return inLength; |
| } |
| // END android-only |
| |
| private native synchronized void setInputImpl(byte[] buf, int off, |
| int nbytes, long handle); |
| |
| // BEGIN android-only |
| private native synchronized int setFileInputImpl(FileDescriptor fd, long off, |
| int nbytes, long handle); |
| // END android-only |
| } |