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 decompression 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\u20AC\u20AC";
44 * byte[] input = inputString.getBytes("UTF-8");
45 *
46 * // Compress the bytes
47 * byte[] output = new byte[100];
49 * compresser.setInput(input);
50 * compresser.finish();
51 * int compressedDataLength = compresser.deflate(output);
52 *
53 * // Decompress the bytes
54 * Inflater decompresser = new Inflater();
55 * decompresser.setInput(output, 0, compressedDataLength);
56 * byte[] result = new byte[100];
57 * int resultLength = decompresser.inflate(result);
58 * decompresser.end();
59 *
60 * // Decode the bytes into a String
61 * String outputString = new String(result, 0, resultLength, "UTF-8");
62 * } catch(java.io.UnsupportedEncodingException ex) {
63 * // handle
64 * } catch (java.util.zip.DataFormatException ex) {
65 * // handle
66 * }
67 * </pre></blockquote>
68 *
69 * @see Deflater
70 * @author David Connelly
71 * @since 1.1
72 *
73 */
74 public
75 class Inflater {
76
77 private final ZStreamRef zsRef;
78 private byte[] buf = defaultBuf;
79 private int off, len;
80 private boolean finished;
81 private boolean needDict;
82 private long bytesRead;
83 private long bytesWritten;
84
85 private static final byte[] defaultBuf = new byte[0];
86
87 static {
88 ZipUtils.loadLibrary();
89 initIDs();
90 }
91
92 /**
93 * Creates a new decompressor. If the parameter 'nowrap' is true then
94 * the ZLIB header and checksum fields will not be used. This provides
95 * compatibility with the compression format used by both GZIP and PKZIP.
96 * <p>
97 * Note: When using the 'nowrap' option it is also necessary to provide
98 * an extra "dummy" byte as input. This is required by the ZLIB native
99 * library in order to support certain optimizations.
100 *
101 * @param nowrap if true then support GZIP compatible compression
102 */
103 public Inflater(boolean nowrap) {
104 zsRef = new ZStreamRef(init(nowrap));
105 }
106
107 /**
108 * Creates a new decompressor.
109 */
110 public Inflater() {
111 this(false);
112 }
113
114 /**
115 * Sets input data for decompression. Should be called whenever
116 * needsInput() returns true indicating that more input data is
117 * required.
118 * @param b the input data bytes
119 * @param off the start offset of the input data
120 * @param len the length of the input data
121 * @see Inflater#needsInput
122 */
123 public void setInput(byte[] b, int off, int len) {
124 if (b == null) {
148 /**
149 * Sets the preset dictionary to the given array of bytes. Should be
150 * called when inflate() returns 0 and needsDictionary() returns true
151 * indicating that a preset dictionary is required. The method getAdler()
152 * can be used to get the Adler-32 value of the dictionary needed.
153 * @param b the dictionary data bytes
154 * @param off the start offset of the data
155 * @param len the length of the data
156 * @see Inflater#needsDictionary
157 * @see Inflater#getAdler
158 */
159 public void setDictionary(byte[] b, int off, int len) {
160 if (b == null) {
161 throw new NullPointerException();
162 }
163 if (off < 0 || len < 0 || off > b.length - len) {
164 throw new ArrayIndexOutOfBoundsException();
165 }
166 synchronized (zsRef) {
167 ensureOpen();
168 setDictionary(zsRef.address(), b, off, len);
169 needDict = false;
170 }
171 }
172
173 /**
174 * Sets the preset dictionary to the given array of bytes. Should be
175 * called when inflate() returns 0 and needsDictionary() returns true
176 * indicating that a preset dictionary is required. The method getAdler()
177 * can be used to get the Adler-32 value of the dictionary needed.
178 * @param b the dictionary data bytes
179 * @see Inflater#needsDictionary
180 * @see Inflater#getAdler
181 */
182 public void setDictionary(byte[] b) {
183 setDictionary(b, 0, b.length);
184 }
185
186 /**
187 * Returns the total number of bytes remaining in the input buffer.
188 * This can be used to find out what bytes still remain in the input
240 * @param b the buffer for the uncompressed data
241 * @param off the start offset of the data
242 * @param len the maximum number of uncompressed bytes
243 * @return the actual number of uncompressed bytes
244 * @exception DataFormatException if the compressed data format is invalid
245 * @see Inflater#needsInput
246 * @see Inflater#needsDictionary
247 */
248 public int inflate(byte[] b, int off, int len)
249 throws DataFormatException
250 {
251 if (b == null) {
252 throw new NullPointerException();
253 }
254 if (off < 0 || len < 0 || off > b.length - len) {
255 throw new ArrayIndexOutOfBoundsException();
256 }
257 synchronized (zsRef) {
258 ensureOpen();
259 int thisLen = this.len;
260 int n = inflateBytes(zsRef.address(), b, off, len);
261 bytesWritten += n;
262 bytesRead += (thisLen - this.len);
263 return n;
264 }
265 }
266
267 /**
268 * Uncompresses bytes into specified buffer. Returns actual number
269 * of bytes uncompressed. A return value of 0 indicates that
270 * needsInput() or needsDictionary() should be called in order to
271 * determine if more input data or a preset dictionary is required.
272 * In the latter case, getAdler() can be used to get the Adler-32
273 * value of the dictionary required.
274 * @param b the buffer for the uncompressed data
275 * @return the actual number of uncompressed bytes
276 * @exception DataFormatException if the compressed data format is invalid
277 * @see Inflater#needsInput
278 * @see Inflater#needsDictionary
279 */
280 public int inflate(byte[] b) throws DataFormatException {
281 return inflate(b, 0, b.length);
282 }
283
284 /**
285 * Returns the ADLER-32 value of the uncompressed data.
286 * @return the ADLER-32 value of the uncompressed data
287 */
288 public int getAdler() {
289 synchronized (zsRef) {
290 ensureOpen();
291 return getAdler(zsRef.address());
292 }
293 }
294
295 /**
296 * Returns the total number of compressed bytes input so far.
297 *
298 * <p>Since the number of bytes may be greater than
299 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
300 * the preferred means of obtaining this information.</p>
301 *
302 * @return the total number of compressed bytes input so far
303 */
304 public int getTotalIn() {
305 return (int) getBytesRead();
306 }
307
308 /**
309 * Returns the total number of compressed bytes input so far.
310 *
311 * @return the total (non-negative) number of compressed bytes input so far
333
334 /**
335 * Returns the total number of uncompressed bytes output so far.
336 *
337 * @return the total (non-negative) number of uncompressed bytes output so far
338 * @since 1.5
339 */
340 public long getBytesWritten() {
341 synchronized (zsRef) {
342 ensureOpen();
343 return bytesWritten;
344 }
345 }
346
347 /**
348 * Resets inflater so that a new set of input data can be processed.
349 */
350 public void reset() {
351 synchronized (zsRef) {
352 ensureOpen();
353 reset(zsRef.address());
354 buf = defaultBuf;
355 finished = false;
356 needDict = false;
357 off = len = 0;
358 bytesRead = bytesWritten = 0;
359 }
360 }
361
362 /**
363 * Closes the decompressor and discards any unprocessed input.
364 * This method should be called when the decompressor is no longer
365 * being used, but will also be called automatically by the finalize()
366 * method. Once this method is called, the behavior of the Inflater
367 * object is undefined.
368 */
369 public void end() {
370 synchronized (zsRef) {
371 long addr = zsRef.address();
372 zsRef.clear();
373 if (addr != 0) {
374 end(addr);
375 buf = null;
376 }
377 }
378 }
379
380 /**
381 * Closes the decompressor when garbage is collected.
382 *
383 * @deprecated The {@code finalize} method has been deprecated.
384 * Subclasses that override {@code finalize} in order to perform cleanup
385 * should be modified to use alternative cleanup mechanisms and
386 * to remove the overriding {@code finalize} method.
387 * When overriding the {@code finalize} method, its implementation must explicitly
388 * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
389 * See the specification for {@link Object#finalize()} for further
390 * information about migration options.
391 */
392 @Deprecated(since="9")
393 protected void finalize() {
394 end();
395 }
396
397 private void ensureOpen () {
398 assert Thread.holdsLock(zsRef);
399 if (zsRef.address() == 0)
400 throw new NullPointerException("Inflater has been closed");
401 }
402
403 boolean ended() {
404 synchronized (zsRef) {
405 return zsRef.address() == 0;
406 }
407 }
408
409 private static native void initIDs();
410 private static native long init(boolean nowrap);
411 private static native void setDictionary(long addr, byte[] b, int off,
412 int len);
413 private native int inflateBytes(long addr, byte[] b, int off, int len)
414 throws DataFormatException;
415 private static native int getAdler(long addr);
416 private static native void reset(long addr);
417 private static native void end(long addr);
418 }
|
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 decompression 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\u20AC\u20AC";
49 * byte[] input = inputString.getBytes("UTF-8");
50 *
51 * // Compress the bytes
52 * byte[] output = new byte[100];
54 * compresser.setInput(input);
55 * compresser.finish();
56 * int compressedDataLength = compresser.deflate(output);
57 *
58 * // Decompress the bytes
59 * Inflater decompresser = new Inflater();
60 * decompresser.setInput(output, 0, compressedDataLength);
61 * byte[] result = new byte[100];
62 * int resultLength = decompresser.inflate(result);
63 * decompresser.end();
64 *
65 * // Decode the bytes into a String
66 * String outputString = new String(result, 0, resultLength, "UTF-8");
67 * } catch(java.io.UnsupportedEncodingException ex) {
68 * // handle
69 * } catch (java.util.zip.DataFormatException ex) {
70 * // handle
71 * }
72 * </pre></blockquote>
73 *
74 * <p>
75 * @apiNote
76 * In earlier versions the {@link Object#finalize} method was overridden and
77 * specified to call the {@code end} method to close the {@code inflater} and
78 * release the resource when the instance becomes unreachable.
79 * The {@code finalize} method is no longer defined. The recommended cleanup
80 * for decompressor is to explicitly call {@code end} method when it is no
81 * longer in use.
82 *
83 * @implNote
84 * The resource of the decompressor will be released when the instance becomes
85 * phantom-reachable, if the {@code end} is not invoked explicitly.
86 * <p>
87 *
88 * @see Deflater
89 * @author David Connelly
90 * @since 1.1
91 *
92 */
93 public
94 class Inflater {
95
96 private final Cleaner.LongCleanableResource zsRef;
97 private byte[] buf = defaultBuf;
98 private int off, len;
99 private boolean finished;
100 private boolean needDict;
101 private long bytesRead;
102 private long bytesWritten;
103
104 private static final byte[] defaultBuf = new byte[0];
105
106 static {
107 ZipUtils.loadLibrary();
108 initIDs();
109 }
110
111 /**
112 * Creates a new decompressor. If the parameter 'nowrap' is true then
113 * the ZLIB header and checksum fields will not be used. This provides
114 * compatibility with the compression format used by both GZIP and PKZIP.
115 * <p>
116 * Note: When using the 'nowrap' option it is also necessary to provide
117 * an extra "dummy" byte as input. This is required by the ZLIB native
118 * library in order to support certain optimizations.
119 *
120 * @param nowrap if true then support GZIP compatible compression
121 */
122 public Inflater(boolean nowrap) {
123 this.zsRef = CleanerFactory
124 .cleaner()
125 .createLongResource(this, () -> init(nowrap), Inflater::end);
126 }
127
128 /**
129 * Creates a new decompressor.
130 */
131 public Inflater() {
132 this(false);
133 }
134
135 /**
136 * Sets input data for decompression. Should be called whenever
137 * needsInput() returns true indicating that more input data is
138 * required.
139 * @param b the input data bytes
140 * @param off the start offset of the input data
141 * @param len the length of the input data
142 * @see Inflater#needsInput
143 */
144 public void setInput(byte[] b, int off, int len) {
145 if (b == null) {
169 /**
170 * Sets the preset dictionary to the given array of bytes. Should be
171 * called when inflate() returns 0 and needsDictionary() returns true
172 * indicating that a preset dictionary is required. The method getAdler()
173 * can be used to get the Adler-32 value of the dictionary needed.
174 * @param b the dictionary data bytes
175 * @param off the start offset of the data
176 * @param len the length of the data
177 * @see Inflater#needsDictionary
178 * @see Inflater#getAdler
179 */
180 public void setDictionary(byte[] b, int off, int len) {
181 if (b == null) {
182 throw new NullPointerException();
183 }
184 if (off < 0 || len < 0 || off > b.length - len) {
185 throw new ArrayIndexOutOfBoundsException();
186 }
187 synchronized (zsRef) {
188 ensureOpen();
189 setDictionary(zsRef.value(), b, off, len);
190 Reference.reachabilityFence(this);
191 needDict = false;
192 }
193 }
194
195 /**
196 * Sets the preset dictionary to the given array of bytes. Should be
197 * called when inflate() returns 0 and needsDictionary() returns true
198 * indicating that a preset dictionary is required. The method getAdler()
199 * can be used to get the Adler-32 value of the dictionary needed.
200 * @param b the dictionary data bytes
201 * @see Inflater#needsDictionary
202 * @see Inflater#getAdler
203 */
204 public void setDictionary(byte[] b) {
205 setDictionary(b, 0, b.length);
206 }
207
208 /**
209 * Returns the total number of bytes remaining in the input buffer.
210 * This can be used to find out what bytes still remain in the input
262 * @param b the buffer for the uncompressed data
263 * @param off the start offset of the data
264 * @param len the maximum number of uncompressed bytes
265 * @return the actual number of uncompressed bytes
266 * @exception DataFormatException if the compressed data format is invalid
267 * @see Inflater#needsInput
268 * @see Inflater#needsDictionary
269 */
270 public int inflate(byte[] b, int off, int len)
271 throws DataFormatException
272 {
273 if (b == null) {
274 throw new NullPointerException();
275 }
276 if (off < 0 || len < 0 || off > b.length - len) {
277 throw new ArrayIndexOutOfBoundsException();
278 }
279 synchronized (zsRef) {
280 ensureOpen();
281 int thisLen = this.len;
282 int n = inflateBytes(zsRef.value(), b, off, len);
283 Reference.reachabilityFence(this);
284 bytesWritten += n;
285 bytesRead += (thisLen - this.len);
286 return n;
287 }
288 }
289
290 /**
291 * Uncompresses bytes into specified buffer. Returns actual number
292 * of bytes uncompressed. A return value of 0 indicates that
293 * needsInput() or needsDictionary() should be called in order to
294 * determine if more input data or a preset dictionary is required.
295 * In the latter case, getAdler() can be used to get the Adler-32
296 * value of the dictionary required.
297 * @param b the buffer for the uncompressed data
298 * @return the actual number of uncompressed bytes
299 * @exception DataFormatException if the compressed data format is invalid
300 * @see Inflater#needsInput
301 * @see Inflater#needsDictionary
302 */
303 public int inflate(byte[] b) throws DataFormatException {
304 return inflate(b, 0, b.length);
305 }
306
307 /**
308 * Returns the ADLER-32 value of the uncompressed data.
309 * @return the ADLER-32 value of the uncompressed data
310 */
311 public int getAdler() {
312 synchronized (zsRef) {
313 ensureOpen();
314 int adler = getAdler(zsRef.value());
315 Reference.reachabilityFence(this);
316 return adler;
317 }
318 }
319
320 /**
321 * Returns the total number of compressed bytes input so far.
322 *
323 * <p>Since the number of bytes may be greater than
324 * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
325 * the preferred means of obtaining this information.</p>
326 *
327 * @return the total number of compressed bytes input so far
328 */
329 public int getTotalIn() {
330 return (int) getBytesRead();
331 }
332
333 /**
334 * Returns the total number of compressed bytes input so far.
335 *
336 * @return the total (non-negative) number of compressed bytes input so far
358
359 /**
360 * Returns the total number of uncompressed bytes output so far.
361 *
362 * @return the total (non-negative) number of uncompressed bytes output so far
363 * @since 1.5
364 */
365 public long getBytesWritten() {
366 synchronized (zsRef) {
367 ensureOpen();
368 return bytesWritten;
369 }
370 }
371
372 /**
373 * Resets inflater so that a new set of input data can be processed.
374 */
375 public void reset() {
376 synchronized (zsRef) {
377 ensureOpen();
378 reset(zsRef.value());
379 Reference.reachabilityFence(this);
380 buf = defaultBuf;
381 finished = false;
382 needDict = false;
383 off = len = 0;
384 bytesRead = bytesWritten = 0;
385 }
386 }
387
388 /**
389 * Closes the decompressor and discards any unprocessed input.
390 *
391 * This method should be called when the decompressor is no longer
392 * being used. Once this method is called, the behavior of the
393 * Inflater object is undefined.
394 */
395 public void end() {
396 synchronized (zsRef) {
397 zsRef.clean();
398 buf = null;
399 }
400 }
401
402 private void ensureOpen () {
403 assert Thread.holdsLock(zsRef);
404 try {
405 zsRef.value();
406 } catch (IllegalStateException e) {
407 throw new NullPointerException("Inflater has been closed");
408 }
409 }
410
411 private static native void initIDs();
412 private static native long init(boolean nowrap);
413 private static native void setDictionary(long addr, byte[] b, int off,
414 int len);
415 private native int inflateBytes(long addr, byte[] b, int off, int len)
416 throws DataFormatException;
417 private static native int getAdler(long addr);
418 private static native void reset(long addr);
419 private static native void end(long addr);
420 }
|