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 + -
显示快捷键?