/*
 * 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
}
