1 /*
2  * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
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 java.lang.ref.Cleaner.Cleanable;
29 import java.lang.ref.Reference;
30 import java.nio.ByteBuffer;
31 import java.nio.ReadOnlyBufferException;
32 import java.util.Objects;
33 
34 import jdk.internal.ref.CleanerFactory;
35 import sun.nio.ch.DirectBuffer;
36 
37 /**
38  * This class provides support for general purpose decompression using the
39  * popular ZLIB compression library. The ZLIB compression library was
40  * initially developed as part of the PNG graphics standard and is not
41  * protected by patents. It is fully described in the specifications at
42  * the <a href="package-summary.html#package.description">java.util.zip
43  * package description</a>.
44  * <p>
45  * This class inflates sequences of ZLIB compressed bytes. The input byte
46  * sequence is provided in either byte array or byte buffer, via one of the
47  * {@code setInput()} methods. The output byte sequence is written to the
48  * output byte array or byte buffer passed to the {@code deflate()} methods.
49  * <p>
50  * The following code fragment demonstrates a trivial compression
51  * and decompression of a string using {@code Deflater} and
52  * {@code Inflater}.
53  *
54  * <blockquote><pre>
55  * try {
56  *     // Encode a String into bytes
57  *     String inputString = "blahblahblah\u20AC\u20AC";
58  *     byte[] input = inputString.getBytes("UTF-8");
59  *
60  *     // Compress the bytes
61  *     byte[] output = new byte[100];
62  *     Deflater compresser = new Deflater();
63  *     compresser.setInput(input);
64  *     compresser.finish();
65  *     int compressedDataLength = compresser.deflate(output);
66  *
67  *     // Decompress the bytes
68  *     Inflater decompresser = new Inflater();
69  *     decompresser.setInput(output, 0, compressedDataLength);
70  *     byte[] result = new byte[100];
71  *     int resultLength = decompresser.inflate(result);
72  *     decompresser.end();
73  *
74  *     // Decode the bytes into a String
75  *     String outputString = new String(result, 0, resultLength, "UTF-8");
76  * } catch (java.io.UnsupportedEncodingException ex) {
77  *     // handle
78  * } catch (java.util.zip.DataFormatException ex) {
79  *     // handle
80  * }
81  * </pre></blockquote>
82  *
83  * @apiNote
84  * To release resources used by this {@code Inflater}, the {@link #end()} method
85  * should be called explicitly. Subclasses are responsible for the cleanup of resources
86  * acquired by the subclass. Subclasses that override {@link #finalize()} in order
87  * to perform cleanup should be modified to use alternative cleanup mechanisms such
88  * as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
89  *
90  * @see         Deflater
91  * @author      David Connelly
92  * @since 1.1
93  *
94  */
95 
96 public class Inflater {
97 
98     private final InflaterZStreamRef zsRef;
99     private ByteBuffer input = ZipUtils.defaultBuf;
100     private byte[] inputArray;
101     private int inputPos, inputLim;
102     private boolean finished;
103     private boolean needDict;
104     private long bytesRead;
105     private long bytesWritten;
106 
107     /*
108      * These fields are used as an "out" parameter from JNI when a
109      * DataFormatException is thrown during the inflate operation.
110      */
111     private int inputConsumed;
112     private int outputConsumed;
113 
114     static {
ZipUtils.loadLibrary()115         ZipUtils.loadLibrary();
initIDs()116         initIDs();
117     }
118 
119     /**
120      * Creates a new decompressor. If the parameter 'nowrap' is true then
121      * the ZLIB header and checksum fields will not be used. This provides
122      * compatibility with the compression format used by both GZIP and PKZIP.
123      * <p>
124      * Note: When using the 'nowrap' option it is also necessary to provide
125      * an extra "dummy" byte as input. This is required by the ZLIB native
126      * library in order to support certain optimizations.
127      *
128      * @param nowrap if true then support GZIP compatible compression
129      */
Inflater(boolean nowrap)130     public Inflater(boolean nowrap) {
131         this.zsRef = new InflaterZStreamRef(this, init(nowrap));
132     }
133 
134     /**
135      * Creates a new decompressor.
136      */
Inflater()137     public Inflater() {
138         this(false);
139     }
140 
141     /**
142      * Sets input data for decompression.
143      * <p>
144      * One of the {@code setInput()} methods should be called whenever
145      * {@code needsInput()} returns true indicating that more input data
146      * is required.
147      *
148      * @param input the input data bytes
149      * @param off the start offset of the input data
150      * @param len the length of the input data
151      * @see Inflater#needsInput
152      */
setInput(byte[] input, int off, int len)153     public void setInput(byte[] input, int off, int len) {
154         if (off < 0 || len < 0 || off > input.length - len) {
155             throw new ArrayIndexOutOfBoundsException();
156         }
157         synchronized (zsRef) {
158             this.input = null;
159             this.inputArray = input;
160             this.inputPos = off;
161             this.inputLim = off + len;
162         }
163     }
164 
165     /**
166      * Sets input data for decompression.
167      * <p>
168      * One of the {@code setInput()} methods should be called whenever
169      * {@code needsInput()} returns true indicating that more input data
170      * is required.
171      *
172      * @param input the input data bytes
173      * @see Inflater#needsInput
174      */
setInput(byte[] input)175     public void setInput(byte[] input) {
176         setInput(input, 0, input.length);
177     }
178 
179     /**
180      * Sets input data for decompression.
181      * <p>
182      * One of the {@code setInput()} methods should be called whenever
183      * {@code needsInput()} returns true indicating that more input data
184      * is required.
185      * <p>
186      * The given buffer's position will be advanced as inflate
187      * operations are performed, up to the buffer's limit.
188      * The input buffer may be modified (refilled) between inflate
189      * operations; doing so is equivalent to creating a new buffer
190      * and setting it with this method.
191      * <p>
192      * Modifying the input buffer's contents, position, or limit
193      * concurrently with an inflate operation will result in
194      * undefined behavior, which may include incorrect operation
195      * results or operation failure.
196      *
197      * @param input the input data bytes
198      * @see Inflater#needsInput
199      * @since 11
200      */
setInput(ByteBuffer input)201     public void setInput(ByteBuffer input) {
202         Objects.requireNonNull(input);
203         synchronized (zsRef) {
204             this.input = input;
205             this.inputArray = null;
206         }
207     }
208 
209     /**
210      * Sets the preset dictionary to the given array of bytes. Should be
211      * called when inflate() returns 0 and needsDictionary() returns true
212      * indicating that a preset dictionary is required. The method getAdler()
213      * can be used to get the Adler-32 value of the dictionary needed.
214      * @param dictionary the dictionary data bytes
215      * @param off the start offset of the data
216      * @param len the length of the data
217      * @see Inflater#needsDictionary
218      * @see Inflater#getAdler
219      */
setDictionary(byte[] dictionary, int off, int len)220     public void setDictionary(byte[] dictionary, int off, int len) {
221         if (off < 0 || len < 0 || off > dictionary.length - len) {
222             throw new ArrayIndexOutOfBoundsException();
223         }
224         synchronized (zsRef) {
225             ensureOpen();
226             setDictionary(zsRef.address(), dictionary, off, len);
227             needDict = false;
228         }
229     }
230 
231     /**
232      * Sets the preset dictionary to the given array of bytes. Should be
233      * called when inflate() returns 0 and needsDictionary() returns true
234      * indicating that a preset dictionary is required. The method getAdler()
235      * can be used to get the Adler-32 value of the dictionary needed.
236      * @param dictionary the dictionary data bytes
237      * @see Inflater#needsDictionary
238      * @see Inflater#getAdler
239      */
setDictionary(byte[] dictionary)240     public void setDictionary(byte[] dictionary) {
241         setDictionary(dictionary, 0, dictionary.length);
242     }
243 
244     /**
245      * Sets the preset dictionary to the bytes in the given buffer. Should be
246      * called when inflate() returns 0 and needsDictionary() returns true
247      * indicating that a preset dictionary is required. The method getAdler()
248      * can be used to get the Adler-32 value of the dictionary needed.
249      * <p>
250      * The bytes in given byte buffer will be fully consumed by this method.  On
251      * return, its position will equal its limit.
252      *
253      * @param dictionary the dictionary data bytes
254      * @see Inflater#needsDictionary
255      * @see Inflater#getAdler
256      * @since 11
257      */
setDictionary(ByteBuffer dictionary)258     public void setDictionary(ByteBuffer dictionary) {
259         synchronized (zsRef) {
260             int position = dictionary.position();
261             int remaining = Math.max(dictionary.limit() - position, 0);
262             ensureOpen();
263             if (dictionary.isDirect()) {
264                 long address = ((DirectBuffer) dictionary).address();
265                 try {
266                     setDictionaryBuffer(zsRef.address(), address + position, remaining);
267                 } finally {
268                     Reference.reachabilityFence(dictionary);
269                 }
270             } else {
271                 byte[] array = ZipUtils.getBufferArray(dictionary);
272                 int offset = ZipUtils.getBufferOffset(dictionary);
273                 setDictionary(zsRef.address(), array, offset + position, remaining);
274             }
275             dictionary.position(position + remaining);
276             needDict = false;
277         }
278     }
279 
280     /**
281      * Returns the total number of bytes remaining in the input buffer.
282      * This can be used to find out what bytes still remain in the input
283      * buffer after decompression has finished.
284      * @return the total number of bytes remaining in the input buffer
285      */
getRemaining()286     public int getRemaining() {
287         synchronized (zsRef) {
288             ByteBuffer input = this.input;
289             return input == null ? inputLim - inputPos : input.remaining();
290         }
291     }
292 
293     /**
294      * Returns true if no data remains in the input buffer. This can
295      * be used to determine if one of the {@code setInput()} methods should be
296      * called in order to provide more input.
297      *
298      * @return true if no data remains in the input buffer
299      */
needsInput()300     public boolean needsInput() {
301         synchronized (zsRef) {
302             ByteBuffer input = this.input;
303             return input == null ? inputLim == inputPos : ! input.hasRemaining();
304         }
305     }
306 
307     /**
308      * Returns true if a preset dictionary is needed for decompression.
309      * @return true if a preset dictionary is needed for decompression
310      * @see Inflater#setDictionary
311      */
needsDictionary()312     public boolean needsDictionary() {
313         synchronized (zsRef) {
314             return needDict;
315         }
316     }
317 
318     /**
319      * Returns true if the end of the compressed data stream has been
320      * reached.
321      * @return true if the end of the compressed data stream has been
322      * reached
323      */
finished()324     public boolean finished() {
325         synchronized (zsRef) {
326             return finished;
327         }
328     }
329 
330     /**
331      * Uncompresses bytes into specified buffer. Returns actual number
332      * of bytes uncompressed. A return value of 0 indicates that
333      * needsInput() or needsDictionary() should be called in order to
334      * determine if more input data or a preset dictionary is required.
335      * In the latter case, getAdler() can be used to get the Adler-32
336      * value of the dictionary required.
337      * <p>
338      * If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
339      * for input, the input buffer's position will be advanced by the number of bytes
340      * consumed by this operation, even in the event that a {@link DataFormatException}
341      * is thrown.
342      * <p>
343      * The {@linkplain #getRemaining() remaining byte count} will be reduced by
344      * the number of consumed input bytes.  If the {@link #setInput(ByteBuffer)}
345      * method was called to provide a buffer for input, the input buffer's position
346      * will be advanced the number of consumed bytes.
347      * <p>
348      * These byte totals, as well as
349      * the {@linkplain #getBytesRead() total bytes read}
350      * and the {@linkplain #getBytesWritten() total bytes written}
351      * values, will be updated even in the event that a {@link DataFormatException}
352      * is thrown to reflect the amount of data consumed and produced before the
353      * exception occurred.
354      *
355      * @param output the buffer for the uncompressed data
356      * @param off the start offset of the data
357      * @param len the maximum number of uncompressed bytes
358      * @return the actual number of uncompressed bytes
359      * @throws DataFormatException if the compressed data format is invalid
360      * @see Inflater#needsInput
361      * @see Inflater#needsDictionary
362      */
inflate(byte[] output, int off, int len)363     public int inflate(byte[] output, int off, int len)
364         throws DataFormatException
365     {
366         if (off < 0 || len < 0 || off > output.length - len) {
367             throw new ArrayIndexOutOfBoundsException();
368         }
369         synchronized (zsRef) {
370             ensureOpen();
371             ByteBuffer input = this.input;
372             long result;
373             int inputPos;
374             try {
375                 if (input == null) {
376                     inputPos = this.inputPos;
377                     try {
378                         result = inflateBytesBytes(zsRef.address(),
379                             inputArray, inputPos, inputLim - inputPos,
380                             output, off, len);
381                     } catch (DataFormatException e) {
382                         this.inputPos = inputPos + inputConsumed;
383                         throw e;
384                     }
385                 } else {
386                     inputPos = input.position();
387                     try {
388                         int inputRem = Math.max(input.limit() - inputPos, 0);
389                         if (input.isDirect()) {
390                             try {
391                                 long inputAddress = ((DirectBuffer) input).address();
392                                 result = inflateBufferBytes(zsRef.address(),
393                                     inputAddress + inputPos, inputRem,
394                                     output, off, len);
395                             } finally {
396                                 Reference.reachabilityFence(input);
397                             }
398                         } else {
399                             byte[] inputArray = ZipUtils.getBufferArray(input);
400                             int inputOffset = ZipUtils.getBufferOffset(input);
401                             result = inflateBytesBytes(zsRef.address(),
402                                 inputArray, inputOffset + inputPos, inputRem,
403                                 output, off, len);
404                         }
405                     } catch (DataFormatException e) {
406                         input.position(inputPos + inputConsumed);
407                         throw e;
408                     }
409                 }
410             } catch (DataFormatException e) {
411                 bytesRead += inputConsumed;
412                 inputConsumed = 0;
413                 int written = outputConsumed;
414                 bytesWritten += written;
415                 outputConsumed = 0;
416                 throw e;
417             }
418             int read = (int) (result & 0x7fff_ffffL);
419             int written = (int) (result >>> 31 & 0x7fff_ffffL);
420             if ((result >>> 62 & 1) != 0) {
421                 finished = true;
422             }
423             if ((result >>> 63 & 1) != 0) {
424                 needDict = true;
425             }
426             if (input != null) {
427                 input.position(inputPos + read);
428             } else {
429                 this.inputPos = inputPos + read;
430             }
431             bytesWritten += written;
432             bytesRead += read;
433             return written;
434         }
435     }
436 
437     /**
438      * Uncompresses bytes into specified buffer. Returns actual number
439      * of bytes uncompressed. A return value of 0 indicates that
440      * needsInput() or needsDictionary() should be called in order to
441      * determine if more input data or a preset dictionary is required.
442      * In the latter case, getAdler() can be used to get the Adler-32
443      * value of the dictionary required.
444      * <p>
445      * The {@linkplain #getRemaining() remaining byte count} will be reduced by
446      * the number of consumed input bytes.  If the {@link #setInput(ByteBuffer)}
447      * method was called to provide a buffer for input, the input buffer's position
448      * will be advanced the number of consumed bytes.
449      * <p>
450      * These byte totals, as well as
451      * the {@linkplain #getBytesRead() total bytes read}
452      * and the {@linkplain #getBytesWritten() total bytes written}
453      * values, will be updated even in the event that a {@link DataFormatException}
454      * is thrown to reflect the amount of data consumed and produced before the
455      * exception occurred.
456      *
457      * @param output the buffer for the uncompressed data
458      * @return the actual number of uncompressed bytes
459      * @throws DataFormatException if the compressed data format is invalid
460      * @see Inflater#needsInput
461      * @see Inflater#needsDictionary
462      */
inflate(byte[] output)463     public int inflate(byte[] output) throws DataFormatException {
464         return inflate(output, 0, output.length);
465     }
466 
467     /**
468      * Uncompresses bytes into specified buffer. Returns actual number
469      * of bytes uncompressed. A return value of 0 indicates that
470      * needsInput() or needsDictionary() should be called in order to
471      * determine if more input data or a preset dictionary is required.
472      * In the latter case, getAdler() can be used to get the Adler-32
473      * value of the dictionary required.
474      * <p>
475      * On success, the position of the given {@code output} byte buffer will be
476      * advanced by as many bytes as were produced by the operation, which is equal
477      * to the number returned by this method.  Note that the position of the
478      * {@code output} buffer will be advanced even in the event that a
479      * {@link DataFormatException} is thrown.
480      * <p>
481      * The {@linkplain #getRemaining() remaining byte count} will be reduced by
482      * the number of consumed input bytes.  If the {@link #setInput(ByteBuffer)}
483      * method was called to provide a buffer for input, the input buffer's position
484      * will be advanced the number of consumed bytes.
485      * <p>
486      * These byte totals, as well as
487      * the {@linkplain #getBytesRead() total bytes read}
488      * and the {@linkplain #getBytesWritten() total bytes written}
489      * values, will be updated even in the event that a {@link DataFormatException}
490      * is thrown to reflect the amount of data consumed and produced before the
491      * exception occurred.
492      *
493      * @param output the buffer for the uncompressed data
494      * @return the actual number of uncompressed bytes
495      * @throws DataFormatException if the compressed data format is invalid
496      * @throws ReadOnlyBufferException if the given output buffer is read-only
497      * @see Inflater#needsInput
498      * @see Inflater#needsDictionary
499      * @since 11
500      */
inflate(ByteBuffer output)501     public int inflate(ByteBuffer output) throws DataFormatException {
502         if (output.isReadOnly()) {
503             throw new ReadOnlyBufferException();
504         }
505         synchronized (zsRef) {
506             ensureOpen();
507             ByteBuffer input = this.input;
508             long result;
509             int inputPos;
510             int outputPos = output.position();
511             int outputRem = Math.max(output.limit() - outputPos, 0);
512             try {
513                 if (input == null) {
514                     inputPos = this.inputPos;
515                     try {
516                         if (output.isDirect()) {
517                             long outputAddress = ((DirectBuffer) output).address();
518                             try {
519                                 result = inflateBytesBuffer(zsRef.address(),
520                                     inputArray, inputPos, inputLim - inputPos,
521                                     outputAddress + outputPos, outputRem);
522                             } finally {
523                                 Reference.reachabilityFence(output);
524                             }
525                         } else {
526                             byte[] outputArray = ZipUtils.getBufferArray(output);
527                             int outputOffset = ZipUtils.getBufferOffset(output);
528                             result = inflateBytesBytes(zsRef.address(),
529                                 inputArray, inputPos, inputLim - inputPos,
530                                 outputArray, outputOffset + outputPos, outputRem);
531                         }
532                     } catch (DataFormatException e) {
533                         this.inputPos = inputPos + inputConsumed;
534                         throw e;
535                     }
536                 } else {
537                     inputPos = input.position();
538                     int inputRem = Math.max(input.limit() - inputPos, 0);
539                     try {
540                         if (input.isDirect()) {
541                             long inputAddress = ((DirectBuffer) input).address();
542                             try {
543                                 if (output.isDirect()) {
544                                     long outputAddress = ((DirectBuffer) output).address();
545                                     try {
546                                         result = inflateBufferBuffer(zsRef.address(),
547                                             inputAddress + inputPos, inputRem,
548                                             outputAddress + outputPos, outputRem);
549                                     } finally {
550                                         Reference.reachabilityFence(output);
551                                     }
552                                 } else {
553                                     byte[] outputArray = ZipUtils.getBufferArray(output);
554                                     int outputOffset = ZipUtils.getBufferOffset(output);
555                                     result = inflateBufferBytes(zsRef.address(),
556                                         inputAddress + inputPos, inputRem,
557                                         outputArray, outputOffset + outputPos, outputRem);
558                                 }
559                             } finally {
560                                 Reference.reachabilityFence(input);
561                             }
562                         } else {
563                             byte[] inputArray = ZipUtils.getBufferArray(input);
564                             int inputOffset = ZipUtils.getBufferOffset(input);
565                             if (output.isDirect()) {
566                                 long outputAddress = ((DirectBuffer) output).address();
567                                 try {
568                                     result = inflateBytesBuffer(zsRef.address(),
569                                         inputArray, inputOffset + inputPos, inputRem,
570                                         outputAddress + outputPos, outputRem);
571                                 } finally {
572                                     Reference.reachabilityFence(output);
573                                 }
574                             } else {
575                                 byte[] outputArray = ZipUtils.getBufferArray(output);
576                                 int outputOffset = ZipUtils.getBufferOffset(output);
577                                 result = inflateBytesBytes(zsRef.address(),
578                                     inputArray, inputOffset + inputPos, inputRem,
579                                     outputArray, outputOffset + outputPos, outputRem);
580                             }
581                         }
582                     } catch (DataFormatException e) {
583                         input.position(inputPos + inputConsumed);
584                         throw e;
585                     }
586                 }
587             } catch (DataFormatException e) {
588                 bytesRead += inputConsumed;
589                 inputConsumed = 0;
590                 int written = outputConsumed;
591                 output.position(outputPos + written);
592                 bytesWritten += written;
593                 outputConsumed = 0;
594                 throw e;
595             }
596             int read = (int) (result & 0x7fff_ffffL);
597             int written = (int) (result >>> 31 & 0x7fff_ffffL);
598             if ((result >>> 62 & 1) != 0) {
599                 finished = true;
600             }
601             if ((result >>> 63 & 1) != 0) {
602                 needDict = true;
603             }
604             if (input != null) {
605                 input.position(inputPos + read);
606             } else {
607                 this.inputPos = inputPos + read;
608             }
609             // Note: this method call also serves to keep the byteBuffer ref alive
610             output.position(outputPos + written);
611             bytesWritten += written;
612             bytesRead += read;
613             return written;
614         }
615     }
616 
617     /**
618      * Returns the ADLER-32 value of the uncompressed data.
619      * @return the ADLER-32 value of the uncompressed data
620      */
getAdler()621     public int getAdler() {
622         synchronized (zsRef) {
623             ensureOpen();
624             return getAdler(zsRef.address());
625         }
626     }
627 
628     /**
629      * Returns the total number of compressed bytes input so far.
630      *
631      * <p>Since the number of bytes may be greater than
632      * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
633      * the preferred means of obtaining this information.</p>
634      *
635      * @return the total number of compressed bytes input so far
636      */
getTotalIn()637     public int getTotalIn() {
638         return (int) getBytesRead();
639     }
640 
641     /**
642      * Returns the total number of compressed bytes input so far.
643      *
644      * @return the total (non-negative) number of compressed bytes input so far
645      * @since 1.5
646      */
getBytesRead()647     public long getBytesRead() {
648         synchronized (zsRef) {
649             ensureOpen();
650             return bytesRead;
651         }
652     }
653 
654     /**
655      * Returns the total number of uncompressed bytes output so far.
656      *
657      * <p>Since the number of bytes may be greater than
658      * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
659      * the preferred means of obtaining this information.</p>
660      *
661      * @return the total number of uncompressed bytes output so far
662      */
getTotalOut()663     public int getTotalOut() {
664         return (int) getBytesWritten();
665     }
666 
667     /**
668      * Returns the total number of uncompressed bytes output so far.
669      *
670      * @return the total (non-negative) number of uncompressed bytes output so far
671      * @since 1.5
672      */
getBytesWritten()673     public long getBytesWritten() {
674         synchronized (zsRef) {
675             ensureOpen();
676             return bytesWritten;
677         }
678     }
679 
680     /**
681      * Resets inflater so that a new set of input data can be processed.
682      */
reset()683     public void reset() {
684         synchronized (zsRef) {
685             ensureOpen();
686             reset(zsRef.address());
687             input = ZipUtils.defaultBuf;
688             inputArray = null;
689             finished = false;
690             needDict = false;
691             bytesRead = bytesWritten = 0;
692         }
693     }
694 
695     /**
696      * Closes the decompressor and discards any unprocessed input.
697      *
698      * This method should be called when the decompressor is no longer
699      * being used. Once this method is called, the behavior of the
700      * Inflater object is undefined.
701      */
end()702     public void end() {
703         synchronized (zsRef) {
704             zsRef.clean();
705             input = ZipUtils.defaultBuf;
706             inputArray = null;
707         }
708     }
709 
710 
ensureOpen()711     private void ensureOpen () {
712         assert Thread.holdsLock(zsRef);
713         if (zsRef.address() == 0)
714             throw new NullPointerException("Inflater has been closed");
715     }
716 
initIDs()717     private static native void initIDs();
init(boolean nowrap)718     private static native long init(boolean nowrap);
setDictionary(long addr, byte[] b, int off, int len)719     private static native void setDictionary(long addr, byte[] b, int off,
720                                              int len);
setDictionaryBuffer(long addr, long bufAddress, int len)721     private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
inflateBytesBytes(long addr, byte[] inputArray, int inputOff, int inputLen, byte[] outputArray, int outputOff, int outputLen)722     private native long inflateBytesBytes(long addr,
723         byte[] inputArray, int inputOff, int inputLen,
724         byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
inflateBytesBuffer(long addr, byte[] inputArray, int inputOff, int inputLen, long outputAddress, int outputLen)725     private native long inflateBytesBuffer(long addr,
726         byte[] inputArray, int inputOff, int inputLen,
727         long outputAddress, int outputLen) throws DataFormatException;
inflateBufferBytes(long addr, long inputAddress, int inputLen, byte[] outputArray, int outputOff, int outputLen)728     private native long inflateBufferBytes(long addr,
729         long inputAddress, int inputLen,
730         byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
inflateBufferBuffer(long addr, long inputAddress, int inputLen, long outputAddress, int outputLen)731     private native long inflateBufferBuffer(long addr,
732         long inputAddress, int inputLen,
733         long outputAddress, int outputLen) throws DataFormatException;
getAdler(long addr)734     private static native int getAdler(long addr);
reset(long addr)735     private static native void reset(long addr);
end(long addr)736     private static native void end(long addr);
737 
738     /**
739      * A reference to the native zlib's z_stream structure. It also
740      * serves as the "cleaner" to clean up the native resource when
741      * the Inflater is ended, closed or cleaned.
742      */
743     static class InflaterZStreamRef implements Runnable {
744 
745         private long address;
746         private final Cleanable cleanable;
747 
InflaterZStreamRef(Inflater owner, long addr)748         private InflaterZStreamRef(Inflater owner, long addr) {
749             this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null;
750             this.address = addr;
751         }
752 
address()753         long address() {
754             return address;
755         }
756 
clean()757         void clean() {
758             cleanable.clean();
759         }
760 
run()761         public synchronized void run() {
762             long addr = address;
763             address = 0;
764             if (addr != 0) {
765                 end(addr);
766             }
767         }
768 
769     }
770 }
771