1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package java.util.zip;
19
20import dalvik.system.CloseGuard;
21import java.util.Arrays;
22import libcore.util.EmptyArray;
23
24/**
25 * This class compresses data using the <i>DEFLATE</i> algorithm (see <a
26 * href="http://www.gzip.org/algorithm.txt">specification</a>).
27 *
28 * <p>It is usually more convenient to use {@link DeflaterOutputStream}.
29 *
30 * <p>To compress an in-memory {@code byte[]} to another in-memory {@code byte[]} manually:
31 * <pre>
32 *     byte[] originalBytes = ...
33 *
34 *     Deflater deflater = new Deflater();
35 *     deflater.setInput(originalBytes);
36 *     deflater.finish();
37 *
38 *     ByteArrayOutputStream baos = new ByteArrayOutputStream();
39 *     byte[] buf = new byte[8192];
40 *     while (!deflater.finished()) {
41 *         int byteCount = deflater.deflate(buf);
42 *         baos.write(buf, 0, byteCount);
43 *     }
44 *     deflater.end();
45 *
46 *     byte[] compressedBytes = baos.toByteArray();
47 * </pre>
48 * <p>In situations where you don't have all the input in one array (or have so much
49 * input that you want to feed it to the deflater in chunks), it's possible to call
50 * {@link #setInput setInput} repeatedly, but you're much better off using
51 * {@link DeflaterOutputStream} to handle all this for you. {@link DeflaterOutputStream} also helps
52 * minimize memory requirements&nbsp;&mdash; the sample code above is very expensive.
53 *
54 * <a name="compression_level"><h3>Compression levels</h3></a>
55 * <p>A compression level must be {@link #DEFAULT_COMPRESSION} to compromise between speed and
56 * compression (currently equivalent to level 6), or between 0 ({@link #NO_COMPRESSION}, where
57 * the input is simply copied) and 9 ({@link #BEST_COMPRESSION}). Level 1 ({@link #BEST_SPEED})
58 * performs some compression, but with minimal speed overhead.
59 */
60public class Deflater {
61
62    /**
63     * This <a href="#compression_level">compression level</a> gives the best compression,
64     * but takes the most time.
65     */
66    public static final int BEST_COMPRESSION = 9;
67
68    /**
69     * This <a href="#compression_level">compression level</a> gives minimal compression,
70     * but takes the least time (of any level that actually performs compression;
71     * see {@link #NO_COMPRESSION}).
72     */
73    public static final int BEST_SPEED = 1;
74
75    /**
76     * This <a href="#compression_level">compression level</a> does no compression.
77     * It is even faster than {@link #BEST_SPEED}.
78     */
79    public static final int NO_COMPRESSION = 0;
80
81    /**
82     * The default <a href="#compression_level">compression level</a>.
83     * This is a trade-off between speed and compression, currently equivalent to level 6.
84     */
85    public static final int DEFAULT_COMPRESSION = -1;
86
87    /**
88     * The default compression strategy.
89     */
90    public static final int DEFAULT_STRATEGY = 0;
91
92    /**
93     * The default compression method.
94     */
95    public static final int DEFLATED = 8;
96
97    /**
98     * A compression strategy.
99     */
100    public static final int FILTERED = 1;
101
102    /**
103     * A compression strategy.
104     */
105    public static final int HUFFMAN_ONLY = 2;
106
107    /**
108     * Use buffering for best compression.
109     * @since 1.7
110     */
111    public static final int NO_FLUSH = 0;
112
113    /**
114     * Flush buffers so recipients can immediately decode the data sent thus
115     * far. This mode may degrade compression.
116     * @since 1.7
117     */
118    public static final int SYNC_FLUSH = 2;
119
120    /**
121     * Flush buffers so recipients can immediately decode the data sent thus
122     * far. The compression state is also reset to permit random access and
123     * recovery for clients who have discarded or damaged their own copy. This
124     * mode may degrade compression.
125     * @since 1.7
126     */
127    public static final int FULL_FLUSH = 3;
128
129    /**
130     * Flush buffers and mark the end of the data stream.
131     */
132    private static final int FINISH = 4;
133
134    /**
135     * The ugly name flushParm is for RI compatibility, should code need to access this
136     * field via reflection if it's not able to use public API to choose what
137     * kind of flushing it gets.
138     */
139    private int flushParm = NO_FLUSH;
140
141    private boolean finished;
142
143    private int compressLevel = DEFAULT_COMPRESSION;
144
145    private int strategy = DEFAULT_STRATEGY;
146
147    private long streamHandle = -1;
148
149    private byte[] inputBuffer;
150
151    private int inRead;
152
153    private int inLength;
154
155    private final CloseGuard guard = CloseGuard.get();
156
157    /**
158     * Constructs a new {@code Deflater} instance using the
159     * default <a href="#compression_level">compression level</a>.
160     * The compression strategy can be specified with {@link #setStrategy}. A
161     * header is added to the output by default; use {@link
162     * #Deflater(int, boolean)} if you need to omit the header.
163     */
164    public Deflater() {
165        this(DEFAULT_COMPRESSION, false);
166    }
167
168    /**
169     * Constructs a new {@code Deflater} instance with the
170     * given <a href="#compression_level">compression level</a>.
171     * The compression strategy can be specified with {@link #setStrategy}.
172     * A header is added to the output by default; use
173     * {@link #Deflater(int, boolean)} if you need to omit the header.
174     */
175    public Deflater(int level) {
176        this(level, false);
177    }
178
179    /**
180     * Constructs a new {@code Deflater} instance with the
181     * given <a href="#compression_level">compression level</a>.
182     * If {@code noHeader} is true, no ZLIB header is added to the
183     * output. In a zip file, every entry (compressed file) comes with such a
184     * header. The strategy can be specified using {@link #setStrategy}.
185     */
186    public Deflater(int level, boolean noHeader) {
187        if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
188            throw new IllegalArgumentException("Bad level: " + level);
189        }
190        compressLevel = level;
191        streamHandle = createStream(compressLevel, strategy, noHeader);
192        guard.open("end");
193    }
194
195    /**
196     * Deflates the data (previously passed to {@link #setInput setInput}) into the
197     * supplied buffer.
198     *
199     * @return number of bytes of compressed data written to {@code buf}.
200     */
201    public int deflate(byte[] buf) {
202        return deflate(buf, 0, buf.length);
203    }
204
205    /**
206     * Deflates data (previously passed to {@link #setInput setInput}) into a specific
207     * region within the supplied buffer.
208     *
209     * @return the number of bytes of compressed data written to {@code buf}.
210     */
211    public synchronized int deflate(byte[] buf, int offset, int byteCount) {
212        return deflateImpl(buf, offset, byteCount, flushParm);
213    }
214
215    /**
216     * Deflates data (previously passed to {@link #setInput setInput}) into a specific
217     * region within the supplied buffer, optionally flushing the input buffer.
218     *
219     * @param flush one of {@link #NO_FLUSH}, {@link #SYNC_FLUSH} or {@link #FULL_FLUSH}.
220     * @return the number of compressed bytes written to {@code buf}. If this
221     *      equals {@code byteCount}, the number of bytes of input to be flushed
222     *      may have exceeded the output buffer's capacity. In this case,
223     *      finishing a flush will require the output buffer to be drained
224     *      and additional calls to {@link #deflate} to be made.
225     * @throws IllegalArgumentException if {@code flush} is invalid.
226     * @since 1.7
227     */
228    public synchronized int deflate(byte[] buf, int offset, int byteCount, int flush) {
229        if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
230            throw new IllegalArgumentException("Bad flush value: " + flush);
231        }
232        return deflateImpl(buf, offset, byteCount, flush);
233    }
234
235    private synchronized int deflateImpl(byte[] buf, int offset, int byteCount, int flush) {
236        checkOpen();
237        Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
238        if (inputBuffer == null) {
239            setInput(EmptyArray.BYTE);
240        }
241        return deflateImpl(buf, offset, byteCount, streamHandle, flush);
242    }
243
244    private native int deflateImpl(byte[] buf, int offset, int byteCount, long handle, int flushParm);
245
246    /**
247     * Frees all resources held onto by this deflating algorithm. Any unused
248     * input or output is discarded. This method should be called explicitly in
249     * order to free native resources as soon as possible. After {@code end()} is
250     * called, other methods will typically throw {@code IllegalStateException}.
251     */
252    public synchronized void end() {
253        guard.close();
254        endImpl();
255    }
256
257    private void endImpl() {
258        if (streamHandle != -1) {
259            endImpl(streamHandle);
260            inputBuffer = null;
261            streamHandle = -1;
262        }
263    }
264
265    private native void endImpl(long handle);
266
267    @Override protected void finalize() {
268        try {
269            if (guard != null) {
270                guard.warnIfOpen();
271            }
272            synchronized (this) {
273                end(); // to allow overriding classes to clean up
274                endImpl(); // in case those classes don't call super.end()
275            }
276        } finally {
277            try {
278                super.finalize();
279            } catch (Throwable t) {
280                throw new AssertionError(t);
281            }
282        }
283    }
284
285    /**
286     * Indicates to the {@code Deflater} that all uncompressed input has been provided
287     * to it.
288     *
289     * @see #finished
290     */
291    public synchronized void finish() {
292        flushParm = FINISH;
293    }
294
295    /**
296     * Returns true if {@link #finish finish} has been called and all
297     * data provided by {@link #setInput setInput} has been
298     * successfully compressed and consumed by {@link #deflate deflate}.
299     */
300    public synchronized boolean finished() {
301        return finished;
302    }
303
304    /**
305     * Returns the {@link Adler32} checksum of the uncompressed data read so far.
306     */
307    public synchronized int getAdler() {
308        checkOpen();
309        return getAdlerImpl(streamHandle);
310    }
311
312    private native int getAdlerImpl(long handle);
313
314    /**
315     * Returns the total number of bytes of input read by this {@code Deflater}. This
316     * method is limited to 32 bits; use {@link #getBytesRead} instead.
317     */
318    public synchronized int getTotalIn() {
319        checkOpen();
320        return (int) getTotalInImpl(streamHandle);
321    }
322
323    private native long getTotalInImpl(long handle);
324
325    /**
326     * Returns the total number of bytes written to the output buffer by this {@code
327     * Deflater}. The method is limited to 32 bits; use {@link #getBytesWritten} instead.
328     */
329    public synchronized int getTotalOut() {
330        checkOpen();
331        return (int) getTotalOutImpl(streamHandle);
332    }
333
334    private native long getTotalOutImpl(long handle);
335
336    /**
337     * Returns true if {@link #setInput setInput} must be called before deflation can continue.
338     * If all uncompressed data has been provided to the {@code Deflater},
339     * {@link #finish} must be called to ensure the compressed data is output.
340     */
341    public synchronized boolean needsInput() {
342        if (inputBuffer == null) {
343            return true;
344        }
345        return inRead == inLength;
346    }
347
348    /**
349     * Resets the {@code Deflater} to accept new input without affecting any
350     * previously made settings for the compression strategy or level. This
351     * operation <i>must</i> be called after {@link #finished} returns
352     * true if the {@code Deflater} is to be reused.
353     */
354    public synchronized void reset() {
355        checkOpen();
356        flushParm = NO_FLUSH;
357        finished = false;
358        resetImpl(streamHandle);
359        inputBuffer = null;
360    }
361
362    private native void resetImpl(long handle);
363
364    /**
365     * Sets the dictionary to be used for compression by this {@code Deflater}.
366     * This method can only be called if this {@code Deflater} supports the writing
367     * of ZLIB headers. This is the default, but can be overridden
368     * using {@link #Deflater(int, boolean)}.
369     */
370    public void setDictionary(byte[] dictionary) {
371        setDictionary(dictionary, 0, dictionary.length);
372    }
373
374    /**
375     * Sets the dictionary to be used for compression by this {@code Deflater}.
376     * This method can only be called if this {@code Deflater} supports the writing
377     * of ZLIB headers. This is the default, but can be overridden
378     * using {@link #Deflater(int, boolean)}.
379     */
380    public synchronized void setDictionary(byte[] buf, int offset, int byteCount) {
381        checkOpen();
382        Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
383        setDictionaryImpl(buf, offset, byteCount, streamHandle);
384    }
385
386    private native void setDictionaryImpl(byte[] buf, int offset, int byteCount, long handle);
387
388    /**
389     * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes
390     * for later compression.
391     */
392    public void setInput(byte[] buf) {
393        setInput(buf, 0, buf.length);
394    }
395
396    /**
397     * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes
398     * for later compression.
399     */
400    public synchronized void setInput(byte[] buf, int offset, int byteCount) {
401        checkOpen();
402        Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
403        inLength = byteCount;
404        inRead = 0;
405        if (inputBuffer == null) {
406            setLevelsImpl(compressLevel, strategy, streamHandle);
407        }
408        inputBuffer = buf;
409        setInputImpl(buf, offset, byteCount, streamHandle);
410    }
411
412    private native void setLevelsImpl(int level, int strategy, long handle);
413
414    private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle);
415
416    /**
417     * Sets the given <a href="#compression_level">compression level</a>
418     * to be used when compressing data. This value must be set
419     * prior to calling {@link #setInput setInput}.
420     * @exception IllegalArgumentException
421     *                If the compression level is invalid.
422     */
423    public synchronized void setLevel(int level) {
424        if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
425            throw new IllegalArgumentException("Bad level: " + level);
426        }
427        if (inputBuffer != null) {
428            throw new IllegalStateException("setLevel cannot be called after setInput");
429        }
430        compressLevel = level;
431    }
432
433    /**
434     * Sets the compression strategy to be used. The strategy must be one of
435     * FILTERED, HUFFMAN_ONLY or DEFAULT_STRATEGY. This value must be set prior
436     * to calling {@link #setInput setInput}.
437     *
438     * @exception IllegalArgumentException
439     *                If the strategy specified is not one of FILTERED,
440     *                HUFFMAN_ONLY or DEFAULT_STRATEGY.
441     */
442    public synchronized void setStrategy(int strategy) {
443        if (strategy < DEFAULT_STRATEGY || strategy > HUFFMAN_ONLY) {
444            throw new IllegalArgumentException("Bad strategy: " + strategy);
445        }
446        if (inputBuffer != null) {
447            throw new IllegalStateException("setStrategy cannot be called after setInput");
448        }
449        this.strategy = strategy;
450    }
451
452    /**
453     * Returns the total number of bytes read by the {@code Deflater}. This
454     * method is the same as {@link #getTotalIn} except that it returns a
455     * {@code long} value instead of an integer.
456     */
457    public synchronized long getBytesRead() {
458        checkOpen();
459        return getTotalInImpl(streamHandle);
460    }
461
462    /**
463     * Returns a the total number of bytes written by this {@code Deflater}. This
464     * method is the same as {@code getTotalOut} except it returns a
465     * {@code long} value instead of an integer.
466     */
467    public synchronized long getBytesWritten() {
468        checkOpen();
469        return getTotalOutImpl(streamHandle);
470    }
471
472    private native long createStream(int level, int strategy1, boolean noHeader1);
473
474    private void checkOpen() {
475        if (streamHandle == -1) {
476            throw new IllegalStateException("attempt to use Deflater after calling end");
477        }
478    }
479}
480