All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.util.zip.Inflater Maven / Gradle / Ivy

There is a newer version: 1.2.9
Show newest version
/*
 * 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 dalvik.system.CloseGuard;
import java.io.FileDescriptor;
import java.util.Arrays;

/**
 * This class decompresses data that was compressed using the DEFLATE
 * algorithm (see specification).
 *
 * 

It is usually more convenient to use {@link InflaterInputStream}. * *

To decompress an in-memory {@code byte[]} to another in-memory {@code byte[]} manually: *

 *     byte[] compressedBytes = ...
 *     int decompressedByteCount = ... // From your format's metadata.
 *     Inflater inflater = new Inflater();
 *     inflater.setInput(compressedBytes, 0, compressedBytes.length);
 *     byte[] decompressedBytes = new byte[decompressedByteCount];
 *     if (inflater.inflate(decompressedBytes) != decompressedByteCount) {
 *         throw new AssertionError();
 *     }
 *     inflater.end();
 * 
*

In situations where you don't have all the input in one array (or have so much * input that you want to feed it to the inflater in chunks), it's possible to call * {@link #setInput} repeatedly, but you're much better off using {@link InflaterInputStream} * to handle all this for you. * *

If you don't know how big the decompressed data will be, you can call {@link #inflate} * repeatedly on a temporary buffer, copying the bytes to a {@link java.io.ByteArrayOutputStream}, * but this is probably another sign you'd be better off using {@link InflaterInputStream}. */ public class Inflater { private int inLength; private int inRead; // Set by inflateImpl. private boolean finished; // Set by inflateImpl. private boolean needsDictionary; // Set by inflateImpl. private long streamHandle = -1; private final CloseGuard guard = CloseGuard.get(); /** * This constructor creates an inflater that expects a header from the input * stream. Use {@link #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); guard.open("end"); } private native long createStream(boolean noHeader1); /** * Releases resources associated with this {@code Inflater}. Any unused * input or output is discarded. This method should be called explicitly in * order to free native resources as soon as possible. After {@code end()} is * called, other methods will typically throw {@code IllegalStateException}. */ public synchronized void end() { guard.close(); if (streamHandle != -1) { endImpl(streamHandle); inRead = 0; inLength = 0; streamHandle = -1; } } private native void endImpl(long handle); @Override protected void finalize() { try { if (guard != null) { guard.warnIfOpen(); } 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 {@link #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 {@link Adler32} checksum of the bytes inflated so far, or the * checksum of the preset dictionary if {@link #needsDictionary} returns true. */ public synchronized int getAdler() { checkOpen(); return getAdlerImpl(streamHandle); } private native int getAdlerImpl(long handle); /** * Returns the total number of bytes read by the {@code Inflater}. This * method is the same as {@link #getTotalIn} except that it returns a * {@code long} value instead of an integer. */ public synchronized long getBytesRead() { checkOpen(); return getTotalInImpl(streamHandle); } /** * Returns a the total number of bytes written by this {@code Inflater}. This * method is the same as {@code getTotalOut} except it returns a * {@code long} value instead of an integer. */ public synchronized long getBytesWritten() { checkOpen(); return getTotalOutImpl(streamHandle); } /** * Returns the number of bytes of current input remaining to be read by this * inflater. */ public synchronized int getRemaining() { return inLength - inRead; } /** * Returns the total number of bytes of input read by this {@code Inflater}. This * method is limited to 32 bits; use {@link #getBytesRead} instead. */ public synchronized int getTotalIn() { checkOpen(); return (int) Math.min(getTotalInImpl(streamHandle), (long) Integer.MAX_VALUE); } private native long getTotalInImpl(long handle); /** * Returns the total number of bytes written to the output buffer by this {@code * Inflater}. The method is limited to 32 bits; use {@link #getBytesWritten} instead. */ public synchronized int getTotalOut() { checkOpen(); return (int) Math.min(getTotalOutImpl(streamHandle), (long) Integer.MAX_VALUE); } private native long getTotalOutImpl(long handle); /** * Inflates bytes from the 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 {@code byteCount} bytes from the current input and stores them in * {@code buf} starting at {@code offset}. * * @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 offset, int byteCount) throws DataFormatException { Arrays.checkOffsetAndCount(buf.length, offset, byteCount); checkOpen(); if (needsInput()) { return 0; } boolean neededDict = needsDictionary; needsDictionary = false; int result = inflateImpl(buf, offset, byteCount, streamHandle); if (needsDictionary && neededDict) { throw new DataFormatException("Needs dictionary"); } return result; } private native int inflateImpl(byte[] buf, int offset, int byteCount, long handle); /** * Returns true if the input bytes were compressed with a preset * dictionary. This method should be called if the first call to {@link #inflate} returns 0, * to determine whether a dictionary is required. If so, {@link #setDictionary} * should be called with the appropriate dictionary before calling {@code * inflate} again. Use {@link #getAdler} to determine which dictionary is required. */ public synchronized boolean needsDictionary() { return needsDictionary; } /** * Returns true if {@link #setInput} must be called before inflation can continue. */ public synchronized boolean needsInput() { return inRead == inLength; } /** * Resets this {@code Inflater}. Should be called prior to inflating a new * set of data. */ public synchronized void reset() { checkOpen(); finished = false; needsDictionary = false; inLength = inRead = 0; resetImpl(streamHandle); } private native void resetImpl(long handle); /** * Sets the preset dictionary to be used for inflation to {@code dictionary}. * See {@link #needsDictionary} for details. */ public synchronized void setDictionary(byte[] dictionary) { setDictionary(dictionary, 0, dictionary.length); } /** * Sets the preset dictionary to be used for inflation to a subsequence of {@code dictionary} * starting at {@code offset} and continuing for {@code byteCount} bytes. See {@link * #needsDictionary} for details. */ public synchronized void setDictionary(byte[] dictionary, int offset, int byteCount) { checkOpen(); Arrays.checkOffsetAndCount(dictionary.length, offset, byteCount); setDictionaryImpl(dictionary, offset, byteCount, streamHandle); } private native void setDictionaryImpl(byte[] dictionary, int offset, int byteCount, long handle); /** * Sets the current input to to be decompressed. This method should only be * called if {@link #needsInput} returns {@code true}. */ public synchronized void setInput(byte[] buf) { setInput(buf, 0, buf.length); } /** * Sets the current input to to be decompressed. This method should only be * called if {@link #needsInput} returns {@code true}. */ public synchronized void setInput(byte[] buf, int offset, int byteCount) { checkOpen(); Arrays.checkOffsetAndCount(buf.length, offset, byteCount); inRead = 0; inLength = byteCount; setInputImpl(buf, offset, byteCount, streamHandle); } private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle); synchronized int setFileInput(FileDescriptor fd, long offset, int byteCount) { checkOpen(); inRead = 0; inLength = setFileInputImpl(fd, offset, byteCount, streamHandle); return inLength; } private native int setFileInputImpl(FileDescriptor fd, long offset, int byteCount, long handle); private void checkOpen() { if (streamHandle == -1) { throw new IllegalStateException("attempt to use Inflater after calling end"); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy