Using GNU ClassPath implementation of ZipInputStream. Taken from http://sourceforge.net/projects/jazzlib/ rev. jazzlib-0.07.zip emul
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 01 Feb 2013 18:02:16 +0100
branchemul
changeset 640693745d01b55
parent 639 960ecf7cea5d
child 641 d4aaa46cac0d
Using GNU ClassPath implementation of ZipInputStream. Taken from http://sourceforge.net/projects/jazzlib/ rev. jazzlib-0.07.zip
emul/mini/src/main/java/java/util/zip/Adler32.java
emul/mini/src/main/java/java/util/zip/CRC32.java
emul/mini/src/main/java/java/util/zip/Inflater.java
vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipFileTest.java
     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() {