1   /*
2    * %W% %E%
3    *
4    * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
5    * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6    */
7   
8   package java.util.zip;
9   
10  /**
11   * This class provides support for general purpose decompression using the
12   * popular ZLIB compression library. The ZLIB compression library was
13   * initially developed as part of the PNG graphics standard and is not
14   * protected by patents. It is fully described in the specifications at 
15   * the <a href="package-summary.html#package_description">java.util.zip
16   * package description</a>.
17   *
18   * <p>The following code fragment demonstrates a trivial compression
19   * and decompression of a string using <tt>Deflater</tt> and
20   * <tt>Inflater</tt>.
21   *
22   * <blockquote><pre>
23   * try {
24   *     // Encode a String into bytes
25   *     String inputString = "blahblahblah€€";
26   *     byte[] input = inputString.getBytes("UTF-8");
27   *
28   *     // Compress the bytes
29   *     byte[] output = new byte[100];
30   *     Deflater compresser = new Deflater();
31   *     compresser.setInput(input);
32   *     compresser.finish();
33   *     int compressedDataLength = compresser.deflate(output);
34   *
35   *     // Decompress the bytes
36   *     Inflater decompresser = new Inflater();
37   *     decompresser.setInput(output, 0, compressedDataLength);
38   *     byte[] result = new byte[100];
39   *     int resultLength = decompresser.inflate(result);
40   *     decompresser.end();
41   *
42   *     // Decode the bytes into a String
43   *     String outputString = new String(result, 0, resultLength, "UTF-8");
44   * } catch(java.io.UnsupportedEncodingException ex) {
45   *     // handle
46   * } catch (java.util.zip.DataFormatException ex) {
47   *     // handle
48   * }
49   * </pre></blockquote>
50   *
51   * @see     Deflater
52   * @version     1.47, 04/07/06
53   * @author  David Connelly
54   *
55   */
56  public
57  class Inflater {
58      private final ZStreamRef zsRef;
59      private byte[] buf = emptyBuf;
60      private int off, len;
61      private boolean finished;
62      private boolean needDict;
63  
64      private static byte[] emptyBuf = new byte[0];
65  
66      static {
67      /* Zip library is loaded from System.initializeSystemClass */
68      initIDs();
69      }
70  
71      /**
72       * Creates a new decompressor. If the parameter 'nowrap' is true then
73       * the ZLIB header and checksum fields will not be used. This provides
74       * compatibility with the compression format used by both GZIP and PKZIP.
75       * <p>
76       * Note: When using the 'nowrap' option it is also necessary to provide
77       * an extra "dummy" byte as input. This is required by the ZLIB native
78       * library in order to support certain optimizations.
79       *
80       * @param nowrap if true then support GZIP compatible compression
81       */
82      public Inflater(boolean nowrap) {
83          zsRef = new ZStreamRef(init(nowrap));
84      }
85  
86      /**
87       * Creates a new decompressor.
88       */
89      public Inflater() {
90      this(false);
91      }
92  
93      /**
94       * Sets input data for decompression. Should be called whenever
95       * needsInput() returns true indicating that more input data is
96       * required.
97       * @param b the input data bytes
98       * @param off the start offset of the input data
99       * @param len the length of the input data
100      * @see Inflater#needsInput
101      */
102     public void setInput(byte[] b, int off, int len) {
103         if (b == null) {
104             throw new NullPointerException();
105         }
106         if (off < 0 || len < 0 || off > b.length - len) {
107             throw new ArrayIndexOutOfBoundsException();
108         }
109         synchronized (zsRef) {
110             this.buf = b;
111             this.off = off;
112             this.len = len;
113         }
114     }
115 
116     /**
117      * Sets input data for decompression. Should be called whenever
118      * needsInput() returns true indicating that more input data is
119      * required.
120      * @param b the input data bytes
121      * @see Inflater#needsInput
122      */
123     public void setInput(byte[] b) {
124     setInput(b, 0, b.length);
125     }
126 
127     /**
128      * Sets the preset dictionary to the given array of bytes. Should be
129      * called when inflate() returns 0 and needsDictionary() returns true
130      * indicating that a preset dictionary is required. The method getAdler()
131      * can be used to get the Adler-32 value of the dictionary needed.
132      * @param b the dictionary data bytes
133      * @param off the start offset of the data
134      * @param len the length of the data
135      * @see Inflater#needsDictionary
136      * @see Inflater#getAdler
137      */
138     public void setDictionary(byte[] b, int off, int len) {
139     if (b == null) {
140         throw new NullPointerException();
141     }
142     if (off < 0 || len < 0 || off > b.length - len) {
143         throw new ArrayIndexOutOfBoundsException();
144     }
145         synchronized (zsRef) {
146             ensureOpen();
147             setDictionary(zsRef.address(), b, off, len);
148             needDict = false;
149         }
150     }
151 
152     /**
153      * Sets the preset dictionary to the given array of bytes. Should be
154      * called when inflate() returns 0 and needsDictionary() returns true
155      * indicating that a preset dictionary is required. The method getAdler()
156      * can be used to get the Adler-32 value of the dictionary needed.
157      * @param b the dictionary data bytes
158      * @see Inflater#needsDictionary
159      * @see Inflater#getAdler
160      */
161     public void setDictionary(byte[] b) {
162     setDictionary(b, 0, b.length);
163     }
164 
165     /**
166      * Returns the total number of bytes remaining in the input buffer.
167      * This can be used to find out what bytes still remain in the input
168      * buffer after decompression has finished.
169      * @return the total number of bytes remaining in the input buffer
170      */
171     public int getRemaining() {
172         synchronized (zsRef) {
173             return len;
174         }
175     }
176 
177     /**
178      * Returns true if no data remains in the input buffer. This can
179      * be used to determine if #setInput should be called in order
180      * to provide more input.
181      * @return true if no data remains in the input buffer
182      */
183     public boolean needsInput() {
184         synchronized (zsRef) {
185             return len <= 0;
186         }
187     }
188 
189     /**
190      * Returns true if a preset dictionary is needed for decompression.
191      * @return true if a preset dictionary is needed for decompression
192      * @see Inflater#setDictionary
193      */
194     public boolean needsDictionary() {
195         synchronized (zsRef) {
196             return needDict;
197         }
198     }
199 
200     /**
201      * Returns true if the end of the compressed data stream has been
202      * reached.
203      * @return true if the end of the compressed data stream has been
204      * reached
205      */
206     public boolean finished() {
207         synchronized (zsRef) {
208             return finished;
209         }
210     }
211 
212     /**
213      * Uncompresses bytes into specified buffer. Returns actual number
214      * of bytes uncompressed. A return value of 0 indicates that
215      * needsInput() or needsDictionary() should be called in order to
216      * determine if more input data or a preset dictionary is required.
217      * In the latter case, getAdler() can be used to get the Adler-32
218      * value of the dictionary required.
219      * @param b the buffer for the uncompressed data
220      * @param off the start offset of the data
221      * @param len the maximum number of uncompressed bytes
222      * @return the actual number of uncompressed bytes
223      * @exception DataFormatException if the compressed data format is invalid
224      * @see Inflater#needsInput
225      * @see Inflater#needsDictionary
226      */
227     public int inflate(byte[] b, int off, int len)
228         throws DataFormatException
229     {
230         if (b == null) {
231             throw new NullPointerException();
232         }
233         if (off < 0 || len < 0 || off > b.length - len) {
234             throw new ArrayIndexOutOfBoundsException();
235         }
236         synchronized (zsRef) {
237             ensureOpen();
238             return inflateBytes(zsRef.address(), b, off, len);
239         }
240     }
241 
242     /**
243      * Uncompresses bytes into specified buffer. Returns actual number
244      * of bytes uncompressed. A return value of 0 indicates that
245      * needsInput() or needsDictionary() should be called in order to
246      * determine if more input data or a preset dictionary is required.
247      * In the latter case, getAdler() can be used to get the Adler-32
248      * value of the dictionary required.
249      * @param b the buffer for the uncompressed data
250      * @return the actual number of uncompressed bytes
251      * @exception DataFormatException if the compressed data format is invalid
252      * @see Inflater#needsInput
253      * @see Inflater#needsDictionary
254      */
255     public int inflate(byte[] b) throws DataFormatException {
256     return inflate(b, 0, b.length);
257     }
258 
259     /**
260      * Returns the ADLER-32 value of the uncompressed data.
261      * @return the ADLER-32 value of the uncompressed data
262      */
263     public int getAdler() {
264         synchronized (zsRef) {
265             ensureOpen();
266             return getAdler(zsRef.address());
267         }
268     }
269 
270     /**
271      * Returns the total number of compressed bytes input so far.
272      *
273      * <p>Since the number of bytes may be greater than
274      * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
275      * the preferred means of obtaining this information.</p>
276      *
277      * @return the total number of compressed bytes input so far
278      */
279     public int getTotalIn() {
280     return (int) getBytesRead();
281     }
282 
283     /**
284      * Returns the total number of compressed bytes input so far.</p>
285      *
286      * @return the total (non-negative) number of compressed bytes input so far
287      * @since 1.5
288      */
289     public long getBytesRead() {
290         synchronized (zsRef) {
291             ensureOpen();
292             return getBytesRead(zsRef.address());
293         }
294     }
295 
296     /**
297      * Returns the total number of uncompressed bytes output so far.
298      *
299      * <p>Since the number of bytes may be greater than
300      * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
301      * the preferred means of obtaining this information.</p>
302      *
303      * @return the total number of uncompressed bytes output so far
304      */
305     public int getTotalOut() {
306     return (int) getBytesWritten();
307     }
308 
309     /**
310      * Returns the total number of uncompressed bytes output so far.</p>
311      *
312      * @return the total (non-negative) number of uncompressed bytes output so far
313      * @since 1.5
314      */
315     public long getBytesWritten() {
316         synchronized (zsRef) {
317             ensureOpen();
318             return getBytesWritten(zsRef.address());
319         }
320     }
321 
322     /**
323      * Resets inflater so that a new set of input data can be processed.
324      */
325     public void reset() {
326         synchronized (zsRef) {
327             ensureOpen();
328             reset(zsRef.address());
329             buf = emptyBuf;
330             finished = false;
331             needDict = false;
332             off = len = 0;
333         }
334     }
335 
336     /**
337      * Closes the decompressor and discards any unprocessed input.
338      * This method should be called when the decompressor is no longer
339      * being used, but will also be called automatically by the finalize()
340      * method. Once this method is called, the behavior of the Inflater
341      * object is undefined.
342      */
343     public void end() {
344         synchronized (zsRef) {
345             long addr = zsRef.address();
346             zsRef.clear();
347             if (addr != 0) {
348                 end(addr);
349                 buf = null;
350             }
351         }
352     }
353 
354     /**
355      * Closes the decompressor when garbage is collected.
356      */
357     protected void finalize() {
358     end();
359     }
360 
361     private void ensureOpen () {
362         assert Thread.holdsLock(zsRef);
363         if (zsRef.address() == 0)
364             throw new NullPointerException("Inflater has been closed");
365     }
366 
367     private native static void initIDs();
368     private native static long init(boolean nowrap);
369     private native static void setDictionary(long addr, byte[] b, int off,
370                          int len);
371     private native int inflateBytes(long addr, byte[] b, int off, int len)
372         throws DataFormatException;
373     private native static int getAdler(long addr);
374     private native static long getBytesRead(long addr);
375     private native static long getBytesWritten(long addr);
376     private native static void reset(long addr);
377     private native static void end(long addr);
378 }
379