diff options
Diffstat (limited to 'libjava/classpath/java/util/zip/Inflater.java')
-rw-r--r-- | libjava/classpath/java/util/zip/Inflater.java | 726 |
1 files changed, 0 insertions, 726 deletions
diff --git a/libjava/classpath/java/util/zip/Inflater.java b/libjava/classpath/java/util/zip/Inflater.java deleted file mode 100644 index 0f094d6..0000000 --- a/libjava/classpath/java/util/zip/Inflater.java +++ /dev/null @@ -1,726 +0,0 @@ -/* Inflater.java - Decompress a data stream - Copyright (C) 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ - -package java.util.zip; - -/* Written using on-line Java Platform 1.2 API Specification - * and JCL book. - * Believed complete and correct. - */ - -/** - * Inflater is used to decompress data that has been compressed according - * to the "deflate" standard described in rfc1950. - * - * The usage is as following. First you have to set some input with - * <code>setInput()</code>, then inflate() it. If inflate doesn't - * inflate any bytes there may be three reasons: - * <ul> - * <li>needsInput() returns true because the input buffer is empty. - * You have to provide more input with <code>setInput()</code>. - * NOTE: needsInput() also returns true when, the stream is finished. - * </li> - * <li>needsDictionary() returns true, you have to provide a preset - * dictionary with <code>setDictionary()</code>.</li> - * <li>finished() returns true, the inflater has finished.</li> - * </ul> - * Once the first output byte is produced, a dictionary will not be - * needed at a later stage. - * - * @author John Leuner, Jochen Hoenicke - * @author Tom Tromey - * @date May 17, 1999 - * @since JDK 1.1 - */ -public class Inflater -{ - /* Copy lengths for literal codes 257..285 */ - private static final int CPLENS[] = - { - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 - }; - - /* Extra bits for literal codes 257..285 */ - private static final int CPLEXT[] = - { - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 - }; - - /* Copy offsets for distance codes 0..29 */ - private static final int CPDIST[] = { - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577 - }; - - /* Extra bits for distance codes */ - private static final int CPDEXT[] = { - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13 - }; - - /* This are the state in which the inflater can be. */ - private static final int DECODE_HEADER = 0; - private static final int DECODE_DICT = 1; - private static final int DECODE_BLOCKS = 2; - private static final int DECODE_STORED_LEN1 = 3; - private static final int DECODE_STORED_LEN2 = 4; - private static final int DECODE_STORED = 5; - private static final int DECODE_DYN_HEADER = 6; - private static final int DECODE_HUFFMAN = 7; - private static final int DECODE_HUFFMAN_LENBITS = 8; - private static final int DECODE_HUFFMAN_DIST = 9; - private static final int DECODE_HUFFMAN_DISTBITS = 10; - private static final int DECODE_CHKSUM = 11; - private static final int FINISHED = 12; - - /** This variable contains the current state. */ - private int mode; - - /** - * The adler checksum of the dictionary or of the decompressed - * stream, as it is written in the header resp. footer of the - * compressed stream. <br> - * - * Only valid if mode is DECODE_DICT or DECODE_CHKSUM. - */ - private int readAdler; - /** - * The number of bits needed to complete the current state. This - * is valid, if mode is DECODE_DICT, DECODE_CHKSUM, - * DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS. - */ - private int neededBits; - private int repLength, repDist; - private int uncomprLen; - /** - * True, if the last block flag was set in the last block of the - * inflated stream. This means that the stream ends after the - * current block. - */ - private boolean isLastBlock; - - /** - * The total number of inflated bytes. - */ - private long totalOut; - /** - * The total number of bytes set with setInput(). This is not the - * value returned by getTotalIn(), since this also includes the - * unprocessed input. - */ - private long totalIn; - /** - * This variable stores the nowrap flag that was given to the constructor. - * True means, that the inflated stream doesn't contain a header nor the - * checksum in the footer. - */ - private boolean nowrap; - - private StreamManipulator input; - private OutputWindow outputWindow; - private InflaterDynHeader dynHeader; - private InflaterHuffmanTree litlenTree, distTree; - private Adler32 adler; - - /** - * Creates a new inflater. - */ - public Inflater () - { - this (false); - } - - /** - * Creates a new inflater. - * @param nowrap true if no header and checksum field appears in the - * stream. This is used for GZIPed input. For compatibility with - * Sun JDK you should provide one byte of input more than needed in - * this case. - */ - public Inflater (boolean nowrap) - { - this.nowrap = nowrap; - this.adler = new Adler32(); - input = new StreamManipulator(); - outputWindow = new OutputWindow(); - mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; - } - - /** - * Finalizes this object. - */ - protected void finalize () - { - /* Exists only for compatibility */ - } - - /** - * Frees all objects allocated by the inflater. There's no reason - * to call this, since you can just rely on garbage collection (even - * for the Sun implementation). Exists only for compatibility - * with Sun's JDK, where the compressor allocates native memory. - * If you call any method (even reset) afterwards the behaviour is - * <i>undefined</i>. - */ - public void end () - { - outputWindow = null; - input = null; - dynHeader = null; - litlenTree = null; - distTree = null; - adler = null; - } - - /** - * Returns true, if the inflater has finished. This means, that no - * input is needed and no output can be produced. - */ - public boolean finished() - { - return mode == FINISHED && outputWindow.getAvailable() == 0; - } - - /** - * Gets the adler checksum. This is either the checksum of all - * uncompressed bytes returned by inflate(), or if needsDictionary() - * returns true (and thus no output was yet produced) this is the - * adler checksum of the expected dictionary. - * @returns the adler checksum. - */ - public int getAdler() - { - return needsDictionary() ? readAdler : (int) adler.getValue(); - } - - /** - * Gets the number of unprocessed input. Useful, if the end of the - * stream is reached and you want to further process the bytes after - * the deflate stream. - * @return the number of bytes of the input which were not processed. - */ - public int getRemaining() - { - return input.getAvailableBytes(); - } - - /** - * Gets the total number of processed compressed input bytes. - * @return the total number of bytes of processed input bytes. - */ - public int getTotalIn() - { - return (int) (totalIn - getRemaining()); - } - - /** - * Gets the total number of processed compressed input bytes. - * @return the total number of bytes of processed input bytes. - * @since 1.5 - */ - public long getBytesRead() - { - return totalIn - getRemaining(); - } - - /** - * Gets the total number of output bytes returned by inflate(). - * @return the total number of output bytes. - */ - public int getTotalOut() - { - return (int) totalOut; - } - - /** - * Gets the total number of output bytes returned by inflate(). - * @return the total number of output bytes. - * @since 1.5 - */ - public long getBytesWritten() - { - return totalOut; - } - - /** - * Inflates the compressed stream to the output buffer. If this - * returns 0, you should check, whether needsDictionary(), - * needsInput() or finished() returns true, to determine why no - * further output is produced. - * @param buf the output buffer. - * @return the number of bytes written to the buffer, 0 if no further - * output can be produced. - * @exception DataFormatException if deflated stream is invalid. - * @exception IllegalArgumentException if buf has length 0. - */ - public int inflate (byte[] buf) throws DataFormatException - { - return inflate (buf, 0, buf.length); - } - - /** - * Inflates the compressed stream to the output buffer. If this - * returns 0, you should check, whether needsDictionary(), - * needsInput() or finished() returns true, to determine why no - * further output is produced. - * @param buf the output buffer. - * @param off the offset into buffer where the output should start. - * @param len the maximum length of the output. - * @return the number of bytes written to the buffer, 0 if no further - * output can be produced. - * @exception DataFormatException if deflated stream is invalid. - * @exception IndexOutOfBoundsException if the off and/or len are wrong. - */ - public int inflate (byte[] buf, int off, int len) throws DataFormatException - { - /* Check for correct buff, off, len triple */ - if (0 > off || off > off + len || off + len > buf.length) - throw new ArrayIndexOutOfBoundsException(); - int count = 0; - for (;;) - { - if (outputWindow.getAvailable() == 0) - { - if (!decode()) - break; - } - else if (len > 0) - { - int more = outputWindow.copyOutput(buf, off, len); - adler.update(buf, off, more); - off += more; - count += more; - totalOut += more; - len -= more; - } - else - break; - } - return count; - } - - /** - * Returns true, if a preset dictionary is needed to inflate the input. - */ - public boolean needsDictionary () - { - return mode == DECODE_DICT && neededBits == 0; - } - - /** - * Returns true, if the input buffer is empty. - * You should then call setInput(). <br> - * - * <em>NOTE</em>: This method also returns true when the stream is finished. - */ - public boolean needsInput () - { - return input.needsInput (); - } - - /** - * Resets the inflater so that a new stream can be decompressed. All - * pending input and output will be discarded. - */ - public void reset () - { - mode = nowrap ? DECODE_BLOCKS : DECODE_HEADER; - totalIn = totalOut = 0; - input.reset(); - outputWindow.reset(); - dynHeader = null; - litlenTree = null; - distTree = null; - isLastBlock = false; - adler.reset(); - } - - /** - * Sets the preset dictionary. This should only be called, if - * needsDictionary() returns true and it should set the same - * dictionary, that was used for deflating. The getAdler() - * function returns the checksum of the dictionary needed. - * @param buffer the dictionary. - * @exception IllegalStateException if no dictionary is needed. - * @exception IllegalArgumentException if the dictionary checksum is - * wrong. - */ - public void setDictionary (byte[] buffer) - { - setDictionary(buffer, 0, buffer.length); - } - - /** - * Sets the preset dictionary. This should only be called, if - * needsDictionary() returns true and it should set the same - * dictionary, that was used for deflating. The getAdler() - * function returns the checksum of the dictionary needed. - * @param buffer the dictionary. - * @param off the offset into buffer where the dictionary starts. - * @param len the length of the dictionary. - * @exception IllegalStateException if no dictionary is needed. - * @exception IllegalArgumentException if the dictionary checksum is - * wrong. - * @exception IndexOutOfBoundsException if the off and/or len are wrong. - */ - public void setDictionary (byte[] buffer, int off, int len) - { - if (!needsDictionary()) - throw new IllegalStateException(); - - adler.update(buffer, off, len); - if ((int) adler.getValue() != readAdler) - throw new IllegalArgumentException("Wrong adler checksum"); - adler.reset(); - outputWindow.copyDict(buffer, off, len); - mode = DECODE_BLOCKS; - } - - /** - * Sets the input. This should only be called, if needsInput() - * returns true. - * @param buf the input. - * @exception IllegalStateException if no input is needed. - */ - public void setInput (byte[] buf) - { - setInput (buf, 0, buf.length); - } - - /** - * Sets the input. This should only be called, if needsInput() - * returns true. - * @param buf the input. - * @param off the offset into buffer where the input starts. - * @param len the length of the input. - * @exception IllegalStateException if no input is needed. - * @exception IndexOutOfBoundsException if the off and/or len are wrong. - */ - public void setInput (byte[] buf, int off, int len) - { - input.setInput (buf, off, len); - totalIn += len; - } - - /** - * Decodes the deflate header. - * @return false if more input is needed. - * @exception DataFormatException if header is invalid. - */ - private boolean decodeHeader () throws DataFormatException - { - int header = input.peekBits(16); - if (header < 0) - return false; - input.dropBits(16); - - /* The header is written in "wrong" byte order */ - header = ((header << 8) | (header >> 8)) & 0xffff; - if (header % 31 != 0) - throw new DataFormatException("Header checksum illegal"); - - if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) - throw new DataFormatException("Compression Method unknown"); - - /* Maximum size of the backwards window in bits. - * We currently ignore this, but we could use it to make the - * inflater window more space efficient. On the other hand the - * full window (15 bits) is needed most times, anyway. - int max_wbits = ((header & 0x7000) >> 12) + 8; - */ - - if ((header & 0x0020) == 0) // Dictionary flag? - { - mode = DECODE_BLOCKS; - } - else - { - mode = DECODE_DICT; - neededBits = 32; - } - return true; - } - - /** - * Decodes the dictionary checksum after the deflate header. - * @return false if more input is needed. - */ - private boolean decodeDict () - { - while (neededBits > 0) - { - int dictByte = input.peekBits(8); - if (dictByte < 0) - return false; - input.dropBits(8); - readAdler = (readAdler << 8) | dictByte; - neededBits -= 8; - } - return false; - } - - /** - * Decodes the huffman encoded symbols in the input stream. - * @return false if more input is needed, true if output window is - * full or the current block ends. - * @exception DataFormatException if deflated stream is invalid. - */ - private boolean decodeHuffman () throws DataFormatException - { - int free = outputWindow.getFreeSpace(); - while (free >= 258) - { - int symbol; - switch (mode) - { - case DECODE_HUFFMAN: - /* This is the inner loop so it is optimized a bit */ - while (((symbol = litlenTree.getSymbol(input)) & ~0xff) == 0) - { - outputWindow.write(symbol); - if (--free < 258) - return true; - } - if (symbol < 257) - { - if (symbol < 0) - return false; - else - { - /* symbol == 256: end of block */ - distTree = null; - litlenTree = null; - mode = DECODE_BLOCKS; - return true; - } - } - - try - { - repLength = CPLENS[symbol - 257]; - neededBits = CPLEXT[symbol - 257]; - } - catch (ArrayIndexOutOfBoundsException ex) - { - throw new DataFormatException("Illegal rep length code"); - } - /* fall through */ - case DECODE_HUFFMAN_LENBITS: - if (neededBits > 0) - { - mode = DECODE_HUFFMAN_LENBITS; - int i = input.peekBits(neededBits); - if (i < 0) - return false; - input.dropBits(neededBits); - repLength += i; - } - mode = DECODE_HUFFMAN_DIST; - /* fall through */ - case DECODE_HUFFMAN_DIST: - symbol = distTree.getSymbol(input); - if (symbol < 0) - return false; - try - { - repDist = CPDIST[symbol]; - neededBits = CPDEXT[symbol]; - } - catch (ArrayIndexOutOfBoundsException ex) - { - throw new DataFormatException("Illegal rep dist code"); - } - /* fall through */ - case DECODE_HUFFMAN_DISTBITS: - if (neededBits > 0) - { - mode = DECODE_HUFFMAN_DISTBITS; - int i = input.peekBits(neededBits); - if (i < 0) - return false; - input.dropBits(neededBits); - repDist += i; - } - outputWindow.repeat(repLength, repDist); - free -= repLength; - mode = DECODE_HUFFMAN; - break; - default: - throw new IllegalStateException(); - } - } - return true; - } - - /** - * Decodes the adler checksum after the deflate stream. - * @return false if more input is needed. - * @exception DataFormatException if checksum doesn't match. - */ - private boolean decodeChksum () throws DataFormatException - { - while (neededBits > 0) - { - int chkByte = input.peekBits(8); - if (chkByte < 0) - return false; - input.dropBits(8); - readAdler = (readAdler << 8) | chkByte; - neededBits -= 8; - } - if ((int) adler.getValue() != readAdler) - throw new DataFormatException("Adler chksum doesn't match: " - +Integer.toHexString((int)adler.getValue()) - +" vs. "+Integer.toHexString(readAdler)); - mode = FINISHED; - return false; - } - - /** - * Decodes the deflated stream. - * @return false if more input is needed, or if finished. - * @exception DataFormatException if deflated stream is invalid. - */ - private boolean decode () throws DataFormatException - { - switch (mode) - { - case DECODE_HEADER: - return decodeHeader(); - case DECODE_DICT: - return decodeDict(); - case DECODE_CHKSUM: - return decodeChksum(); - - case DECODE_BLOCKS: - if (isLastBlock) - { - if (nowrap) - { - mode = FINISHED; - return false; - } - else - { - input.skipToByteBoundary(); - neededBits = 32; - mode = DECODE_CHKSUM; - return true; - } - } - - int type = input.peekBits(3); - if (type < 0) - return false; - input.dropBits(3); - - if ((type & 1) != 0) - isLastBlock = true; - switch (type >> 1) - { - case DeflaterConstants.STORED_BLOCK: - input.skipToByteBoundary(); - mode = DECODE_STORED_LEN1; - break; - case DeflaterConstants.STATIC_TREES: - litlenTree = InflaterHuffmanTree.defLitLenTree; - distTree = InflaterHuffmanTree.defDistTree; - mode = DECODE_HUFFMAN; - break; - case DeflaterConstants.DYN_TREES: - dynHeader = new InflaterDynHeader(); - mode = DECODE_DYN_HEADER; - break; - default: - throw new DataFormatException("Unknown block type "+type); - } - return true; - - case DECODE_STORED_LEN1: - { - if ((uncomprLen = input.peekBits(16)) < 0) - return false; - input.dropBits(16); - mode = DECODE_STORED_LEN2; - } - /* fall through */ - case DECODE_STORED_LEN2: - { - int nlen = input.peekBits(16); - if (nlen < 0) - return false; - input.dropBits(16); - if (nlen != (uncomprLen ^ 0xffff)) - throw new DataFormatException("broken uncompressed block"); - mode = DECODE_STORED; - } - /* fall through */ - case DECODE_STORED: - { - int more = outputWindow.copyStored(input, uncomprLen); - uncomprLen -= more; - if (uncomprLen == 0) - { - mode = DECODE_BLOCKS; - return true; - } - return !input.needsInput(); - } - - case DECODE_DYN_HEADER: - if (!dynHeader.decode(input)) - return false; - litlenTree = dynHeader.buildLitLenTree(); - distTree = dynHeader.buildDistTree(); - mode = DECODE_HUFFMAN; - /* fall through */ - case DECODE_HUFFMAN: - case DECODE_HUFFMAN_LENBITS: - case DECODE_HUFFMAN_DIST: - case DECODE_HUFFMAN_DISTBITS: - return decodeHuffman(); - case FINISHED: - return false; - default: - throw new IllegalStateException(); - } - } -} |