inflater.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 641 行 · 第 1/2 页

JAVA
641
字号
		}
		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();
		}
	}

	/**
	 * 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 buffer 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 buffer 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;
	}

	/**
	 * 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 buffer 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 buffer 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 {
		/* Special case: len may be zero */
		if (len == 0)
			return 0;
		/* Check for correct buff, off, len triple */
		if (0 > off || off > off + len || off + len > buf.length)
			throw new ArrayIndexOutOfBoundsException();
		int count = 0;
		int more;
		do {
			if (mode != DECODE_CHKSUM) {
				/* Don't give away any output, if we are waiting for the
				 * checksum in the input stream.
				 *
				 * With this trick we have always:
				 *   needsInput() and not finished() 
				 *   implies more output can be produced.  
				 */
				more = outputWindow.copyOutput(buf, off, len);
				adler.update(buf, off, more);
				off += more;
				count += more;
				totalOut += more;
				len -= more;
				if (len == 0)
					return count;
			}
		} while (decode() || (outputWindow.getAvailable() > 0 && mode != DECODE_CHKSUM));
		return count;
	}

	/**
	 * 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();
	}

	/**
	 * 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 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 total number of output bytes returned by inflate().
	 * @return the total number of output bytes.
	 */
	public int getTotalOut() {
		return totalOut;
	}

	/**
	 * Gets the total number of processed compressed input bytes.
	 * @return the total number of bytes of processed input bytes.
	 */
	public int getTotalIn() {
		return totalIn - getRemaining();
	}

	/**
	 * 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();
	}

	/**
	 * 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>.  
	 * @deprecated Just clear all references to inflater instead.
	 */
	public void end() {
		outputWindow = null;
		input = null;
		dynHeader = null;
		litlenTree = null;
		distTree = null;
		adler = null;
	}

	/**
	 * Finalizes this object.
	 */
	protected void finalize() {
		/* Exists only for compatibility */
	}
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?