emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/Inflater.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 07 Feb 2013 12:58:12 +0100
branchemul
changeset 694 0d277415ed02
parent 687 emul/mini/src/main/java/java/util/zip/Inflater.java@a9e506a27b55
permissions -rw-r--r--
Rebasing the Inflater support on jzlib which, unlike GNU ClassPath, has correct implementation of Huffman code. Making the implementation more easily testable by turning Inflater and ZipInputStream into pure delegates. Current implementation is going to need proper long support.
     1 /*
     2  * Copyright (c) 1996, 2011, 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 org.apidesign.bck2brwsr.emul.zip;
    27 
    28 import java.util.zip.*;
    29 import java.io.IOException;
    30 
    31 /**
    32  * This class provides support for general purpose decompression using the
    33  * popular ZLIB compression library. The ZLIB compression library was
    34  * initially developed as part of the PNG graphics standard and is not
    35  * protected by patents. It is fully described in the specifications at
    36  * the <a href="package-summary.html#package_description">java.util.zip
    37  * package description</a>.
    38  *
    39  * <p>The following code fragment demonstrates a trivial compression
    40  * and decompression of a string using <tt>Deflater</tt> and
    41  * <tt>Inflater</tt>.
    42  *
    43  * <blockquote><pre>
    44  * try {
    45  *     // Encode a String into bytes
    46  *     String inputString = "blahblahblah\u20AC\u20AC";
    47  *     byte[] input = inputString.getBytes("UTF-8");
    48  *
    49  *     // Compress the bytes
    50  *     byte[] output = new byte[100];
    51  *     Deflater compresser = new Deflater();
    52  *     compresser.setInput(input);
    53  *     compresser.finish();
    54  *     int compressedDataLength = compresser.deflate(output);
    55  *
    56  *     // Decompress the bytes
    57  *     Inflater decompresser = new Inflater();
    58  *     decompresser.setInput(output, 0, compressedDataLength);
    59  *     byte[] result = new byte[100];
    60  *     int resultLength = decompresser.inflate(result);
    61  *     decompresser.end();
    62  *
    63  *     // Decode the bytes into a String
    64  *     String outputString = new String(result, 0, resultLength, "UTF-8");
    65  * } catch(java.io.UnsupportedEncodingException ex) {
    66  *     // handle
    67  * } catch (java.util.zip.DataFormatException ex) {
    68  *     // handle
    69  * }
    70  * </pre></blockquote>
    71  *
    72  * @see         Deflater
    73  * @author      David Connelly
    74  *
    75  */
    76 public
    77 class Inflater extends java.util.zip.Inflater {
    78     private final boolean nowrap;
    79     private JzLibInflater impl;
    80     
    81     /**
    82      * Creates a new decompressor. If the parameter 'nowrap' is true then
    83      * the ZLIB header and checksum fields will not be used. This provides
    84      * compatibility with the compression format used by both GZIP and PKZIP.
    85      * <p>
    86      * Note: When using the 'nowrap' option it is also necessary to provide
    87      * an extra "dummy" byte as input. This is required by the ZLIB native
    88      * library in order to support certain optimizations.
    89      *
    90      * @param nowrap if true then support GZIP compatible compression
    91      */
    92     public Inflater(boolean nowrap) {
    93         this.nowrap = nowrap;
    94         reset();
    95     }
    96 
    97     /**
    98      * Creates a new decompressor.
    99      */
   100     public Inflater() {
   101         this(false);
   102     }
   103 
   104     /**
   105      * Sets input data for decompression. Should be called whenever
   106      * needsInput() returns true indicating that more input data is
   107      * required.
   108      * @param b the input data bytes
   109      * @param off the start offset of the input data
   110      * @param len the length of the input data
   111      * @see Inflater#needsInput
   112      */
   113     public void setInput(byte[] b, int off, int len) {
   114         if (b == null) {
   115             throw new NullPointerException();
   116         }
   117         if (off < 0 || len < 0 || off > b.length - len) {
   118             throw new ArrayIndexOutOfBoundsException();
   119         }
   120         impl.setInput(b, off, len, false);
   121     }
   122 
   123     /**
   124      * Sets input data for decompression. Should be called whenever
   125      * needsInput() returns true indicating that more input data is
   126      * required.
   127      * @param b the input data bytes
   128      * @see Inflater#needsInput
   129      */
   130     public void setInput(byte[] b) {
   131         setInput(b, 0, b.length);
   132     }
   133 
   134     /**
   135      * Sets the preset dictionary to the given array of bytes. Should be
   136      * called when inflate() returns 0 and needsDictionary() returns true
   137      * indicating that a preset dictionary is required. The method getAdler()
   138      * can be used to get the Adler-32 value of the dictionary needed.
   139      * @param b the dictionary data bytes
   140      * @param off the start offset of the data
   141      * @param len the length of the data
   142      * @see Inflater#needsDictionary
   143      * @see Inflater#getAdler
   144      */
   145     public void setDictionary(byte[] b, int off, int len) {
   146         if (b == null) {
   147             throw new NullPointerException();
   148         }
   149         if (off < 0 || len < 0 || off > b.length - len) {
   150             throw new ArrayIndexOutOfBoundsException();
   151         }
   152         byte[] arr;
   153         if (off == 0) {
   154             arr = b;
   155         } else {
   156             arr = new byte[len];
   157             org.apidesign.bck2brwsr.emul.lang.System.arraycopy(b, off, arr, 0, len);
   158         }
   159         impl.setDictionary(arr, len);
   160     }
   161 
   162     /**
   163      * Sets the preset dictionary to the given array of bytes. Should be
   164      * called when inflate() returns 0 and needsDictionary() returns true
   165      * indicating that a preset dictionary is required. The method getAdler()
   166      * can be used to get the Adler-32 value of the dictionary needed.
   167      * @param b the dictionary data bytes
   168      * @see Inflater#needsDictionary
   169      * @see Inflater#getAdler
   170      */
   171     public void setDictionary(byte[] b) {
   172         impl.setDictionary(b, b.length);
   173     }
   174 
   175     /**
   176      * Returns the total number of bytes remaining in the input buffer.
   177      * This can be used to find out what bytes still remain in the input
   178      * buffer after decompression has finished.
   179      * @return the total number of bytes remaining in the input buffer
   180      */
   181     public int getRemaining() {
   182         return impl.getAvailIn();
   183     }
   184 
   185     /**
   186      * Returns true if no data remains in the input buffer. This can
   187      * be used to determine if #setInput should be called in order
   188      * to provide more input.
   189      * @return true if no data remains in the input buffer
   190      */
   191     public boolean needsInput() {
   192         return getRemaining() <= 0;
   193     }
   194 
   195     /**
   196      * Returns true if a preset dictionary is needed for decompression.
   197      * @return true if a preset dictionary is needed for decompression
   198      * @see Inflater#setDictionary
   199      */
   200     public boolean needsDictionary() {
   201         return impl.needDict();
   202     }
   203 
   204     /**
   205      * Returns true if the end of the compressed data stream has been
   206      * reached.
   207      * @return true if the end of the compressed data stream has been
   208      * reached
   209      */
   210     public boolean finished() {
   211         return impl.finished();
   212     }
   213 
   214     /**
   215      * Uncompresses bytes into specified buffer. Returns actual number
   216      * of bytes uncompressed. A return value of 0 indicates that
   217      * needsInput() or needsDictionary() should be called in order to
   218      * determine if more input data or a preset dictionary is required.
   219      * In the latter case, getAdler() can be used to get the Adler-32
   220      * value of the dictionary required.
   221      * @param b the buffer for the uncompressed data
   222      * @param off the start offset of the data
   223      * @param len the maximum number of uncompressed bytes
   224      * @return the actual number of uncompressed bytes
   225      * @exception DataFormatException if the compressed data format is invalid
   226      * @see Inflater#needsInput
   227      * @see Inflater#needsDictionary
   228      */
   229     public int inflate(byte[] b, int off, int len)
   230         throws DataFormatException
   231     {
   232         if (b == null) {
   233             throw new NullPointerException();
   234         }
   235         if (off < 0 || len < 0 || off > b.length - len) {
   236             throw new ArrayIndexOutOfBoundsException();
   237         }
   238         impl.setOutput(b, off, len);
   239         int err = impl.inflate(JzLibInflater.Z_NO_FLUSH);
   240         return impl.next_out_index - off;
   241     }
   242 
   243     /**
   244      * Uncompresses bytes into specified buffer. Returns actual number
   245      * of bytes uncompressed. A return value of 0 indicates that
   246      * needsInput() or needsDictionary() should be called in order to
   247      * determine if more input data or a preset dictionary is required.
   248      * In the latter case, getAdler() can be used to get the Adler-32
   249      * value of the dictionary required.
   250      * @param b the buffer for the uncompressed data
   251      * @return the actual number of uncompressed bytes
   252      * @exception DataFormatException if the compressed data format is invalid
   253      * @see Inflater#needsInput
   254      * @see Inflater#needsDictionary
   255      */
   256     public int inflate(byte[] b) throws DataFormatException {
   257         return inflate(b, 0, b.length);
   258     }
   259 
   260     /**
   261      * Returns the ADLER-32 value of the uncompressed data.
   262      * @return the ADLER-32 value of the uncompressed data
   263      */
   264     public int getAdler() {
   265         return (int) impl.getAdler();
   266     }
   267 
   268     /**
   269      * Returns the total number of compressed bytes input so far.
   270      *
   271      * <p>Since the number of bytes may be greater than
   272      * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
   273      * the preferred means of obtaining this information.</p>
   274      *
   275      * @return the total number of compressed bytes input so far
   276      */
   277     public int getTotalIn() {
   278         return (int) getBytesRead();
   279     }
   280 
   281     /**
   282      * Returns the total number of compressed bytes input so far.</p>
   283      *
   284      * @return the total (non-negative) number of compressed bytes input so far
   285      * @since 1.5
   286      */
   287     public long getBytesRead() {
   288         return impl.total_in;
   289     }
   290 
   291     /**
   292      * Returns the total number of uncompressed bytes output so far.
   293      *
   294      * <p>Since the number of bytes may be greater than
   295      * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
   296      * the preferred means of obtaining this information.</p>
   297      *
   298      * @return the total number of uncompressed bytes output so far
   299      */
   300     public int getTotalOut() {
   301         return (int) getBytesWritten();
   302     }
   303 
   304     /**
   305      * Returns the total number of uncompressed bytes output so far.</p>
   306      *
   307      * @return the total (non-negative) number of uncompressed bytes output so far
   308      * @since 1.5
   309      */
   310     public long getBytesWritten() {
   311         return impl.total_out;
   312     }
   313 
   314     /**
   315      * Resets inflater so that a new set of input data can be processed.
   316      */
   317     public void reset() {
   318         impl = new JzLibInflater(15, nowrap);
   319     }
   320 
   321     /**
   322      * Closes the decompressor and discards any unprocessed input.
   323      * This method should be called when the decompressor is no longer
   324      * being used, but will also be called automatically by the finalize()
   325      * method. Once this method is called, the behavior of the Inflater
   326      * object is undefined.
   327      */
   328     public void end() {
   329         impl.end();
   330     }
   331 
   332     /**
   333      * Closes the decompressor when garbage is collected.
   334      */
   335     protected void finalize() {
   336         end();
   337     }
   338 }