Introduction
This code will compress/decompress data from ISequentialStream
to ISequentialStream
. It also has functions to compress/decompress CFile
and CByteArray
.
Background
While developing software, sometimes I need to compress data to decrease size. The gzip library does compression for me, but it is not ready to handle in-memory or CFile
in MFC. So, here is the class that assists me compressing data.
Using the code
The class Flate
does compression/decompression for ISquentialStream
, CFile
, CByteArray
. Compression for CByteArray
is done by another small utility class CBAStreamReader
/CBAStreamWriter
.
class Flate
{
public:
Flate()
{
}
void Inflate(ISequentialStream* pOutput, ISequentialStream* pInput);
void Deflate(ISequentialStream* pOutput, ISequentialStream* pInput);
void Inflate(CFile* pOutput, CFile* pInput);
void Deflate(CFile* pOutput, CFile* pInput);
BOOL Compress(CByteArray& dst, const CByteArray& src)
{
return Compress(dst, src.GetData(), src.GetSize());
}
BOOL Compress(CByteArray& dst, const BYTE* src, UINT srcLen);
BOOL Uncompress(CByteArray& dst, const CByteArray& src)
{
return Uncompress(dst, src.GetData(), src.GetSize());
}
BOOL Uncompress(CByteArray& dst, const BYTE* src, UINT srcLen);
};
Here is one function that compresses CFile
data. The internal function uses z_stream
to support custom streams. First, it reads data from input CFile
, compresses it by deflate method and saves it to output CFile
.
void Flate::Deflate(CFile* pOutput, CFile* pInput)
{
z_stream zstm;
memset(&zstm,0,sizeof(z_stream));
BYTE zBufIn[UNCOMP_BUFSIZE];
BYTE zBufOut[COMP_BUFSIZE];
deflateInit(&zstm, Z_DEFAULT_COMPRESSION);
int err = Z_OK;
while ( TRUE )
{
UINT cbRead = 0;
cbRead = pInput->Read(zBufIn, sizeof(zBufIn));
if ( cbRead == 0 )
break;
zstm.next_in = (Bytef*)zBufIn;
zstm.avail_in = (uInt)cbRead;
while ( TRUE )
{
zstm.next_out = (Bytef*)zBufOut;
zstm.avail_out = sizeof(zBufOut);
err = deflate(&zstm, Z_SYNC_FLUSH);
if (err != Z_OK)
break;
UINT cbWrite = sizeof(zBufOut) - zstm.avail_out;
if ( cbWrite == 0 )
break;
pOutput->Write(zBufOut, cbWrite);
if ( zstm.avail_out != 0 )
break;
}
}
err = deflateEnd(&zstm);
}
Here is the other function that uncompresses CFile
data. It is almost same as Inflate
.
void Flate::Inflate(CFile* pOutput, CFile* pInput)
{
z_stream zstm;
memset(&zstm,0,sizeof(z_stream));
BYTE zBufIn[COMP_BUFSIZE];
BYTE zBufOut[UNCOMP_BUFSIZE];
inflateInit(&zstm);
int err = Z_OK;
while ( TRUE )
{
UINT cbRead = 0;
cbRead = pInput->Read(zBufIn, sizeof(zBufIn));
if ( cbRead == 0 )
break;
zstm.next_in = (Bytef*)zBufIn;
zstm.avail_in = (uInt)cbRead;
while ( TRUE )
{
zstm.next_out = (Bytef*)zBufOut;
zstm.avail_out = sizeof(zBufOut);
err = inflate(&zstm, Z_SYNC_FLUSH);
if (err != Z_OK)
break;
UINT cbWrite = sizeof(zBufOut) - zstm.avail_out;
if ( cbWrite == 0 )
break;
pOutput->Write(zBufOut, cbWrite);
if ( zstm.avail_out != 0 )
break;
}
}
err = inflateEnd(&zstm);
}