8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.util.zip;
27
28 /**
29 * This class provides support for general purpose compression using the
30 * popular ZLIB compression library. The ZLIB compression library was
31 * initially developed as part of the PNG graphics standard and is not
32 * protected by patents. It is fully described in the specifications at
33 * the <a href="package-summary.html#package.description">java.util.zip
34 * package description</a>.
35 *
36 * <p>The following code fragment demonstrates a trivial compression
37 * and decompression of a string using {@code Deflater} and
38 * {@code Inflater}.
39 *
40 * <blockquote><pre>
41 * try {
42 * // Encode a String into bytes
43 * String inputString = "blahblahblah";
44 * byte[] input = inputString.getBytes("UTF-8");
45 *
46 * // Compress the bytes
47 * byte[] output = new byte[100];
50 * compresser.finish();
51 * int compressedDataLength = compresser.deflate(output);
52 * compresser.end();
53 *
54 * // Decompress the bytes
55 * Inflater decompresser = new Inflater();
56 * decompresser.setInput(output, 0, compressedDataLength);
57 * byte[] result = new byte[100];
58 * int resultLength = decompresser.inflate(result);
59 * decompresser.end();
60 *
61 * // Decode the bytes into a String
62 * String outputString = new String(result, 0, resultLength, "UTF-8");
63 * } catch(java.io.UnsupportedEncodingException ex) {
64 * // handle
65 * } catch (java.util.zip.DataFormatException ex) {
66 * // handle
67 * }
68 * </pre></blockquote>
69 *
70 * @see Inflater
71 * @author David Connelly
72 * @since 1.1
73 */
74 public
75 class Deflater {
76
77 private final ZStreamRef zsRef;
78 private byte[] buf = new byte[0];
79 private int off, len;
80 private int level, strategy;
81 private boolean setParams;
82 private boolean finish, finished;
83 private long bytesRead;
84 private long bytesWritten;
85
86 /**
87 * Compression method for the deflate algorithm (the only one currently
88 * supported).
89 */
90 public static final int DEFLATED = 8;
91
92 /**
93 * Compression level for no compression.
94 */
95 public static final int NO_COMPRESSION = 0;
96
97 /**
152 * @since 1.7
153 */
154 public static final int FULL_FLUSH = 3;
155
156 static {
157 ZipUtils.loadLibrary();
158 initIDs();
159 }
160
161 /**
162 * Creates a new compressor using the specified compression level.
163 * If 'nowrap' is true then the ZLIB header and checksum fields will
164 * not be used in order to support the compression format used in
165 * both GZIP and PKZIP.
166 * @param level the compression level (0-9)
167 * @param nowrap if true then use GZIP compatible compression
168 */
169 public Deflater(int level, boolean nowrap) {
170 this.level = level;
171 this.strategy = DEFAULT_STRATEGY;
172 this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap));
173 }
174
175 /**
176 * Creates a new compressor using the specified compression level.
177 * Compressed data will be generated in ZLIB format.
178 * @param level the compression level (0-9)
179 */
180 public Deflater(int level) {
181 this(level, false);
182 }
183
184 /**
185 * Creates a new compressor with the default compression level.
186 * Compressed data will be generated in ZLIB format.
187 */
188 public Deflater() {
189 this(DEFAULT_COMPRESSION, false);
190 }
191
192 /**
225 * Sets preset dictionary for compression. A preset dictionary is used
226 * when the history buffer can be predetermined. When the data is later
227 * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
228 * in order to get the Adler-32 value of the dictionary required for
229 * decompression.
230 * @param b the dictionary data bytes
231 * @param off the start offset of the data
232 * @param len the length of the data
233 * @see Inflater#inflate
234 * @see Inflater#getAdler
235 */
236 public void setDictionary(byte[] b, int off, int len) {
237 if (b == null) {
238 throw new NullPointerException();
239 }
240 if (off < 0 || len < 0 || off > b.length - len) {
241 throw new ArrayIndexOutOfBoundsException();
242 }
243 synchronized (zsRef) {
244 ensureOpen();
245 setDictionary(zsRef.address(), b, off, len);
246 }
247 }
248
249 /**
250 * Sets preset dictionary for compression. A preset dictionary is used
251 * when the history buffer can be predetermined. When the data is later
252 * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
253 * in order to get the Adler-32 value of the dictionary required for
254 * decompression.
255 * @param b the dictionary data bytes
256 * @see Inflater#inflate
257 * @see Inflater#getAdler
258 */
259 public void setDictionary(byte[] b) {
260 setDictionary(b, 0, b.length);
261 }
262
263 /**
264 * Sets the compression strategy to the specified value.
265 *
428 * @param len the maximum number of bytes of compressed data
429 * @param flush the compression flush mode
430 * @return the actual number of bytes of compressed data written to
431 * the output buffer
432 *
433 * @throws IllegalArgumentException if the flush mode is invalid
434 * @since 1.7
435 */
436 public int deflate(byte[] b, int off, int len, int flush) {
437 if (b == null) {
438 throw new NullPointerException();
439 }
440 if (off < 0 || len < 0 || off > b.length - len) {
441 throw new ArrayIndexOutOfBoundsException();
442 }
443 synchronized (zsRef) {
444 ensureOpen();
445 if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
446 flush == FULL_FLUSH) {
447 int thisLen = this.len;
448 int n = deflateBytes(zsRef.address(), b, off, len, flush);
449 bytesWritten += n;
450 bytesRead += (thisLen - this.len);
451 return n;
452 }
453 throw new IllegalArgumentException();
454 }
455 }
456
457 /**
458 * Returns the ADLER-32 value of the uncompressed data.
459 * @return the ADLER-32 value of the uncompressed data
460 */
461 public int getAdler() {
462 synchronized (zsRef) {
463 ensureOpen();
464 return getAdler(zsRef.address());
465 }
466 }
467
468 /**
469 * Returns the total number of uncompressed bytes input so far.
470 *
471 * <p>Since the number of bytes may be greater than
472 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
473 * the preferred means of obtaining this information.</p>
474 *
475 * @return the total number of uncompressed bytes input so far
476 */
477 public int getTotalIn() {
478 return (int) getBytesRead();
479 }
480
481 /**
482 * Returns the total number of uncompressed bytes input so far.
483 *
484 * @return the total (non-negative) number of uncompressed bytes input so far
507 /**
508 * Returns the total number of compressed bytes output so far.
509 *
510 * @return the total (non-negative) number of compressed bytes output so far
511 * @since 1.5
512 */
513 public long getBytesWritten() {
514 synchronized (zsRef) {
515 ensureOpen();
516 return bytesWritten;
517 }
518 }
519
520 /**
521 * Resets deflater so that a new set of input data can be processed.
522 * Keeps current compression level and strategy settings.
523 */
524 public void reset() {
525 synchronized (zsRef) {
526 ensureOpen();
527 reset(zsRef.address());
528 finish = false;
529 finished = false;
530 off = len = 0;
531 bytesRead = bytesWritten = 0;
532 }
533 }
534
535 /**
536 * Closes the compressor and discards any unprocessed input.
537 * This method should be called when the compressor is no longer
538 * being used, but will also be called automatically by the
539 * finalize() method. Once this method is called, the behavior
540 * of the Deflater object is undefined.
541 */
542 public void end() {
543 synchronized (zsRef) {
544 long addr = zsRef.address();
545 zsRef.clear();
546 if (addr != 0) {
547 end(addr);
548 buf = null;
549 }
550 }
551 }
552
553 /**
554 * Closes the compressor when garbage is collected.
555 *
556 * @deprecated The {@code finalize} method has been deprecated.
557 * Subclasses that override {@code finalize} in order to perform cleanup
558 * should be modified to use alternative cleanup mechanisms and
559 * to remove the overriding {@code finalize} method.
560 * When overriding the {@code finalize} method, its implementation must explicitly
561 * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
562 * See the specification for {@link Object#finalize()} for further
563 * information about migration options.
564 */
565 @Deprecated(since="9")
566 protected void finalize() {
567 end();
568 }
569
570 private void ensureOpen() {
571 assert Thread.holdsLock(zsRef);
572 if (zsRef.address() == 0)
573 throw new NullPointerException("Deflater has been closed");
574 }
575
576 private static native void initIDs();
577 private static native long init(int level, int strategy, boolean nowrap);
578 private static native void setDictionary(long addr, byte[] b, int off, int len);
579 private native int deflateBytes(long addr, byte[] b, int off, int len,
580 int flush);
581 private static native int getAdler(long addr);
582 private static native void reset(long addr);
583 private static native void end(long addr);
584 }
|
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.util.zip;
27
28 import jdk.internal.ref.CleanerFactory;
29
30 import java.lang.ref.Cleaner;
31 import java.lang.ref.Reference;
32
33 /**
34 * This class provides support for general purpose compression using the
35 * popular ZLIB compression library. The ZLIB compression library was
36 * initially developed as part of the PNG graphics standard and is not
37 * protected by patents. It is fully described in the specifications at
38 * the <a href="package-summary.html#package.description">java.util.zip
39 * package description</a>.
40 *
41 * <p>The following code fragment demonstrates a trivial compression
42 * and decompression of a string using {@code Deflater} and
43 * {@code Inflater}.
44 *
45 * <blockquote><pre>
46 * try {
47 * // Encode a String into bytes
48 * String inputString = "blahblahblah";
49 * byte[] input = inputString.getBytes("UTF-8");
50 *
51 * // Compress the bytes
52 * byte[] output = new byte[100];
55 * compresser.finish();
56 * int compressedDataLength = compresser.deflate(output);
57 * compresser.end();
58 *
59 * // Decompress the bytes
60 * Inflater decompresser = new Inflater();
61 * decompresser.setInput(output, 0, compressedDataLength);
62 * byte[] result = new byte[100];
63 * int resultLength = decompresser.inflate(result);
64 * decompresser.end();
65 *
66 * // Decode the bytes into a String
67 * String outputString = new String(result, 0, resultLength, "UTF-8");
68 * } catch(java.io.UnsupportedEncodingException ex) {
69 * // handle
70 * } catch (java.util.zip.DataFormatException ex) {
71 * // handle
72 * }
73 * </pre></blockquote>
74 *
75 * <p>
76 * @apiNote
77 * In earlier versions the {@link Object#finalize} method was overridden and
78 * specified to call the {@code end} method to close the {@code deflater} and
79 * release the resource when the instance becomes unreachable.
80 * The {@code finalize} method is no longer defined. The recommended cleanup
81 * for compressor is to explicitly call {@code end} method when it is no
82 * longer in use.
83 *
84 * @implNote
85 * The resource of the compressor will be released when the instance becomes
86 * phantom-reachable, if the {@code end} is not invoked explicitly.
87 * <p>
88 *
89 * @see Inflater
90 * @author David Connelly
91 * @since 1.1
92 */
93 public
94 class Deflater {
95
96 private final Cleaner.LongCleanableResource zsRef;
97 private byte[] buf = new byte[0];
98 private int off, len;
99 private int level, strategy;
100 private boolean setParams;
101 private boolean finish, finished;
102 private long bytesRead;
103 private long bytesWritten;
104
105 /**
106 * Compression method for the deflate algorithm (the only one currently
107 * supported).
108 */
109 public static final int DEFLATED = 8;
110
111 /**
112 * Compression level for no compression.
113 */
114 public static final int NO_COMPRESSION = 0;
115
116 /**
171 * @since 1.7
172 */
173 public static final int FULL_FLUSH = 3;
174
175 static {
176 ZipUtils.loadLibrary();
177 initIDs();
178 }
179
180 /**
181 * Creates a new compressor using the specified compression level.
182 * If 'nowrap' is true then the ZLIB header and checksum fields will
183 * not be used in order to support the compression format used in
184 * both GZIP and PKZIP.
185 * @param level the compression level (0-9)
186 * @param nowrap if true then use GZIP compatible compression
187 */
188 public Deflater(int level, boolean nowrap) {
189 this.level = level;
190 this.strategy = DEFAULT_STRATEGY;
191 this.zsRef = CleanerFactory
192 .cleaner()
193 .createLongResource(this,
194 () -> init(level, DEFAULT_STRATEGY, nowrap),
195 Deflater::end);
196 }
197
198 /**
199 * Creates a new compressor using the specified compression level.
200 * Compressed data will be generated in ZLIB format.
201 * @param level the compression level (0-9)
202 */
203 public Deflater(int level) {
204 this(level, false);
205 }
206
207 /**
208 * Creates a new compressor with the default compression level.
209 * Compressed data will be generated in ZLIB format.
210 */
211 public Deflater() {
212 this(DEFAULT_COMPRESSION, false);
213 }
214
215 /**
248 * Sets preset dictionary for compression. A preset dictionary is used
249 * when the history buffer can be predetermined. When the data is later
250 * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
251 * in order to get the Adler-32 value of the dictionary required for
252 * decompression.
253 * @param b the dictionary data bytes
254 * @param off the start offset of the data
255 * @param len the length of the data
256 * @see Inflater#inflate
257 * @see Inflater#getAdler
258 */
259 public void setDictionary(byte[] b, int off, int len) {
260 if (b == null) {
261 throw new NullPointerException();
262 }
263 if (off < 0 || len < 0 || off > b.length - len) {
264 throw new ArrayIndexOutOfBoundsException();
265 }
266 synchronized (zsRef) {
267 ensureOpen();
268 setDictionary(zsRef.value(), b, off, len);
269 Reference.reachabilityFence(this);
270 }
271 }
272
273 /**
274 * Sets preset dictionary for compression. A preset dictionary is used
275 * when the history buffer can be predetermined. When the data is later
276 * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
277 * in order to get the Adler-32 value of the dictionary required for
278 * decompression.
279 * @param b the dictionary data bytes
280 * @see Inflater#inflate
281 * @see Inflater#getAdler
282 */
283 public void setDictionary(byte[] b) {
284 setDictionary(b, 0, b.length);
285 }
286
287 /**
288 * Sets the compression strategy to the specified value.
289 *
452 * @param len the maximum number of bytes of compressed data
453 * @param flush the compression flush mode
454 * @return the actual number of bytes of compressed data written to
455 * the output buffer
456 *
457 * @throws IllegalArgumentException if the flush mode is invalid
458 * @since 1.7
459 */
460 public int deflate(byte[] b, int off, int len, int flush) {
461 if (b == null) {
462 throw new NullPointerException();
463 }
464 if (off < 0 || len < 0 || off > b.length - len) {
465 throw new ArrayIndexOutOfBoundsException();
466 }
467 synchronized (zsRef) {
468 ensureOpen();
469 if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
470 flush == FULL_FLUSH) {
471 int thisLen = this.len;
472 int n = deflateBytes(zsRef.value(), b, off, len, flush);
473 Reference.reachabilityFence(this);
474 bytesWritten += n;
475 bytesRead += (thisLen - this.len);
476 return n;
477 }
478 throw new IllegalArgumentException();
479 }
480 }
481
482 /**
483 * Returns the ADLER-32 value of the uncompressed data.
484 * @return the ADLER-32 value of the uncompressed data
485 */
486 public int getAdler() {
487 synchronized (zsRef) {
488 ensureOpen();
489 int adler = getAdler(zsRef.value());
490 Reference.reachabilityFence(this);
491 return adler;
492 }
493 }
494
495 /**
496 * Returns the total number of uncompressed bytes input so far.
497 *
498 * <p>Since the number of bytes may be greater than
499 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
500 * the preferred means of obtaining this information.</p>
501 *
502 * @return the total number of uncompressed bytes input so far
503 */
504 public int getTotalIn() {
505 return (int) getBytesRead();
506 }
507
508 /**
509 * Returns the total number of uncompressed bytes input so far.
510 *
511 * @return the total (non-negative) number of uncompressed bytes input so far
534 /**
535 * Returns the total number of compressed bytes output so far.
536 *
537 * @return the total (non-negative) number of compressed bytes output so far
538 * @since 1.5
539 */
540 public long getBytesWritten() {
541 synchronized (zsRef) {
542 ensureOpen();
543 return bytesWritten;
544 }
545 }
546
547 /**
548 * Resets deflater so that a new set of input data can be processed.
549 * Keeps current compression level and strategy settings.
550 */
551 public void reset() {
552 synchronized (zsRef) {
553 ensureOpen();
554 reset(zsRef.value());
555 Reference.reachabilityFence(this);
556 finish = false;
557 finished = false;
558 off = len = 0;
559 bytesRead = bytesWritten = 0;
560 }
561 }
562
563 /**
564 * Closes the compressor and discards any unprocessed input.
565 *
566 * This method should be called when the compressor is no longer
567 * being used. Once this method is called, the behavior of the
568 * Deflater object is undefined.
569 */
570 public void end() {
571 synchronized (zsRef) {
572 zsRef.clean();
573 buf = null;
574 }
575 }
576
577 private void ensureOpen() {
578 assert Thread.holdsLock(zsRef);
579 try {
580 zsRef.value();
581 } catch (IllegalStateException e) {
582 throw new NullPointerException("Deflater has been closed");
583 }
584 }
585
586 private static native void initIDs();
587 private static native long init(int level, int strategy, boolean nowrap);
588 private static native void setDictionary(long addr, byte[] b, int off, int len);
589 private native int deflateBytes(long addr, byte[] b, int off, int len,
590 int flush);
591 private static native int getAdler(long addr);
592 private static native void reset(long addr);
593 private static native void end(long addr);
594 }
|