| /* |
| * 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; |
| |
| |
| /** |
| * This class compresses data 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 DeflaterOutputStream} and its |
| * descendants. |
| * <p> |
| * The typical usage of a {@code Deflater} instance outside this package |
| * consists of a specific call to one of its constructors before being passed to |
| * an instance of {@code DeflaterOutputStream}. |
| * |
| * @see DeflaterOutputStream |
| * @see Inflater |
| */ |
| public class Deflater { |
| |
| /** |
| * Upper bound for the compression level range. |
| */ |
| public static final int BEST_COMPRESSION = 9; |
| |
| /** |
| * Lower bound for compression level range. |
| */ |
| public static final int BEST_SPEED = 1; |
| |
| /** |
| * Usage of the default compression level. |
| */ |
| public static final int DEFAULT_COMPRESSION = -1; |
| |
| /** |
| * Default value for compression strategy. |
| */ |
| public static final int DEFAULT_STRATEGY = 0; |
| |
| /** |
| * Default value for compression method. |
| */ |
| public static final int DEFLATED = 8; |
| |
| /** |
| * Possible value for compression strategy. |
| */ |
| public static final int FILTERED = 1; |
| |
| /** |
| * Possible value for compression strategy. |
| */ |
| public static final int HUFFMAN_ONLY = 2; |
| |
| /** |
| * Possible value for compression level. |
| */ |
| public static final int NO_COMPRESSION = 0; |
| |
| /** |
| * Use buffering for best compression. |
| * |
| * @hide |
| * @since 1.7 |
| */ |
| public static final int NO_FLUSH = 0; |
| |
| /** |
| * Flush buffers so recipients can immediately decode the data sent thus |
| * far. This mode may degrade compression. |
| * |
| * @hide |
| * @since 1.7 |
| */ |
| public static final int SYNC_FLUSH = 2; |
| |
| /** |
| * Flush buffers so recipients can immediately decode the data sent thus |
| * far. The compression state is also reset to permit random access and |
| * recovery for clients who have discarded or damaged their own copy. This |
| * mode may degrade compression. |
| * |
| * @hide |
| * @since 1.7 |
| */ |
| public static final int FULL_FLUSH = 3; |
| |
| /** |
| * Flush buffers and mark the end of the datastream. |
| */ |
| private static final int FINISH = 4; |
| |
| // A stub buffer used when deflate() called while inputBuffer has not been |
| // set. |
| private static final byte[] STUB_INPUT_BUFFER = new byte[0]; |
| |
| private int flushParm = NO_FLUSH; |
| |
| private boolean finished; |
| |
| private int compressLevel = DEFAULT_COMPRESSION; |
| |
| private int strategy = DEFAULT_STRATEGY; |
| |
| private long streamHandle = -1; |
| |
| private byte[] inputBuffer; |
| |
| private int inRead; |
| |
| private int inLength; |
| |
| /** |
| * Constructs a new {@code Deflater} instance with default compression |
| * level. The strategy can be specified with {@link #setStrategy}, only. A |
| * header is added to the output by default; use constructor {@code |
| * Deflater(level, boolean)} if you need to omit the header. |
| */ |
| public Deflater() { |
| this(DEFAULT_COMPRESSION, false); |
| } |
| |
| /** |
| * Constructs a new {@code Deflater} instance with a specific compression |
| * level. The strategy can be specified with {@code setStrategy}, only. A |
| * header is added to the output by default; use |
| * {@code Deflater(level, boolean)} if you need to omit the header. |
| * |
| * @param level |
| * the compression level in the range between 0 and 9. |
| */ |
| public Deflater(int level) { |
| this(level, false); |
| } |
| |
| /** |
| * Constructs a new {@code Deflater} instance with a specific compression |
| * level. If noHeader is passed as true no ZLib header is added to the |
| * output. In a ZIP archive every entry (compressed file) comes with such a |
| * header. The strategy can be specified with the setStrategy method, only. |
| * |
| * @param level |
| * the compression level in the range between 0 and 9. |
| * @param noHeader |
| * {@code true} indicates that no ZLIB header should be written. |
| */ |
| public Deflater(int level, boolean noHeader) { |
| super(); |
| if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) { |
| throw new IllegalArgumentException(); |
| } |
| compressLevel = level; |
| streamHandle = createStream(compressLevel, strategy, noHeader); |
| } |
| |
| /** |
| * Deflates the data (previously passed to {@code setInput}) into the |
| * supplied buffer. |
| * |
| * @param buf |
| * buffer to write compressed data to. |
| * @return number of bytes of compressed data written to {@code buf}. |
| * @see #deflate(byte[], int, int) |
| */ |
| public int deflate(byte[] buf) { |
| return deflate(buf, 0, buf.length); |
| } |
| |
| /** |
| * Deflates data (previously passed to {@code setInput}) into a specific |
| * region within the supplied buffer. |
| * |
| * @param buf |
| * the buffer to write compressed data to. |
| * @param off |
| * the offset within {@code buf} at which to start writing to. |
| * @param nbytes |
| * maximum number of bytes of compressed data to be written. |
| * @return the number of bytes of compressed data written to {@code buf}. |
| */ |
| public synchronized int deflate(byte[] buf, int off, int nbytes) { |
| return deflateImpl(buf, off, nbytes, flushParm); |
| } |
| |
| /** |
| * Deflates data (previously passed to {@code setInput}) into a specific |
| * region within the supplied buffer, optionally flushing the input buffer. |
| * |
| * @param buf the buffer to write compressed data to. |
| * @param off the offset within {@code buf} at which to start writing to. |
| * @param nbytes maximum number of bytes of compressed data to be written. |
| * @param flush one of {@link #NO_FLUSH}, {@link #SYNC_FLUSH} or |
| * {@link #FULL_FLUSH}. |
| * @return the number of compressed bytes written to {@code buf}. If this |
| * equals {@code nbytes}, the number of bytes of input to be flushed |
| * may have exceeded the output buffer's capacity. In this case, |
| * finishing a flush will require the output buffer to be drained |
| * and additional calls to {@link #deflate} to be made. |
| * @hide |
| * @since 1.7 |
| */ |
| public synchronized int deflate(byte[] buf, int off, int nbytes, int flush) { |
| if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) { |
| throw new IllegalArgumentException(); |
| } |
| return deflateImpl(buf, off, nbytes, flush); |
| } |
| |
| private synchronized int deflateImpl( |
| byte[] buf, int off, int nbytes, int flush) { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| if (off > buf.length || nbytes < 0 || off < 0 || buf.length - off < nbytes) { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| if (inputBuffer == null) { |
| setInput(STUB_INPUT_BUFFER); |
| } |
| return deflateImpl(buf, off, nbytes, streamHandle, flush); |
| } |
| |
| private synchronized native int deflateImpl(byte[] buf, int off, |
| int nbytes, long handle, int flushParm1); |
| |
| private synchronized native void endImpl(long handle); |
| |
| /** |
| * Frees all resources held onto by this deflating algorithm. Any unused |
| * input or output is discarded. While this method is used by {@code |
| * finalize()}, it can be called explicitly in order to free native |
| * resources before the next GC cycle. After {@code end()} was called other |
| * methods will typically throw an {@code IllegalStateException}. |
| */ |
| public synchronized void end() { |
| endImpl(); |
| } |
| |
| private void endImpl() { |
| if (streamHandle != -1) { |
| endImpl(streamHandle); |
| inputBuffer = null; |
| streamHandle = -1; |
| } |
| } |
| |
| @Override protected void finalize() { |
| try { |
| synchronized (this) { |
| end(); // to allow overriding classes to clean up |
| endImpl(); // in case those classes don't call super.end() |
| } |
| } finally { |
| try { |
| super.finalize(); |
| } catch (Throwable t) { |
| throw new AssertionError(t); |
| } |
| } |
| } |
| |
| /** |
| * Indicates to the {@code Deflater} that all uncompressed input has been provided |
| * to it. |
| * |
| * @see #finished |
| */ |
| public synchronized void finish() { |
| flushParm = FINISH; |
| } |
| |
| /** |
| * Returns whether or not all provided data has been successfully |
| * compressed. |
| * |
| * @return true if all data has been compressed, false otherwise. |
| */ |
| public synchronized boolean finished() { |
| return finished; |
| } |
| |
| /** |
| * Returns the Adler32 checksum of uncompressed data currently read. If a |
| * preset dictionary is used getAdler() will return the Adler32 checksum of |
| * the dictionary used. |
| * |
| * @return the Adler32 checksum of uncompressed data or preset dictionary if |
| * used. |
| * @see #setDictionary(byte[]) |
| * @see #setDictionary(byte[], int, int) |
| */ |
| public synchronized int getAdler() { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| |
| return getAdlerImpl(streamHandle); |
| } |
| |
| private synchronized native int getAdlerImpl(long handle); |
| |
| /** |
| * Returns the total number of bytes of input consumed by the {@code Deflater}. |
| * |
| * @return number of bytes of input read. |
| */ |
| public synchronized int getTotalIn() { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| |
| return (int) getTotalInImpl(streamHandle); |
| } |
| |
| private synchronized native long getTotalInImpl(long handle); |
| |
| /** |
| * Returns the total number of compressed bytes output by this {@code Deflater}. |
| * |
| * @return number of compressed bytes output. |
| */ |
| public synchronized int getTotalOut() { |
| if (streamHandle == -1) { |
| throw new IllegalStateException(); |
| } |
| |
| return (int) getTotalOutImpl(streamHandle); |
| } |
| |
| private synchronized native long getTotalOutImpl(long handle); |
| |
| /** |
| * Counterpart to setInput(). Indicates whether or not all bytes of |
| * uncompressed input have been consumed by the {@code Deflater}. If needsInput() |
| * returns true setInput() must be called before deflation can continue. If |
| * all bytes of uncompressed data have been provided to the {@code Deflater} |
| * finish() must be called to ensure the compressed data is output. |
| * |
| * @return {@code true} if input is required for deflation to continue, |
| * {@code false} otherwise. |
| * @see #finished() |
| * @see #setInput(byte[]) |
| * @see #setInput(byte[], int, int) |
| */ |
| public synchronized boolean needsInput() { |
| if (inputBuffer == null) { |
| return true; |
| } |
| return inRead == inLength; |
| } |
| |
| /** |
| * Resets the {@code Deflater} to accept new input without affecting any |
| * previously made settings for the compression strategy or level. This |
| * operation <i>must</i> be called after {@code finished()} returns |
| * {@code true} if the {@code Deflater} is to be reused. |
| * |
| * @see #finished |
| */ |
| public synchronized void reset() { |
| if (streamHandle == -1) { |
| throw new NullPointerException(); |
| } |
| |
| flushParm = NO_FLUSH; |
| finished = false; |
| resetImpl(streamHandle); |
| inputBuffer = null; |
| } |
| |
| private synchronized native void resetImpl(long handle); |
| |
| /** |
| * Sets the dictionary to be used for compression by this {@code Deflater}. |
| * setDictionary() can only be called if this {@code Deflater} supports the writing |
| * of ZLIB headers. This is the default behaviour but can be overridden |
| * using {@code Deflater(int, boolean)}. |
| * |
| * @param buf |
| * the buffer containing the dictionary data bytes. |
| * @see Deflater#Deflater(int, boolean) |
| */ |
| public void setDictionary(byte[] buf) { |
| setDictionary(buf, 0, buf.length); |
| } |
| |
| /** |
| * Sets the dictionary to be used for compression by this {@code Deflater}. |
| * setDictionary() can only be called if this {@code Deflater} supports the writing |
| * of ZLIB headers. This is the default behaviour but can be overridden |
| * using {@code Deflater(int, boolean)}. |
| * |
| * @param buf |
| * the buffer containing the dictionary data bytes. |
| * @param off |
| * the offset of the data. |
| * @param nbytes |
| * the length of the data. |
| * @see Deflater#Deflater(int, boolean) |
| */ |
| 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 synchronized native void setDictionaryImpl(byte[] buf, int off, |
| int nbytes, long handle); |
| |
| /** |
| * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes |
| * for later compression. |
| * |
| * @param buf |
| * the buffer. |
| */ |
| public void setInput(byte[] buf) { |
| setInput(buf, 0, buf.length); |
| } |
| |
| /** |
| * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes |
| * for later compression. Input will be taken from the buffer region |
| * starting at off and ending at nbytes - 1. |
| * |
| * @param buf |
| * the buffer containing the input data bytes. |
| * @param off |
| * the offset of the data. |
| * @param nbytes |
| * the length of the data. |
| */ |
| 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) { |
| inLength = nbytes; |
| inRead = 0; |
| if (inputBuffer == null) { |
| setLevelsImpl(compressLevel, strategy, streamHandle); |
| } |
| inputBuffer = buf; |
| setInputImpl(buf, off, nbytes, streamHandle); |
| } else { |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| } |
| |
| private synchronized native void setLevelsImpl(int level, int strategy, |
| long handle); |
| |
| private synchronized native void setInputImpl(byte[] buf, int off, |
| int nbytes, long handle); |
| |
| /** |
| * Sets the compression level to be used when compressing data. The |
| * compression level must be a value between 0 and 9. This value must be set |
| * prior to calling setInput(). |
| * |
| * @param level |
| * compression level to use |
| * @exception IllegalArgumentException |
| * If the compression level is invalid. |
| */ |
| public synchronized void setLevel(int level) { |
| if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) { |
| throw new IllegalArgumentException(); |
| } |
| if (inputBuffer != null) { |
| throw new IllegalStateException(); |
| } |
| compressLevel = level; |
| } |
| |
| /** |
| * Sets the compression strategy to be used. The strategy must be one of |
| * FILTERED, HUFFMAN_ONLY or DEFAULT_STRATEGY.This value must be set prior |
| * to calling setInput(). |
| * |
| * @param strategy |
| * compression strategy to use |
| * @exception IllegalArgumentException |
| * If the strategy specified is not one of FILTERED, |
| * HUFFMAN_ONLY or DEFAULT_STRATEGY. |
| */ |
| public synchronized void setStrategy(int strategy) { |
| if (strategy < DEFAULT_STRATEGY || strategy > HUFFMAN_ONLY) { |
| throw new IllegalArgumentException(); |
| } |
| if (inputBuffer != null) { |
| throw new IllegalStateException(); |
| } |
| this.strategy = strategy; |
| } |
| |
| /** |
| * Returns a long int of total number of bytes read by the {@code Deflater}. This |
| * method performs the same as {@code getTotalIn} except it returns a long value |
| * instead of an integer |
| * |
| * @see #getTotalIn() |
| * @return total number of bytes read by {@code Deflater}. |
| */ |
| public synchronized long getBytesRead() { |
| // Throw NPE here |
| if (streamHandle == -1) { |
| throw new NullPointerException(); |
| } |
| return getTotalInImpl(streamHandle); |
| } |
| |
| /** |
| * Returns a long int of total number of bytes of read by the {@code Deflater}. This |
| * method performs the same as {@code getTotalOut} except it returns a long |
| * value instead of an integer |
| * |
| * @see #getTotalOut() |
| * @return bytes exactly write by {@code Deflater} |
| */ |
| public synchronized long getBytesWritten() { |
| // Throw NPE here |
| if (streamHandle == -1) { |
| throw new NullPointerException(); |
| } |
| return getTotalOutImpl(streamHandle); |
| } |
| |
| private native long createStream(int level, int strategy1, boolean noHeader1); |
| } |