emul/mini/src/main/java/java/util/zip/Inflater.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Thu, 07 Feb 2013 12:58:12 +0100
branchemul
changeset 694 0d277415ed02
parent 687 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.
jaroslav@694
     1
/*
jaroslav@694
     2
 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
jaroslav@694
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jaroslav@694
     4
 *
jaroslav@694
     5
 * This code is free software; you can redistribute it and/or modify it
jaroslav@694
     6
 * under the terms of the GNU General Public License version 2 only, as
jaroslav@694
     7
 * published by the Free Software Foundation.  Oracle designates this
jaroslav@694
     8
 * particular file as subject to the "Classpath" exception as provided
jaroslav@694
     9
 * by Oracle in the LICENSE file that accompanied this code.
jaroslav@694
    10
 *
jaroslav@694
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
jaroslav@694
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jaroslav@694
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
jaroslav@694
    14
 * version 2 for more details (a copy is included in the LICENSE file that
jaroslav@694
    15
 * accompanied this code).
jaroslav@694
    16
 *
jaroslav@694
    17
 * You should have received a copy of the GNU General Public License version
jaroslav@694
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
jaroslav@694
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jaroslav@694
    20
 *
jaroslav@694
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jaroslav@694
    22
 * or visit www.oracle.com if you need additional information or have any
jaroslav@694
    23
 * questions.
jaroslav@694
    24
 */
jaroslav@609
    25
jaroslav@609
    26
package java.util.zip;
jaroslav@609
    27
jaroslav@609
    28
/**
jaroslav@609
    29
 * This class provides support for general purpose decompression using the
jaroslav@609
    30
 * popular ZLIB compression library. The ZLIB compression library was
jaroslav@609
    31
 * initially developed as part of the PNG graphics standard and is not
jaroslav@609
    32
 * protected by patents. It is fully described in the specifications at
jaroslav@609
    33
 * the <a href="package-summary.html#package_description">java.util.zip
jaroslav@609
    34
 * package description</a>.
jaroslav@609
    35
 *
jaroslav@609
    36
 * <p>The following code fragment demonstrates a trivial compression
jaroslav@609
    37
 * and decompression of a string using <tt>Deflater</tt> and
jaroslav@609
    38
 * <tt>Inflater</tt>.
jaroslav@609
    39
 *
jaroslav@609
    40
 * <blockquote><pre>
jaroslav@609
    41
 * try {
jaroslav@609
    42
 *     // Encode a String into bytes
jaroslav@609
    43
 *     String inputString = "blahblahblah\u20AC\u20AC";
jaroslav@609
    44
 *     byte[] input = inputString.getBytes("UTF-8");
jaroslav@609
    45
 *
jaroslav@609
    46
 *     // Compress the bytes
jaroslav@609
    47
 *     byte[] output = new byte[100];
jaroslav@609
    48
 *     Deflater compresser = new Deflater();
jaroslav@609
    49
 *     compresser.setInput(input);
jaroslav@609
    50
 *     compresser.finish();
jaroslav@609
    51
 *     int compressedDataLength = compresser.deflate(output);
jaroslav@609
    52
 *
jaroslav@609
    53
 *     // Decompress the bytes
jaroslav@609
    54
 *     Inflater decompresser = new Inflater();
jaroslav@609
    55
 *     decompresser.setInput(output, 0, compressedDataLength);
jaroslav@609
    56
 *     byte[] result = new byte[100];
jaroslav@609
    57
 *     int resultLength = decompresser.inflate(result);
jaroslav@609
    58
 *     decompresser.end();
jaroslav@609
    59
 *
jaroslav@609
    60
 *     // Decode the bytes into a String
jaroslav@609
    61
 *     String outputString = new String(result, 0, resultLength, "UTF-8");
jaroslav@609
    62
 * } catch(java.io.UnsupportedEncodingException ex) {
jaroslav@609
    63
 *     // handle
jaroslav@609
    64
 * } catch (java.util.zip.DataFormatException ex) {
jaroslav@609
    65
 *     // handle
jaroslav@609
    66
 * }
jaroslav@609
    67
 * </pre></blockquote>
jaroslav@609
    68
 *
jaroslav@609
    69
 * @see         Deflater
jaroslav@609
    70
 * @author      David Connelly
jaroslav@609
    71
 *
jaroslav@609
    72
 */
jaroslav@694
    73
public
jaroslav@694
    74
class Inflater {
jaroslav@694
    75
    private final org.apidesign.bck2brwsr.emul.zip.Inflater impl;
jaroslav@640
    76
    
jaroslav@694
    77
    /**
jaroslav@694
    78
     * Creates a new decompressor. If the parameter 'nowrap' is true then
jaroslav@694
    79
     * the ZLIB header and checksum fields will not be used. This provides
jaroslav@694
    80
     * compatibility with the compression format used by both GZIP and PKZIP.
jaroslav@694
    81
     * <p>
jaroslav@694
    82
     * Note: When using the 'nowrap' option it is also necessary to provide
jaroslav@694
    83
     * an extra "dummy" byte as input. This is required by the ZLIB native
jaroslav@694
    84
     * library in order to support certain optimizations.
jaroslav@694
    85
     *
jaroslav@694
    86
     * @param nowrap if true then support GZIP compatible compression
jaroslav@640
    87
     */
jaroslav@694
    88
    public Inflater(boolean nowrap) {
jaroslav@694
    89
        if (getClass() == org.apidesign.bck2brwsr.emul.zip.Inflater.class) {
jaroslav@694
    90
            impl = null;
jaroslav@694
    91
        } else {
jaroslav@694
    92
            impl = new org.apidesign.bck2brwsr.emul.zip.Inflater(nowrap);
jaroslav@687
    93
        }
jaroslav@640
    94
    }
jaroslav@694
    95
jaroslav@694
    96
    /**
jaroslav@694
    97
     * Creates a new decompressor.
jaroslav@694
    98
     */
jaroslav@694
    99
    public Inflater() {
jaroslav@694
   100
        this(false);
jaroslav@694
   101
    }
jaroslav@694
   102
jaroslav@694
   103
    /**
jaroslav@694
   104
     * Sets input data for decompression. Should be called whenever
jaroslav@694
   105
     * needsInput() returns true indicating that more input data is
jaroslav@694
   106
     * required.
jaroslav@694
   107
     * @param b the input data bytes
jaroslav@694
   108
     * @param off the start offset of the input data
jaroslav@694
   109
     * @param len the length of the input data
jaroslav@694
   110
     * @see Inflater#needsInput
jaroslav@694
   111
     */
jaroslav@694
   112
    public void setInput(byte[] b, int off, int len) {
jaroslav@694
   113
        impl.setInput(b, off, len);
jaroslav@694
   114
    }
jaroslav@694
   115
jaroslav@694
   116
    /**
jaroslav@694
   117
     * Sets input data for decompression. Should be called whenever
jaroslav@694
   118
     * needsInput() returns true indicating that more input data is
jaroslav@694
   119
     * required.
jaroslav@694
   120
     * @param b the input data bytes
jaroslav@694
   121
     * @see Inflater#needsInput
jaroslav@694
   122
     */
jaroslav@694
   123
    public void setInput(byte[] b) {
jaroslav@694
   124
        impl.setInput(b);
jaroslav@694
   125
    }
jaroslav@694
   126
jaroslav@694
   127
    /**
jaroslav@694
   128
     * Sets the preset dictionary to the given array of bytes. Should be
jaroslav@694
   129
     * called when inflate() returns 0 and needsDictionary() returns true
jaroslav@694
   130
     * indicating that a preset dictionary is required. The method getAdler()
jaroslav@694
   131
     * can be used to get the Adler-32 value of the dictionary needed.
jaroslav@694
   132
     * @param b the dictionary data bytes
jaroslav@694
   133
     * @param off the start offset of the data
jaroslav@694
   134
     * @param len the length of the data
jaroslav@694
   135
     * @see Inflater#needsDictionary
jaroslav@694
   136
     * @see Inflater#getAdler
jaroslav@694
   137
     */
jaroslav@694
   138
    public void setDictionary(byte[] b, int off, int len) {
jaroslav@694
   139
        impl.setDictionary(b, off, len);
jaroslav@694
   140
    }
jaroslav@694
   141
jaroslav@694
   142
    /**
jaroslav@694
   143
     * Sets the preset dictionary to the given array of bytes. Should be
jaroslav@694
   144
     * called when inflate() returns 0 and needsDictionary() returns true
jaroslav@694
   145
     * indicating that a preset dictionary is required. The method getAdler()
jaroslav@694
   146
     * can be used to get the Adler-32 value of the dictionary needed.
jaroslav@694
   147
     * @param b the dictionary data bytes
jaroslav@694
   148
     * @see Inflater#needsDictionary
jaroslav@694
   149
     * @see Inflater#getAdler
jaroslav@694
   150
     */
jaroslav@694
   151
    public void setDictionary(byte[] b) {
jaroslav@694
   152
        impl.setDictionary(b);
jaroslav@694
   153
    }
jaroslav@694
   154
jaroslav@694
   155
    /**
jaroslav@694
   156
     * Returns the total number of bytes remaining in the input buffer.
jaroslav@694
   157
     * This can be used to find out what bytes still remain in the input
jaroslav@694
   158
     * buffer after decompression has finished.
jaroslav@694
   159
     * @return the total number of bytes remaining in the input buffer
jaroslav@694
   160
     */
jaroslav@694
   161
    public int getRemaining() {
jaroslav@694
   162
        return impl.getRemaining();
jaroslav@694
   163
    }
jaroslav@694
   164
jaroslav@694
   165
    /**
jaroslav@694
   166
     * Returns true if no data remains in the input buffer. This can
jaroslav@694
   167
     * be used to determine if #setInput should be called in order
jaroslav@694
   168
     * to provide more input.
jaroslav@694
   169
     * @return true if no data remains in the input buffer
jaroslav@694
   170
     */
jaroslav@694
   171
    public boolean needsInput() {
jaroslav@694
   172
        return impl.needsInput();
jaroslav@694
   173
    }
jaroslav@694
   174
jaroslav@694
   175
    /**
jaroslav@694
   176
     * Returns true if a preset dictionary is needed for decompression.
jaroslav@694
   177
     * @return true if a preset dictionary is needed for decompression
jaroslav@694
   178
     * @see Inflater#setDictionary
jaroslav@694
   179
     */
jaroslav@694
   180
    public boolean needsDictionary() {
jaroslav@694
   181
        return impl.needsDictionary();
jaroslav@694
   182
    }
jaroslav@694
   183
jaroslav@694
   184
    /**
jaroslav@694
   185
     * Returns true if the end of the compressed data stream has been
jaroslav@694
   186
     * reached.
jaroslav@694
   187
     * @return true if the end of the compressed data stream has been
jaroslav@694
   188
     * reached
jaroslav@694
   189
     */
jaroslav@694
   190
    public boolean finished() {
jaroslav@694
   191
        return impl.finished();
jaroslav@694
   192
    }
jaroslav@694
   193
jaroslav@694
   194
    /**
jaroslav@694
   195
     * Uncompresses bytes into specified buffer. Returns actual number
jaroslav@694
   196
     * of bytes uncompressed. A return value of 0 indicates that
jaroslav@694
   197
     * needsInput() or needsDictionary() should be called in order to
jaroslav@694
   198
     * determine if more input data or a preset dictionary is required.
jaroslav@694
   199
     * In the latter case, getAdler() can be used to get the Adler-32
jaroslav@694
   200
     * value of the dictionary required.
jaroslav@694
   201
     * @param b the buffer for the uncompressed data
jaroslav@694
   202
     * @param off the start offset of the data
jaroslav@694
   203
     * @param len the maximum number of uncompressed bytes
jaroslav@694
   204
     * @return the actual number of uncompressed bytes
jaroslav@694
   205
     * @exception DataFormatException if the compressed data format is invalid
jaroslav@694
   206
     * @see Inflater#needsInput
jaroslav@694
   207
     * @see Inflater#needsDictionary
jaroslav@694
   208
     */
jaroslav@694
   209
    public int inflate(byte[] b, int off, int len)
jaroslav@694
   210
        throws DataFormatException
jaroslav@640
   211
    {
jaroslav@694
   212
        return impl.inflate(b, off, len);
jaroslav@694
   213
    }
jaroslav@640
   214
jaroslav@694
   215
    /**
jaroslav@694
   216
     * Uncompresses bytes into specified buffer. Returns actual number
jaroslav@694
   217
     * of bytes uncompressed. A return value of 0 indicates that
jaroslav@694
   218
     * needsInput() or needsDictionary() should be called in order to
jaroslav@694
   219
     * determine if more input data or a preset dictionary is required.
jaroslav@694
   220
     * In the latter case, getAdler() can be used to get the Adler-32
jaroslav@694
   221
     * value of the dictionary required.
jaroslav@694
   222
     * @param b the buffer for the uncompressed data
jaroslav@694
   223
     * @return the actual number of uncompressed bytes
jaroslav@694
   224
     * @exception DataFormatException if the compressed data format is invalid
jaroslav@694
   225
     * @see Inflater#needsInput
jaroslav@694
   226
     * @see Inflater#needsDictionary
jaroslav@694
   227
     */
jaroslav@694
   228
    public int inflate(byte[] b) throws DataFormatException {
jaroslav@694
   229
        return impl.inflate(b);
jaroslav@694
   230
    }
jaroslav@640
   231
jaroslav@694
   232
    /**
jaroslav@694
   233
     * Returns the ADLER-32 value of the uncompressed data.
jaroslav@694
   234
     * @return the ADLER-32 value of the uncompressed data
jaroslav@694
   235
     */
jaroslav@694
   236
    public int getAdler() {
jaroslav@694
   237
        return impl.getAdler();
jaroslav@694
   238
    }
jaroslav@640
   239
jaroslav@694
   240
    /**
jaroslav@694
   241
     * Returns the total number of compressed bytes input so far.
jaroslav@694
   242
     *
jaroslav@694
   243
     * <p>Since the number of bytes may be greater than
jaroslav@694
   244
     * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
jaroslav@694
   245
     * the preferred means of obtaining this information.</p>
jaroslav@694
   246
     *
jaroslav@694
   247
     * @return the total number of compressed bytes input so far
jaroslav@694
   248
     */
jaroslav@694
   249
    public int getTotalIn() {
jaroslav@694
   250
        return impl.getTotalIn();
jaroslav@694
   251
    }
jaroslav@640
   252
jaroslav@694
   253
    /**
jaroslav@694
   254
     * Returns the total number of compressed bytes input so far.</p>
jaroslav@694
   255
     *
jaroslav@694
   256
     * @return the total (non-negative) number of compressed bytes input so far
jaroslav@694
   257
     * @since 1.5
jaroslav@694
   258
     */
jaroslav@694
   259
    public long getBytesRead() {
jaroslav@694
   260
        return impl.getBytesRead();
jaroslav@694
   261
    }
jaroslav@640
   262
jaroslav@694
   263
    /**
jaroslav@694
   264
     * Returns the total number of uncompressed bytes output so far.
jaroslav@694
   265
     *
jaroslav@694
   266
     * <p>Since the number of bytes may be greater than
jaroslav@694
   267
     * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
jaroslav@694
   268
     * the preferred means of obtaining this information.</p>
jaroslav@694
   269
     *
jaroslav@694
   270
     * @return the total number of uncompressed bytes output so far
jaroslav@694
   271
     */
jaroslav@694
   272
    public int getTotalOut() {
jaroslav@694
   273
        return impl.getTotalOut();
jaroslav@694
   274
    }
jaroslav@640
   275
jaroslav@694
   276
    /**
jaroslav@694
   277
     * Returns the total number of uncompressed bytes output so far.</p>
jaroslav@694
   278
     *
jaroslav@694
   279
     * @return the total (non-negative) number of uncompressed bytes output so far
jaroslav@694
   280
     * @since 1.5
jaroslav@694
   281
     */
jaroslav@694
   282
    public long getBytesWritten() {
jaroslav@694
   283
        return impl.getBytesWritten();
jaroslav@694
   284
    }
jaroslav@640
   285
jaroslav@694
   286
    /**
jaroslav@694
   287
     * Resets inflater so that a new set of input data can be processed.
jaroslav@694
   288
     */
jaroslav@694
   289
    public void reset() {
jaroslav@694
   290
        impl.reset();
jaroslav@694
   291
    }
jaroslav@640
   292
jaroslav@694
   293
    /**
jaroslav@694
   294
     * Closes the decompressor and discards any unprocessed input.
jaroslav@694
   295
     * This method should be called when the decompressor is no longer
jaroslav@694
   296
     * being used, but will also be called automatically by the finalize()
jaroslav@694
   297
     * method. Once this method is called, the behavior of the Inflater
jaroslav@694
   298
     * object is undefined.
jaroslav@694
   299
     */
jaroslav@694
   300
    public void end() {
jaroslav@694
   301
        impl.end();
jaroslav@694
   302
    }
jaroslav@640
   303
jaroslav@694
   304
    /**
jaroslav@694
   305
     * Closes the decompressor when garbage is collected.
jaroslav@694
   306
     */
jaroslav@694
   307
    protected void finalize() {
jaroslav@694
   308
        end();
jaroslav@640
   309
    }
jaroslav@609
   310
}