1f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements.  See the NOTICE file distributed with
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership.
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License.  You may obtain a copy of the License at
8f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson *
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
10f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson *
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.util.zip;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstromimport dalvik.system.CloseGuard;
21c941a854631c4bf2369adc84887bb6dd386a1bccElliott Hughesimport java.io.FileDescriptor;
222d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughesimport java.util.Arrays;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
252d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * This class decompresses data that was compressed using the <i>DEFLATE</i>
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * algorithm (see <a href="http://www.gzip.org/algorithm.txt">specification</a>).
2757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson *
282d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * <p>It is usually more convenient to use {@link InflaterInputStream}.
292d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *
302d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * <p>To decompress an in-memory {@code byte[]} to another in-memory {@code byte[]} manually:
312d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * <pre>
322d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *     byte[] compressedBytes = ...
332d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *     int decompressedByteCount = ... // From your format's metadata.
342d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *     Inflater inflater = new Inflater();
352d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *     inflater.setInput(compressedBytes, 0, compressedBytes.length);
362d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *     byte[] decompressedBytes = new byte[decompressedByteCount];
372d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *     if (inflater.inflate(decompressedBytes) != decompressedByteCount) {
382d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *         throw new AssertionError();
392d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *     }
402d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *     inflater.end();
412d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * </pre>
422d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * <p>In situations where you don't have all the input in one array (or have so much
432d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * input that you want to feed it to the inflater in chunks), it's possible to call
442d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * {@link #setInput} repeatedly, but you're much better off using {@link InflaterInputStream}
452d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * to handle all this for you.
462d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes *
472d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * <p>If you don't know how big the decompressed data will be, you can call {@link #inflate}
482d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * repeatedly on a temporary buffer, copying the bytes to a {@link java.io.ByteArrayOutputStream},
492d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes * but this is probably another sign you'd be better off using {@link InflaterInputStream}.
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class Inflater {
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
532d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private int inLength;
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
552d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private int inRead; // Set by inflateImpl.
562d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private boolean finished; // Set by inflateImpl.
572d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private boolean needsDictionary; // Set by inflateImpl.
58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    private long streamHandle = -1;
6057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson
6112f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom    private final CloseGuard guard = CloseGuard.get();
62f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
6357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    /**
6457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     * This constructor creates an inflater that expects a header from the input
652d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * stream. Use {@link #Inflater(boolean)} if the input comes without a ZLIB
6657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     * header.
6757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     */
6857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    public Inflater() {
6957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson        this(false);
7057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    }
7157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson
7257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    /**
7357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     * This constructor allows to create an inflater that expects no header from
7457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     * the input stream.
7557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     *
7657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     * @param noHeader
7757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     *            {@code true} indicates that no ZLIB header comes with the
7857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     *            input.
7957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     */
8057995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    public Inflater(boolean noHeader) {
8157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson        streamHandle = createStream(noHeader);
8212f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom        guard.open("end");
8357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    }
8457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson
8557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    private native long createStream(boolean noHeader1);
8657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
882d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Releases resources associated with this {@code Inflater}. Any unused
892d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * input or output is discarded. This method should be called explicitly in
902d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * order to free native resources as soon as possible. After {@code end()} is
912d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * called, other methods will typically throw {@code IllegalStateException}.
92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void end() {
94f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (streamHandle != -1) {
96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            endImpl(streamHandle);
97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            inRead = 0;
98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            inLength = 0;
99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            streamHandle = -1;
100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1032d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native void endImpl(long handle);
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
105e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() {
106e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
10712f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
10812f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
10912f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
110e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            end();
111e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
112e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            try {
113e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                super.finalize();
114e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            } catch (Throwable t) {
115e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom                throw new AssertionError(t);
116e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            }
117e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Indicates if the {@code Inflater} has inflated the entire deflated
1222d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * stream. If deflated bytes remain and {@link #needsInput} returns {@code
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * true} this method will return {@code false}. This method should be
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * called after all deflated input is supplied to the {@code Inflater}.
12557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     *
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return {@code true} if all input has been inflated, {@code false}
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *         otherwise.
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized boolean finished() {
130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return finished;
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1342d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Returns the {@link Adler32} checksum of the bytes inflated so far, or the
1352d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * checksum of the preset dictionary if {@link #needsDictionary} returns true.
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized int getAdler() {
138aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return getAdlerImpl(streamHandle);
140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1422d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native int getAdlerImpl(long handle);
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
14557995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     * Returns the total number of bytes read by the {@code Inflater}. This
1462d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * method is the same as {@link #getTotalIn} except that it returns a
14757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     * {@code long} value instead of an integer.
14857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     */
14957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    public synchronized long getBytesRead() {
150aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
15157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson        return getTotalInImpl(streamHandle);
15257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    }
15357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson
15457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    /**
1552d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Returns a the total number of bytes written by this {@code Inflater}. This
1562d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * method is the same as {@code getTotalOut} except it returns a
15757995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     * {@code long} value instead of an integer.
15857995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     */
15957995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    public synchronized long getBytesWritten() {
160aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
16157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson        return getTotalOutImpl(streamHandle);
16257995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    }
16357995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson
16457995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson    /**
1652d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Returns the number of bytes of current input remaining to be read by this
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * inflater.
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized int getRemaining() {
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return inLength - inRead;
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1732d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Returns the total number of bytes of input read by this {@code Inflater}. This
1742d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * method is limited to 32 bits; use {@link #getBytesRead} instead.
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized int getTotalIn() {
177aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
1782d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        return (int) Math.min(getTotalInImpl(streamHandle), (long) Integer.MAX_VALUE);
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1812d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native long getTotalInImpl(long handle);
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1842d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Returns the total number of bytes written to the output buffer by this {@code
1852d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Inflater}. The method is limited to 32 bits; use {@link #getBytesWritten} instead.
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized int getTotalOut() {
188aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
1892d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        return (int) Math.min(getTotalOutImpl(streamHandle), (long) Integer.MAX_VALUE);
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1922d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native long getTotalOutImpl(long handle);
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
1952d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Inflates bytes from the current input and stores them in {@code buf}.
19657995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     *
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @param buf
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *            the buffer where decompressed data bytes are written.
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the number of bytes inflated.
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws DataFormatException
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the underlying stream is corrupted or was not compressed
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             using a {@code Deflater}.
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public int inflate(byte[] buf) throws DataFormatException {
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return inflate(buf, 0, buf.length);
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
207adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
208adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2092d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Inflates up to {@code byteCount} bytes from the current input and stores them in
2102d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * {@code buf} starting at {@code offset}.
21157995e8186b54515d5a03bf2ab104c3dc247f1b6Jesse Wilson     *
212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @throws DataFormatException
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             if the underlying stream is corrupted or was not compressed
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     *             using a {@code Deflater}.
215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * @return the number of bytes inflated.
216adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
2172d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    public synchronized int inflate(byte[] buf, int offset, int byteCount) throws DataFormatException {
2182d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
219f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson
220aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
221f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson
222f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson        if (needsInput()) {
223f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson            return 0;
224f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson        }
225f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson
226f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson        boolean neededDict = needsDictionary;
227f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson        needsDictionary = false;
2282d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        int result = inflateImpl(buf, offset, byteCount, streamHandle);
229f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson        if (needsDictionary && neededDict) {
230b1433b3bd4dfc05426e5d9c3100b5fbaa198d8a0Elliott Hughes            throw new DataFormatException("Needs dictionary");
231f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson        }
232f7c6911047d63bc76292f55ce538da32818dd931Jesse Wilson        return result;
233adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
234adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2352d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native int inflateImpl(byte[] buf, int offset, int byteCount, long handle);
236adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
237adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2382d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Returns true if the input bytes were compressed with a preset
2392d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * dictionary. This method should be called if the first call to {@link #inflate} returns 0,
2402d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * to determine whether a dictionary is required. If so, {@link #setDictionary}
2412d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * should be called with the appropriate dictionary before calling {@code
2422d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * inflate} again. Use {@link #getAdler} to determine which dictionary is required.
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized boolean needsDictionary() {
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return needsDictionary;
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2492d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Returns true if {@link #setInput} must be called before inflation can continue.
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized boolean needsInput() {
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return inRead == inLength;
253adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
254adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
255adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2562d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Resets this {@code Inflater}. Should be called prior to inflating a new
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * set of data.
258adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
259adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void reset() {
260aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
261adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        finished = false;
262adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        needsDictionary = false;
263adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        inLength = inRead = 0;
264adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        resetImpl(streamHandle);
265adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2672d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native void resetImpl(long handle);
268adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
269adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2702d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Sets the preset dictionary to be used for inflation to {@code dictionary}.
2712d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * See {@link #needsDictionary} for details.
272adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
2732d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    public synchronized void setDictionary(byte[] dictionary) {
2742d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        setDictionary(dictionary, 0, dictionary.length);
275adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
276adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2782d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Sets the preset dictionary to be used for inflation to a subsequence of {@code dictionary}
2792d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * starting at {@code offset} and continuing for {@code byteCount} bytes. See {@link
2802d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * #needsDictionary} for details.
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
2822d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    public synchronized void setDictionary(byte[] dictionary, int offset, int byteCount) {
283aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
2842d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        Arrays.checkOffsetAndCount(dictionary.length, offset, byteCount);
2852d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        setDictionaryImpl(dictionary, offset, byteCount, streamHandle);
286adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2882d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native void setDictionaryImpl(byte[] dictionary, int offset, int byteCount, long handle);
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2912d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Sets the current input to to be decompressed. This method should only be
2922d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * called if {@link #needsInput} returns {@code true}.
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    public synchronized void setInput(byte[] buf) {
295adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        setInput(buf, 0, buf.length);
296adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
2992d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * Sets the current input to to be decompressed. This method should only be
3002d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes     * called if {@link #needsInput} returns {@code true}.
301adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
3022d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    public synchronized void setInput(byte[] buf, int offset, int byteCount) {
303aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
3042d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
3052d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        inRead = 0;
3062d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        inLength = byteCount;
3072d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        setInputImpl(buf, offset, byteCount, streamHandle);
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3102d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle);
3112d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes
3122d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    synchronized int setFileInput(FileDescriptor fd, long offset, int byteCount) {
313aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        checkOpen();
314adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        inRead = 0;
3152d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes        inLength = setFileInputImpl(fd, offset, byteCount, streamHandle);
316adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return inLength;
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3192d9c5fa8ce0182cd8c14736241b709fd50cab6f8Elliott Hughes    private native int setFileInputImpl(FileDescriptor fd, long offset, int byteCount, long handle);
320aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes
321aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes    private void checkOpen() {
322aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        if (streamHandle == -1) {
323aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes            throw new IllegalStateException("attempt to use Inflater after calling end");
324aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes        }
325aee3e4d2e0a2830fc2ef8e96a13796d012becab2Elliott Hughes    }
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
327