Lz77 compression/decompression algorithm 源代码
测试压缩一个425K的文件需要9.4秒,压缩后的文件为177K。
http://blog.
/*********************************************************************
*
* Project description:
* Lz77 compression/decompression algorithm.
*
*********************************************************************/
#include <windows.h>
#include <conio.h>
#include <stdio.h>
#include <assert.h>
#define OFFSET_CODING_LENGTH (10)
#define MAX_WND_SIZE 1024
//#define MAX_WND_SIZE (1<<OFFSET_CODING_LENGTH)
#define OFFSET_MASK_CODE (MAX_WND_SIZE-1)
const ULONG m=3;
UCHAR __buffer1__[0x200000];
UCHAR __buffer2__[0x200000];
////////////////////////////////////////////////////////////////////////////////
void
Write1ToBitStream(
PUCHAR pBuffer,
ULONG ulBitOffset
)
{
ULONG ulByteBoundary;
ULONG ulOffsetInByte;
ulByteBoundary = ulBitOffset>>3 ;
ulOffsetInByte = ulBitOffset&7;
*(pBuffer+ulByteBoundary) |= (1<<ulOffsetInByte);
}
void
Write0ToBitStream(
PUCHAR pBuffer,
ULONG ulBitOffset
)
{
ULONG ulByteBoundary;
ULONG ulOffsetInByte;
ulByteBoundary = ulBitOffset>>3 ;
ulOffsetInByte = ulBitOffset&7;
*(pBuffer+ulByteBoundary) &= (~(1<<ulOffsetInByte));
}
ULONG
ReadBitFromBitStream(
PUCHAR pBuffer,
ULONG ulBitOffset
)
{
ULONG ulByteBoundary;
ULONG ulOffsetInByte;
ulByteBoundary = ulBitOffset>>3 ;
ulOffsetInByte = ulBitOffset&7;
return ((*(PULONG)(pBuffer+ulByteBoundary))>>ulOffsetInByte)&1 ;
}
ULONG WINAPI
WriteGolombCode(
ULONG x,
PUCHAR pBuffer,
ULONG ulBitOffset
)
{
ULONG q, r;
int i;
q = (x-1)>>m;
r = x-(q<<m)-1;
for(i=0; (ULONG)i<q; i++, ulBitOffset++)
{
Write1ToBitStream(pBuffer, ulBitOffset);
}
Write0ToBitStream(pBuffer, ulBitOffset);
ulBitOffset++;
for(i=0; i<m; i++, ulBitOffset++)
{
if( (r>>i)&1 )
{
Write1ToBitStream(pBuffer, ulBitOffset);
}
else
{
Write0ToBitStream(pBuffer, ulBitOffset);
}
}
return m+q+1;
}
ULONG
ReadGolombCode(
PULONG pulCodingLength,
PUCHAR pBuffer,
ULONG ulBitOffset
)
{
ULONG q, r;
ULONG bit;
int i;
for(q=0; ;q++)
{
bit = (ULONG)ReadBitFromBitStream(pBuffer, ulBitOffset);
ulBitOffset++;
if( !bit )
{
break;
}
}
for(i=0, r=0; (ULONG)i<m; i++, ulBitOffset++)
{
bit = (ULONG)ReadBitFromBitStream(pBuffer, ulBitOffset);
bit <<= i;
r |= bit;
}
*pulCodingLength = m + q + 1;
return r+(q<<m)+1;
}
ULONG
CompareStrings(
PUCHAR string1,
PUCHAR string2,
ULONG length
)
{
ULONG i;
PUCHAR p1, p2;
p1 = string1;
p2 = string2;
for(i=0; i<length; i++)
{
if( *p1==*p2 )
{
p1++;
p2++;
}
else
{
break;
}
}
return p1-string1;
}
void WINAPI
FindLongestSubstring(
PUCHAR pSourceString,
PUCHAR pString,
ULONG ulSourceStringLength,
PULONG pulSubstringOffset,
PULONG pulSubstringLength
)
{
PUCHAR pSrc;
ULONG offset, length;
ULONG ulMaxLength;
*pulSubstringOffset = offset = 0;
*pulSubstringLength = 0;
if( NULL==pSourceString || NULL==pString )
{
return;
}
ulMaxLength = ulSourceStringLength;
pSrc = pSourceString;
while( ulMaxLength>0 )
{
length = CompareStrings(pSrc, pString, ulMaxLength);
if( length>*pulSubstringLength )
{
*pulSubstringLength = length;
*pulSubstringOffset = offset;
}
pSrc++;
offset++;
ulMaxLength--;
}
}
/*
void
FindLongestSubstring(
PUCHAR pSourceString,
PUCHAR pString,
ULONG ulSourceStringLength,
PULONG pulSubstringOffset,
PULONG pulSubstringLength
)
{
PUCHAR pCurrentOffset;
PUCHAR p1, p2;
ULONG offset, length;
pCurrentOffset = pSourceString;
*pulSubstringOffset = offset = 0;
*pulSubstringLength = length = 0;
while( pCurrentOffset<pSourceString+ulSourceStringLength )
{
p1 = pCurrentOffset;
p2 = pString;
if( *p1==*p2 )
{
while( p1<pSourceString+ulSourceStringLength && *p1==*p2 )
{
p1++;
p2++;
}
length = p1 - pCurrentOffset;
}
else
{
length = 0;
}
if( length>*pulSubstringLength )
{
*pulSubstringLength = length;
*pulSubstringOffset = (ULONG)pCurrentOffset - (ULONG)pSourceString;
}
pCurrentOffset++;
}
}
*/
void
WriteBits(
PUCHAR pDataBuffer,
ULONG ulOffsetToWrite,
ULONG ulBits,
ULONG ulBitLength
)
{
ULONG ulDwordsOffset;
ULONG ulBitsOffset, ulBitsRemained;
ulDwordsOffset = ulOffsetToWrite>>5;
ulBitsOffset = ulOffsetToWrite&31;
ulBitsRemained = 32 - ulBitsOffset;
if( 0==ulBitsOffset )
{
*((PULONG)pDataBuffer+ulDwordsOffset) = ulBits;
}
else if( ulBitsRemained>=ulBitLength )
{
*((PULONG)pDataBuffer+ulDwordsOffset) |= (ulBits<<ulBitsOffset);
}
else
{
*((PULONG)pDataBuffer+ulDwordsOffset) |= (ulBits<<ulBitsOffset);
*((PULONG)pDataBuffer+ulDwordsOffset+1) = ulBits>>ulBitsRemained;
}
}
void
ReadBits(
PUCHAR pDataBuffer,
ULONG ulOffsetToRead,
PULONG pulBits
)
{
ULONG ulDwordsOffset;
ULONG ulBitsOffset, ulBitsLength;
ulDwordsOffset = ulOffsetToRead>>5;
ulBitsOffset = ulOffsetToRead&31;
ulBitsLength = 32 - ulBitsOffset;
*pulBits = *((PULONG)pDataBuffer+ulDwordsOffset);
if( 0!=ulBitsOffset )
{
(*pulBits) >>= ulBitsOffset;
(*pulBits) |= (*((PULONG)pDataBuffer+ulDwordsOffset+1))<<ulBitsLength;
}
}
void
lz77compress(
PUCHAR pDataBuffer,
ULONG ulDataLength,
PUCHAR pOutputBuffer,
PULONG pulNumberOfBits
)
{
LONG iSlideWindowPtr;
ULONG ulBytesCoded;
ULONG ulMaxlength;
PUCHAR pSlideWindowPtr;
PUCHAR pUnprocessedDataPtr;
ULONG offset;
ULONG length;
ULONG ulCodingLength;
ULONG ulBitOffset;
UCHAR cc;
int i;
iSlideWindowPtr = -MAX_WND_SIZE;
pSlideWindowPtr = NULL;
ulBitOffset = 0;
ulBytesCoded = 0;
while( ulBytesCoded<ulDataLength )
{
if( iSlideWindowPtr>=0 )
{
pSlideWindowPtr = pDataBuffer+iSlideWindowPtr;
ulMaxlength = MAX_WND_SIZE;
}
else if( iSlideWindowPtr>=-MAX_WND_SIZE )
{
pSlideWindowPtr = pDataBuffer;
ulMaxlength = MAX_WND_SIZE + iSlideWindowPtr;
}
else
{
pSlideWindowPtr = NULL;
ulMaxlength = 0;
}
pUnprocessedDataPtr = pDataBuffer + ulBytesCoded;
if( ulMaxlength>ulDataLength-ulBytesCoded )
{
ulMaxlength = ulDataLength-ulBytesCoded;
}
FindLongestSubstring(
pSlideWindowPtr,
pUnprocessedDataPtr,
ulMaxlength,
&offset,
&length
);
assert( length<=MAX_WND_SIZE );
assert( offset<MAX_WND_SIZE );
if(length>1)
{
Write1ToBitStream(pOutputBuffer, ulBitOffset);
ulBitOffset++;
for(i=0; i<OFFSET_CODING_LENGTH; i++, ulBitOffset++)
{
if( (offset>>i)&1 )
{
Write1ToBitStream(pOutputBuffer, ulBitOffset);
}
else
{
Write0ToBitStream(pOutputBuffer, ulBitOffset);
}
}
ulCodingLength = WriteGolombCode(length, pOutputBuffer, ulBitOffset);
ulBitOffset += ulCodingLength;
iSlideWindowPtr += length;
ulBytesCoded += length;
}
else
{
Write0ToBitStream(pOutputBuffer, ulBitOffset);
ulBitOffset++;
cc = (*pUnprocessedDataPtr);
for(i=0; i<8; i++, ulBitOffset++)
{
if( (cc>>i)&1 )
{
Write1ToBitStream(pOutputBuffer, ulBitOffset);
}
else
{
Write0ToBitStream(pOutputBuffer, ulBitOffset);
}
}
iSlideWindowPtr++;
ulBytesCoded++;
}
}
if( ulBytesCoded!=ulDataLength )
{
assert(ulBytesCoded==ulDataLength);
}
*pulNumberOfBits = ulBitOffset;
}
void lz77decompress(
PUCHAR pDataBuffer,
ULONG ulNumberOfBits,
PUCHAR pOutputBuffer,
PULONG pulNumberOfBytes
)
{
LONG iSlideWindowPtr;
PUCHAR pSlideWindowPtr;
ULONG length, offset;
ULONG bit;
UCHAR cc;
int i;
ULONG ulBytesDecoded;
ULONG ulBitOffset;
ULONG ulCodingLength;
PUCHAR pWrite;
iSlideWindowPtr = -MAX_WND_SIZE;
pWrite = (PUCHAR)pOutputBuffer;
ulBitOffset = 0;
ulBytesDecoded = 0;
while( ulBitOffset<ulNumberOfBits )
{
bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset);
ulBitOffset++;
if( bit )
{
if( iSlideWindowPtr>=0 )
{
pSlideWindowPtr = pOutputBuffer + iSlideWindowPtr;
}
else if( iSlideWindowPtr>=-MAX_WND_SIZE )
{
pSlideWindowPtr = pOutputBuffer;
}
else
{
pSlideWindowPtr = NULL;
}
for(i=0, offset=0; i<OFFSET_CODING_LENGTH; i++, ulBitOffset++)
{
bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset);
offset |= (bit<<i);
}
length= ReadGolombCode(&ulCodingLength, pDataBuffer, ulBitOffset);
assert(offset<MAX_WND_SIZE);
if( length>MAX_WND_SIZE )
{
assert(length<=MAX_WND_SIZE);
}
ulBitOffset += ulCodingLength;
RtlMoveMemory(pWrite, pSlideWindowPtr+offset, length);
pWrite+=length;
iSlideWindowPtr+=length;
ulBytesDecoded+=length;
}
else
{
for(i=0, cc=0; i<8 ; i++, ulBitOffset++)
{
bit = ReadBitFromBitStream(pDataBuffer, ulBitOffset);
cc |= ((UCHAR)bit<<i);
}
*pWrite++ = cc;
iSlideWindowPtr++;
ulBytesDecoded++;
}
}
*pulNumberOfBytes = ulBytesDecoded;
}
extern "C"
void WINAPI
LZ77Compress(
PUCHAR __pDataBuffer,
ULONG __ulDataLength,
PUCHAR __pOutputBuffer,
PULONG __pulNumberOfBits
);
extern "C"
void WINAPI
LZ77Decompress(
PUCHAR __pDataBuffer,
ULONG __ulNumberOfBits,
PUCHAR __pOutputBuffer,
PULONG __pulNumberOfBytes
);
int
main(
int argc,
char *argv[]
)
{
FILE *fp=NULL;
FILE *fp1;
ULONG fsize;
ULONG ulNumberOfBits;
ULONG ulFileCompressedSize;
ULONG ulFileDecompressedSize;
SYSTEMTIME t1, t2;
if( 3!=argc )
{
printf("Usage: lz77 [/c | /d] filename\n");
return -1;
}
// char s1[]="abcdabcdefgabcdefaffasda";
// ULONG a, b;
// FindLongestSubstring((PUCHAR)s1, (PUCHAR)s1+11, 11,&a, &b );
// return 0;
fp = fopen(argv[2], "rb");
if( !fp )
{
return -1;
}
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(__buffer1__, 1, fsize, fp);
GetSystemTime(&t1);
lz77compress(__buffer1__, fsize, __buffer2__, &ulNumberOfBits);
//LZ77Compress(__buffer1__, fsize, __buffer2__, &ulNumberOfBits);
GetSystemTime(&t2);
ulFileCompressedSize = ((ulNumberOfBits+7)>>3);
fp1=fopen("peinfo.c_", "wb+");
if( !fp1 )
{
goto l1;
}
fwrite(__buffer2__, 1, ulFileCompressedSize, fp1);
fclose(fp1);
RtlZeroMemory(__buffer1__, sizeof(__buffer1__));
lz77decompress(__buffer2__, ulNumberOfBits, __buffer1__, &ulFileDecompressedSize);
//LZ77Decompress(__buffer2__, ulNumberOfBits, __buffer1__, &ulFileDecompressedSize);
fp1=fopen("peinfo.d_", "wb+");
if( !fp1 )
{
goto l1;
}
fwrite(__buffer1__, 1, ulFileDecompressedSize, fp1);
fclose(fp1);
l1:
if( fp )
{
fclose(fp);
}
ULONG milliS;
milliS = ((t2.wHour - t1.wHour)*3600 + (t2.wMinute-t1.wMinute)*60 + (t2.wSecond-t1.wSecond)) * 1000 + (t2.wMilliseconds-t1.wMilliseconds);
printf("Totally %ld milliseconds elapsed!\n\n", milliS);
printf("Press any key to exit!\n");
getch();
return 0;
}