package org.geometerplus.fbreader.formats.pdb; /** * @author hym E-mail:hymmyh@gmail.com * @version 创建时间:2011-2-8 下午08:44:00 * 类说明 */ public class LZ77T { private final int MAX_WND_SIZE = 10; private final int OFFSET_CODING_LENGTH = 9; private final int constM = 1; private byte[] pOutputBuffer; private int pulNumberOfBytes; public LZ77T() { pOutputBuffer=new byte[400000]; pulNumberOfBytes=0; } public void lz77decompress(byte[] pDataBuffer, int ulNumberOfBits) { int iSlideWindowPtr = 0; int offset; int offset2; int length = 0, wndOffset = 0; int bit = 0; byte cc = 0; int i = 0; int ulBytesDecoded = 0; int ulBitOffset = 0; ReturnData returnData = new ReturnData(); int ulCodingLength = 0; iSlideWindowPtr = -MAX_WND_SIZE; ulBitOffset = 0; ulBytesDecoded = 0; offset2 = 0; offset = 0; while (ulBitOffset < ulNumberOfBits) { bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset); ulBitOffset++; if (bit == 1) { if (iSlideWindowPtr >= 0) { offset = iSlideWindowPtr; } else if (iSlideWindowPtr >= -MAX_WND_SIZE) { offset = 0; } else { offset = 0; } for (i = 0, wndOffset = 0; i < OFFSET_CODING_LENGTH; i++, ulBitOffset++) { bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset); wndOffset |= (bit << i); } returnData = ReadGolombCode(pDataBuffer, ulBitOffset); length = returnData.getByteNum(); ulCodingLength = returnData.getBitNum(); wndOffset = wndOffset % MAX_WND_SIZE; if (length > MAX_WND_SIZE) { length = length % MAX_WND_SIZE; } ulBitOffset += ulCodingLength; for (i = 0; i < length; i++) { pOutputBuffer[offset2 + i] = pOutputBuffer[offset + wndOffset]; offset++; } offset2 += length; iSlideWindowPtr += length; ulBytesDecoded += length; } else { for (i = 0, cc = 0; i < 8; i++, ulBitOffset++) { bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset); cc |= ( (byte) bit << i); } pOutputBuffer[offset2] = cc; offset2++; iSlideWindowPtr++; ulBytesDecoded++; } } pulNumberOfBytes = ulBytesDecoded; setPulNumberOfBytes(pulNumberOfBytes); setPOutputBuffer(pOutputBuffer); } private int ReadBitFromBitStream(byte[] pBuffer, int ulBitOffset) { int ulByteBoundary = 0; int ulOffsetInByte = 0; ulByteBoundary = (int) (ulBitOffset >> 3); ulOffsetInByte = ulBitOffset & 7; return ( ( (byte) (pBuffer[ulByteBoundary] >> ulOffsetInByte)) & ( (byte) 0x01)); } private ReturnData ReadGolombCode(byte[] pBuffer, int ulBitOffset) { int q, r; int bit = 0; int i; int pulCodingLength; ReturnData returnData = new ReturnData(); for (q = 0; ; q++) { bit = ReadBitFromBitStream(pBuffer, ulBitOffset); ulBitOffset++; if (bit != 1) { break; } } for (i = 0, r = 0; (int) i < constM; i++, ulBitOffset++) { bit = (int) ReadBitFromBitStream(pBuffer, ulBitOffset); bit <<= i; r |= bit; } pulCodingLength = constM + q + 1; returnData.setBitNum(pulCodingLength); returnData.setByteNum(r + (q << constM) + 1); return returnData; } public byte[] getPOutputBuffer() { return pOutputBuffer; } public int getPulNumberOfBytes() { return pulNumberOfBytes; } private void setPOutputBuffer(byte[] pOutputBuffer) { this.pOutputBuffer = pOutputBuffer; } private void setPulNumberOfBytes(int pulNumberOfBytes) { this.pulNumberOfBytes = pulNumberOfBytes; } }