• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 package java.util.zip;
19 
20 import dalvik.system.CloseGuard;
21 import java.util.Arrays;
22 import 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  */
60 public 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      *
110      * @hide
111      * @since 1.7
112      */
113     public static final int NO_FLUSH = 0;
114 
115     /**
116      * Flush buffers so recipients can immediately decode the data sent thus
117      * far. This mode may degrade compression.
118      *
119      * @hide
120      * @since 1.7
121      */
122     public static final int SYNC_FLUSH = 2;
123 
124     /**
125      * Flush buffers so recipients can immediately decode the data sent thus
126      * far. The compression state is also reset to permit random access and
127      * recovery for clients who have discarded or damaged their own copy. This
128      * mode may degrade compression.
129      *
130      * @hide
131      * @since 1.7
132      */
133     public static final int FULL_FLUSH = 3;
134 
135     /**
136      * Flush buffers and mark the end of the data stream.
137      */
138     private static final int FINISH = 4;
139 
140     /**
141      * The ugly name flushParm is for RI compatibility, should code need to access this
142      * field via reflection if it's not able to use public API to choose what
143      * kind of flushing it gets.
144      */
145     private int flushParm = NO_FLUSH;
146 
147     private boolean finished;
148 
149     private int compressLevel = DEFAULT_COMPRESSION;
150 
151     private int strategy = DEFAULT_STRATEGY;
152 
153     private long streamHandle = -1;
154 
155     private byte[] inputBuffer;
156 
157     private int inRead;
158 
159     private int inLength;
160 
161     private final CloseGuard guard = CloseGuard.get();
162 
163     /**
164      * Constructs a new {@code Deflater} instance using the
165      * default <a href="#compression_level">compression level</a>.
166      * The compression strategy can be specified with {@link #setStrategy}. A
167      * header is added to the output by default; use {@link
168      * #Deflater(int, boolean)} if you need to omit the header.
169      */
Deflater()170     public Deflater() {
171         this(DEFAULT_COMPRESSION, false);
172     }
173 
174     /**
175      * Constructs a new {@code Deflater} instance with the
176      * given <a href="#compression_level">compression level</a>.
177      * The compression strategy can be specified with {@link #setStrategy}.
178      * A header is added to the output by default; use
179      * {@link #Deflater(int, boolean)} if you need to omit the header.
180      */
Deflater(int level)181     public Deflater(int level) {
182         this(level, false);
183     }
184 
185     /**
186      * Constructs a new {@code Deflater} instance with the
187      * given <a href="#compression_level">compression level</a>.
188      * If {@code noHeader} is true, no ZLIB header is added to the
189      * output. In a zip file, every entry (compressed file) comes with such a
190      * header. The strategy can be specified using {@link #setStrategy}.
191      */
Deflater(int level, boolean noHeader)192     public Deflater(int level, boolean noHeader) {
193         if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
194             throw new IllegalArgumentException("Bad level: " + level);
195         }
196         compressLevel = level;
197         streamHandle = createStream(compressLevel, strategy, noHeader);
198         guard.open("end");
199     }
200 
201     /**
202      * Deflates the data (previously passed to {@link #setInput setInput}) into the
203      * supplied buffer.
204      *
205      * @return number of bytes of compressed data written to {@code buf}.
206      */
deflate(byte[] buf)207     public int deflate(byte[] buf) {
208         return deflate(buf, 0, buf.length);
209     }
210 
211     /**
212      * Deflates data (previously passed to {@link #setInput setInput}) into a specific
213      * region within the supplied buffer.
214      *
215      * @return the number of bytes of compressed data written to {@code buf}.
216      */
deflate(byte[] buf, int offset, int byteCount)217     public synchronized int deflate(byte[] buf, int offset, int byteCount) {
218         return deflateImpl(buf, offset, byteCount, flushParm);
219     }
220 
221     /**
222      * Deflates data (previously passed to {@link #setInput setInput}) into a specific
223      * region within the supplied buffer, optionally flushing the input buffer.
224      *
225      * @param flush one of {@link #NO_FLUSH}, {@link #SYNC_FLUSH} or {@link #FULL_FLUSH}.
226      * @return the number of compressed bytes written to {@code buf}. If this
227      *      equals {@code byteCount}, the number of bytes of input to be flushed
228      *      may have exceeded the output buffer's capacity. In this case,
229      *      finishing a flush will require the output buffer to be drained
230      *      and additional calls to {@link #deflate} to be made.
231      * @hide
232      * @since 1.7
233      */
deflate(byte[] buf, int offset, int byteCount, int flush)234     public synchronized int deflate(byte[] buf, int offset, int byteCount, int flush) {
235         if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
236             throw new IllegalArgumentException("Bad flush value: " + flush);
237         }
238         return deflateImpl(buf, offset, byteCount, flush);
239     }
240 
deflateImpl(byte[] buf, int offset, int byteCount, int flush)241     private synchronized int deflateImpl(byte[] buf, int offset, int byteCount, int flush) {
242         checkOpen();
243         Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
244         if (inputBuffer == null) {
245             setInput(EmptyArray.BYTE);
246         }
247         return deflateImpl(buf, offset, byteCount, streamHandle, flush);
248     }
249 
deflateImpl(byte[] buf, int offset, int byteCount, long handle, int flushParm)250     private native int deflateImpl(byte[] buf, int offset, int byteCount, long handle, int flushParm);
251 
252     /**
253      * Frees all resources held onto by this deflating algorithm. Any unused
254      * input or output is discarded. This method should be called explicitly in
255      * order to free native resources as soon as possible. After {@code end()} is
256      * called, other methods will typically throw {@code IllegalStateException}.
257      */
end()258     public synchronized void end() {
259         guard.close();
260         endImpl();
261     }
262 
endImpl()263     private void endImpl() {
264         if (streamHandle != -1) {
265             endImpl(streamHandle);
266             inputBuffer = null;
267             streamHandle = -1;
268         }
269     }
270 
endImpl(long handle)271     private native void endImpl(long handle);
272 
finalize()273     @Override protected void finalize() {
274         try {
275             if (guard != null) {
276                 guard.warnIfOpen();
277             }
278             synchronized (this) {
279                 end(); // to allow overriding classes to clean up
280                 endImpl(); // in case those classes don't call super.end()
281             }
282         } finally {
283             try {
284                 super.finalize();
285             } catch (Throwable t) {
286                 throw new AssertionError(t);
287             }
288         }
289     }
290 
291     /**
292      * Indicates to the {@code Deflater} that all uncompressed input has been provided
293      * to it.
294      *
295      * @see #finished
296      */
finish()297     public synchronized void finish() {
298         flushParm = FINISH;
299     }
300 
301     /**
302      * Returns true if {@link #finish finish} has been called and all
303      * data provided by {@link #setInput setInput} has been
304      * successfully compressed and consumed by {@link #deflate deflate}.
305      */
finished()306     public synchronized boolean finished() {
307         return finished;
308     }
309 
310     /**
311      * Returns the {@link Adler32} checksum of the uncompressed data read so far.
312      */
getAdler()313     public synchronized int getAdler() {
314         checkOpen();
315         return getAdlerImpl(streamHandle);
316     }
317 
getAdlerImpl(long handle)318     private native int getAdlerImpl(long handle);
319 
320     /**
321      * Returns the total number of bytes of input read by this {@code Deflater}. This
322      * method is limited to 32 bits; use {@link #getBytesRead} instead.
323      */
getTotalIn()324     public synchronized int getTotalIn() {
325         checkOpen();
326         return (int) getTotalInImpl(streamHandle);
327     }
328 
getTotalInImpl(long handle)329     private native long getTotalInImpl(long handle);
330 
331     /**
332      * Returns the total number of bytes written to the output buffer by this {@code
333      * Deflater}. The method is limited to 32 bits; use {@link #getBytesWritten} instead.
334      */
getTotalOut()335     public synchronized int getTotalOut() {
336         checkOpen();
337         return (int) getTotalOutImpl(streamHandle);
338     }
339 
getTotalOutImpl(long handle)340     private native long getTotalOutImpl(long handle);
341 
342     /**
343      * Returns true if {@link #setInput setInput} must be called before deflation can continue.
344      * If all uncompressed data has been provided to the {@code Deflater},
345      * {@link #finish} must be called to ensure the compressed data is output.
346      */
needsInput()347     public synchronized boolean needsInput() {
348         if (inputBuffer == null) {
349             return true;
350         }
351         return inRead == inLength;
352     }
353 
354     /**
355      * Resets the {@code Deflater} to accept new input without affecting any
356      * previously made settings for the compression strategy or level. This
357      * operation <i>must</i> be called after {@link #finished} returns
358      * true if the {@code Deflater} is to be reused.
359      */
reset()360     public synchronized void reset() {
361         checkOpen();
362         flushParm = NO_FLUSH;
363         finished = false;
364         resetImpl(streamHandle);
365         inputBuffer = null;
366     }
367 
resetImpl(long handle)368     private native void resetImpl(long handle);
369 
370     /**
371      * Sets the dictionary to be used for compression by this {@code Deflater}.
372      * This method can only be called if this {@code Deflater} supports the writing
373      * of ZLIB headers. This is the default, but can be overridden
374      * using {@link #Deflater(int, boolean)}.
375      */
setDictionary(byte[] dictionary)376     public void setDictionary(byte[] dictionary) {
377         setDictionary(dictionary, 0, dictionary.length);
378     }
379 
380     /**
381      * Sets the dictionary to be used for compression by this {@code Deflater}.
382      * This method can only be called if this {@code Deflater} supports the writing
383      * of ZLIB headers. This is the default, but can be overridden
384      * using {@link #Deflater(int, boolean)}.
385      */
setDictionary(byte[] buf, int offset, int byteCount)386     public synchronized void setDictionary(byte[] buf, int offset, int byteCount) {
387         checkOpen();
388         Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
389         setDictionaryImpl(buf, offset, byteCount, streamHandle);
390     }
391 
setDictionaryImpl(byte[] buf, int offset, int byteCount, long handle)392     private native void setDictionaryImpl(byte[] buf, int offset, int byteCount, long handle);
393 
394     /**
395      * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes
396      * for later compression.
397      */
setInput(byte[] buf)398     public void setInput(byte[] buf) {
399         setInput(buf, 0, buf.length);
400     }
401 
402     /**
403      * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes
404      * for later compression.
405      */
setInput(byte[] buf, int offset, int byteCount)406     public synchronized void setInput(byte[] buf, int offset, int byteCount) {
407         checkOpen();
408         Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
409         inLength = byteCount;
410         inRead = 0;
411         if (inputBuffer == null) {
412             setLevelsImpl(compressLevel, strategy, streamHandle);
413         }
414         inputBuffer = buf;
415         setInputImpl(buf, offset, byteCount, streamHandle);
416     }
417 
setLevelsImpl(int level, int strategy, long handle)418     private native void setLevelsImpl(int level, int strategy, long handle);
419 
setInputImpl(byte[] buf, int offset, int byteCount, long handle)420     private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle);
421 
422     /**
423      * Sets the given <a href="#compression_level">compression level</a>
424      * to be used when compressing data. This value must be set
425      * prior to calling {@link #setInput setInput}.
426      * @exception IllegalArgumentException
427      *                If the compression level is invalid.
428      */
setLevel(int level)429     public synchronized void setLevel(int level) {
430         if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
431             throw new IllegalArgumentException("Bad level: " + level);
432         }
433         if (inputBuffer != null) {
434             throw new IllegalStateException("setLevel cannot be called after setInput");
435         }
436         compressLevel = level;
437     }
438 
439     /**
440      * Sets the compression strategy to be used. The strategy must be one of
441      * FILTERED, HUFFMAN_ONLY or DEFAULT_STRATEGY. This value must be set prior
442      * to calling {@link #setInput setInput}.
443      *
444      * @exception IllegalArgumentException
445      *                If the strategy specified is not one of FILTERED,
446      *                HUFFMAN_ONLY or DEFAULT_STRATEGY.
447      */
setStrategy(int strategy)448     public synchronized void setStrategy(int strategy) {
449         if (strategy < DEFAULT_STRATEGY || strategy > HUFFMAN_ONLY) {
450             throw new IllegalArgumentException("Bad strategy: " + strategy);
451         }
452         if (inputBuffer != null) {
453             throw new IllegalStateException("setStrategy cannot be called after setInput");
454         }
455         this.strategy = strategy;
456     }
457 
458     /**
459      * Returns the total number of bytes read by the {@code Deflater}. This
460      * method is the same as {@link #getTotalIn} except that it returns a
461      * {@code long} value instead of an integer.
462      */
getBytesRead()463     public synchronized long getBytesRead() {
464         checkOpen();
465         return getTotalInImpl(streamHandle);
466     }
467 
468     /**
469      * Returns a the total number of bytes written by this {@code Deflater}. This
470      * method is the same as {@code getTotalOut} except it returns a
471      * {@code long} value instead of an integer.
472      */
getBytesWritten()473     public synchronized long getBytesWritten() {
474         checkOpen();
475         return getTotalOutImpl(streamHandle);
476     }
477 
createStream(int level, int strategy1, boolean noHeader1)478     private native long createStream(int level, int strategy1, boolean noHeader1);
479 
checkOpen()480     private void checkOpen() {
481         if (streamHandle == -1) {
482             throw new IllegalStateException("attempt to use Deflater after calling end");
483         }
484     }
485 }
486