• 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 public class Deflater {
55 
56     /**
57      * Upper bound for the compression level range.
58      */
59     public static final int BEST_COMPRESSION = 9;
60 
61     /**
62      * Lower bound for compression level range.
63      */
64     public static final int BEST_SPEED = 1;
65 
66     /**
67      * The default compression level.
68      */
69     public static final int DEFAULT_COMPRESSION = -1;
70 
71     /**
72      * The default compression strategy.
73      */
74     public static final int DEFAULT_STRATEGY = 0;
75 
76     /**
77      * The default compression method.
78      */
79     public static final int DEFLATED = 8;
80 
81     /**
82      * A compression strategy.
83      */
84     public static final int FILTERED = 1;
85 
86     /**
87      * A compression strategy.
88      */
89     public static final int HUFFMAN_ONLY = 2;
90 
91     /**
92      * A compression level.
93      */
94     public static final int NO_COMPRESSION = 0;
95 
96     /**
97      * Use buffering for best compression.
98      *
99      * @hide
100      * @since 1.7
101      */
102     public static final int NO_FLUSH = 0;
103 
104     /**
105      * Flush buffers so recipients can immediately decode the data sent thus
106      * far. This mode may degrade compression.
107      *
108      * @hide
109      * @since 1.7
110      */
111     public static final int SYNC_FLUSH = 2;
112 
113     /**
114      * Flush buffers so recipients can immediately decode the data sent thus
115      * far. The compression state is also reset to permit random access and
116      * recovery for clients who have discarded or damaged their own copy. This
117      * mode may degrade compression.
118      *
119      * @hide
120      * @since 1.7
121      */
122     public static final int FULL_FLUSH = 3;
123 
124     /**
125      * Flush buffers and mark the end of the data stream.
126      */
127     private static final int FINISH = 4;
128 
129     /**
130      * The ugly name flushParm is for RI compatibility, should code need to access this
131      * field via reflection if it's not able to use public API to choose what
132      * kind of flushing it gets.
133      */
134     private int flushParm = NO_FLUSH;
135 
136     private boolean finished;
137 
138     private int compressLevel = DEFAULT_COMPRESSION;
139 
140     private int strategy = DEFAULT_STRATEGY;
141 
142     private long streamHandle = -1;
143 
144     private byte[] inputBuffer;
145 
146     private int inRead;
147 
148     private int inLength;
149 
150     private final CloseGuard guard = CloseGuard.get();
151 
152     /**
153      * Constructs a new {@code Deflater} instance using the default compression
154      * level. The strategy can be specified with {@link #setStrategy}. A
155      * header is added to the output by default; use {@link
156      * #Deflater(int, boolean)} if you need to omit the header.
157      */
Deflater()158     public Deflater() {
159         this(DEFAULT_COMPRESSION, false);
160     }
161 
162     /**
163      * Constructs a new {@code Deflater} instance using compression
164      * level {@code level}. The strategy can be specified with {@link #setStrategy}.
165      * A header is added to the output by default; use
166      * {@link #Deflater(int, boolean)} if you need to omit the header.
167      *
168      * @param level
169      *            the compression level in the range between 0 and 9.
170      */
Deflater(int level)171     public Deflater(int level) {
172         this(level, false);
173     }
174 
175     /**
176      * Constructs a new {@code Deflater} instance with a specific compression
177      * level. If {@code noHeader} is true, no ZLIB header is added to the
178      * output. In a ZIP archive every entry (compressed file) comes with such a
179      * header. The strategy can be specified using {@link #setStrategy}.
180      *
181      * @param level
182      *            the compression level in the range between 0 and 9.
183      * @param noHeader
184      *            {@code true} indicates that no ZLIB header should be written.
185      */
Deflater(int level, boolean noHeader)186     public Deflater(int level, boolean noHeader) {
187         if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
188             throw new IllegalArgumentException();
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      */
deflate(byte[] buf)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      */
deflate(byte[] buf, int offset, int byteCount)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      * @hide
226      * @since 1.7
227      */
deflate(byte[] buf, int offset, int byteCount, int flush)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 
deflateImpl(byte[] buf, int offset, int byteCount, int flush)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 
deflateImpl(byte[] buf, int offset, int byteCount, long handle, int flushParm)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      */
end()252     public synchronized void end() {
253         guard.close();
254         endImpl();
255     }
256 
endImpl()257     private void endImpl() {
258         if (streamHandle != -1) {
259             endImpl(streamHandle);
260             inputBuffer = null;
261             streamHandle = -1;
262         }
263     }
264 
endImpl(long handle)265     private native void endImpl(long handle);
266 
finalize()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      */
finish()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      */
finished()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      */
getAdler()307     public synchronized int getAdler() {
308         checkOpen();
309         return getAdlerImpl(streamHandle);
310     }
311 
getAdlerImpl(long handle)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      */
getTotalIn()318     public synchronized int getTotalIn() {
319         checkOpen();
320         return (int) getTotalInImpl(streamHandle);
321     }
322 
getTotalInImpl(long handle)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      */
getTotalOut()329     public synchronized int getTotalOut() {
330         checkOpen();
331         return (int) getTotalOutImpl(streamHandle);
332     }
333 
getTotalOutImpl(long handle)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      */
needsInput()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      */
reset()354     public synchronized void reset() {
355         checkOpen();
356         flushParm = NO_FLUSH;
357         finished = false;
358         resetImpl(streamHandle);
359         inputBuffer = null;
360     }
361 
resetImpl(long handle)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      */
setDictionary(byte[] dictionary)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      */
setDictionary(byte[] buf, int offset, int byteCount)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 
setDictionaryImpl(byte[] buf, int offset, int byteCount, long handle)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      */
setInput(byte[] buf)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      */
setInput(byte[] buf, int offset, int byteCount)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 
setLevelsImpl(int level, int strategy, long handle)412     private native void setLevelsImpl(int level, int strategy, long handle);
413 
setInputImpl(byte[] buf, int offset, int byteCount, long handle)414     private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle);
415 
416     /**
417      * Sets the compression level to be used when compressing data. The
418      * compression level must be a value between 0 and 9. This value must be set
419      * prior to calling {@link #setInput setInput}.
420      * @exception IllegalArgumentException
421      *                If the compression level is invalid.
422      */
setLevel(int level)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      */
setStrategy(int strategy)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      */
getBytesRead()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      */
getBytesWritten()467     public synchronized long getBytesWritten() {
468         checkOpen();
469         return getTotalOutImpl(streamHandle);
470     }
471 
createStream(int level, int strategy1, boolean noHeader1)472     private native long createStream(int level, int strategy1, boolean noHeader1);
473 
checkOpen()474     private void checkOpen() {
475         if (streamHandle == -1) {
476             throw new IllegalStateException("attempt to use Deflater after calling end");
477         }
478     }
479 }
480