Using GNU ClassPath implementation of ZipInputStream. Taken from http://sourceforge.net/projects/jazzlib/ rev. jazzlib-0.07.zip
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/emul/mini/src/main/java/java/util/zip/Adler32.java Fri Feb 01 18:02:16 2013 +0100
1.3 @@ -0,0 +1,205 @@
1.4 +/* Adler32.java - Computes Adler32 data checksum of a data stream
1.5 + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
1.6 +
1.7 +This file is part of GNU Classpath.
1.8 +
1.9 +GNU Classpath is free software; you can redistribute it and/or modify
1.10 +it under the terms of the GNU General Public License as published by
1.11 +the Free Software Foundation; either version 2, or (at your option)
1.12 +any later version.
1.13 +
1.14 +GNU Classpath is distributed in the hope that it will be useful, but
1.15 +WITHOUT ANY WARRANTY; without even the implied warranty of
1.16 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1.17 +General Public License for more details.
1.18 +
1.19 +You should have received a copy of the GNU General Public License
1.20 +along with GNU Classpath; see the file COPYING. If not, write to the
1.21 +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
1.22 +02111-1307 USA.
1.23 +
1.24 +Linking this library statically or dynamically with other modules is
1.25 +making a combined work based on this library. Thus, the terms and
1.26 +conditions of the GNU General Public License cover the whole
1.27 +combination.
1.28 +
1.29 +As a special exception, the copyright holders of this library give you
1.30 +permission to link this library with independent modules to produce an
1.31 +executable, regardless of the license terms of these independent
1.32 +modules, and to copy and distribute the resulting executable under
1.33 +terms of your choice, provided that you also meet, for each linked
1.34 +independent module, the terms and conditions of the license of that
1.35 +module. An independent module is a module which is not derived from
1.36 +or based on this library. If you modify this library, you may extend
1.37 +this exception to your version of the library, but you are not
1.38 +obligated to do so. If you do not wish to do so, delete this
1.39 +exception statement from your version. */
1.40 +
1.41 +package java.util.zip;
1.42 +
1.43 +/*
1.44 + * Written using on-line Java Platform 1.2 API Specification, as well
1.45 + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
1.46 + * The actual Adler32 algorithm is taken from RFC 1950.
1.47 + * Status: Believed complete and correct.
1.48 + */
1.49 +
1.50 +/**
1.51 + * Computes Adler32 checksum for a stream of data. An Adler32
1.52 + * checksum is not as reliable as a CRC32 checksum, but a lot faster to
1.53 + * compute.
1.54 + *<p>
1.55 + * The specification for Adler32 may be found in RFC 1950.
1.56 + * (ZLIB Compressed Data Format Specification version 3.3)
1.57 + *<p>
1.58 + *<p>
1.59 + * From that document:
1.60 + *<p>
1.61 + * "ADLER32 (Adler-32 checksum)
1.62 + * This contains a checksum value of the uncompressed data
1.63 + * (excluding any dictionary data) computed according to Adler-32
1.64 + * algorithm. This algorithm is a 32-bit extension and improvement
1.65 + * of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073
1.66 + * standard.
1.67 + *<p>
1.68 + * Adler-32 is composed of two sums accumulated per byte: s1 is
1.69 + * the sum of all bytes, s2 is the sum of all s1 values. Both sums
1.70 + * are done modulo 65521. s1 is initialized to 1, s2 to zero. The
1.71 + * Adler-32 checksum is stored as s2*65536 + s1 in most-
1.72 + * significant-byte first (network) order."
1.73 + *<p>
1.74 + * "8.2. The Adler-32 algorithm
1.75 + *<p>
1.76 + * The Adler-32 algorithm is much faster than the CRC32 algorithm yet
1.77 + * still provides an extremely low probability of undetected errors.
1.78 + *<p>
1.79 + * The modulo on unsigned long accumulators can be delayed for 5552
1.80 + * bytes, so the modulo operation time is negligible. If the bytes
1.81 + * are a, b, c, the second sum is 3a + 2b + c + 3, and so is position
1.82 + * and order sensitive, unlike the first sum, which is just a
1.83 + * checksum. That 65521 is prime is important to avoid a possible
1.84 + * large class of two-byte errors that leave the check unchanged.
1.85 + * (The Fletcher checksum uses 255, which is not prime and which also
1.86 + * makes the Fletcher check insensitive to single byte changes 0 <->
1.87 + * 255.)
1.88 + *<p>
1.89 + * The sum s1 is initialized to 1 instead of zero to make the length
1.90 + * of the sequence part of s2, so that the length does not have to be
1.91 + * checked separately. (Any sequence of zeroes has a Fletcher
1.92 + * checksum of zero.)"
1.93 + *
1.94 + * @author John Leuner, Per Bothner
1.95 + * @since JDK 1.1
1.96 + *
1.97 + * @see InflaterInputStream
1.98 + * @see DeflaterOutputStream
1.99 + */
1.100 +public class Adler32 implements Checksum
1.101 +{
1.102 +
1.103 + /** largest prime smaller than 65536 */
1.104 + private static final int BASE = 65521;
1.105 +
1.106 + private int checksum; //we do all in int.
1.107 +
1.108 + //Note that java doesn't have unsigned integers,
1.109 + //so we have to be careful with what arithmetic
1.110 + //we do. We return the checksum as a long to
1.111 + //avoid sign confusion.
1.112 +
1.113 + /**
1.114 + * Creates a new instance of the <code>Adler32</code> class.
1.115 + * The checksum starts off with a value of 1.
1.116 + */
1.117 + public Adler32 ()
1.118 + {
1.119 + reset();
1.120 + }
1.121 +
1.122 + /**
1.123 + * Resets the Adler32 checksum to the initial value.
1.124 + */
1.125 + public void reset ()
1.126 + {
1.127 + checksum = 1; //Initialize to 1
1.128 + }
1.129 +
1.130 + /**
1.131 + * Updates the checksum with the byte b.
1.132 + *
1.133 + * @param bval the data value to add. The high byte of the int is ignored.
1.134 + */
1.135 + public void update (int bval)
1.136 + {
1.137 + //We could make a length 1 byte array and call update again, but I
1.138 + //would rather not have that overhead
1.139 + int s1 = checksum & 0xffff;
1.140 + int s2 = checksum >>> 16;
1.141 +
1.142 + s1 = (s1 + (bval & 0xFF)) % BASE;
1.143 + s2 = (s1 + s2) % BASE;
1.144 +
1.145 + checksum = (s2 << 16) + s1;
1.146 + }
1.147 +
1.148 + /**
1.149 + * Updates the checksum with the bytes taken from the array.
1.150 + *
1.151 + * @param buffer an array of bytes
1.152 + */
1.153 + public void update (byte[] buffer)
1.154 + {
1.155 + update(buffer, 0, buffer.length);
1.156 + }
1.157 +
1.158 + /**
1.159 + * Updates the checksum with the bytes taken from the array.
1.160 + *
1.161 + * @param buf an array of bytes
1.162 + * @param off the start of the data used for this update
1.163 + * @param len the number of bytes to use for this update
1.164 + */
1.165 + public void update (byte[] buf, int off, int len)
1.166 + {
1.167 + //(By Per Bothner)
1.168 + int s1 = checksum & 0xffff;
1.169 + int s2 = checksum >>> 16;
1.170 +
1.171 + while (len > 0)
1.172 + {
1.173 + // We can defer the modulo operation:
1.174 + // s1 maximally grows from 65521 to 65521 + 255 * 3800
1.175 + // s2 maximally grows by 3800 * median(s1) = 2090079800 < 2^31
1.176 + int n = 3800;
1.177 + if (n > len)
1.178 + n = len;
1.179 + len -= n;
1.180 + while (--n >= 0)
1.181 + {
1.182 + s1 = s1 + (buf[off++] & 0xFF);
1.183 + s2 = s2 + s1;
1.184 + }
1.185 + s1 %= BASE;
1.186 + s2 %= BASE;
1.187 + }
1.188 +
1.189 + /*Old implementation, borrowed from somewhere:
1.190 + int n;
1.191 +
1.192 + while (len-- > 0) {
1.193 +
1.194 + s1 = (s1 + (bs[offset++] & 0xff)) % BASE;
1.195 + s2 = (s2 + s1) % BASE;
1.196 + }*/
1.197 +
1.198 + checksum = (s2 << 16) | s1;
1.199 + }
1.200 +
1.201 + /**
1.202 + * Returns the Adler32 data checksum computed so far.
1.203 + */
1.204 + public long getValue()
1.205 + {
1.206 + return (long) checksum & 0xffffffffL;
1.207 + }
1.208 +}
2.1 --- a/emul/mini/src/main/java/java/util/zip/CRC32.java Fri Feb 01 15:19:16 2013 +0100
2.2 +++ b/emul/mini/src/main/java/java/util/zip/CRC32.java Fri Feb 01 18:02:16 2013 +0100
2.3 @@ -1,113 +1,132 @@
2.4 -/*
2.5 - * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
2.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2.7 - *
2.8 - * This code is free software; you can redistribute it and/or modify it
2.9 - * under the terms of the GNU General Public License version 2 only, as
2.10 - * published by the Free Software Foundation. Oracle designates this
2.11 - * particular file as subject to the "Classpath" exception as provided
2.12 - * by Oracle in the LICENSE file that accompanied this code.
2.13 - *
2.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
2.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2.17 - * version 2 for more details (a copy is included in the LICENSE file that
2.18 - * accompanied this code).
2.19 - *
2.20 - * You should have received a copy of the GNU General Public License version
2.21 - * 2 along with this work; if not, write to the Free Software Foundation,
2.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2.23 - *
2.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2.25 - * or visit www.oracle.com if you need additional information or have any
2.26 - * questions.
2.27 - */
2.28 +/* CRC32.java - Computes CRC32 data checksum of a data stream
2.29 + Copyright (C) 1999. 2000, 2001 Free Software Foundation, Inc.
2.30 +
2.31 +This file is part of GNU Classpath.
2.32 +
2.33 +GNU Classpath is free software; you can redistribute it and/or modify
2.34 +it under the terms of the GNU General Public License as published by
2.35 +the Free Software Foundation; either version 2, or (at your option)
2.36 +any later version.
2.37 +
2.38 +GNU Classpath is distributed in the hope that it will be useful, but
2.39 +WITHOUT ANY WARRANTY; without even the implied warranty of
2.40 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2.41 +General Public License for more details.
2.42 +
2.43 +You should have received a copy of the GNU General Public License
2.44 +along with GNU Classpath; see the file COPYING. If not, write to the
2.45 +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
2.46 +02111-1307 USA.
2.47 +
2.48 +Linking this library statically or dynamically with other modules is
2.49 +making a combined work based on this library. Thus, the terms and
2.50 +conditions of the GNU General Public License cover the whole
2.51 +combination.
2.52 +
2.53 +As a special exception, the copyright holders of this library give you
2.54 +permission to link this library with independent modules to produce an
2.55 +executable, regardless of the license terms of these independent
2.56 +modules, and to copy and distribute the resulting executable under
2.57 +terms of your choice, provided that you also meet, for each linked
2.58 +independent module, the terms and conditions of the license of that
2.59 +module. An independent module is a module which is not derived from
2.60 +or based on this library. If you modify this library, you may extend
2.61 +this exception to your version of the library, but you are not
2.62 +obligated to do so. If you do not wish to do so, delete this
2.63 +exception statement from your version. */
2.64
2.65 package java.util.zip;
2.66
2.67 +/*
2.68 + * Written using on-line Java Platform 1.2 API Specification, as well
2.69 + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
2.70 + * The actual CRC32 algorithm is taken from RFC 1952.
2.71 + * Status: Believed complete and correct.
2.72 + */
2.73 +
2.74 /**
2.75 - * A class that can be used to compute the CRC-32 of a data stream.
2.76 + * Computes CRC32 data checksum of a data stream.
2.77 + * The actual CRC32 algorithm is described in RFC 1952
2.78 + * (GZIP file format specification version 4.3).
2.79 + * Can be used to get the CRC32 over a stream if used with checked input/output
2.80 + * streams.
2.81 *
2.82 - * @see Checksum
2.83 - * @author David Connelly
2.84 + * @see InflaterInputStream
2.85 + * @see DeflaterOutputStream
2.86 + *
2.87 + * @author Per Bothner
2.88 + * @date April 1, 1999.
2.89 */
2.90 -public
2.91 -class CRC32 implements Checksum {
2.92 - private int crc = 0xFFFFFFFF;
2.93 +public class CRC32 implements Checksum
2.94 +{
2.95 + /** The crc data checksum so far. */
2.96 + private int crc = 0;
2.97
2.98 - /**
2.99 - * Creates a new CRC32 object.
2.100 - */
2.101 - public CRC32() {
2.102 - }
2.103 + /** The fast CRC table. Computed once when the CRC32 class is loaded. */
2.104 + private static int[] crc_table = make_crc_table();
2.105
2.106 + /** Make the table for a fast CRC. */
2.107 + private static int[] make_crc_table ()
2.108 + {
2.109 + int[] crc_table = new int[256];
2.110 + for (int n = 0; n < 256; n++)
2.111 + {
2.112 + int c = n;
2.113 + for (int k = 8; --k >= 0; )
2.114 + {
2.115 + if ((c & 1) != 0)
2.116 + c = 0xedb88320 ^ (c >>> 1);
2.117 + else
2.118 + c = c >>> 1;
2.119 + }
2.120 + crc_table[n] = c;
2.121 + }
2.122 + return crc_table;
2.123 + }
2.124
2.125 - /**
2.126 - * Updates the CRC-32 checksum with the specified byte (the low
2.127 - * eight bits of the argument b).
2.128 - *
2.129 - * @param b the byte to update the checksum with
2.130 - */
2.131 - public void update(int b) {
2.132 - byte[] arr = { (byte)b };
2.133 - update(arr);
2.134 - }
2.135 + /**
2.136 + * Returns the CRC32 data checksum computed so far.
2.137 + */
2.138 + public long getValue ()
2.139 + {
2.140 + return (long) crc & 0xffffffffL;
2.141 + }
2.142
2.143 - /**
2.144 - * Updates the CRC-32 checksum with the specified array of bytes.
2.145 - */
2.146 - public void update(byte[] b, int off, int len) {
2.147 - if (b == null) {
2.148 - throw new NullPointerException();
2.149 - }
2.150 - if (off < 0 || len < 0 || off > b.length - len) {
2.151 - throw new ArrayIndexOutOfBoundsException();
2.152 - }
2.153 - crc = updateBytes(crc, b, off, len);
2.154 - }
2.155 + /**
2.156 + * Resets the CRC32 data checksum as if no update was ever called.
2.157 + */
2.158 + public void reset () { crc = 0; }
2.159
2.160 - /**
2.161 - * Updates the CRC-32 checksum with the specified array of bytes.
2.162 - *
2.163 - * @param b the array of bytes to update the checksum with
2.164 - */
2.165 - public void update(byte[] b) {
2.166 - crc = updateBytes(crc, b, 0, b.length);
2.167 - }
2.168 + /**
2.169 + * Updates the checksum with the int bval.
2.170 + *
2.171 + * @param bval (the byte is taken as the lower 8 bits of bval)
2.172 + */
2.173
2.174 - /**
2.175 - * Resets CRC-32 to initial value.
2.176 - */
2.177 - public void reset() {
2.178 - crc = 0;
2.179 - }
2.180 + public void update (int bval)
2.181 + {
2.182 + int c = ~crc;
2.183 + c = crc_table[(c ^ bval) & 0xff] ^ (c >>> 8);
2.184 + crc = ~c;
2.185 + }
2.186
2.187 - /**
2.188 - * Returns CRC-32 value.
2.189 - */
2.190 - public long getValue() {
2.191 - return (long)crc & 0xffffffffL;
2.192 - }
2.193 + /**
2.194 + * Adds the byte array to the data checksum.
2.195 + *
2.196 + * @param buf the buffer which contains the data
2.197 + * @param off the offset in the buffer where the data starts
2.198 + * @param len the length of the data
2.199 + */
2.200 + public void update (byte[] buf, int off, int len)
2.201 + {
2.202 + int c = ~crc;
2.203 + while (--len >= 0)
2.204 + c = crc_table[(c ^ buf[off++]) & 0xff] ^ (c >>> 8);
2.205 + crc = ~c;
2.206 + }
2.207
2.208 - // XXX: taken from
2.209 - // http://introcs.cs.princeton.edu/java/51data/CRC32.java.html
2.210 - private static int updateBytes(int crc, byte[] arr, int off, int len) {
2.211 - int poly = 0xEDB88320; // reverse polynomial
2.212 -
2.213 - while (len-- > 0) {
2.214 - byte b = arr[off++];
2.215 - int temp = (crc ^ b) & 0xff;
2.216 -
2.217 - // read 8 bits one at a time
2.218 - for (int i = 0; i < 8; i++) {
2.219 - if ((temp & 1) == 1) {
2.220 - temp = (temp >>> 1) ^ poly;
2.221 - } else {
2.222 - temp = (temp >>> 1);
2.223 - }
2.224 - }
2.225 - crc = (crc >>> 8) ^ temp;
2.226 - }
2.227 - return crc ^ 0xffffffff;
2.228 - }
2.229 + /**
2.230 + * Adds the complete byte array to the data checksum.
2.231 + */
2.232 + public void update (byte[] buf) { update(buf, 0, buf.length); }
2.233 }
3.1 --- a/emul/mini/src/main/java/java/util/zip/Inflater.java Fri Feb 01 15:19:16 2013 +0100
3.2 +++ b/emul/mini/src/main/java/java/util/zip/Inflater.java Fri Feb 01 18:02:16 2013 +0100
3.3 @@ -1,32 +1,43 @@
3.4 -/*
3.5 - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
3.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3.7 - *
3.8 - * This code is free software; you can redistribute it and/or modify it
3.9 - * under the terms of the GNU General Public License version 2 only, as
3.10 - * published by the Free Software Foundation. Oracle designates this
3.11 - * particular file as subject to the "Classpath" exception as provided
3.12 - * by Oracle in the LICENSE file that accompanied this code.
3.13 - *
3.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
3.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
3.16 - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
3.17 - * version 2 for more details (a copy is included in the LICENSE file that
3.18 - * accompanied this code).
3.19 - *
3.20 - * You should have received a copy of the GNU General Public License version
3.21 - * 2 along with this work; if not, write to the Free Software Foundation,
3.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
3.23 - *
3.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
3.25 - * or visit www.oracle.com if you need additional information or have any
3.26 - * questions.
3.27 - */
3.28 +/* Inflater.java - Decompress a data stream
3.29 + Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
3.30 +
3.31 +This file is part of GNU Classpath.
3.32 +
3.33 +GNU Classpath is free software; you can redistribute it and/or modify
3.34 +it under the terms of the GNU General Public License as published by
3.35 +the Free Software Foundation; either version 2, or (at your option)
3.36 +any later version.
3.37 +
3.38 +GNU Classpath is distributed in the hope that it will be useful, but
3.39 +WITHOUT ANY WARRANTY; without even the implied warranty of
3.40 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3.41 +General Public License for more details.
3.42 +
3.43 +You should have received a copy of the GNU General Public License
3.44 +along with GNU Classpath; see the file COPYING. If not, write to the
3.45 +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
3.46 +02111-1307 USA.
3.47 +
3.48 +Linking this library statically or dynamically with other modules is
3.49 +making a combined work based on this library. Thus, the terms and
3.50 +conditions of the GNU General Public License cover the whole
3.51 +combination.
3.52 +
3.53 +As a special exception, the copyright holders of this library give you
3.54 +permission to link this library with independent modules to produce an
3.55 +executable, regardless of the license terms of these independent
3.56 +modules, and to copy and distribute the resulting executable under
3.57 +terms of your choice, provided that you also meet, for each linked
3.58 +independent module, the terms and conditions of the license of that
3.59 +module. An independent module is a module which is not derived from
3.60 +or based on this library. If you modify this library, you may extend
3.61 +this exception to your version of the library, but you are not
3.62 +obligated to do so. If you do not wish to do so, delete this
3.63 +exception statement from your version. */
3.64
3.65 package java.util.zip;
3.66
3.67 -import org.apidesign.bck2brwsr.core.ExtraJavaScript;
3.68 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
3.69 +import org.apidesign.bck2brwsr.emul.lang.System;
3.70
3.71 /**
3.72 * This class provides support for general purpose decompression using the
3.73 @@ -73,271 +84,1392 @@
3.74 * @author David Connelly
3.75 *
3.76 */
3.77 -@ExtraJavaScript(
3.78 - resource = "/org/apidesign/vm4brwsr/emul/zip/js-inflate.min.js"
3.79 -)
3.80 -public
3.81 -class Inflater {
3.82 - private String data = "";
3.83 - private int offset;
3.84 - private long counter;
3.85 - private boolean finished;
3.86 - private boolean needDict;
3.87
3.88 - private static final byte[] defaultBuf = new byte[0];
3.89 +/* Written using on-line Java Platform 1.2 API Specification
3.90 + * and JCL book.
3.91 + * Believed complete and correct.
3.92 + */
3.93
3.94 +/**
3.95 + * Inflater is used to decompress data that has been compressed according
3.96 + * to the "deflate" standard described in rfc1950.
3.97 + *
3.98 + * The usage is as following. First you have to set some input with
3.99 + * <code>setInput()</code>, then inflate() it. If inflate doesn't
3.100 + * inflate any bytes there may be three reasons:
3.101 + * <ul>
3.102 + * <li>needsInput() returns true because the input buffer is empty.
3.103 + * You have to provide more input with <code>setInput()</code>.
3.104 + * NOTE: needsInput() also returns true when, the stream is finished.
3.105 + * </li>
3.106 + * <li>needsDictionary() returns true, you have to provide a preset
3.107 + * dictionary with <code>setDictionary()</code>.</li>
3.108 + * <li>finished() returns true, the inflater has finished.</li>
3.109 + * </ul>
3.110 + * Once the first output byte is produced, a dictionary will not be
3.111 + * needed at a later stage.
3.112 + *
3.113 + * @author John Leuner, Jochen Hoenicke
3.114 + * @author Tom Tromey
3.115 + * @date May 17, 1999
3.116 + * @since JDK 1.1
3.117 + */
3.118 +public class Inflater
3.119 +{
3.120 + /* Copy lengths for literal codes 257..285 */
3.121 + private static final int CPLENS[] =
3.122 + {
3.123 + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
3.124 + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
3.125 + };
3.126 +
3.127 + /* Extra bits for literal codes 257..285 */
3.128 + private static final int CPLEXT[] =
3.129 + {
3.130 + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
3.131 + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
3.132 + };
3.133 +
3.134 + /* Copy offsets for distance codes 0..29 */
3.135 + private static final int CPDIST[] = {
3.136 + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
3.137 + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
3.138 + 8193, 12289, 16385, 24577
3.139 + };
3.140 +
3.141 + /* Extra bits for distance codes */
3.142 + private static final int CPDEXT[] = {
3.143 + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
3.144 + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
3.145 + 12, 12, 13, 13
3.146 + };
3.147 +
3.148 + /* This are the state in which the inflater can be. */
3.149 + private static final int DECODE_HEADER = 0;
3.150 + private static final int DECODE_DICT = 1;
3.151 + private static final int DECODE_BLOCKS = 2;
3.152 + private static final int DECODE_STORED_LEN1 = 3;
3.153 + private static final int DECODE_STORED_LEN2 = 4;
3.154 + private static final int DECODE_STORED = 5;
3.155 + private static final int DECODE_DYN_HEADER = 6;
3.156 + private static final int DECODE_HUFFMAN = 7;
3.157 + private static final int DECODE_HUFFMAN_LENBITS = 8;
3.158 + private static final int DECODE_HUFFMAN_DIST = 9;
3.159 + private static final int DECODE_HUFFMAN_DISTBITS = 10;
3.160 + private static final int DECODE_CHKSUM = 11;
3.161 + private static final int FINISHED = 12;
3.162 +
3.163 + /** This variable contains the current state. */
3.164 + private int mode;
3.165 +
3.166 + /**
3.167 + * The adler checksum of the dictionary or of the decompressed
3.168 + * stream, as it is written in the header resp. footer of the
3.169 + * compressed stream. <br>
3.170 + *
3.171 + * Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
3.172 + */
3.173 + private int readAdler;
3.174 + /**
3.175 + * The number of bits needed to complete the current state. This
3.176 + * is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
3.177 + * DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
3.178 + */
3.179 + private int neededBits;
3.180 + private int repLength, repDist;
3.181 + private int uncomprLen;
3.182 + /**
3.183 + * True, if the last block flag was set in the last block of the
3.184 + * inflated stream. This means that the stream ends after the
3.185 + * current block.
3.186 + */
3.187 + private boolean isLastBlock;
3.188 +
3.189 + /**
3.190 + * The total number of inflated bytes.
3.191 + */
3.192 + private long totalOut;
3.193 + /**
3.194 + * The total number of bytes set with setInput(). This is not the
3.195 + * value returned by getTotalIn(), since this also includes the
3.196 + * unprocessed input.
3.197 + */
3.198 + private long totalIn;
3.199 + /**
3.200 + * This variable stores the nowrap flag that was given to the constructor.
3.201 + * True means, that the inflated stream doesn't contain a header nor the
3.202 + * checksum in the footer.
3.203 + */
3.204 + private boolean nowrap;
3.205 +
3.206 + private StreamManipulator input;
3.207 + private OutputWindow outputWindow;
3.208 + private InflaterDynHeader dynHeader;
3.209 + private InflaterHuffmanTree litlenTree, distTree;
3.210 + private Adler32 adler;
3.211 +
3.212 + /**
3.213 + * Creates a new inflater.
3.214 + */
3.215 + public Inflater ()
3.216 + {
3.217 + this (false);
3.218 + }
3.219 +
3.220 + /**
3.221 + * Creates a new inflater.
3.222 + * @param nowrap true if no header and checksum field appears in the
3.223 + * stream. This is used for GZIPed input. For compatibility with
3.224 + * Sun JDK you should provide one byte of input more than needed in
3.225 + * this case.
3.226 + */
3.227 + public Inflater (boolean nowrap)
3.228 + {
3.229 + this.nowrap = nowrap;
3.230 + this.adler = new Adler32();
3.231 + input = new StreamManipulator();
3.232 + outputWindow = new OutputWindow();
3.233 + mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
3.234 + }
3.235 +
3.236 + /**
3.237 + * Finalizes this object.
3.238 + */
3.239 + protected void finalize ()
3.240 + {
3.241 + /* Exists only for compatibility */
3.242 + }
3.243 +
3.244 + /**
3.245 + * Frees all objects allocated by the inflater. There's no reason
3.246 + * to call this, since you can just rely on garbage collection (even
3.247 + * for the Sun implementation). Exists only for compatibility
3.248 + * with Sun's JDK, where the compressor allocates native memory.
3.249 + * If you call any method (even reset) afterwards the behaviour is
3.250 + * <i>undefined</i>.
3.251 + * @deprecated Just clear all references to inflater instead.
3.252 + */
3.253 + public void end ()
3.254 + {
3.255 + outputWindow = null;
3.256 + input = null;
3.257 + dynHeader = null;
3.258 + litlenTree = null;
3.259 + distTree = null;
3.260 + adler = null;
3.261 + }
3.262 +
3.263 + /**
3.264 + * Returns true, if the inflater has finished. This means, that no
3.265 + * input is needed and no output can be produced.
3.266 + */
3.267 + public boolean finished()
3.268 + {
3.269 + return mode == FINISHED && outputWindow.getAvailable() == 0;
3.270 + }
3.271 +
3.272 + /**
3.273 + * Gets the adler checksum. This is either the checksum of all
3.274 + * uncompressed bytes returned by inflate(), or if needsDictionary()
3.275 + * returns true (and thus no output was yet produced) this is the
3.276 + * adler checksum of the expected dictionary.
3.277 + * @returns the adler checksum.
3.278 + */
3.279 + public int getAdler()
3.280 + {
3.281 + return needsDictionary() ? readAdler : (int) adler.getValue();
3.282 + }
3.283 +
3.284 + /**
3.285 + * Gets the number of unprocessed input. Useful, if the end of the
3.286 + * stream is reached and you want to further process the bytes after
3.287 + * the deflate stream.
3.288 + * @return the number of bytes of the input which were not processed.
3.289 + */
3.290 + public int getRemaining()
3.291 + {
3.292 + return input.getAvailableBytes();
3.293 + }
3.294 +
3.295 + /**
3.296 + * Gets the total number of processed compressed input bytes.
3.297 + * @return the total number of bytes of processed input bytes.
3.298 + */
3.299 + public int getTotalIn()
3.300 + {
3.301 + return (int)getBytesRead();
3.302 + }
3.303 +
3.304 + /**
3.305 + * Gets the total number of output bytes returned by inflate().
3.306 + * @return the total number of output bytes.
3.307 + */
3.308 + public int getTotalOut()
3.309 + {
3.310 + return (int)totalOut;
3.311 + }
3.312 +
3.313 + public long getBytesWritten() {
3.314 + return totalOut;
3.315 + }
3.316 +
3.317 + public long getBytesRead() {
3.318 + return totalIn - getRemaining();
3.319 + }
3.320 +
3.321 +
3.322 + /**
3.323 + * Inflates the compressed stream to the output buffer. If this
3.324 + * returns 0, you should check, whether needsDictionary(),
3.325 + * needsInput() or finished() returns true, to determine why no
3.326 + * further output is produced.
3.327 + * @param buffer the output buffer.
3.328 + * @return the number of bytes written to the buffer, 0 if no further
3.329 + * output can be produced.
3.330 + * @exception DataFormatException if deflated stream is invalid.
3.331 + * @exception IllegalArgumentException if buf has length 0.
3.332 + */
3.333 + public int inflate (byte[] buf) throws DataFormatException
3.334 + {
3.335 + return inflate (buf, 0, buf.length);
3.336 + }
3.337 +
3.338 + /**
3.339 + * Inflates the compressed stream to the output buffer. If this
3.340 + * returns 0, you should check, whether needsDictionary(),
3.341 + * needsInput() or finished() returns true, to determine why no
3.342 + * further output is produced.
3.343 + * @param buffer the output buffer.
3.344 + * @param off the offset into buffer where the output should start.
3.345 + * @param len the maximum length of the output.
3.346 + * @return the number of bytes written to the buffer, 0 if no further
3.347 + * output can be produced.
3.348 + * @exception DataFormatException if deflated stream is invalid.
3.349 + * @exception IndexOutOfBoundsException if the off and/or len are wrong.
3.350 + */
3.351 + public int inflate (byte[] buf, int off, int len) throws DataFormatException
3.352 + {
3.353 + /* Special case: len may be zero */
3.354 + if (len == 0)
3.355 + return 0;
3.356 + /* Check for correct buff, off, len triple */
3.357 + if (0 > off || off > off + len || off + len > buf.length)
3.358 + throw new ArrayIndexOutOfBoundsException();
3.359 + int count = 0;
3.360 + int more;
3.361 + do
3.362 + {
3.363 + if (mode != DECODE_CHKSUM)
3.364 + {
3.365 + /* Don't give away any output, if we are waiting for the
3.366 + * checksum in the input stream.
3.367 + *
3.368 + * With this trick we have always:
3.369 + * needsInput() and not finished()
3.370 + * implies more output can be produced.
3.371 + */
3.372 + more = outputWindow.copyOutput(buf, off, len);
3.373 + adler.update(buf, off, more);
3.374 + off += more;
3.375 + count += more;
3.376 + totalOut += more;
3.377 + len -= more;
3.378 + if (len == 0)
3.379 + return count;
3.380 + }
3.381 + }
3.382 + while (decode() || (outputWindow.getAvailable() > 0
3.383 + && mode != DECODE_CHKSUM));
3.384 + return count;
3.385 + }
3.386 +
3.387 + /**
3.388 + * Returns true, if a preset dictionary is needed to inflate the input.
3.389 + */
3.390 + public boolean needsDictionary ()
3.391 + {
3.392 + return mode == DECODE_DICT && neededBits == 0;
3.393 + }
3.394 +
3.395 + /**
3.396 + * Returns true, if the input buffer is empty.
3.397 + * You should then call setInput(). <br>
3.398 + *
3.399 + * <em>NOTE</em>: This method also returns true when the stream is finished.
3.400 + */
3.401 + public boolean needsInput ()
3.402 + {
3.403 + return input.needsInput ();
3.404 + }
3.405 +
3.406 + /**
3.407 + * Resets the inflater so that a new stream can be decompressed. All
3.408 + * pending input and output will be discarded.
3.409 + */
3.410 + public void reset ()
3.411 + {
3.412 + mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
3.413 + totalIn = totalOut = 0;
3.414 + input.reset();
3.415 + outputWindow.reset();
3.416 + dynHeader = null;
3.417 + litlenTree = null;
3.418 + distTree = null;
3.419 + isLastBlock = false;
3.420 + adler.reset();
3.421 + }
3.422 +
3.423 + /**
3.424 + * Sets the preset dictionary. This should only be called, if
3.425 + * needsDictionary() returns true and it should set the same
3.426 + * dictionary, that was used for deflating. The getAdler()
3.427 + * function returns the checksum of the dictionary needed.
3.428 + * @param buffer the dictionary.
3.429 + * @exception IllegalStateException if no dictionary is needed.
3.430 + * @exception IllegalArgumentException if the dictionary checksum is
3.431 + * wrong.
3.432 + */
3.433 + public void setDictionary (byte[] buffer)
3.434 + {
3.435 + setDictionary(buffer, 0, buffer.length);
3.436 + }
3.437 +
3.438 + /**
3.439 + * Sets the preset dictionary. This should only be called, if
3.440 + * needsDictionary() returns true and it should set the same
3.441 + * dictionary, that was used for deflating. The getAdler()
3.442 + * function returns the checksum of the dictionary needed.
3.443 + * @param buffer the dictionary.
3.444 + * @param off the offset into buffer where the dictionary starts.
3.445 + * @param len the length of the dictionary.
3.446 + * @exception IllegalStateException if no dictionary is needed.
3.447 + * @exception IllegalArgumentException if the dictionary checksum is
3.448 + * wrong.
3.449 + * @exception IndexOutOfBoundsException if the off and/or len are wrong.
3.450 + */
3.451 + public void setDictionary (byte[] buffer, int off, int len)
3.452 + {
3.453 + if (!needsDictionary())
3.454 + throw new IllegalStateException();
3.455 +
3.456 + adler.update(buffer, off, len);
3.457 + if ((int) adler.getValue() != readAdler)
3.458 + throw new IllegalArgumentException("Wrong adler checksum");
3.459 + adler.reset();
3.460 + outputWindow.copyDict(buffer, off, len);
3.461 + mode = DECODE_BLOCKS;
3.462 + }
3.463 +
3.464 + /**
3.465 + * Sets the input. This should only be called, if needsInput()
3.466 + * returns true.
3.467 + * @param buffer the input.
3.468 + * @exception IllegalStateException if no input is needed.
3.469 + */
3.470 + public void setInput (byte[] buf)
3.471 + {
3.472 + setInput (buf, 0, buf.length);
3.473 + }
3.474 +
3.475 + /**
3.476 + * Sets the input. This should only be called, if needsInput()
3.477 + * returns true.
3.478 + * @param buffer the input.
3.479 + * @param off the offset into buffer where the input starts.
3.480 + * @param len the length of the input.
3.481 + * @exception IllegalStateException if no input is needed.
3.482 + * @exception IndexOutOfBoundsException if the off and/or len are wrong.
3.483 + */
3.484 + public void setInput (byte[] buf, int off, int len)
3.485 + {
3.486 + input.setInput (buf, off, len);
3.487 + totalIn += len;
3.488 + }
3.489 + private static final int DEFLATED = 8;
3.490 + /**
3.491 + * Decodes the deflate header.
3.492 + * @return false if more input is needed.
3.493 + * @exception DataFormatException if header is invalid.
3.494 + */
3.495 + private boolean decodeHeader () throws DataFormatException
3.496 + {
3.497 + int header = input.peekBits(16);
3.498 + if (header < 0)
3.499 + return false;
3.500 + input.dropBits(16);
3.501 +
3.502 + /* The header is written in "wrong" byte order */
3.503 + header = ((header << 8) | (header >> 8)) & 0xffff;
3.504 + if (header % 31 != 0)
3.505 + throw new DataFormatException("Header checksum illegal");
3.506 +
3.507 + if ((header & 0x0f00) != (DEFLATED << 8))
3.508 + throw new DataFormatException("Compression Method unknown");
3.509 +
3.510 + /* Maximum size of the backwards window in bits.
3.511 + * We currently ignore this, but we could use it to make the
3.512 + * inflater window more space efficient. On the other hand the
3.513 + * full window (15 bits) is needed most times, anyway.
3.514 + int max_wbits = ((header & 0x7000) >> 12) + 8;
3.515 + */
3.516 +
3.517 + if ((header & 0x0020) == 0) // Dictionary flag?
3.518 + {
3.519 + mode = DECODE_BLOCKS;
3.520 + }
3.521 + else
3.522 + {
3.523 + mode = DECODE_DICT;
3.524 + neededBits = 32;
3.525 + }
3.526 + return true;
3.527 + }
3.528 +
3.529 + /**
3.530 + * Decodes the dictionary checksum after the deflate header.
3.531 + * @return false if more input is needed.
3.532 + */
3.533 + private boolean decodeDict ()
3.534 + {
3.535 + while (neededBits > 0)
3.536 + {
3.537 + int dictByte = input.peekBits(8);
3.538 + if (dictByte < 0)
3.539 + return false;
3.540 + input.dropBits(8);
3.541 + readAdler = (readAdler << 8) | dictByte;
3.542 + neededBits -= 8;
3.543 + }
3.544 + return false;
3.545 + }
3.546 +
3.547 + /**
3.548 + * Decodes the huffman encoded symbols in the input stream.
3.549 + * @return false if more input is needed, true if output window is
3.550 + * full or the current block ends.
3.551 + * @exception DataFormatException if deflated stream is invalid.
3.552 + */
3.553 + private boolean decodeHuffman () throws DataFormatException
3.554 + {
3.555 + int free = outputWindow.getFreeSpace();
3.556 + while (free >= 258)
3.557 + {
3.558 + int symbol;
3.559 + switch (mode)
3.560 + {
3.561 + case DECODE_HUFFMAN:
3.562 + /* This is the inner loop so it is optimized a bit */
3.563 + while (((symbol = litlenTree.getSymbol(input)) & ~0xff) == 0)
3.564 + {
3.565 + outputWindow.write(symbol);
3.566 + if (--free < 258)
3.567 + return true;
3.568 + }
3.569 + if (symbol < 257)
3.570 + {
3.571 + if (symbol < 0)
3.572 + return false;
3.573 + else
3.574 + {
3.575 + /* symbol == 256: end of block */
3.576 + distTree = null;
3.577 + litlenTree = null;
3.578 + mode = DECODE_BLOCKS;
3.579 + return true;
3.580 + }
3.581 + }
3.582 +
3.583 + try
3.584 + {
3.585 + repLength = CPLENS[symbol - 257];
3.586 + neededBits = CPLEXT[symbol - 257];
3.587 + }
3.588 + catch (ArrayIndexOutOfBoundsException ex)
3.589 + {
3.590 + throw new DataFormatException("Illegal rep length code");
3.591 + }
3.592 + /* fall through */
3.593 + case DECODE_HUFFMAN_LENBITS:
3.594 + if (neededBits > 0)
3.595 + {
3.596 + mode = DECODE_HUFFMAN_LENBITS;
3.597 + int i = input.peekBits(neededBits);
3.598 + if (i < 0)
3.599 + return false;
3.600 + input.dropBits(neededBits);
3.601 + repLength += i;
3.602 + }
3.603 + mode = DECODE_HUFFMAN_DIST;
3.604 + /* fall through */
3.605 + case DECODE_HUFFMAN_DIST:
3.606 + symbol = distTree.getSymbol(input);
3.607 + if (symbol < 0)
3.608 + return false;
3.609 + try
3.610 + {
3.611 + repDist = CPDIST[symbol];
3.612 + neededBits = CPDEXT[symbol];
3.613 + }
3.614 + catch (ArrayIndexOutOfBoundsException ex)
3.615 + {
3.616 + throw new DataFormatException("Illegal rep dist code");
3.617 + }
3.618 + /* fall through */
3.619 + case DECODE_HUFFMAN_DISTBITS:
3.620 + if (neededBits > 0)
3.621 + {
3.622 + mode = DECODE_HUFFMAN_DISTBITS;
3.623 + int i = input.peekBits(neededBits);
3.624 + if (i < 0)
3.625 + return false;
3.626 + input.dropBits(neededBits);
3.627 + repDist += i;
3.628 + }
3.629 + outputWindow.repeat(repLength, repDist);
3.630 + free -= repLength;
3.631 + mode = DECODE_HUFFMAN;
3.632 + break;
3.633 + default:
3.634 + throw new IllegalStateException();
3.635 + }
3.636 + }
3.637 + return true;
3.638 + }
3.639 +
3.640 + /**
3.641 + * Decodes the adler checksum after the deflate stream.
3.642 + * @return false if more input is needed.
3.643 + * @exception DataFormatException if checksum doesn't match.
3.644 + */
3.645 + private boolean decodeChksum () throws DataFormatException
3.646 + {
3.647 + while (neededBits > 0)
3.648 + {
3.649 + int chkByte = input.peekBits(8);
3.650 + if (chkByte < 0)
3.651 + return false;
3.652 + input.dropBits(8);
3.653 + readAdler = (readAdler << 8) | chkByte;
3.654 + neededBits -= 8;
3.655 + }
3.656 + if ((int) adler.getValue() != readAdler)
3.657 + throw new DataFormatException("Adler chksum doesn't match: "
3.658 + +Integer.toHexString((int)adler.getValue())
3.659 + +" vs. "+Integer.toHexString(readAdler));
3.660 + mode = FINISHED;
3.661 + return false;
3.662 + }
3.663 +
3.664 + /**
3.665 + * Decodes the deflated stream.
3.666 + * @return false if more input is needed, or if finished.
3.667 + * @exception DataFormatException if deflated stream is invalid.
3.668 + */
3.669 + private boolean decode () throws DataFormatException
3.670 + {
3.671 + switch (mode)
3.672 + {
3.673 + case DECODE_HEADER:
3.674 + return decodeHeader();
3.675 + case DECODE_DICT:
3.676 + return decodeDict();
3.677 + case DECODE_CHKSUM:
3.678 + return decodeChksum();
3.679 +
3.680 + case DECODE_BLOCKS:
3.681 + if (isLastBlock)
3.682 + {
3.683 + if (nowrap)
3.684 + {
3.685 + mode = FINISHED;
3.686 + return false;
3.687 + }
3.688 + else
3.689 + {
3.690 + input.skipToByteBoundary();
3.691 + neededBits = 32;
3.692 + mode = DECODE_CHKSUM;
3.693 + return true;
3.694 + }
3.695 + }
3.696 +
3.697 + int type = input.peekBits(3);
3.698 + if (type < 0)
3.699 + return false;
3.700 + input.dropBits(3);
3.701 +
3.702 + if ((type & 1) != 0)
3.703 + isLastBlock = true;
3.704 + switch (type >> 1)
3.705 + {
3.706 + case DeflaterConstants.STORED_BLOCK:
3.707 + input.skipToByteBoundary();
3.708 + mode = DECODE_STORED_LEN1;
3.709 + break;
3.710 + case DeflaterConstants.STATIC_TREES:
3.711 + litlenTree = InflaterHuffmanTree.defLitLenTree;
3.712 + distTree = InflaterHuffmanTree.defDistTree;
3.713 + mode = DECODE_HUFFMAN;
3.714 + break;
3.715 + case DeflaterConstants.DYN_TREES:
3.716 + dynHeader = new InflaterDynHeader();
3.717 + mode = DECODE_DYN_HEADER;
3.718 + break;
3.719 + default:
3.720 + throw new DataFormatException("Unknown block type "+type);
3.721 + }
3.722 + return true;
3.723 +
3.724 + case DECODE_STORED_LEN1:
3.725 + {
3.726 + if ((uncomprLen = input.peekBits(16)) < 0)
3.727 + return false;
3.728 + input.dropBits(16);
3.729 + mode = DECODE_STORED_LEN2;
3.730 + }
3.731 + /* fall through */
3.732 + case DECODE_STORED_LEN2:
3.733 + {
3.734 + int nlen = input.peekBits(16);
3.735 + if (nlen < 0)
3.736 + return false;
3.737 + input.dropBits(16);
3.738 + if (nlen != (uncomprLen ^ 0xffff))
3.739 + throw new DataFormatException("broken uncompressed block");
3.740 + mode = DECODE_STORED;
3.741 + }
3.742 + /* fall through */
3.743 + case DECODE_STORED:
3.744 + {
3.745 + int more = outputWindow.copyStored(input, uncomprLen);
3.746 + uncomprLen -= more;
3.747 + if (uncomprLen == 0)
3.748 + {
3.749 + mode = DECODE_BLOCKS;
3.750 + return true;
3.751 + }
3.752 + return !input.needsInput();
3.753 + }
3.754 +
3.755 + case DECODE_DYN_HEADER:
3.756 + if (!dynHeader.decode(input))
3.757 + return false;
3.758 + litlenTree = dynHeader.buildLitLenTree();
3.759 + distTree = dynHeader.buildDistTree();
3.760 + mode = DECODE_HUFFMAN;
3.761 + /* fall through */
3.762 + case DECODE_HUFFMAN:
3.763 + case DECODE_HUFFMAN_LENBITS:
3.764 + case DECODE_HUFFMAN_DIST:
3.765 + case DECODE_HUFFMAN_DISTBITS:
3.766 + return decodeHuffman();
3.767 + case FINISHED:
3.768 + return false;
3.769 + default:
3.770 + throw new IllegalStateException();
3.771 + }
3.772 + }
3.773 +
3.774 +
3.775 + interface DeflaterConstants {
3.776 + final static boolean DEBUGGING = false;
3.777 +
3.778 + final static int STORED_BLOCK = 0;
3.779 + final static int STATIC_TREES = 1;
3.780 + final static int DYN_TREES = 2;
3.781 + final static int PRESET_DICT = 0x20;
3.782 +
3.783 + final static int DEFAULT_MEM_LEVEL = 8;
3.784 +
3.785 + final static int MAX_MATCH = 258;
3.786 + final static int MIN_MATCH = 3;
3.787 +
3.788 + final static int MAX_WBITS = 15;
3.789 + final static int WSIZE = 1 << MAX_WBITS;
3.790 + final static int WMASK = WSIZE - 1;
3.791 +
3.792 + final static int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
3.793 + final static int HASH_SIZE = 1 << HASH_BITS;
3.794 + final static int HASH_MASK = HASH_SIZE - 1;
3.795 + final static int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
3.796 +
3.797 + final static int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
3.798 + final static int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
3.799 +
3.800 + final static int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
3.801 + final static int MAX_BLOCK_SIZE = Math.min(65535, PENDING_BUF_SIZE-5);
3.802 +
3.803 + final static int DEFLATE_STORED = 0;
3.804 + final static int DEFLATE_FAST = 1;
3.805 + final static int DEFLATE_SLOW = 2;
3.806 +
3.807 + final static int GOOD_LENGTH[] = { 0,4, 4, 4, 4, 8, 8, 8, 32, 32 };
3.808 + final static int MAX_LAZY[] = { 0,4, 5, 6, 4,16, 16, 32, 128, 258 };
3.809 + final static int NICE_LENGTH[] = { 0,8,16,32,16,32,128,128, 258, 258 };
3.810 + final static int MAX_CHAIN[] = { 0,4, 8,32,16,32,128,256,1024,4096 };
3.811 + final static int COMPR_FUNC[] = { 0,1, 1, 1, 1, 2, 2, 2, 2, 2 };
3.812 + }
3.813 + private static class InflaterHuffmanTree {
3.814 + private final static int MAX_BITLEN = 15;
3.815 + private short[] tree;
3.816 +
3.817 + public static InflaterHuffmanTree defLitLenTree, defDistTree;
3.818 +
3.819 + static
3.820 + {
3.821 + try
3.822 + {
3.823 + byte[] codeLengths = new byte[288];
3.824 + int i = 0;
3.825 + while (i < 144)
3.826 + codeLengths[i++] = 8;
3.827 + while (i < 256)
3.828 + codeLengths[i++] = 9;
3.829 + while (i < 280)
3.830 + codeLengths[i++] = 7;
3.831 + while (i < 288)
3.832 + codeLengths[i++] = 8;
3.833 + defLitLenTree = new InflaterHuffmanTree(codeLengths);
3.834 +
3.835 + codeLengths = new byte[32];
3.836 + i = 0;
3.837 + while (i < 32)
3.838 + codeLengths[i++] = 5;
3.839 + defDistTree = new InflaterHuffmanTree(codeLengths);
3.840 + }
3.841 + catch (DataFormatException ex)
3.842 + {
3.843 + throw new IllegalStateException
3.844 + ("InflaterHuffmanTree: static tree length illegal");
3.845 + }
3.846 + }
3.847 +
3.848 + /**
3.849 + * Constructs a Huffman tree from the array of code lengths.
3.850 + *
3.851 + * @param codeLengths the array of code lengths
3.852 + */
3.853 + public InflaterHuffmanTree(byte[] codeLengths) throws DataFormatException
3.854 + {
3.855 + buildTree(codeLengths);
3.856 + }
3.857 +
3.858 + private void buildTree(byte[] codeLengths) throws DataFormatException
3.859 + {
3.860 + int[] blCount = new int[MAX_BITLEN+1];
3.861 + int[] nextCode = new int[MAX_BITLEN+1];
3.862 + for (int i = 0; i < codeLengths.length; i++)
3.863 + {
3.864 + int bits = codeLengths[i];
3.865 + if (bits > 0)
3.866 + blCount[bits]++;
3.867 + }
3.868 +
3.869 + int code = 0;
3.870 + int treeSize = 512;
3.871 + for (int bits = 1; bits <= MAX_BITLEN; bits++)
3.872 + {
3.873 + nextCode[bits] = code;
3.874 + code += blCount[bits] << (16 - bits);
3.875 + if (bits >= 10)
3.876 + {
3.877 + /* We need an extra table for bit lengths >= 10. */
3.878 + int start = nextCode[bits] & 0x1ff80;
3.879 + int end = code & 0x1ff80;
3.880 + treeSize += (end - start) >> (16 - bits);
3.881 + }
3.882 + }
3.883 + if (code != 65536)
3.884 + throw new DataFormatException("Code lengths don't add up properly.");
3.885 +
3.886 + /* Now create and fill the extra tables from longest to shortest
3.887 + * bit len. This way the sub trees will be aligned.
3.888 + */
3.889 + tree = new short[treeSize];
3.890 + int treePtr = 512;
3.891 + for (int bits = MAX_BITLEN; bits >= 10; bits--)
3.892 + {
3.893 + int end = code & 0x1ff80;
3.894 + code -= blCount[bits] << (16 - bits);
3.895 + int start = code & 0x1ff80;
3.896 + for (int i = start; i < end; i += 1 << 7)
3.897 + {
3.898 + tree[bitReverse(i)]
3.899 + = (short) ((-treePtr << 4) | bits);
3.900 + treePtr += 1 << (bits-9);
3.901 + }
3.902 + }
3.903 +
3.904 + for (int i = 0; i < codeLengths.length; i++)
3.905 + {
3.906 + int bits = codeLengths[i];
3.907 + if (bits == 0)
3.908 + continue;
3.909 + code = nextCode[bits];
3.910 + int revcode = bitReverse(code);
3.911 + if (bits <= 9)
3.912 + {
3.913 + do
3.914 + {
3.915 + tree[revcode] = (short) ((i << 4) | bits);
3.916 + revcode += 1 << bits;
3.917 + }
3.918 + while (revcode < 512);
3.919 + }
3.920 + else
3.921 + {
3.922 + int subTree = tree[revcode & 511];
3.923 + int treeLen = 1 << (subTree & 15);
3.924 + subTree = -(subTree >> 4);
3.925 + do
3.926 + {
3.927 + tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
3.928 + revcode += 1 << bits;
3.929 + }
3.930 + while (revcode < treeLen);
3.931 + }
3.932 + nextCode[bits] = code + (1 << (16 - bits));
3.933 + }
3.934 + }
3.935 + private final static String bit4Reverse =
3.936 + "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017";
3.937 + static short bitReverse(int value) {
3.938 + return (short) (bit4Reverse.charAt(value & 0xf) << 12
3.939 + | bit4Reverse.charAt((value >> 4) & 0xf) << 8
3.940 + | bit4Reverse.charAt((value >> 8) & 0xf) << 4
3.941 + | bit4Reverse.charAt(value >> 12));
3.942 + }
3.943 +
3.944 + /**
3.945 + * Reads the next symbol from input. The symbol is encoded using the
3.946 + * huffman tree.
3.947 + * @param input the input source.
3.948 + * @return the next symbol, or -1 if not enough input is available.
3.949 + */
3.950 + public int getSymbol(StreamManipulator input) throws DataFormatException
3.951 + {
3.952 + int lookahead, symbol;
3.953 + if ((lookahead = input.peekBits(9)) >= 0)
3.954 + {
3.955 + if ((symbol = tree[lookahead]) >= 0)
3.956 + {
3.957 + input.dropBits(symbol & 15);
3.958 + return symbol >> 4;
3.959 + }
3.960 + int subtree = -(symbol >> 4);
3.961 + int bitlen = symbol & 15;
3.962 + if ((lookahead = input.peekBits(bitlen)) >= 0)
3.963 + {
3.964 + symbol = tree[subtree | (lookahead >> 9)];
3.965 + input.dropBits(symbol & 15);
3.966 + return symbol >> 4;
3.967 + }
3.968 + else
3.969 + {
3.970 + int bits = input.getAvailableBits();
3.971 + lookahead = input.peekBits(bits);
3.972 + symbol = tree[subtree | (lookahead >> 9)];
3.973 + if ((symbol & 15) <= bits)
3.974 + {
3.975 + input.dropBits(symbol & 15);
3.976 + return symbol >> 4;
3.977 + }
3.978 + else
3.979 + return -1;
3.980 + }
3.981 + }
3.982 + else
3.983 + {
3.984 + int bits = input.getAvailableBits();
3.985 + lookahead = input.peekBits(bits);
3.986 + symbol = tree[lookahead];
3.987 + if (symbol >= 0 && (symbol & 15) <= bits)
3.988 + {
3.989 + input.dropBits(symbol & 15);
3.990 + return symbol >> 4;
3.991 + }
3.992 + else
3.993 + return -1;
3.994 + }
3.995 + }
3.996 + }
3.997 + private static class InflaterDynHeader
3.998 + {
3.999 + private static final int LNUM = 0;
3.1000 + private static final int DNUM = 1;
3.1001 + private static final int BLNUM = 2;
3.1002 + private static final int BLLENS = 3;
3.1003 + private static final int LENS = 4;
3.1004 + private static final int REPS = 5;
3.1005 +
3.1006 + private static final int repMin[] = { 3, 3, 11 };
3.1007 + private static final int repBits[] = { 2, 3, 7 };
3.1008 +
3.1009 +
3.1010 + private byte[] blLens;
3.1011 + private byte[] litdistLens;
3.1012 +
3.1013 + private InflaterHuffmanTree blTree;
3.1014 +
3.1015 + private int mode;
3.1016 + private int lnum, dnum, blnum, num;
3.1017 + private int repSymbol;
3.1018 + private byte lastLen;
3.1019 + private int ptr;
3.1020 +
3.1021 + private static final int[] BL_ORDER =
3.1022 + { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
3.1023 +
3.1024 + public InflaterDynHeader()
3.1025 + {
3.1026 + }
3.1027 +
3.1028 + public boolean decode(StreamManipulator input) throws DataFormatException
3.1029 + {
3.1030 + decode_loop:
3.1031 + for (;;)
3.1032 + {
3.1033 + switch (mode)
3.1034 + {
3.1035 + case LNUM:
3.1036 + lnum = input.peekBits(5);
3.1037 + if (lnum < 0)
3.1038 + return false;
3.1039 + lnum += 257;
3.1040 + input.dropBits(5);
3.1041 + // System.err.println("LNUM: "+lnum);
3.1042 + mode = DNUM;
3.1043 + /* fall through */
3.1044 + case DNUM:
3.1045 + dnum = input.peekBits(5);
3.1046 + if (dnum < 0)
3.1047 + return false;
3.1048 + dnum++;
3.1049 + input.dropBits(5);
3.1050 + // System.err.println("DNUM: "+dnum);
3.1051 + num = lnum+dnum;
3.1052 + litdistLens = new byte[num];
3.1053 + mode = BLNUM;
3.1054 + /* fall through */
3.1055 + case BLNUM:
3.1056 + blnum = input.peekBits(4);
3.1057 + if (blnum < 0)
3.1058 + return false;
3.1059 + blnum += 4;
3.1060 + input.dropBits(4);
3.1061 + blLens = new byte[19];
3.1062 + ptr = 0;
3.1063 + // System.err.println("BLNUM: "+blnum);
3.1064 + mode = BLLENS;
3.1065 + /* fall through */
3.1066 + case BLLENS:
3.1067 + while (ptr < blnum)
3.1068 + {
3.1069 + int len = input.peekBits(3);
3.1070 + if (len < 0)
3.1071 + return false;
3.1072 + input.dropBits(3);
3.1073 + // System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
3.1074 + blLens[BL_ORDER[ptr]] = (byte) len;
3.1075 + ptr++;
3.1076 + }
3.1077 + blTree = new InflaterHuffmanTree(blLens);
3.1078 + blLens = null;
3.1079 + ptr = 0;
3.1080 + mode = LENS;
3.1081 + /* fall through */
3.1082 + case LENS:
3.1083 + {
3.1084 + int symbol;
3.1085 + while (((symbol = blTree.getSymbol(input)) & ~15) == 0)
3.1086 + {
3.1087 + /* Normal case: symbol in [0..15] */
3.1088 +
3.1089 + // System.err.println("litdistLens["+ptr+"]: "+symbol);
3.1090 + litdistLens[ptr++] = lastLen = (byte) symbol;
3.1091 +
3.1092 + if (ptr == num)
3.1093 + {
3.1094 + /* Finished */
3.1095 + return true;
3.1096 + }
3.1097 + }
3.1098 +
3.1099 + /* need more input ? */
3.1100 + if (symbol < 0)
3.1101 + return false;
3.1102 +
3.1103 + /* otherwise repeat code */
3.1104 + if (symbol >= 17)
3.1105 + {
3.1106 + /* repeat zero */
3.1107 + // System.err.println("repeating zero");
3.1108 + lastLen = 0;
3.1109 + }
3.1110 + else
3.1111 + {
3.1112 + if (ptr == 0)
3.1113 + throw new DataFormatException();
3.1114 + }
3.1115 + repSymbol = symbol-16;
3.1116 + mode = REPS;
3.1117 + }
3.1118 + /* fall through */
3.1119 +
3.1120 + case REPS:
3.1121 + {
3.1122 + int bits = repBits[repSymbol];
3.1123 + int count = input.peekBits(bits);
3.1124 + if (count < 0)
3.1125 + return false;
3.1126 + input.dropBits(bits);
3.1127 + count += repMin[repSymbol];
3.1128 + // System.err.println("litdistLens repeated: "+count);
3.1129 +
3.1130 + if (ptr + count > num)
3.1131 + throw new DataFormatException();
3.1132 + while (count-- > 0)
3.1133 + litdistLens[ptr++] = lastLen;
3.1134 +
3.1135 + if (ptr == num)
3.1136 + {
3.1137 + /* Finished */
3.1138 + return true;
3.1139 + }
3.1140 + }
3.1141 + mode = LENS;
3.1142 + continue decode_loop;
3.1143 + }
3.1144 + }
3.1145 + }
3.1146 +
3.1147 + public InflaterHuffmanTree buildLitLenTree() throws DataFormatException
3.1148 + {
3.1149 + byte[] litlenLens = new byte[lnum];
3.1150 + System.arraycopy(litdistLens, 0, litlenLens, 0, lnum);
3.1151 + return new InflaterHuffmanTree(litlenLens);
3.1152 + }
3.1153 +
3.1154 + public InflaterHuffmanTree buildDistTree() throws DataFormatException
3.1155 + {
3.1156 + byte[] distLens = new byte[dnum];
3.1157 + System.arraycopy(litdistLens, lnum, distLens, 0, dnum);
3.1158 + return new InflaterHuffmanTree(distLens);
3.1159 + }
3.1160 + }
3.1161 /**
3.1162 - * Creates a new decompressor. If the parameter 'nowrap' is true then
3.1163 - * the ZLIB header and checksum fields will not be used. This provides
3.1164 - * compatibility with the compression format used by both GZIP and PKZIP.
3.1165 - * <p>
3.1166 - * Note: When using the 'nowrap' option it is also necessary to provide
3.1167 - * an extra "dummy" byte as input. This is required by the ZLIB native
3.1168 - * library in order to support certain optimizations.
3.1169 + * This class allows us to retrieve a specified amount of bits from
3.1170 + * the input buffer, as well as copy big byte blocks.
3.1171 *
3.1172 - * @param nowrap if true then support GZIP compatible compression
3.1173 + * It uses an int buffer to store up to 31 bits for direct
3.1174 + * manipulation. This guarantees that we can get at least 16 bits,
3.1175 + * but we only need at most 15, so this is all safe.
3.1176 + *
3.1177 + * There are some optimizations in this class, for example, you must
3.1178 + * never peek more then 8 bits more than needed, and you must first
3.1179 + * peek bits before you may drop them. This is not a general purpose
3.1180 + * class but optimized for the behaviour of the Inflater.
3.1181 + *
3.1182 + * @author John Leuner, Jochen Hoenicke
3.1183 */
3.1184 - public Inflater(boolean nowrap) {
3.1185 +
3.1186 + private static class StreamManipulator
3.1187 + {
3.1188 + private byte[] window;
3.1189 + private int window_start = 0;
3.1190 + private int window_end = 0;
3.1191 +
3.1192 + private int buffer = 0;
3.1193 + private int bits_in_buffer = 0;
3.1194 +
3.1195 + /**
3.1196 + * Get the next n bits but don't increase input pointer. n must be
3.1197 + * less or equal 16 and if you if this call succeeds, you must drop
3.1198 + * at least n-8 bits in the next call.
3.1199 + *
3.1200 + * @return the value of the bits, or -1 if not enough bits available. */
3.1201 + public final int peekBits(int n)
3.1202 + {
3.1203 + if (bits_in_buffer < n)
3.1204 + {
3.1205 + if (window_start == window_end)
3.1206 + return -1;
3.1207 + buffer |= (window[window_start++] & 0xff
3.1208 + | (window[window_start++] & 0xff) << 8) << bits_in_buffer;
3.1209 + bits_in_buffer += 16;
3.1210 + }
3.1211 + return buffer & ((1 << n) - 1);
3.1212 + }
3.1213 +
3.1214 + /* Drops the next n bits from the input. You should have called peekBits
3.1215 + * with a bigger or equal n before, to make sure that enough bits are in
3.1216 + * the bit buffer.
3.1217 + */
3.1218 + public final void dropBits(int n)
3.1219 + {
3.1220 + buffer >>>= n;
3.1221 + bits_in_buffer -= n;
3.1222 + }
3.1223 +
3.1224 + /**
3.1225 + * Gets the next n bits and increases input pointer. This is equivalent
3.1226 + * to peekBits followed by dropBits, except for correct error handling.
3.1227 + * @return the value of the bits, or -1 if not enough bits available.
3.1228 + */
3.1229 + public final int getBits(int n)
3.1230 + {
3.1231 + int bits = peekBits(n);
3.1232 + if (bits >= 0)
3.1233 + dropBits(n);
3.1234 + return bits;
3.1235 + }
3.1236 + /**
3.1237 + * Gets the number of bits available in the bit buffer. This must be
3.1238 + * only called when a previous peekBits() returned -1.
3.1239 + * @return the number of bits available.
3.1240 + */
3.1241 + public final int getAvailableBits()
3.1242 + {
3.1243 + return bits_in_buffer;
3.1244 + }
3.1245 +
3.1246 + /**
3.1247 + * Gets the number of bytes available.
3.1248 + * @return the number of bytes available.
3.1249 + */
3.1250 + public final int getAvailableBytes()
3.1251 + {
3.1252 + return window_end - window_start + (bits_in_buffer >> 3);
3.1253 + }
3.1254 +
3.1255 + /**
3.1256 + * Skips to the next byte boundary.
3.1257 + */
3.1258 + public void skipToByteBoundary()
3.1259 + {
3.1260 + buffer >>= (bits_in_buffer & 7);
3.1261 + bits_in_buffer &= ~7;
3.1262 + }
3.1263 +
3.1264 + public final boolean needsInput() {
3.1265 + return window_start == window_end;
3.1266 + }
3.1267 +
3.1268 +
3.1269 + /* Copies length bytes from input buffer to output buffer starting
3.1270 + * at output[offset]. You have to make sure, that the buffer is
3.1271 + * byte aligned. If not enough bytes are available, copies fewer
3.1272 + * bytes.
3.1273 + * @param length the length to copy, 0 is allowed.
3.1274 + * @return the number of bytes copied, 0 if no byte is available.
3.1275 + */
3.1276 + public int copyBytes(byte[] output, int offset, int length)
3.1277 + {
3.1278 + if (length < 0)
3.1279 + throw new IllegalArgumentException("length negative");
3.1280 + if ((bits_in_buffer & 7) != 0)
3.1281 + /* bits_in_buffer may only be 0 or 8 */
3.1282 + throw new IllegalStateException("Bit buffer is not aligned!");
3.1283 +
3.1284 + int count = 0;
3.1285 + while (bits_in_buffer > 0 && length > 0)
3.1286 + {
3.1287 + output[offset++] = (byte) buffer;
3.1288 + buffer >>>= 8;
3.1289 + bits_in_buffer -= 8;
3.1290 + length--;
3.1291 + count++;
3.1292 + }
3.1293 + if (length == 0)
3.1294 + return count;
3.1295 +
3.1296 + int avail = window_end - window_start;
3.1297 + if (length > avail)
3.1298 + length = avail;
3.1299 + System.arraycopy(window, window_start, output, offset, length);
3.1300 + window_start += length;
3.1301 +
3.1302 + if (((window_start - window_end) & 1) != 0)
3.1303 + {
3.1304 + /* We always want an even number of bytes in input, see peekBits */
3.1305 + buffer = (window[window_start++] & 0xff);
3.1306 + bits_in_buffer = 8;
3.1307 + }
3.1308 + return count + length;
3.1309 + }
3.1310 +
3.1311 + public StreamManipulator()
3.1312 + {
3.1313 + }
3.1314 +
3.1315 + public void reset()
3.1316 + {
3.1317 + window_start = window_end = buffer = bits_in_buffer = 0;
3.1318 + }
3.1319 +
3.1320 + public void setInput(byte[] buf, int off, int len)
3.1321 + {
3.1322 + if (window_start < window_end)
3.1323 + throw new IllegalStateException
3.1324 + ("Old input was not completely processed");
3.1325 +
3.1326 + int end = off + len;
3.1327 +
3.1328 + /* We want to throw an ArrayIndexOutOfBoundsException early. The
3.1329 + * check is very tricky: it also handles integer wrap around.
3.1330 + */
3.1331 + if (0 > off || off > end || end > buf.length)
3.1332 + throw new ArrayIndexOutOfBoundsException();
3.1333 +
3.1334 + if ((len & 1) != 0)
3.1335 + {
3.1336 + /* We always want an even number of bytes in input, see peekBits */
3.1337 + buffer |= (buf[off++] & 0xff) << bits_in_buffer;
3.1338 + bits_in_buffer += 8;
3.1339 + }
3.1340 +
3.1341 + window = buf;
3.1342 + window_start = off;
3.1343 + window_end = end;
3.1344 + }
3.1345 }
3.1346 + /*
3.1347 + * Contains the output from the Inflation process.
3.1348 + *
3.1349 + * We need to have a window so that we can refer backwards into the output stream
3.1350 + * to repeat stuff.
3.1351 + *
3.1352 + * @author John Leuner
3.1353 + * @since JDK 1.1
3.1354 + */
3.1355
3.1356 - /**
3.1357 - * Creates a new decompressor.
3.1358 - */
3.1359 - public Inflater() {
3.1360 - this(false);
3.1361 + private static class OutputWindow
3.1362 + {
3.1363 + private final int WINDOW_SIZE = 1 << 15;
3.1364 + private final int WINDOW_MASK = WINDOW_SIZE - 1;
3.1365 +
3.1366 + private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes
3.1367 + private int window_end = 0;
3.1368 + private int window_filled = 0;
3.1369 +
3.1370 + public void write(int abyte)
3.1371 + {
3.1372 + if (window_filled++ == WINDOW_SIZE)
3.1373 + throw new IllegalStateException("Window full");
3.1374 + window[window_end++] = (byte) abyte;
3.1375 + window_end &= WINDOW_MASK;
3.1376 + }
3.1377 +
3.1378 +
3.1379 + private final void slowRepeat(int rep_start, int len, int dist)
3.1380 + {
3.1381 + while (len-- > 0)
3.1382 + {
3.1383 + window[window_end++] = window[rep_start++];
3.1384 + window_end &= WINDOW_MASK;
3.1385 + rep_start &= WINDOW_MASK;
3.1386 + }
3.1387 + }
3.1388 +
3.1389 + public void repeat(int len, int dist)
3.1390 + {
3.1391 + if ((window_filled += len) > WINDOW_SIZE)
3.1392 + throw new IllegalStateException("Window full");
3.1393 +
3.1394 + int rep_start = (window_end - dist) & WINDOW_MASK;
3.1395 + int border = WINDOW_SIZE - len;
3.1396 + if (rep_start <= border && window_end < border)
3.1397 + {
3.1398 + if (len <= dist)
3.1399 + {
3.1400 + System.arraycopy(window, rep_start, window, window_end, len);
3.1401 + window_end += len;
3.1402 + }
3.1403 + else
3.1404 + {
3.1405 + /* We have to copy manually, since the repeat pattern overlaps.
3.1406 + */
3.1407 + while (len-- > 0)
3.1408 + window[window_end++] = window[rep_start++];
3.1409 + }
3.1410 + }
3.1411 + else
3.1412 + slowRepeat(rep_start, len, dist);
3.1413 + }
3.1414 +
3.1415 + public int copyStored(StreamManipulator input, int len)
3.1416 + {
3.1417 + len = Math.min(Math.min(len, WINDOW_SIZE - window_filled),
3.1418 + input.getAvailableBytes());
3.1419 + int copied;
3.1420 +
3.1421 + int tailLen = WINDOW_SIZE - window_end;
3.1422 + if (len > tailLen)
3.1423 + {
3.1424 + copied = input.copyBytes(window, window_end, tailLen);
3.1425 + if (copied == tailLen)
3.1426 + copied += input.copyBytes(window, 0, len - tailLen);
3.1427 + }
3.1428 + else
3.1429 + copied = input.copyBytes(window, window_end, len);
3.1430 +
3.1431 + window_end = (window_end + copied) & WINDOW_MASK;
3.1432 + window_filled += copied;
3.1433 + return copied;
3.1434 + }
3.1435 +
3.1436 + public void copyDict(byte[] dict, int offset, int len)
3.1437 + {
3.1438 + if (window_filled > 0)
3.1439 + throw new IllegalStateException();
3.1440 +
3.1441 + if (len > WINDOW_SIZE)
3.1442 + {
3.1443 + offset += len - WINDOW_SIZE;
3.1444 + len = WINDOW_SIZE;
3.1445 + }
3.1446 + System.arraycopy(dict, offset, window, 0, len);
3.1447 + window_end = len & WINDOW_MASK;
3.1448 + }
3.1449 +
3.1450 + public int getFreeSpace()
3.1451 + {
3.1452 + return WINDOW_SIZE - window_filled;
3.1453 + }
3.1454 +
3.1455 + public int getAvailable()
3.1456 + {
3.1457 + return window_filled;
3.1458 + }
3.1459 +
3.1460 + public int copyOutput(byte[] output, int offset, int len)
3.1461 + {
3.1462 + int copy_end = window_end;
3.1463 + if (len > window_filled)
3.1464 + len = window_filled;
3.1465 + else
3.1466 + copy_end = (window_end - window_filled + len) & WINDOW_MASK;
3.1467 +
3.1468 + int copied = len;
3.1469 + int tailLen = len - copy_end;
3.1470 +
3.1471 + if (tailLen > 0)
3.1472 + {
3.1473 + System.arraycopy(window, WINDOW_SIZE - tailLen,
3.1474 + output, offset, tailLen);
3.1475 + offset += tailLen;
3.1476 + len = copy_end;
3.1477 + }
3.1478 + System.arraycopy(window, copy_end - len, output, offset, len);
3.1479 + window_filled -= copied;
3.1480 + if (window_filled < 0)
3.1481 + throw new IllegalStateException();
3.1482 + return copied;
3.1483 + }
3.1484 +
3.1485 + public void reset() {
3.1486 + window_filled = window_end = 0;
3.1487 + }
3.1488 }
3.1489 -
3.1490 - /**
3.1491 - * Sets input data for decompression. Should be called whenever
3.1492 - * needsInput() returns true indicating that more input data is
3.1493 - * required.
3.1494 - * @param b the input data bytes
3.1495 - * @param off the start offset of the input data
3.1496 - * @param len the length of the input data
3.1497 - * @see Inflater#needsInput
3.1498 - */
3.1499 - public void setInput(byte[] b, int off, int len) {
3.1500 - if (b == null) {
3.1501 - throw new NullPointerException();
3.1502 - }
3.1503 - if (off < 0 || len < 0 || off > b.length - len) {
3.1504 - throw new ArrayIndexOutOfBoundsException();
3.1505 - }
3.1506 - data = (String) infl(b, off, len);
3.1507 - }
3.1508 -
3.1509 - /**
3.1510 - * Sets input data for decompression. Should be called whenever
3.1511 - * needsInput() returns true indicating that more input data is
3.1512 - * required.
3.1513 - * @param b the input data bytes
3.1514 - * @see Inflater#needsInput
3.1515 - */
3.1516 - public void setInput(byte[] b) {
3.1517 - setInput(b, 0, b.length);
3.1518 - }
3.1519 -
3.1520 - /**
3.1521 - * Sets the preset dictionary to the given array of bytes. Should be
3.1522 - * called when inflate() returns 0 and needsDictionary() returns true
3.1523 - * indicating that a preset dictionary is required. The method getAdler()
3.1524 - * can be used to get the Adler-32 value of the dictionary needed.
3.1525 - * @param b the dictionary data bytes
3.1526 - * @param off the start offset of the data
3.1527 - * @param len the length of the data
3.1528 - * @see Inflater#needsDictionary
3.1529 - * @see Inflater#getAdler
3.1530 - */
3.1531 - public void setDictionary(byte[] b, int off, int len) {
3.1532 - if (b == null) {
3.1533 - throw new NullPointerException();
3.1534 - }
3.1535 - if (off < 0 || len < 0 || off > b.length - len) {
3.1536 - throw new ArrayIndexOutOfBoundsException();
3.1537 - }
3.1538 - needDict = false;
3.1539 - }
3.1540 -
3.1541 - /**
3.1542 - * Sets the preset dictionary to the given array of bytes. Should be
3.1543 - * called when inflate() returns 0 and needsDictionary() returns true
3.1544 - * indicating that a preset dictionary is required. The method getAdler()
3.1545 - * can be used to get the Adler-32 value of the dictionary needed.
3.1546 - * @param b the dictionary data bytes
3.1547 - * @see Inflater#needsDictionary
3.1548 - * @see Inflater#getAdler
3.1549 - */
3.1550 - public void setDictionary(byte[] b) {
3.1551 - setDictionary(b, 0, b.length);
3.1552 - }
3.1553 -
3.1554 - /**
3.1555 - * Returns the total number of bytes remaining in the input buffer.
3.1556 - * This can be used to find out what bytes still remain in the input
3.1557 - * buffer after decompression has finished.
3.1558 - * @return the total number of bytes remaining in the input buffer
3.1559 - */
3.1560 - public int getRemaining() {
3.1561 - return data.length() - offset;
3.1562 - }
3.1563 -
3.1564 - /**
3.1565 - * Returns true if no data remains in the input buffer. This can
3.1566 - * be used to determine if #setInput should be called in order
3.1567 - * to provide more input.
3.1568 - * @return true if no data remains in the input buffer
3.1569 - */
3.1570 - public boolean needsInput() {
3.1571 - return getRemaining() <= 0;
3.1572 - }
3.1573 -
3.1574 - /**
3.1575 - * Returns true if a preset dictionary is needed for decompression.
3.1576 - * @return true if a preset dictionary is needed for decompression
3.1577 - * @see Inflater#setDictionary
3.1578 - */
3.1579 - public boolean needsDictionary() {
3.1580 - return needDict;
3.1581 - }
3.1582 -
3.1583 - /**
3.1584 - * Returns true if the end of the compressed data stream has been
3.1585 - * reached.
3.1586 - * @return true if the end of the compressed data stream has been
3.1587 - * reached
3.1588 - */
3.1589 - public boolean finished() {
3.1590 - return finished;
3.1591 - }
3.1592 -
3.1593 - /**
3.1594 - * Uncompresses bytes into specified buffer. Returns actual number
3.1595 - * of bytes uncompressed. A return value of 0 indicates that
3.1596 - * needsInput() or needsDictionary() should be called in order to
3.1597 - * determine if more input data or a preset dictionary is required.
3.1598 - * In the latter case, getAdler() can be used to get the Adler-32
3.1599 - * value of the dictionary required.
3.1600 - * @param b the buffer for the uncompressed data
3.1601 - * @param off the start offset of the data
3.1602 - * @param len the maximum number of uncompressed bytes
3.1603 - * @return the actual number of uncompressed bytes
3.1604 - * @exception DataFormatException if the compressed data format is invalid
3.1605 - * @see Inflater#needsInput
3.1606 - * @see Inflater#needsDictionary
3.1607 - */
3.1608 - public int inflate(byte[] b, int off, int len)
3.1609 - throws DataFormatException
3.1610 - {
3.1611 - if (b == null) {
3.1612 - throw new NullPointerException();
3.1613 - }
3.1614 - if (off < 0 || len < 0 || off > b.length - len) {
3.1615 - throw new ArrayIndexOutOfBoundsException();
3.1616 - }
3.1617 - int cnt = 0;
3.1618 - while (offset < data.length()) {
3.1619 - b[off++] = (byte)data.charAt(offset++);
3.1620 - cnt++;
3.1621 - counter++;
3.1622 - }
3.1623 - return cnt;
3.1624 - }
3.1625 -
3.1626 - @JavaScriptBody(args = { "arr", "offset", "len" }, body =
3.1627 - "var r = {};\n"
3.1628 - + "r.charCodeAt = function(idx) { return arr[offset + idx]; };\n"
3.1629 - + "return JSInflate.inflate(r);"
3.1630 - )
3.1631 - private static native Object infl(byte[] arr, int offset, int len);
3.1632 -
3.1633 - /**
3.1634 - * Uncompresses bytes into specified buffer. Returns actual number
3.1635 - * of bytes uncompressed. A return value of 0 indicates that
3.1636 - * needsInput() or needsDictionary() should be called in order to
3.1637 - * determine if more input data or a preset dictionary is required.
3.1638 - * In the latter case, getAdler() can be used to get the Adler-32
3.1639 - * value of the dictionary required.
3.1640 - * @param b the buffer for the uncompressed data
3.1641 - * @return the actual number of uncompressed bytes
3.1642 - * @exception DataFormatException if the compressed data format is invalid
3.1643 - * @see Inflater#needsInput
3.1644 - * @see Inflater#needsDictionary
3.1645 - */
3.1646 - public int inflate(byte[] b) throws DataFormatException {
3.1647 - return inflate(b, 0, b.length);
3.1648 - }
3.1649 -
3.1650 - /**
3.1651 - * Returns the ADLER-32 value of the uncompressed data.
3.1652 - * @return the ADLER-32 value of the uncompressed data
3.1653 - */
3.1654 - public int getAdler() {
3.1655 - return 0;
3.1656 - }
3.1657 -
3.1658 - /**
3.1659 - * Returns the total number of compressed bytes input so far.
3.1660 - *
3.1661 - * <p>Since the number of bytes may be greater than
3.1662 - * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
3.1663 - * the preferred means of obtaining this information.</p>
3.1664 - *
3.1665 - * @return the total number of compressed bytes input so far
3.1666 - */
3.1667 - public int getTotalIn() {
3.1668 - return (int) getBytesRead();
3.1669 - }
3.1670 -
3.1671 - /**
3.1672 - * Returns the total number of compressed bytes input so far.</p>
3.1673 - *
3.1674 - * @return the total (non-negative) number of compressed bytes input so far
3.1675 - * @since 1.5
3.1676 - */
3.1677 - public long getBytesRead() {
3.1678 - return counter;
3.1679 - }
3.1680 -
3.1681 - /**
3.1682 - * Returns the total number of uncompressed bytes output so far.
3.1683 - *
3.1684 - * <p>Since the number of bytes may be greater than
3.1685 - * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
3.1686 - * the preferred means of obtaining this information.</p>
3.1687 - *
3.1688 - * @return the total number of uncompressed bytes output so far
3.1689 - */
3.1690 - public int getTotalOut() {
3.1691 - return (int) getBytesWritten();
3.1692 - }
3.1693 -
3.1694 - /**
3.1695 - * Returns the total number of uncompressed bytes output so far.</p>
3.1696 - *
3.1697 - * @return the total (non-negative) number of uncompressed bytes output so far
3.1698 - * @since 1.5
3.1699 - */
3.1700 - public long getBytesWritten() {
3.1701 - return counter;
3.1702 - }
3.1703 -
3.1704 - /**
3.1705 - * Resets inflater so that a new set of input data can be processed.
3.1706 - */
3.1707 - public void reset() {
3.1708 - data = "";
3.1709 - finished = false;
3.1710 - needDict = false;
3.1711 - offset = 0;
3.1712 - }
3.1713 -
3.1714 - /**
3.1715 - * Closes the decompressor and discards any unprocessed input.
3.1716 - * This method should be called when the decompressor is no longer
3.1717 - * being used, but will also be called automatically by the finalize()
3.1718 - * method. Once this method is called, the behavior of the Inflater
3.1719 - * object is undefined.
3.1720 - */
3.1721 - public void end() {
3.1722 - }
3.1723 +
3.1724 }
4.1 --- a/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java Fri Feb 01 15:19:16 2013 +0100
4.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java Fri Feb 01 18:02:16 2013 +0100
4.3 @@ -19,9 +19,13 @@
4.4
4.5 import java.io.IOException;
4.6 import java.io.InputStream;
4.7 +import java.util.Objects;
4.8 import java.util.zip.ZipEntry;
4.9 import java.util.zip.ZipInputStream;
4.10 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
4.11 +import org.apidesign.bck2brwsr.vmtest.BrwsrTest;
4.12 import org.apidesign.bck2brwsr.vmtest.Compare;
4.13 +import org.apidesign.bck2brwsr.vmtest.HttpResource;
4.14 import org.apidesign.bck2brwsr.vmtest.VMTest;
4.15 import org.testng.annotations.Factory;
4.16
4.17 @@ -29,23 +33,29 @@
4.18 *
4.19 * @author Jaroslav Tulach <jtulach@netbeans.org>
4.20 */
4.21 +@GenerateZip(name = "readAnEntry.zip", contents = {
4.22 + "my/main/file.txt", "Hello World!"
4.23 +})
4.24 public class ZipFileTest {
4.25
4.26 - @GenerateZip(name = "readAnEntry.zip", contents = { "my/main/file.txt", "Hello World!" })
4.27 @Compare public String readAnEntry() throws IOException {
4.28 InputStream is = ZipFileTest.class.getResourceAsStream("readAnEntry.zip");
4.29 ZipInputStream zip = new ZipInputStream(is);
4.30 ZipEntry entry = zip.getNextEntry();
4.31 assertEquals(entry.getName(), "my/main/file.txt", "Correct entry");
4.32 -
4.33 +
4.34 byte[] arr = new byte[4096];
4.35 int len = zip.read(arr);
4.36
4.37 - return new String(arr, 0, len, "UTF-8");
4.38 + assertEquals(zip.getNextEntry(), null, "No next entry");
4.39 +
4.40 + final String ret = new String(arr, 0, len, "UTF-8");
4.41 + return ret;
4.42 }
4.43 -
4.44 - private static void assertEquals(String real, String exp, String msg) {
4.45 - assert exp.equals(real) : msg + " exp: " + exp + " real: " + real;
4.46 +
4.47 +
4.48 + private static void assertEquals(Object real, Object exp, String msg) {
4.49 + assert Objects.equals(exp, real) : msg + " exp: " + exp + " real: " + real;
4.50 }
4.51
4.52 @Factory public static Object[] create() {