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 }