emul/mini/src/main/java/java/util/zip/Inflater.java
branchemul
changeset 640 693745d01b55
parent 611 9839e9a75bcf
child 687 a9e506a27b55
     1.1 --- a/emul/mini/src/main/java/java/util/zip/Inflater.java	Wed Jan 30 14:03:49 2013 +0100
     1.2 +++ b/emul/mini/src/main/java/java/util/zip/Inflater.java	Fri Feb 01 18:02:16 2013 +0100
     1.3 @@ -1,32 +1,43 @@
     1.4 -/*
     1.5 - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
     1.6 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 - *
     1.8 - * This code is free software; you can redistribute it and/or modify it
     1.9 - * under the terms of the GNU General Public License version 2 only, as
    1.10 - * published by the Free Software Foundation.  Oracle designates this
    1.11 - * particular file as subject to the "Classpath" exception as provided
    1.12 - * by Oracle in the LICENSE file that accompanied this code.
    1.13 - *
    1.14 - * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 - * version 2 for more details (a copy is included in the LICENSE file that
    1.18 - * accompanied this code).
    1.19 - *
    1.20 - * You should have received a copy of the GNU General Public License version
    1.21 - * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 - *
    1.24 - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 - * or visit www.oracle.com if you need additional information or have any
    1.26 - * questions.
    1.27 - */
    1.28 +/* Inflater.java - Decompress a data stream
    1.29 +   Copyright (C) 1999, 2000, 2001, 2003  Free Software Foundation, Inc.
    1.30 +
    1.31 +This file is part of GNU Classpath.
    1.32 +
    1.33 +GNU Classpath is free software; you can redistribute it and/or modify
    1.34 +it under the terms of the GNU General Public License as published by
    1.35 +the Free Software Foundation; either version 2, or (at your option)
    1.36 +any later version.
    1.37 + 
    1.38 +GNU Classpath is distributed in the hope that it will be useful, but
    1.39 +WITHOUT ANY WARRANTY; without even the implied warranty of
    1.40 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.41 +General Public License for more details.
    1.42 +
    1.43 +You should have received a copy of the GNU General Public License
    1.44 +along with GNU Classpath; see the file COPYING.  If not, write to the
    1.45 +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    1.46 +02111-1307 USA.
    1.47 +
    1.48 +Linking this library statically or dynamically with other modules is
    1.49 +making a combined work based on this library.  Thus, the terms and
    1.50 +conditions of the GNU General Public License cover the whole
    1.51 +combination.
    1.52 +
    1.53 +As a special exception, the copyright holders of this library give you
    1.54 +permission to link this library with independent modules to produce an
    1.55 +executable, regardless of the license terms of these independent
    1.56 +modules, and to copy and distribute the resulting executable under
    1.57 +terms of your choice, provided that you also meet, for each linked
    1.58 +independent module, the terms and conditions of the license of that
    1.59 +module.  An independent module is a module which is not derived from
    1.60 +or based on this library.  If you modify this library, you may extend
    1.61 +this exception to your version of the library, but you are not
    1.62 +obligated to do so.  If you do not wish to do so, delete this
    1.63 +exception statement from your version. */
    1.64  
    1.65  package java.util.zip;
    1.66  
    1.67 -import org.apidesign.bck2brwsr.core.ExtraJavaScript;
    1.68 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
    1.69 +import org.apidesign.bck2brwsr.emul.lang.System;
    1.70  
    1.71  /**
    1.72   * This class provides support for general purpose decompression using the
    1.73 @@ -73,271 +84,1392 @@
    1.74   * @author      David Connelly
    1.75   *
    1.76   */
    1.77 -@ExtraJavaScript(
    1.78 -    resource = "/org/apidesign/vm4brwsr/emul/zip/js-inflate.min.js"
    1.79 -)
    1.80 -public
    1.81 -class Inflater {
    1.82 -    private String data = "";
    1.83 -    private int offset;
    1.84 -    private long counter;
    1.85 -    private boolean finished;
    1.86 -    private boolean needDict;
    1.87  
    1.88 -    private static final byte[] defaultBuf = new byte[0];
    1.89 +/* Written using on-line Java Platform 1.2 API Specification
    1.90 + * and JCL book.
    1.91 + * Believed complete and correct.
    1.92 + */
    1.93  
    1.94 +/**
    1.95 + * Inflater is used to decompress data that has been compressed according 
    1.96 + * to the "deflate" standard described in rfc1950.
    1.97 + *
    1.98 + * The usage is as following.  First you have to set some input with
    1.99 + * <code>setInput()</code>, then inflate() it.  If inflate doesn't
   1.100 + * inflate any bytes there may be three reasons:
   1.101 + * <ul>
   1.102 + * <li>needsInput() returns true because the input buffer is empty.
   1.103 + * You have to provide more input with <code>setInput()</code>.  
   1.104 + * NOTE: needsInput() also returns true when, the stream is finished.
   1.105 + * </li>
   1.106 + * <li>needsDictionary() returns true, you have to provide a preset 
   1.107 + *     dictionary with <code>setDictionary()</code>.</li>
   1.108 + * <li>finished() returns true, the inflater has finished.</li>
   1.109 + * </ul>
   1.110 + * Once the first output byte is produced, a dictionary will not be
   1.111 + * needed at a later stage.
   1.112 + *
   1.113 + * @author John Leuner, Jochen Hoenicke
   1.114 + * @author Tom Tromey
   1.115 + * @date May 17, 1999
   1.116 + * @since JDK 1.1
   1.117 + */
   1.118 +public class Inflater
   1.119 +{
   1.120 +  /* Copy lengths for literal codes 257..285 */
   1.121 +  private static final int CPLENS[] = 
   1.122 +  { 
   1.123 +    3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
   1.124 +    35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
   1.125 +  };
   1.126 +  
   1.127 +  /* Extra bits for literal codes 257..285 */  
   1.128 +  private static final int CPLEXT[] = 
   1.129 +  { 
   1.130 +    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
   1.131 +    3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
   1.132 +  };
   1.133 +
   1.134 +  /* Copy offsets for distance codes 0..29 */
   1.135 +  private static final int CPDIST[] = {
   1.136 +    1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
   1.137 +    257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
   1.138 +    8193, 12289, 16385, 24577
   1.139 +  };
   1.140 +  
   1.141 +  /* Extra bits for distance codes */
   1.142 +  private static final int CPDEXT[] = {
   1.143 +    0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
   1.144 +    7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 
   1.145 +    12, 12, 13, 13
   1.146 +  };
   1.147 +
   1.148 +  /* This are the state in which the inflater can be.  */
   1.149 +  private static final int DECODE_HEADER           = 0;
   1.150 +  private static final int DECODE_DICT             = 1;
   1.151 +  private static final int DECODE_BLOCKS           = 2;
   1.152 +  private static final int DECODE_STORED_LEN1      = 3;
   1.153 +  private static final int DECODE_STORED_LEN2      = 4;
   1.154 +  private static final int DECODE_STORED           = 5;
   1.155 +  private static final int DECODE_DYN_HEADER       = 6;
   1.156 +  private static final int DECODE_HUFFMAN          = 7;
   1.157 +  private static final int DECODE_HUFFMAN_LENBITS  = 8;
   1.158 +  private static final int DECODE_HUFFMAN_DIST     = 9;
   1.159 +  private static final int DECODE_HUFFMAN_DISTBITS = 10;
   1.160 +  private static final int DECODE_CHKSUM           = 11;
   1.161 +  private static final int FINISHED                = 12;
   1.162 +
   1.163 +  /** This variable contains the current state. */
   1.164 +  private int mode;
   1.165 +
   1.166 +  /**
   1.167 +   * The adler checksum of the dictionary or of the decompressed
   1.168 +   * stream, as it is written in the header resp. footer of the
   1.169 +   * compressed stream.  <br>
   1.170 +   *
   1.171 +   * Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
   1.172 +   */
   1.173 +  private int readAdler;
   1.174 +  /** 
   1.175 +   * The number of bits needed to complete the current state.  This
   1.176 +   * is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
   1.177 +   * DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.  
   1.178 +   */
   1.179 +  private int neededBits;
   1.180 +  private int repLength, repDist;
   1.181 +  private int uncomprLen;
   1.182 +  /**
   1.183 +   * True, if the last block flag was set in the last block of the
   1.184 +   * inflated stream.  This means that the stream ends after the
   1.185 +   * current block.  
   1.186 +   */
   1.187 +  private boolean isLastBlock;
   1.188 +
   1.189 +  /**
   1.190 +   * The total number of inflated bytes.
   1.191 +   */
   1.192 +  private long totalOut;
   1.193 +  /**
   1.194 +   * The total number of bytes set with setInput().  This is not the
   1.195 +   * value returned by getTotalIn(), since this also includes the 
   1.196 +   * unprocessed input.
   1.197 +   */
   1.198 +  private long totalIn;
   1.199 +  /**
   1.200 +   * This variable stores the nowrap flag that was given to the constructor.
   1.201 +   * True means, that the inflated stream doesn't contain a header nor the
   1.202 +   * checksum in the footer.
   1.203 +   */
   1.204 +  private boolean nowrap;
   1.205 +
   1.206 +  private StreamManipulator input;
   1.207 +  private OutputWindow outputWindow;
   1.208 +  private InflaterDynHeader dynHeader;
   1.209 +  private InflaterHuffmanTree litlenTree, distTree;
   1.210 +  private Adler32 adler;
   1.211 +
   1.212 +  /**
   1.213 +   * Creates a new inflater.
   1.214 +   */
   1.215 +  public Inflater ()
   1.216 +  {
   1.217 +    this (false);
   1.218 +  }
   1.219 +
   1.220 +  /**
   1.221 +   * Creates a new inflater.
   1.222 +   * @param nowrap true if no header and checksum field appears in the
   1.223 +   * stream.  This is used for GZIPed input.  For compatibility with
   1.224 +   * Sun JDK you should provide one byte of input more than needed in
   1.225 +   * this case.
   1.226 +   */
   1.227 +  public Inflater (boolean nowrap)
   1.228 +  {
   1.229 +    this.nowrap = nowrap;
   1.230 +    this.adler = new Adler32();
   1.231 +    input = new StreamManipulator();
   1.232 +    outputWindow = new OutputWindow();
   1.233 +    mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
   1.234 +  }
   1.235 +
   1.236 +  /**
   1.237 +   * Finalizes this object.
   1.238 +   */
   1.239 +  protected void finalize ()
   1.240 +  {
   1.241 +    /* Exists only for compatibility */
   1.242 +  }
   1.243 +
   1.244 +  /**
   1.245 +   * Frees all objects allocated by the inflater.  There's no reason
   1.246 +   * to call this, since you can just rely on garbage collection (even
   1.247 +   * for the Sun implementation).  Exists only for compatibility
   1.248 +   * with Sun's JDK, where the compressor allocates native memory.
   1.249 +   * If you call any method (even reset) afterwards the behaviour is
   1.250 +   * <i>undefined</i>.  
   1.251 +   * @deprecated Just clear all references to inflater instead.
   1.252 +   */
   1.253 +  public void end ()
   1.254 +  {
   1.255 +    outputWindow = null;
   1.256 +    input = null;
   1.257 +    dynHeader = null;
   1.258 +    litlenTree = null;
   1.259 +    distTree = null;
   1.260 +    adler = null;
   1.261 +  }
   1.262 +
   1.263 +  /**
   1.264 +   * Returns true, if the inflater has finished.  This means, that no
   1.265 +   * input is needed and no output can be produced.
   1.266 +   */
   1.267 +  public boolean finished() 
   1.268 +  {
   1.269 +    return mode == FINISHED && outputWindow.getAvailable() == 0;
   1.270 +  }
   1.271 +
   1.272 +  /**
   1.273 +   * Gets the adler checksum.  This is either the checksum of all
   1.274 +   * uncompressed bytes returned by inflate(), or if needsDictionary()
   1.275 +   * returns true (and thus no output was yet produced) this is the
   1.276 +   * adler checksum of the expected dictionary.
   1.277 +   * @returns the adler checksum.
   1.278 +   */
   1.279 +  public int getAdler()
   1.280 +  {
   1.281 +    return needsDictionary() ? readAdler : (int) adler.getValue();
   1.282 +  }
   1.283 +  
   1.284 +  /**
   1.285 +   * Gets the number of unprocessed input.  Useful, if the end of the
   1.286 +   * stream is reached and you want to further process the bytes after
   1.287 +   * the deflate stream.  
   1.288 +   * @return the number of bytes of the input which were not processed.
   1.289 +   */
   1.290 +  public int getRemaining()
   1.291 +  {
   1.292 +    return input.getAvailableBytes();
   1.293 +  }
   1.294 +  
   1.295 +  /**
   1.296 +   * Gets the total number of processed compressed input bytes.
   1.297 +   * @return the total number of bytes of processed input bytes.
   1.298 +   */
   1.299 +  public int getTotalIn()
   1.300 +  {
   1.301 +    return (int)getBytesRead();
   1.302 +  }
   1.303 +  
   1.304 +  /**
   1.305 +   * Gets the total number of output bytes returned by inflate().
   1.306 +   * @return the total number of output bytes.
   1.307 +   */
   1.308 +  public int getTotalOut()
   1.309 +  {
   1.310 +    return (int)totalOut;
   1.311 +  }
   1.312 +  
   1.313 +  public long getBytesWritten() {
   1.314 +     return totalOut;
   1.315 +  }
   1.316 +
   1.317 +  public long getBytesRead() {
   1.318 +    return totalIn - getRemaining();
   1.319 +  }
   1.320 +  
   1.321 +
   1.322 +  /**
   1.323 +   * Inflates the compressed stream to the output buffer.  If this
   1.324 +   * returns 0, you should check, whether needsDictionary(),
   1.325 +   * needsInput() or finished() returns true, to determine why no 
   1.326 +   * further output is produced.
   1.327 +   * @param buffer the output buffer.
   1.328 +   * @return the number of bytes written to the buffer, 0 if no further
   1.329 +   * output can be produced.  
   1.330 +   * @exception DataFormatException if deflated stream is invalid.
   1.331 +   * @exception IllegalArgumentException if buf has length 0.
   1.332 +   */
   1.333 +  public int inflate (byte[] buf) throws DataFormatException
   1.334 +  {
   1.335 +    return inflate (buf, 0, buf.length);
   1.336 +  }
   1.337 +
   1.338 +  /**
   1.339 +   * Inflates the compressed stream to the output buffer.  If this
   1.340 +   * returns 0, you should check, whether needsDictionary(),
   1.341 +   * needsInput() or finished() returns true, to determine why no 
   1.342 +   * further output is produced.
   1.343 +   * @param buffer the output buffer.
   1.344 +   * @param off the offset into buffer where the output should start.
   1.345 +   * @param len the maximum length of the output.
   1.346 +   * @return the number of bytes written to the buffer, 0 if no further
   1.347 +   * output can be produced.  
   1.348 +   * @exception DataFormatException if deflated stream is invalid.
   1.349 +   * @exception IndexOutOfBoundsException if the off and/or len are wrong.
   1.350 +   */
   1.351 +  public int inflate (byte[] buf, int off, int len) throws DataFormatException
   1.352 +  {
   1.353 +    /* Special case: len may be zero */
   1.354 +    if (len == 0)
   1.355 +      return 0;
   1.356 +    /* Check for correct buff, off, len triple */
   1.357 +    if (0 > off || off > off + len || off + len > buf.length)
   1.358 +      throw new ArrayIndexOutOfBoundsException();
   1.359 +    int count = 0;
   1.360 +    int more;
   1.361 +    do
   1.362 +      {
   1.363 +	if (mode != DECODE_CHKSUM)
   1.364 +	  {
   1.365 +	    /* Don't give away any output, if we are waiting for the
   1.366 +	     * checksum in the input stream.
   1.367 +	     *
   1.368 +	     * With this trick we have always:
   1.369 +	     *   needsInput() and not finished() 
   1.370 +	     *   implies more output can be produced.  
   1.371 +	     */
   1.372 +	    more = outputWindow.copyOutput(buf, off, len);
   1.373 +	    adler.update(buf, off, more);
   1.374 +	    off += more;
   1.375 +	    count += more;
   1.376 +	    totalOut += more;
   1.377 +	    len -= more;
   1.378 +	    if (len == 0)
   1.379 +	      return count;
   1.380 +	  }
   1.381 +      }
   1.382 +    while (decode() || (outputWindow.getAvailable() > 0
   1.383 +			&& mode != DECODE_CHKSUM));
   1.384 +    return count;
   1.385 +  }
   1.386 +
   1.387 +  /**
   1.388 +   * Returns true, if a preset dictionary is needed to inflate the input.
   1.389 +   */
   1.390 +  public boolean needsDictionary ()
   1.391 +  {
   1.392 +    return mode == DECODE_DICT && neededBits == 0;
   1.393 +  }
   1.394 +
   1.395 +  /**
   1.396 +   * Returns true, if the input buffer is empty.
   1.397 +   * You should then call setInput(). <br>
   1.398 +   *
   1.399 +   * <em>NOTE</em>: This method also returns true when the stream is finished.
   1.400 +   */
   1.401 +  public boolean needsInput () 
   1.402 +  {
   1.403 +    return input.needsInput ();
   1.404 +  }
   1.405 +
   1.406 +  /**
   1.407 +   * Resets the inflater so that a new stream can be decompressed.  All
   1.408 +   * pending input and output will be discarded.
   1.409 +   */
   1.410 +  public void reset ()
   1.411 +  {
   1.412 +    mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER;
   1.413 +    totalIn = totalOut = 0;
   1.414 +    input.reset();
   1.415 +    outputWindow.reset();
   1.416 +    dynHeader = null;
   1.417 +    litlenTree = null;
   1.418 +    distTree = null;
   1.419 +    isLastBlock = false;
   1.420 +    adler.reset();
   1.421 +  }
   1.422 +
   1.423 +  /**
   1.424 +   * Sets the preset dictionary.  This should only be called, if
   1.425 +   * needsDictionary() returns true and it should set the same
   1.426 +   * dictionary, that was used for deflating.  The getAdler()
   1.427 +   * function returns the checksum of the dictionary needed.
   1.428 +   * @param buffer the dictionary.
   1.429 +   * @exception IllegalStateException if no dictionary is needed.
   1.430 +   * @exception IllegalArgumentException if the dictionary checksum is
   1.431 +   * wrong.  
   1.432 +   */
   1.433 +  public void setDictionary (byte[] buffer)
   1.434 +  {
   1.435 +    setDictionary(buffer, 0, buffer.length);
   1.436 +  }
   1.437 +
   1.438 +  /**
   1.439 +   * Sets the preset dictionary.  This should only be called, if
   1.440 +   * needsDictionary() returns true and it should set the same
   1.441 +   * dictionary, that was used for deflating.  The getAdler()
   1.442 +   * function returns the checksum of the dictionary needed.
   1.443 +   * @param buffer the dictionary.
   1.444 +   * @param off the offset into buffer where the dictionary starts.
   1.445 +   * @param len the length of the dictionary.
   1.446 +   * @exception IllegalStateException if no dictionary is needed.
   1.447 +   * @exception IllegalArgumentException if the dictionary checksum is
   1.448 +   * wrong.  
   1.449 +   * @exception IndexOutOfBoundsException if the off and/or len are wrong.
   1.450 +   */
   1.451 +  public void setDictionary (byte[] buffer, int off, int len)
   1.452 +  {
   1.453 +    if (!needsDictionary())
   1.454 +      throw new IllegalStateException();
   1.455 +
   1.456 +    adler.update(buffer, off, len);
   1.457 +    if ((int) adler.getValue() != readAdler)
   1.458 +      throw new IllegalArgumentException("Wrong adler checksum");
   1.459 +    adler.reset();
   1.460 +    outputWindow.copyDict(buffer, off, len);
   1.461 +    mode = DECODE_BLOCKS;
   1.462 +  }
   1.463 +
   1.464 +  /**
   1.465 +   * Sets the input.  This should only be called, if needsInput()
   1.466 +   * returns true.
   1.467 +   * @param buffer the input.
   1.468 +   * @exception IllegalStateException if no input is needed.
   1.469 +   */
   1.470 +  public void setInput (byte[] buf) 
   1.471 +  {
   1.472 +    setInput (buf, 0, buf.length);
   1.473 +  }
   1.474 +
   1.475 +  /**
   1.476 +   * Sets the input.  This should only be called, if needsInput()
   1.477 +   * returns true.
   1.478 +   * @param buffer the input.
   1.479 +   * @param off the offset into buffer where the input starts.
   1.480 +   * @param len the length of the input.  
   1.481 +   * @exception IllegalStateException if no input is needed.
   1.482 +   * @exception IndexOutOfBoundsException if the off and/or len are wrong.
   1.483 +   */
   1.484 +  public void setInput (byte[] buf, int off, int len) 
   1.485 +  {
   1.486 +    input.setInput (buf, off, len);
   1.487 +    totalIn += len;
   1.488 +  }
   1.489 +  private static final int DEFLATED = 8;
   1.490 +  /**
   1.491 +   * Decodes the deflate header.
   1.492 +   * @return false if more input is needed. 
   1.493 +   * @exception DataFormatException if header is invalid.
   1.494 +   */
   1.495 +  private boolean decodeHeader () throws DataFormatException
   1.496 +  {
   1.497 +    int header = input.peekBits(16);
   1.498 +    if (header < 0)
   1.499 +      return false;
   1.500 +    input.dropBits(16);
   1.501 +    
   1.502 +    /* The header is written in "wrong" byte order */
   1.503 +    header = ((header << 8) | (header >> 8)) & 0xffff;
   1.504 +    if (header % 31 != 0)
   1.505 +      throw new DataFormatException("Header checksum illegal");
   1.506 +    
   1.507 +    if ((header & 0x0f00) != (DEFLATED << 8))
   1.508 +      throw new DataFormatException("Compression Method unknown");
   1.509 +
   1.510 +    /* Maximum size of the backwards window in bits. 
   1.511 +     * We currently ignore this, but we could use it to make the
   1.512 +     * inflater window more space efficient. On the other hand the
   1.513 +     * full window (15 bits) is needed most times, anyway.
   1.514 +     int max_wbits = ((header & 0x7000) >> 12) + 8;
   1.515 +     */
   1.516 +    
   1.517 +    if ((header & 0x0020) == 0) // Dictionary flag?
   1.518 +      {
   1.519 +	mode = DECODE_BLOCKS;
   1.520 +      }
   1.521 +    else
   1.522 +      {
   1.523 +	mode = DECODE_DICT;
   1.524 +	neededBits = 32;      
   1.525 +      }
   1.526 +    return true;
   1.527 +  }
   1.528 +   
   1.529 +  /**
   1.530 +   * Decodes the dictionary checksum after the deflate header.
   1.531 +   * @return false if more input is needed. 
   1.532 +   */
   1.533 +  private boolean decodeDict ()
   1.534 +  {
   1.535 +    while (neededBits > 0)
   1.536 +      {
   1.537 +	int dictByte = input.peekBits(8);
   1.538 +	if (dictByte < 0)
   1.539 +	  return false;
   1.540 +	input.dropBits(8);
   1.541 +	readAdler = (readAdler << 8) | dictByte;
   1.542 +	neededBits -= 8;
   1.543 +      }
   1.544 +    return false;
   1.545 +  }
   1.546 +
   1.547 +  /**
   1.548 +   * Decodes the huffman encoded symbols in the input stream.
   1.549 +   * @return false if more input is needed, true if output window is
   1.550 +   * full or the current block ends.
   1.551 +   * @exception DataFormatException if deflated stream is invalid.  
   1.552 +   */
   1.553 +  private boolean decodeHuffman () throws DataFormatException
   1.554 +  {
   1.555 +    int free = outputWindow.getFreeSpace();
   1.556 +    while (free >= 258)
   1.557 +      {
   1.558 +	int symbol;
   1.559 +	switch (mode)
   1.560 +	  {
   1.561 +	  case DECODE_HUFFMAN:
   1.562 +	    /* This is the inner loop so it is optimized a bit */
   1.563 +	    while (((symbol = litlenTree.getSymbol(input)) & ~0xff) == 0)
   1.564 +	      {
   1.565 +		outputWindow.write(symbol);
   1.566 +		if (--free < 258)
   1.567 +		  return true;
   1.568 +	      } 
   1.569 +	    if (symbol < 257)
   1.570 +	      {
   1.571 +		if (symbol < 0)
   1.572 +		  return false;
   1.573 +		else
   1.574 +		  {
   1.575 +		    /* symbol == 256: end of block */
   1.576 +		    distTree = null;
   1.577 +		    litlenTree = null;
   1.578 +		    mode = DECODE_BLOCKS;
   1.579 +		    return true;
   1.580 +		  }
   1.581 +	      }
   1.582 +		
   1.583 +	    try
   1.584 +	      {
   1.585 +		repLength = CPLENS[symbol - 257];
   1.586 +		neededBits = CPLEXT[symbol - 257];
   1.587 +	      }
   1.588 +	    catch (ArrayIndexOutOfBoundsException ex)
   1.589 +	      {
   1.590 +		throw new DataFormatException("Illegal rep length code");
   1.591 +	      }
   1.592 +	    /* fall through */
   1.593 +	  case DECODE_HUFFMAN_LENBITS:
   1.594 +	    if (neededBits > 0)
   1.595 +	      {
   1.596 +		mode = DECODE_HUFFMAN_LENBITS;
   1.597 +		int i = input.peekBits(neededBits);
   1.598 +		if (i < 0)
   1.599 +		  return false;
   1.600 +		input.dropBits(neededBits);
   1.601 +		repLength += i;
   1.602 +	      }
   1.603 +	    mode = DECODE_HUFFMAN_DIST;
   1.604 +	    /* fall through */
   1.605 +	  case DECODE_HUFFMAN_DIST:
   1.606 +	    symbol = distTree.getSymbol(input);
   1.607 +	    if (symbol < 0)
   1.608 +	      return false;
   1.609 +	    try 
   1.610 +	      {
   1.611 +		repDist = CPDIST[symbol];
   1.612 +		neededBits = CPDEXT[symbol];
   1.613 +	      }
   1.614 +	    catch (ArrayIndexOutOfBoundsException ex)
   1.615 +	      {
   1.616 +		throw new DataFormatException("Illegal rep dist code");
   1.617 +	      }
   1.618 +	    /* fall through */
   1.619 +	  case DECODE_HUFFMAN_DISTBITS:
   1.620 +	    if (neededBits > 0)
   1.621 +	      {
   1.622 +		mode = DECODE_HUFFMAN_DISTBITS;
   1.623 +		int i = input.peekBits(neededBits);
   1.624 +		if (i < 0)
   1.625 +		  return false;
   1.626 +		input.dropBits(neededBits);
   1.627 +		repDist += i;
   1.628 +	      }
   1.629 +	    outputWindow.repeat(repLength, repDist);
   1.630 +	    free -= repLength;
   1.631 +	    mode = DECODE_HUFFMAN;
   1.632 +	    break;
   1.633 +	  default:
   1.634 +	    throw new IllegalStateException();
   1.635 +	  }
   1.636 +      }
   1.637 +    return true;
   1.638 +  }
   1.639 +
   1.640 +  /**
   1.641 +   * Decodes the adler checksum after the deflate stream.
   1.642 +   * @return false if more input is needed. 
   1.643 +   * @exception DataFormatException if checksum doesn't match.
   1.644 +   */
   1.645 +  private boolean decodeChksum () throws DataFormatException
   1.646 +  {
   1.647 +    while (neededBits > 0)
   1.648 +      {
   1.649 +	int chkByte = input.peekBits(8);
   1.650 +	if (chkByte < 0)
   1.651 +	  return false;
   1.652 +	input.dropBits(8);
   1.653 +	readAdler = (readAdler << 8) | chkByte;
   1.654 +	neededBits -= 8;
   1.655 +      }
   1.656 +    if ((int) adler.getValue() != readAdler)
   1.657 +      throw new DataFormatException("Adler chksum doesn't match: "
   1.658 +				    +Integer.toHexString((int)adler.getValue())
   1.659 +				    +" vs. "+Integer.toHexString(readAdler));
   1.660 +    mode = FINISHED;
   1.661 +    return false;
   1.662 +  }
   1.663 +
   1.664 +  /**
   1.665 +   * Decodes the deflated stream.
   1.666 +   * @return false if more input is needed, or if finished. 
   1.667 +   * @exception DataFormatException if deflated stream is invalid.
   1.668 +   */
   1.669 +  private boolean decode () throws DataFormatException
   1.670 +  {
   1.671 +    switch (mode) 
   1.672 +      {
   1.673 +      case DECODE_HEADER:
   1.674 +	return decodeHeader();
   1.675 +      case DECODE_DICT:
   1.676 +	return decodeDict();
   1.677 +      case DECODE_CHKSUM:
   1.678 +	return decodeChksum();
   1.679 +
   1.680 +      case DECODE_BLOCKS:
   1.681 +	if (isLastBlock)
   1.682 +	  {
   1.683 +	    if (nowrap)
   1.684 +	      {
   1.685 +		mode = FINISHED;
   1.686 +		return false;
   1.687 +	      }
   1.688 +	    else
   1.689 +	      {
   1.690 +		input.skipToByteBoundary();
   1.691 +		neededBits = 32;
   1.692 +		mode = DECODE_CHKSUM;
   1.693 +		return true;
   1.694 +	      }
   1.695 +	  }
   1.696 +
   1.697 +	int type = input.peekBits(3);
   1.698 +	if (type < 0)
   1.699 +	  return false;
   1.700 +	input.dropBits(3);
   1.701 +
   1.702 +	if ((type & 1) != 0)
   1.703 +	  isLastBlock = true;
   1.704 +	switch (type >> 1)
   1.705 +	  {
   1.706 +	  case DeflaterConstants.STORED_BLOCK:
   1.707 +	    input.skipToByteBoundary();
   1.708 +	    mode = DECODE_STORED_LEN1;
   1.709 +	    break;
   1.710 +	  case DeflaterConstants.STATIC_TREES:
   1.711 +	    litlenTree = InflaterHuffmanTree.defLitLenTree;
   1.712 +	    distTree = InflaterHuffmanTree.defDistTree;
   1.713 +	    mode = DECODE_HUFFMAN;
   1.714 +	    break;
   1.715 +	  case DeflaterConstants.DYN_TREES:
   1.716 +	    dynHeader = new InflaterDynHeader();
   1.717 +	    mode = DECODE_DYN_HEADER;
   1.718 +	    break;
   1.719 +	  default:
   1.720 +	    throw new DataFormatException("Unknown block type "+type);
   1.721 +	  }
   1.722 +	return true;
   1.723 +
   1.724 +      case DECODE_STORED_LEN1:
   1.725 +	{
   1.726 +	  if ((uncomprLen = input.peekBits(16)) < 0)
   1.727 +	    return false;
   1.728 +	  input.dropBits(16);
   1.729 +	  mode = DECODE_STORED_LEN2;
   1.730 +	}
   1.731 +	/* fall through */
   1.732 +      case DECODE_STORED_LEN2:
   1.733 +	{
   1.734 +	  int nlen = input.peekBits(16);
   1.735 +	  if (nlen < 0)
   1.736 +	    return false;
   1.737 +	  input.dropBits(16);
   1.738 +	  if (nlen != (uncomprLen ^ 0xffff))
   1.739 +	    throw new DataFormatException("broken uncompressed block");
   1.740 +	  mode = DECODE_STORED;
   1.741 +	}
   1.742 +	/* fall through */
   1.743 +      case DECODE_STORED:
   1.744 +	{
   1.745 +	  int more = outputWindow.copyStored(input, uncomprLen);
   1.746 +	  uncomprLen -= more;
   1.747 +	  if (uncomprLen == 0)
   1.748 +	    {
   1.749 +	      mode = DECODE_BLOCKS;
   1.750 +	      return true;
   1.751 +	    }
   1.752 +	  return !input.needsInput();
   1.753 +	}
   1.754 +
   1.755 +      case DECODE_DYN_HEADER:
   1.756 +	if (!dynHeader.decode(input))
   1.757 +	  return false;
   1.758 +	litlenTree = dynHeader.buildLitLenTree();
   1.759 +	distTree = dynHeader.buildDistTree();
   1.760 +	mode = DECODE_HUFFMAN;
   1.761 +	/* fall through */
   1.762 +      case DECODE_HUFFMAN:
   1.763 +      case DECODE_HUFFMAN_LENBITS:
   1.764 +      case DECODE_HUFFMAN_DIST:
   1.765 +      case DECODE_HUFFMAN_DISTBITS:
   1.766 +	return decodeHuffman();
   1.767 +      case FINISHED:
   1.768 +	return false;
   1.769 +      default:
   1.770 +	throw new IllegalStateException();
   1.771 +      }	
   1.772 +  }
   1.773 +
   1.774 +
   1.775 +    interface DeflaterConstants {
   1.776 +      final static boolean DEBUGGING = false;
   1.777 +
   1.778 +      final static int STORED_BLOCK = 0;
   1.779 +      final static int STATIC_TREES = 1;
   1.780 +      final static int DYN_TREES    = 2;
   1.781 +      final static int PRESET_DICT  = 0x20;
   1.782 +
   1.783 +      final static int DEFAULT_MEM_LEVEL = 8;
   1.784 +
   1.785 +      final static int MAX_MATCH = 258;
   1.786 +      final static int MIN_MATCH = 3;
   1.787 +
   1.788 +      final static int MAX_WBITS = 15;
   1.789 +      final static int WSIZE = 1 << MAX_WBITS;
   1.790 +      final static int WMASK = WSIZE - 1;
   1.791 +
   1.792 +      final static int HASH_BITS = DEFAULT_MEM_LEVEL + 7;
   1.793 +      final static int HASH_SIZE = 1 << HASH_BITS;
   1.794 +      final static int HASH_MASK = HASH_SIZE - 1;
   1.795 +      final static int HASH_SHIFT = (HASH_BITS + MIN_MATCH - 1) / MIN_MATCH;
   1.796 +
   1.797 +      final static int MIN_LOOKAHEAD = MAX_MATCH + MIN_MATCH + 1;
   1.798 +      final static int MAX_DIST = WSIZE - MIN_LOOKAHEAD;
   1.799 +
   1.800 +      final static int PENDING_BUF_SIZE = 1 << (DEFAULT_MEM_LEVEL + 8);
   1.801 +      final static int MAX_BLOCK_SIZE = Math.min(65535, PENDING_BUF_SIZE-5);
   1.802 +
   1.803 +      final static int DEFLATE_STORED = 0;
   1.804 +      final static int DEFLATE_FAST   = 1;
   1.805 +      final static int DEFLATE_SLOW   = 2;
   1.806 +
   1.807 +      final static int GOOD_LENGTH[] = { 0,4, 4, 4, 4, 8,  8,  8,  32,  32 };
   1.808 +      final static int MAX_LAZY[]    = { 0,4, 5, 6, 4,16, 16, 32, 128, 258 };
   1.809 +      final static int NICE_LENGTH[] = { 0,8,16,32,16,32,128,128, 258, 258 };
   1.810 +      final static int MAX_CHAIN[]   = { 0,4, 8,32,16,32,128,256,1024,4096 };
   1.811 +      final static int COMPR_FUNC[]  = { 0,1, 1, 1, 1, 2,  2,  2,   2,   2 };
   1.812 +    }
   1.813 +    private static class InflaterHuffmanTree {
   1.814 +      private final static int MAX_BITLEN = 15;
   1.815 +      private short[] tree;
   1.816 +
   1.817 +      public static InflaterHuffmanTree defLitLenTree, defDistTree;
   1.818 +
   1.819 +      static
   1.820 +      {
   1.821 +        try 
   1.822 +          {
   1.823 +        byte[] codeLengths = new byte[288];
   1.824 +        int i = 0;
   1.825 +        while (i < 144)
   1.826 +          codeLengths[i++] = 8;
   1.827 +        while (i < 256)
   1.828 +          codeLengths[i++] = 9;
   1.829 +        while (i < 280)
   1.830 +          codeLengths[i++] = 7;
   1.831 +        while (i < 288)
   1.832 +          codeLengths[i++] = 8;
   1.833 +        defLitLenTree = new InflaterHuffmanTree(codeLengths);
   1.834 +
   1.835 +        codeLengths = new byte[32];
   1.836 +        i = 0;
   1.837 +        while (i < 32)
   1.838 +          codeLengths[i++] = 5;
   1.839 +        defDistTree = new InflaterHuffmanTree(codeLengths);
   1.840 +          } 
   1.841 +        catch (DataFormatException ex)
   1.842 +          {
   1.843 +        throw new IllegalStateException
   1.844 +          ("InflaterHuffmanTree: static tree length illegal");
   1.845 +          }
   1.846 +      }
   1.847 +
   1.848 +      /**
   1.849 +       * Constructs a Huffman tree from the array of code lengths.
   1.850 +       *
   1.851 +       * @param codeLengths the array of code lengths
   1.852 +       */
   1.853 +      public InflaterHuffmanTree(byte[] codeLengths) throws DataFormatException
   1.854 +      {
   1.855 +        buildTree(codeLengths);
   1.856 +      }
   1.857 +
   1.858 +      private void buildTree(byte[] codeLengths) throws DataFormatException
   1.859 +      {
   1.860 +        int[] blCount = new int[MAX_BITLEN+1];
   1.861 +        int[] nextCode = new int[MAX_BITLEN+1];
   1.862 +        for (int i = 0; i < codeLengths.length; i++)
   1.863 +          {
   1.864 +        int bits = codeLengths[i];
   1.865 +        if (bits > 0)
   1.866 +          blCount[bits]++;
   1.867 +          }
   1.868 +
   1.869 +        int code = 0;
   1.870 +        int treeSize = 512;
   1.871 +        for (int bits = 1; bits <= MAX_BITLEN; bits++)
   1.872 +          {
   1.873 +        nextCode[bits] = code;
   1.874 +        code += blCount[bits] << (16 - bits);
   1.875 +        if (bits >= 10)
   1.876 +          {
   1.877 +            /* We need an extra table for bit lengths >= 10. */
   1.878 +            int start = nextCode[bits] & 0x1ff80;
   1.879 +            int end   = code & 0x1ff80;
   1.880 +            treeSize += (end - start) >> (16 - bits);
   1.881 +          }
   1.882 +          }
   1.883 +        if (code != 65536)
   1.884 +          throw new DataFormatException("Code lengths don't add up properly.");
   1.885 +
   1.886 +        /* Now create and fill the extra tables from longest to shortest
   1.887 +         * bit len.  This way the sub trees will be aligned.
   1.888 +         */
   1.889 +        tree = new short[treeSize];
   1.890 +        int treePtr = 512;
   1.891 +        for (int bits = MAX_BITLEN; bits >= 10; bits--)
   1.892 +          {
   1.893 +        int end   = code & 0x1ff80;
   1.894 +        code -= blCount[bits] << (16 - bits);
   1.895 +        int start = code & 0x1ff80;
   1.896 +        for (int i = start; i < end; i += 1 << 7)
   1.897 +          {
   1.898 +            tree[bitReverse(i)]
   1.899 +              = (short) ((-treePtr << 4) | bits);
   1.900 +            treePtr += 1 << (bits-9);
   1.901 +          }
   1.902 +          }
   1.903 +
   1.904 +        for (int i = 0; i < codeLengths.length; i++)
   1.905 +          {
   1.906 +        int bits = codeLengths[i];
   1.907 +        if (bits == 0)
   1.908 +          continue;
   1.909 +        code = nextCode[bits];
   1.910 +        int revcode = bitReverse(code);
   1.911 +        if (bits <= 9)
   1.912 +          {
   1.913 +            do
   1.914 +              {
   1.915 +            tree[revcode] = (short) ((i << 4) | bits);
   1.916 +            revcode += 1 << bits;
   1.917 +              }
   1.918 +            while (revcode < 512);
   1.919 +          }
   1.920 +        else
   1.921 +          {
   1.922 +            int subTree = tree[revcode & 511];
   1.923 +            int treeLen = 1 << (subTree & 15);
   1.924 +            subTree = -(subTree >> 4);
   1.925 +            do
   1.926 +              { 
   1.927 +            tree[subTree | (revcode >> 9)] = (short) ((i << 4) | bits);
   1.928 +            revcode += 1 << bits;
   1.929 +              }
   1.930 +            while (revcode < treeLen);
   1.931 +          }
   1.932 +        nextCode[bits] = code + (1 << (16 - bits));
   1.933 +          }
   1.934 +      }
   1.935 +      private final static String bit4Reverse =
   1.936 +        "\000\010\004\014\002\012\006\016\001\011\005\015\003\013\007\017";
   1.937 +      static short bitReverse(int value) {
   1.938 +            return (short) (bit4Reverse.charAt(value & 0xf) << 12
   1.939 +                | bit4Reverse.charAt((value >> 4) & 0xf) << 8
   1.940 +                | bit4Reverse.charAt((value >> 8) & 0xf) << 4
   1.941 +                | bit4Reverse.charAt(value >> 12));
   1.942 +      }
   1.943 +
   1.944 +      /**
   1.945 +       * Reads the next symbol from input.  The symbol is encoded using the
   1.946 +       * huffman tree.
   1.947 +       * @param input the input source.
   1.948 +       * @return the next symbol, or -1 if not enough input is available.
   1.949 +       */
   1.950 +      public int getSymbol(StreamManipulator input) throws DataFormatException
   1.951 +      {
   1.952 +        int lookahead, symbol;
   1.953 +        if ((lookahead = input.peekBits(9)) >= 0)
   1.954 +          {
   1.955 +        if ((symbol = tree[lookahead]) >= 0)
   1.956 +          {
   1.957 +            input.dropBits(symbol & 15);
   1.958 +            return symbol >> 4;
   1.959 +          }
   1.960 +        int subtree = -(symbol >> 4);
   1.961 +        int bitlen = symbol & 15;
   1.962 +        if ((lookahead = input.peekBits(bitlen)) >= 0)
   1.963 +          {
   1.964 +            symbol = tree[subtree | (lookahead >> 9)];
   1.965 +            input.dropBits(symbol & 15);
   1.966 +            return symbol >> 4;
   1.967 +          }
   1.968 +        else
   1.969 +          {
   1.970 +            int bits = input.getAvailableBits();
   1.971 +            lookahead = input.peekBits(bits);
   1.972 +            symbol = tree[subtree | (lookahead >> 9)];
   1.973 +            if ((symbol & 15) <= bits)
   1.974 +              {
   1.975 +            input.dropBits(symbol & 15);
   1.976 +            return symbol >> 4;
   1.977 +              }
   1.978 +            else
   1.979 +              return -1;
   1.980 +          }
   1.981 +          }
   1.982 +        else
   1.983 +          {
   1.984 +        int bits = input.getAvailableBits();
   1.985 +        lookahead = input.peekBits(bits);
   1.986 +        symbol = tree[lookahead];
   1.987 +        if (symbol >= 0 && (symbol & 15) <= bits)
   1.988 +          {
   1.989 +            input.dropBits(symbol & 15);
   1.990 +            return symbol >> 4;
   1.991 +          }
   1.992 +        else
   1.993 +          return -1;
   1.994 +          }
   1.995 +      }
   1.996 +    }
   1.997 +    private static class InflaterDynHeader
   1.998 +    {
   1.999 +      private static final int LNUM   = 0;
  1.1000 +      private static final int DNUM   = 1;
  1.1001 +      private static final int BLNUM  = 2;
  1.1002 +      private static final int BLLENS = 3;
  1.1003 +      private static final int LENS   = 4;
  1.1004 +      private static final int REPS   = 5;
  1.1005 +
  1.1006 +      private static final int repMin[]  = { 3, 3, 11 };
  1.1007 +      private static final int repBits[] = { 2, 3,  7 };
  1.1008 +
  1.1009 +
  1.1010 +      private byte[] blLens;
  1.1011 +      private byte[] litdistLens;
  1.1012 +
  1.1013 +      private InflaterHuffmanTree blTree;
  1.1014 +
  1.1015 +      private int mode;
  1.1016 +      private int lnum, dnum, blnum, num;
  1.1017 +      private int repSymbol;
  1.1018 +      private byte lastLen;
  1.1019 +      private int ptr;
  1.1020 +
  1.1021 +      private static final int[] BL_ORDER =
  1.1022 +      { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
  1.1023 +
  1.1024 +      public InflaterDynHeader()
  1.1025 +      {
  1.1026 +      }
  1.1027 +
  1.1028 +      public boolean decode(StreamManipulator input) throws DataFormatException
  1.1029 +      {
  1.1030 +      decode_loop:
  1.1031 +        for (;;)
  1.1032 +          {
  1.1033 +        switch (mode)
  1.1034 +          {
  1.1035 +          case LNUM:
  1.1036 +            lnum = input.peekBits(5);
  1.1037 +            if (lnum < 0)
  1.1038 +              return false;
  1.1039 +            lnum += 257;
  1.1040 +            input.dropBits(5);
  1.1041 +    //  	    System.err.println("LNUM: "+lnum);
  1.1042 +            mode = DNUM;
  1.1043 +            /* fall through */
  1.1044 +          case DNUM:
  1.1045 +            dnum = input.peekBits(5);
  1.1046 +            if (dnum < 0)
  1.1047 +              return false;
  1.1048 +            dnum++;
  1.1049 +            input.dropBits(5);
  1.1050 +    //  	    System.err.println("DNUM: "+dnum);
  1.1051 +            num = lnum+dnum;
  1.1052 +            litdistLens = new byte[num];
  1.1053 +            mode = BLNUM;
  1.1054 +            /* fall through */
  1.1055 +          case BLNUM:
  1.1056 +            blnum = input.peekBits(4);
  1.1057 +            if (blnum < 0)
  1.1058 +              return false;
  1.1059 +            blnum += 4;
  1.1060 +            input.dropBits(4);
  1.1061 +            blLens = new byte[19];
  1.1062 +            ptr = 0;
  1.1063 +    //  	    System.err.println("BLNUM: "+blnum);
  1.1064 +            mode = BLLENS;
  1.1065 +            /* fall through */
  1.1066 +          case BLLENS:
  1.1067 +            while (ptr < blnum)
  1.1068 +              {
  1.1069 +            int len = input.peekBits(3);
  1.1070 +            if (len < 0)
  1.1071 +              return false;
  1.1072 +            input.dropBits(3);
  1.1073 +    //  		System.err.println("blLens["+BL_ORDER[ptr]+"]: "+len);
  1.1074 +            blLens[BL_ORDER[ptr]] = (byte) len;
  1.1075 +            ptr++;
  1.1076 +              }
  1.1077 +            blTree = new InflaterHuffmanTree(blLens);
  1.1078 +            blLens = null;
  1.1079 +            ptr = 0;
  1.1080 +            mode = LENS;
  1.1081 +            /* fall through */
  1.1082 +          case LENS:
  1.1083 +            {
  1.1084 +              int symbol;
  1.1085 +              while (((symbol = blTree.getSymbol(input)) & ~15) == 0)
  1.1086 +            {
  1.1087 +              /* Normal case: symbol in [0..15] */
  1.1088 +
  1.1089 +    //  		  System.err.println("litdistLens["+ptr+"]: "+symbol);
  1.1090 +              litdistLens[ptr++] = lastLen = (byte) symbol;
  1.1091 +
  1.1092 +              if (ptr == num)
  1.1093 +                {
  1.1094 +                  /* Finished */
  1.1095 +                  return true;
  1.1096 +                }
  1.1097 +            }
  1.1098 +
  1.1099 +              /* need more input ? */
  1.1100 +              if (symbol < 0)
  1.1101 +            return false;
  1.1102 +
  1.1103 +              /* otherwise repeat code */
  1.1104 +              if (symbol >= 17)
  1.1105 +            {
  1.1106 +              /* repeat zero */
  1.1107 +    //  		  System.err.println("repeating zero");
  1.1108 +              lastLen = 0;
  1.1109 +            }
  1.1110 +              else
  1.1111 +            {
  1.1112 +              if (ptr == 0)
  1.1113 +                throw new DataFormatException();
  1.1114 +            }
  1.1115 +              repSymbol = symbol-16;
  1.1116 +              mode = REPS;
  1.1117 +            }
  1.1118 +            /* fall through */
  1.1119 +
  1.1120 +          case REPS:
  1.1121 +            {
  1.1122 +              int bits = repBits[repSymbol];
  1.1123 +              int count = input.peekBits(bits);
  1.1124 +              if (count < 0)
  1.1125 +            return false;
  1.1126 +              input.dropBits(bits);
  1.1127 +              count += repMin[repSymbol];
  1.1128 +    //  	      System.err.println("litdistLens repeated: "+count);
  1.1129 +
  1.1130 +              if (ptr + count > num)
  1.1131 +            throw new DataFormatException();
  1.1132 +              while (count-- > 0)
  1.1133 +            litdistLens[ptr++] = lastLen;
  1.1134 +
  1.1135 +              if (ptr == num)
  1.1136 +            {
  1.1137 +              /* Finished */
  1.1138 +              return true;
  1.1139 +            }
  1.1140 +            }
  1.1141 +            mode = LENS;
  1.1142 +            continue decode_loop;
  1.1143 +          }
  1.1144 +          }
  1.1145 +      }
  1.1146 +
  1.1147 +      public InflaterHuffmanTree buildLitLenTree() throws DataFormatException
  1.1148 +      {
  1.1149 +        byte[] litlenLens = new byte[lnum];
  1.1150 +        System.arraycopy(litdistLens, 0, litlenLens, 0, lnum);
  1.1151 +        return new InflaterHuffmanTree(litlenLens);
  1.1152 +      }
  1.1153 +
  1.1154 +      public InflaterHuffmanTree buildDistTree() throws DataFormatException
  1.1155 +      {
  1.1156 +        byte[] distLens = new byte[dnum];
  1.1157 +        System.arraycopy(litdistLens, lnum, distLens, 0, dnum);
  1.1158 +        return new InflaterHuffmanTree(distLens);
  1.1159 +      }
  1.1160 +    }
  1.1161      /**
  1.1162 -     * Creates a new decompressor. If the parameter 'nowrap' is true then
  1.1163 -     * the ZLIB header and checksum fields will not be used. This provides
  1.1164 -     * compatibility with the compression format used by both GZIP and PKZIP.
  1.1165 -     * <p>
  1.1166 -     * Note: When using the 'nowrap' option it is also necessary to provide
  1.1167 -     * an extra "dummy" byte as input. This is required by the ZLIB native
  1.1168 -     * library in order to support certain optimizations.
  1.1169 +     * This class allows us to retrieve a specified amount of bits from
  1.1170 +     * the input buffer, as well as copy big byte blocks.
  1.1171       *
  1.1172 -     * @param nowrap if true then support GZIP compatible compression
  1.1173 +     * It uses an int buffer to store up to 31 bits for direct
  1.1174 +     * manipulation.  This guarantees that we can get at least 16 bits,
  1.1175 +     * but we only need at most 15, so this is all safe.
  1.1176 +     *
  1.1177 +     * There are some optimizations in this class, for example, you must
  1.1178 +     * never peek more then 8 bits more than needed, and you must first 
  1.1179 +     * peek bits before you may drop them.  This is not a general purpose
  1.1180 +     * class but optimized for the behaviour of the Inflater.
  1.1181 +     *
  1.1182 +     * @author John Leuner, Jochen Hoenicke
  1.1183       */
  1.1184 -    public Inflater(boolean nowrap) {
  1.1185 +
  1.1186 +    private static class StreamManipulator
  1.1187 +    {
  1.1188 +      private byte[] window;
  1.1189 +      private int window_start = 0;
  1.1190 +      private int window_end = 0;
  1.1191 +
  1.1192 +      private int buffer = 0;
  1.1193 +      private int bits_in_buffer = 0;
  1.1194 +
  1.1195 +      /**
  1.1196 +       * Get the next n bits but don't increase input pointer.  n must be
  1.1197 +       * less or equal 16 and if you if this call succeeds, you must drop
  1.1198 +       * at least n-8 bits in the next call.
  1.1199 +       * 
  1.1200 +       * @return the value of the bits, or -1 if not enough bits available.  */
  1.1201 +      public final int peekBits(int n)
  1.1202 +      {
  1.1203 +        if (bits_in_buffer < n)
  1.1204 +          {
  1.1205 +        if (window_start == window_end)
  1.1206 +          return -1;
  1.1207 +        buffer |= (window[window_start++] & 0xff
  1.1208 +               | (window[window_start++] & 0xff) << 8) << bits_in_buffer;
  1.1209 +        bits_in_buffer += 16;
  1.1210 +          }
  1.1211 +        return buffer & ((1 << n) - 1);
  1.1212 +      }
  1.1213 +
  1.1214 +      /* Drops the next n bits from the input.  You should have called peekBits
  1.1215 +       * with a bigger or equal n before, to make sure that enough bits are in
  1.1216 +       * the bit buffer.
  1.1217 +       */
  1.1218 +      public final void dropBits(int n)
  1.1219 +      {
  1.1220 +        buffer >>>= n;
  1.1221 +        bits_in_buffer -= n;
  1.1222 +      }
  1.1223 +
  1.1224 +      /**
  1.1225 +       * Gets the next n bits and increases input pointer.  This is equivalent
  1.1226 +       * to peekBits followed by dropBits, except for correct error handling.
  1.1227 +       * @return the value of the bits, or -1 if not enough bits available. 
  1.1228 +       */
  1.1229 +      public final int getBits(int n)
  1.1230 +      {
  1.1231 +        int bits = peekBits(n);
  1.1232 +        if (bits >= 0)
  1.1233 +          dropBits(n);
  1.1234 +        return bits;
  1.1235 +      }
  1.1236 +      /**
  1.1237 +       * Gets the number of bits available in the bit buffer.  This must be
  1.1238 +       * only called when a previous peekBits() returned -1.
  1.1239 +       * @return the number of bits available.
  1.1240 +       */
  1.1241 +      public final int getAvailableBits()
  1.1242 +      {
  1.1243 +        return bits_in_buffer;
  1.1244 +      }
  1.1245 +
  1.1246 +      /**
  1.1247 +       * Gets the number of bytes available.  
  1.1248 +       * @return the number of bytes available.
  1.1249 +       */
  1.1250 +      public final int getAvailableBytes()
  1.1251 +      {
  1.1252 +        return window_end - window_start + (bits_in_buffer >> 3);
  1.1253 +      }
  1.1254 +
  1.1255 +      /**
  1.1256 +       * Skips to the next byte boundary.
  1.1257 +       */
  1.1258 +      public void skipToByteBoundary()
  1.1259 +      {
  1.1260 +        buffer >>= (bits_in_buffer & 7);
  1.1261 +        bits_in_buffer &= ~7;
  1.1262 +      }
  1.1263 +
  1.1264 +      public final boolean needsInput() {
  1.1265 +        return window_start == window_end;
  1.1266 +      }
  1.1267 +
  1.1268 +
  1.1269 +      /* Copies length bytes from input buffer to output buffer starting
  1.1270 +       * at output[offset].  You have to make sure, that the buffer is
  1.1271 +       * byte aligned.  If not enough bytes are available, copies fewer
  1.1272 +       * bytes.
  1.1273 +       * @param length the length to copy, 0 is allowed.
  1.1274 +       * @return the number of bytes copied, 0 if no byte is available.  
  1.1275 +       */
  1.1276 +      public int copyBytes(byte[] output, int offset, int length)
  1.1277 +      {
  1.1278 +        if (length < 0)
  1.1279 +          throw new IllegalArgumentException("length negative");
  1.1280 +        if ((bits_in_buffer & 7) != 0)  
  1.1281 +          /* bits_in_buffer may only be 0 or 8 */
  1.1282 +          throw new IllegalStateException("Bit buffer is not aligned!");
  1.1283 +
  1.1284 +        int count = 0;
  1.1285 +        while (bits_in_buffer > 0 && length > 0)
  1.1286 +          {
  1.1287 +        output[offset++] = (byte) buffer;
  1.1288 +        buffer >>>= 8;
  1.1289 +        bits_in_buffer -= 8;
  1.1290 +        length--;
  1.1291 +        count++;
  1.1292 +          }
  1.1293 +        if (length == 0)
  1.1294 +          return count;
  1.1295 +
  1.1296 +        int avail = window_end - window_start;
  1.1297 +        if (length > avail)
  1.1298 +          length = avail;
  1.1299 +        System.arraycopy(window, window_start, output, offset, length);
  1.1300 +        window_start += length;
  1.1301 +
  1.1302 +        if (((window_start - window_end) & 1) != 0)
  1.1303 +          {
  1.1304 +        /* We always want an even number of bytes in input, see peekBits */
  1.1305 +        buffer = (window[window_start++] & 0xff);
  1.1306 +        bits_in_buffer = 8;
  1.1307 +          }
  1.1308 +        return count + length;
  1.1309 +      }
  1.1310 +
  1.1311 +      public StreamManipulator()
  1.1312 +      {
  1.1313 +      }
  1.1314 +
  1.1315 +      public void reset()
  1.1316 +      {
  1.1317 +        window_start = window_end = buffer = bits_in_buffer = 0;
  1.1318 +      }
  1.1319 +
  1.1320 +      public void setInput(byte[] buf, int off, int len)
  1.1321 +      {
  1.1322 +        if (window_start < window_end)
  1.1323 +          throw new IllegalStateException
  1.1324 +        ("Old input was not completely processed");
  1.1325 +
  1.1326 +        int end = off + len;
  1.1327 +
  1.1328 +        /* We want to throw an ArrayIndexOutOfBoundsException early.  The
  1.1329 +         * check is very tricky: it also handles integer wrap around.  
  1.1330 +         */
  1.1331 +        if (0 > off || off > end || end > buf.length)
  1.1332 +          throw new ArrayIndexOutOfBoundsException();
  1.1333 +
  1.1334 +        if ((len & 1) != 0)
  1.1335 +          {
  1.1336 +        /* We always want an even number of bytes in input, see peekBits */
  1.1337 +        buffer |= (buf[off++] & 0xff) << bits_in_buffer;
  1.1338 +        bits_in_buffer += 8;
  1.1339 +          }
  1.1340 +
  1.1341 +        window = buf;
  1.1342 +        window_start = off;
  1.1343 +        window_end = end;
  1.1344 +      }
  1.1345      }
  1.1346 +    /*
  1.1347 +     * Contains the output from the Inflation process.
  1.1348 +     *
  1.1349 +     * We need to have a window so that we can refer backwards into the output stream
  1.1350 +     * to repeat stuff.
  1.1351 +     *
  1.1352 +     * @author John Leuner
  1.1353 +     * @since JDK 1.1
  1.1354 +     */
  1.1355  
  1.1356 -    /**
  1.1357 -     * Creates a new decompressor.
  1.1358 -     */
  1.1359 -    public Inflater() {
  1.1360 -        this(false);
  1.1361 +    private static class OutputWindow
  1.1362 +    {
  1.1363 +      private final int WINDOW_SIZE = 1 << 15;
  1.1364 +      private final int WINDOW_MASK = WINDOW_SIZE - 1;
  1.1365 +
  1.1366 +      private byte[] window = new byte[WINDOW_SIZE]; //The window is 2^15 bytes
  1.1367 +      private int window_end  = 0;
  1.1368 +      private int window_filled = 0;
  1.1369 +
  1.1370 +      public void write(int abyte)
  1.1371 +      {
  1.1372 +        if (window_filled++ == WINDOW_SIZE)
  1.1373 +          throw new IllegalStateException("Window full");
  1.1374 +        window[window_end++] = (byte) abyte;
  1.1375 +        window_end &= WINDOW_MASK;
  1.1376 +      }
  1.1377 +
  1.1378 +
  1.1379 +      private final void slowRepeat(int rep_start, int len, int dist)
  1.1380 +      {
  1.1381 +        while (len-- > 0)
  1.1382 +          {
  1.1383 +        window[window_end++] = window[rep_start++];
  1.1384 +        window_end &= WINDOW_MASK;
  1.1385 +        rep_start &= WINDOW_MASK;
  1.1386 +          }
  1.1387 +      }
  1.1388 +
  1.1389 +      public void repeat(int len, int dist)
  1.1390 +      {
  1.1391 +        if ((window_filled += len) > WINDOW_SIZE)
  1.1392 +          throw new IllegalStateException("Window full");
  1.1393 +
  1.1394 +        int rep_start = (window_end - dist) & WINDOW_MASK;
  1.1395 +        int border = WINDOW_SIZE - len;
  1.1396 +        if (rep_start <= border && window_end < border)
  1.1397 +          {
  1.1398 +        if (len <= dist)
  1.1399 +          {
  1.1400 +            System.arraycopy(window, rep_start, window, window_end, len);
  1.1401 +            window_end += len;
  1.1402 +          }
  1.1403 +        else
  1.1404 +          {
  1.1405 +            /* We have to copy manually, since the repeat pattern overlaps.
  1.1406 +             */
  1.1407 +            while (len-- > 0)
  1.1408 +              window[window_end++] = window[rep_start++];
  1.1409 +          }
  1.1410 +          }
  1.1411 +        else
  1.1412 +          slowRepeat(rep_start, len, dist);
  1.1413 +      }
  1.1414 +
  1.1415 +      public int copyStored(StreamManipulator input, int len)
  1.1416 +      {
  1.1417 +        len = Math.min(Math.min(len, WINDOW_SIZE - window_filled), 
  1.1418 +               input.getAvailableBytes());
  1.1419 +        int copied;
  1.1420 +
  1.1421 +        int tailLen = WINDOW_SIZE - window_end;
  1.1422 +        if (len > tailLen)
  1.1423 +          {
  1.1424 +        copied = input.copyBytes(window, window_end, tailLen);
  1.1425 +        if (copied == tailLen)
  1.1426 +          copied += input.copyBytes(window, 0, len - tailLen);
  1.1427 +          }
  1.1428 +        else
  1.1429 +          copied = input.copyBytes(window, window_end, len);
  1.1430 +
  1.1431 +        window_end = (window_end + copied) & WINDOW_MASK;
  1.1432 +        window_filled += copied;
  1.1433 +        return copied;
  1.1434 +      }
  1.1435 +
  1.1436 +      public void copyDict(byte[] dict, int offset, int len)
  1.1437 +      {
  1.1438 +        if (window_filled > 0)
  1.1439 +          throw new IllegalStateException();
  1.1440 +
  1.1441 +        if (len > WINDOW_SIZE)
  1.1442 +          {
  1.1443 +        offset += len - WINDOW_SIZE;
  1.1444 +        len = WINDOW_SIZE;
  1.1445 +          }
  1.1446 +        System.arraycopy(dict, offset, window, 0, len);
  1.1447 +        window_end = len & WINDOW_MASK;
  1.1448 +      }
  1.1449 +
  1.1450 +      public int getFreeSpace()
  1.1451 +      {
  1.1452 +        return WINDOW_SIZE - window_filled;
  1.1453 +      }
  1.1454 +
  1.1455 +      public int getAvailable()
  1.1456 +      {
  1.1457 +        return window_filled;
  1.1458 +      }
  1.1459 +
  1.1460 +      public int copyOutput(byte[] output, int offset, int len)
  1.1461 +      {
  1.1462 +        int copy_end = window_end;
  1.1463 +        if (len > window_filled)
  1.1464 +          len = window_filled;
  1.1465 +        else
  1.1466 +          copy_end = (window_end - window_filled + len) & WINDOW_MASK;
  1.1467 +
  1.1468 +        int copied = len;
  1.1469 +        int tailLen = len - copy_end;
  1.1470 +
  1.1471 +        if (tailLen > 0)
  1.1472 +          {
  1.1473 +        System.arraycopy(window, WINDOW_SIZE - tailLen,
  1.1474 +                 output, offset, tailLen);
  1.1475 +        offset += tailLen;
  1.1476 +        len = copy_end;
  1.1477 +          }
  1.1478 +        System.arraycopy(window, copy_end - len, output, offset, len);
  1.1479 +        window_filled -= copied;
  1.1480 +        if (window_filled < 0)
  1.1481 +          throw new IllegalStateException();
  1.1482 +        return copied;
  1.1483 +      }
  1.1484 +
  1.1485 +      public void reset() {
  1.1486 +        window_filled = window_end = 0;
  1.1487 +      }
  1.1488      }
  1.1489 -
  1.1490 -    /**
  1.1491 -     * Sets input data for decompression. Should be called whenever
  1.1492 -     * needsInput() returns true indicating that more input data is
  1.1493 -     * required.
  1.1494 -     * @param b the input data bytes
  1.1495 -     * @param off the start offset of the input data
  1.1496 -     * @param len the length of the input data
  1.1497 -     * @see Inflater#needsInput
  1.1498 -     */
  1.1499 -    public void setInput(byte[] b, int off, int len) {
  1.1500 -        if (b == null) {
  1.1501 -            throw new NullPointerException();
  1.1502 -        }
  1.1503 -        if (off < 0 || len < 0 || off > b.length - len) {
  1.1504 -            throw new ArrayIndexOutOfBoundsException();
  1.1505 -        }
  1.1506 -        data = (String) infl(b, off, len);
  1.1507 -    }
  1.1508 -
  1.1509 -    /**
  1.1510 -     * Sets input data for decompression. Should be called whenever
  1.1511 -     * needsInput() returns true indicating that more input data is
  1.1512 -     * required.
  1.1513 -     * @param b the input data bytes
  1.1514 -     * @see Inflater#needsInput
  1.1515 -     */
  1.1516 -    public void setInput(byte[] b) {
  1.1517 -        setInput(b, 0, b.length);
  1.1518 -    }
  1.1519 -
  1.1520 -    /**
  1.1521 -     * Sets the preset dictionary to the given array of bytes. Should be
  1.1522 -     * called when inflate() returns 0 and needsDictionary() returns true
  1.1523 -     * indicating that a preset dictionary is required. The method getAdler()
  1.1524 -     * can be used to get the Adler-32 value of the dictionary needed.
  1.1525 -     * @param b the dictionary data bytes
  1.1526 -     * @param off the start offset of the data
  1.1527 -     * @param len the length of the data
  1.1528 -     * @see Inflater#needsDictionary
  1.1529 -     * @see Inflater#getAdler
  1.1530 -     */
  1.1531 -    public void setDictionary(byte[] b, int off, int len) {
  1.1532 -        if (b == null) {
  1.1533 -            throw new NullPointerException();
  1.1534 -        }
  1.1535 -        if (off < 0 || len < 0 || off > b.length - len) {
  1.1536 -            throw new ArrayIndexOutOfBoundsException();
  1.1537 -        }
  1.1538 -        needDict = false;
  1.1539 -    }
  1.1540 -
  1.1541 -    /**
  1.1542 -     * Sets the preset dictionary to the given array of bytes. Should be
  1.1543 -     * called when inflate() returns 0 and needsDictionary() returns true
  1.1544 -     * indicating that a preset dictionary is required. The method getAdler()
  1.1545 -     * can be used to get the Adler-32 value of the dictionary needed.
  1.1546 -     * @param b the dictionary data bytes
  1.1547 -     * @see Inflater#needsDictionary
  1.1548 -     * @see Inflater#getAdler
  1.1549 -     */
  1.1550 -    public void setDictionary(byte[] b) {
  1.1551 -        setDictionary(b, 0, b.length);
  1.1552 -    }
  1.1553 -
  1.1554 -    /**
  1.1555 -     * Returns the total number of bytes remaining in the input buffer.
  1.1556 -     * This can be used to find out what bytes still remain in the input
  1.1557 -     * buffer after decompression has finished.
  1.1558 -     * @return the total number of bytes remaining in the input buffer
  1.1559 -     */
  1.1560 -    public int getRemaining() {
  1.1561 -        return data.length() - offset;
  1.1562 -    }
  1.1563 -
  1.1564 -    /**
  1.1565 -     * Returns true if no data remains in the input buffer. This can
  1.1566 -     * be used to determine if #setInput should be called in order
  1.1567 -     * to provide more input.
  1.1568 -     * @return true if no data remains in the input buffer
  1.1569 -     */
  1.1570 -    public boolean needsInput() {
  1.1571 -        return getRemaining() <= 0;
  1.1572 -    }
  1.1573 -
  1.1574 -    /**
  1.1575 -     * Returns true if a preset dictionary is needed for decompression.
  1.1576 -     * @return true if a preset dictionary is needed for decompression
  1.1577 -     * @see Inflater#setDictionary
  1.1578 -     */
  1.1579 -    public boolean needsDictionary() {
  1.1580 -        return needDict;
  1.1581 -    }
  1.1582 -
  1.1583 -    /**
  1.1584 -     * Returns true if the end of the compressed data stream has been
  1.1585 -     * reached.
  1.1586 -     * @return true if the end of the compressed data stream has been
  1.1587 -     * reached
  1.1588 -     */
  1.1589 -    public boolean finished() {
  1.1590 -        return finished;
  1.1591 -    }
  1.1592 -
  1.1593 -    /**
  1.1594 -     * Uncompresses bytes into specified buffer. Returns actual number
  1.1595 -     * of bytes uncompressed. A return value of 0 indicates that
  1.1596 -     * needsInput() or needsDictionary() should be called in order to
  1.1597 -     * determine if more input data or a preset dictionary is required.
  1.1598 -     * In the latter case, getAdler() can be used to get the Adler-32
  1.1599 -     * value of the dictionary required.
  1.1600 -     * @param b the buffer for the uncompressed data
  1.1601 -     * @param off the start offset of the data
  1.1602 -     * @param len the maximum number of uncompressed bytes
  1.1603 -     * @return the actual number of uncompressed bytes
  1.1604 -     * @exception DataFormatException if the compressed data format is invalid
  1.1605 -     * @see Inflater#needsInput
  1.1606 -     * @see Inflater#needsDictionary
  1.1607 -     */
  1.1608 -    public int inflate(byte[] b, int off, int len)
  1.1609 -        throws DataFormatException
  1.1610 -    {
  1.1611 -        if (b == null) {
  1.1612 -            throw new NullPointerException();
  1.1613 -        }
  1.1614 -        if (off < 0 || len < 0 || off > b.length - len) {
  1.1615 -            throw new ArrayIndexOutOfBoundsException();
  1.1616 -        }
  1.1617 -        int cnt = 0;
  1.1618 -        while (offset < data.length()) {
  1.1619 -            b[off++] = (byte)data.charAt(offset++);
  1.1620 -            cnt++;
  1.1621 -            counter++;
  1.1622 -        }
  1.1623 -        return cnt;
  1.1624 -    }
  1.1625 -    
  1.1626 -    @JavaScriptBody(args = { "arr", "offset", "len" }, body = 
  1.1627 -          "var r = {};\n"
  1.1628 -        + "r.charCodeAt = function(idx) { return arr[offset + idx]; };\n"
  1.1629 -        + "return JSInflate.inflate(r);"
  1.1630 -    )
  1.1631 -    private static native Object infl(byte[] arr, int offset, int len);
  1.1632 -
  1.1633 -    /**
  1.1634 -     * Uncompresses bytes into specified buffer. Returns actual number
  1.1635 -     * of bytes uncompressed. A return value of 0 indicates that
  1.1636 -     * needsInput() or needsDictionary() should be called in order to
  1.1637 -     * determine if more input data or a preset dictionary is required.
  1.1638 -     * In the latter case, getAdler() can be used to get the Adler-32
  1.1639 -     * value of the dictionary required.
  1.1640 -     * @param b the buffer for the uncompressed data
  1.1641 -     * @return the actual number of uncompressed bytes
  1.1642 -     * @exception DataFormatException if the compressed data format is invalid
  1.1643 -     * @see Inflater#needsInput
  1.1644 -     * @see Inflater#needsDictionary
  1.1645 -     */
  1.1646 -    public int inflate(byte[] b) throws DataFormatException {
  1.1647 -        return inflate(b, 0, b.length);
  1.1648 -    }
  1.1649 -
  1.1650 -    /**
  1.1651 -     * Returns the ADLER-32 value of the uncompressed data.
  1.1652 -     * @return the ADLER-32 value of the uncompressed data
  1.1653 -     */
  1.1654 -    public int getAdler() {
  1.1655 -        return 0;
  1.1656 -    }
  1.1657 -
  1.1658 -    /**
  1.1659 -     * Returns the total number of compressed bytes input so far.
  1.1660 -     *
  1.1661 -     * <p>Since the number of bytes may be greater than
  1.1662 -     * Integer.MAX_VALUE, the {@link #getBytesRead()} method is now
  1.1663 -     * the preferred means of obtaining this information.</p>
  1.1664 -     *
  1.1665 -     * @return the total number of compressed bytes input so far
  1.1666 -     */
  1.1667 -    public int getTotalIn() {
  1.1668 -        return (int) getBytesRead();
  1.1669 -    }
  1.1670 -
  1.1671 -    /**
  1.1672 -     * Returns the total number of compressed bytes input so far.</p>
  1.1673 -     *
  1.1674 -     * @return the total (non-negative) number of compressed bytes input so far
  1.1675 -     * @since 1.5
  1.1676 -     */
  1.1677 -    public long getBytesRead() {
  1.1678 -        return counter;
  1.1679 -    }
  1.1680 -
  1.1681 -    /**
  1.1682 -     * Returns the total number of uncompressed bytes output so far.
  1.1683 -     *
  1.1684 -     * <p>Since the number of bytes may be greater than
  1.1685 -     * Integer.MAX_VALUE, the {@link #getBytesWritten()} method is now
  1.1686 -     * the preferred means of obtaining this information.</p>
  1.1687 -     *
  1.1688 -     * @return the total number of uncompressed bytes output so far
  1.1689 -     */
  1.1690 -    public int getTotalOut() {
  1.1691 -        return (int) getBytesWritten();
  1.1692 -    }
  1.1693 -
  1.1694 -    /**
  1.1695 -     * Returns the total number of uncompressed bytes output so far.</p>
  1.1696 -     *
  1.1697 -     * @return the total (non-negative) number of uncompressed bytes output so far
  1.1698 -     * @since 1.5
  1.1699 -     */
  1.1700 -    public long getBytesWritten() {
  1.1701 -        return counter;
  1.1702 -    }
  1.1703 -
  1.1704 -    /**
  1.1705 -     * Resets inflater so that a new set of input data can be processed.
  1.1706 -     */
  1.1707 -    public void reset() {
  1.1708 -        data = "";
  1.1709 -        finished = false;
  1.1710 -        needDict = false;
  1.1711 -        offset = 0;
  1.1712 -    }
  1.1713 -
  1.1714 -    /**
  1.1715 -     * Closes the decompressor and discards any unprocessed input.
  1.1716 -     * This method should be called when the decompressor is no longer
  1.1717 -     * being used, but will also be called automatically by the finalize()
  1.1718 -     * method. Once this method is called, the behavior of the Inflater
  1.1719 -     * object is undefined.
  1.1720 -     */
  1.1721 -    public void end() {
  1.1722 -    }
  1.1723 +  
  1.1724  }