使用zlib压缩IStream流2 by sdraogn
这是修改zlib实例的一段代码,用于学习zlib之用。CompressStream()将打开的文件流压缩进IStream流。UncompressStream()反之。注意的是,文件流的读取指针一定要在流的开头,当然也可以在中间,读取中间的数据。其他的问题看看原码再说吧。
#ifndef zipstreamH
#define zipstreamH
//---------------------------------------------------------------------------
#include <windows.h>
#include <objbase.h> //IStorage, IStream
#include <atl/atlbase.h> //CComPtr, CComBSTR
namespace zlib{
#include <zlib/zlib.h>
}using namespace zlib;
#pragma link "zlib.lib"
#define Z_BUFFER 8192//8K
#include <cstdio>
#include <cassert>
using namespace std;
int CompressStream(FILE* fin, IStream *stmout, int level = Z_DEFAULT_COMPRESSION);
int UncompressStream(LPSTREAM stmin, FILE *fout);
//---------------------------------------------------------------------------
#endif
源文件:
//---------------------------------------------------------------------------
#pragma hdrstop
#include "zipstream.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
int CompressStream(FILE* fin, IStream *stmout, int level)
{
int ret = 0, flush = 0;
unsigned int nhave = 0;
z_stream strm = {0};
char in[Z_BUFFER] = {0};
char out[Z_BUFFER] = {0};
/* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, level);
if (ret != Z_OK) return ret;
/* compress until end of file */
do
{
strm.avail_in = fread(in, 1, Z_BUFFER, fin);
if (ferror(fin))//on error
{
(void) deflateEnd(&strm);
return Z_ERRNO;
}
flush = feof(fin) ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = in;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do
{
strm.avail_out = Z_BUFFER;
strm.next_out = out;
ret = deflate(&strm, flush); /* no bad return value */
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
nhave = Z_BUFFER - strm.avail_out;
DWORD written = 0;
stmout->Write(out, nhave, &written);
if(written!=nhave)
{
deflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /* all input will be used */
/* done when last data in file processed */
} while (flush != Z_FINISH);
assert(ret == Z_STREAM_END); /* stream will be complete */
/* clean up and return */
(void)deflateEnd(&strm);
return Z_OK;
}
int UncompressStream(LPSTREAM stmin, FILE *fout)
{
int ret;
unsigned have;
z_stream strm;
char in[Z_BUFFER];
char out[Z_BUFFER];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do
{
DWORD dwRead = 0;
stmin->Read(in, Z_BUFFER, &dwRead);
strm.avail_in = dwRead;//fread(in, 1, Z_BUFFER, source);
/*
if (ferror(source)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}*/
if (strm.avail_in == 0)
break;
strm.next_in = in;
/* run inflate() on input until output buffer not full */
do {
strm.avail_out = Z_BUFFER;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch(ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = Z_BUFFER - strm.avail_out;
if (fwrite(out, 1, have, fout) != have || ferror(fout))
{
(void)inflateEnd(&strm);
return Z_ERRNO;
}
//char buf[32];
//itoa(strm.avail_in, buf, 10);
//MessageBox(GetTopWindow(NULL), "", buf, 0);
} while (strm.avail_out == 0);
assert(strm.avail_in == 0); /* all input will be used */
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END);
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}