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