导航:[首页]->[cpp]->[deflate/inflate算法封装]
#ifndef MY_ZIP__H_
#define MY_ZIP__H_
#include "zlib.h"
#include <cassert>
#include <cstring>
class ZipListener
{
public:
virtual ~ZipListener(){}
virtual void OnZipdata(const char* data,size_t size,int magic) = 0;
virtual void OnZipEnd(int magic) = 0;
};
class ZipBase
{
protected:
enum{
BUF_SIZE = 4096,
};
ZipBase():m_stream_(NULL),m_listener_(NULL),m_magic_(0){}
inline void ResetInput(const char* buf,size_t size){
m_stream_->avail_in = size;
m_stream_->next_in = (Bytef*)buf;
}
inline void ResetOutput(){
m_stream_->next_out = (Bytef*)m_buf_;
m_stream_->avail_out = sizeof(m_buf_);
}
inline void Dispatch(){
assert(m_stream_);
if(m_stream_->avail_out < sizeof(m_buf_) && m_listener_){
this->m_listener_->OnZipdata(m_buf_,sizeof(m_buf_) - m_stream_->avail_out,m_magic_);
}
}
inline void Dispatch2(){
assert(m_stream_);
Dispatch();
ResetOutput();
}
void InitInside(ZipListener* listener,int magic){
assert(!m_stream_ && magic);
m_stream_ = new z_stream;
memset(this->m_stream_,0,sizeof(z_stream));
this->m_listener_ = listener;
this->m_magic_ = magic;
}
inline void CleanInside(){
assert(m_stream_);
delete m_stream_;
m_stream_ = NULL;
m_listener_ = NULL;
m_magic_ = 0;
}
z_stream* m_stream_;
ZipListener* m_listener_;
int m_magic_;
char m_buf_[BUF_SIZE];
};
class ZipDeflate : public ZipBase{
private:
bool Clean(bool notify){
assert(m_stream_);
int ret = deflateEnd(m_stream_);
if(Z_OK == ret && notify && m_listener_)
m_listener_->OnZipEnd(m_magic_);
this->CleanInside();
return Z_OK == ret;
}
public:
~ZipDeflate(){
if(m_stream_)
Clean(false);
}
inline bool Init(ZipListener* listener,int magic){
InitInside(listener,magic);
if(Z_OK == deflateInit(m_stream_, Z_DEFAULT_COMPRESSION))
return true;
else{
CleanInside();
return false;
}
}
bool Append(const char* buf,size_t size){
assert(m_stream_);
ResetInput(buf,size);
ResetOutput();
int ret;
do{
ret = deflate(m_stream_, Z_NO_FLUSH);
if(Z_OK != ret){
Clean(false);
return false;
}
if(0 == m_stream_->avail_in){
Dispatch();
return true;
}
if(0 == m_stream_->avail_out){
Dispatch2();
}
}while(true);
}
bool Fini(){
assert(m_stream_);
ResetOutput();
int ret;
do{
ret = deflate(m_stream_, Z_FINISH);
if(Z_STREAM_END == ret){
Dispatch();
return Clean(true);
}else if(Z_OK == ret){
if(0 == m_stream_->avail_out){
Dispatch2();
}
continue;
}else{
Clean(false);
return false;
}
}while(true);
}
};
class ZipInflate : public ZipBase{
private:
bool Clean(bool notify){
assert(m_stream_);
int ret = inflateEnd(m_stream_);
if(Z_OK == ret && notify && m_listener_)
m_listener_->OnZipEnd(m_magic_);
this->CleanInside();
return Z_OK == ret;
}
public:
~ZipInflate(){
if(m_stream_)
Clean(false);
}
bool Init(ZipListener* listener,int magic){
InitInside(listener,magic);
if(Z_OK == inflateInit(m_stream_))
return true;
else{
CleanInside();
return false;
}
}
/*
1.解压结束
0.解压成功,但是尚未结束
-1.解压失败
*/
int Append(const char* buf,size_t size){
ResetInput(buf,size);
ResetOutput();
int ret;
do{
ret = inflate(m_stream_, Z_NO_FLUSH);
if(Z_STREAM_END == ret){
//已经处理完毕
//dispatch
Dispatch();
//关闭,并通知回调
return Clean(true)?1:-1;
}
else if(Z_OK == ret){
//如果输入已经处理完毕
if(0 == m_stream_->avail_in){
Dispatch();
return true;
}
//如果输出已经处理完毕,则dispatch,并重设输出
if(0 == m_stream_->avail_out){
Dispatch2();
}
//继续inflate
}
else{
//出现错误
Clean(false);
return false;
}
}while(true);
}
};
#endif
//测试用例
#include "my_zip.h"
#include <cassert>
#include <cstdio>
#if 1
class XXX : public ZipListener{
public:
XXX(ZipInflate* inflate,FILE* fp):
count_(0),count2_(0){
this->inflate_ = inflate;
this->fp_ = fp;
}
virtual void OnZipdata(const char* data,size_t size,int magic){
if(magic == 1){
count_ += size;
inflate_->Append(data,size);
}else if(magic == 2){
count2_ += size;
fwrite(data,1,size,fp_);
}
}
virtual void OnZipEnd(int magic) {
}
int count_;
int count2_;
ZipInflate* inflate_;
FILE* fp_;
};
int main(int argc,const char** argv){
if(argc < 3)
return 1;
FILE* ifp_ = fopen(argv[1],"rb");
FILE* ofp_ = fopen(argv[2],"wb");
if(!ifp_ || !ofp_ )
return 2;
ZipDeflate deflate_;
ZipInflate inflate_;
XXX xxxx_(&inflate_,ofp_);
assert(deflate_.Init(&xxxx_,1));
assert(inflate_.Init(&xxxx_,2));
char buf[4096] = {0};
size_t readed_;
do{
readed_ = fread(buf,1,sizeof(buf),ifp_);
if(!readed_)
break;
assert(deflate_.Append(buf,readed_));
}while(true);
assert(deflate_.Fini());
return 0;
}
#else
class XXX : public ZipListener{
public:
XXX(ZipInflate* inflate):
count_(0),count2_(0){
this->inflate_ = inflate;
}
virtual void OnZipdata(const char* data,size_t size,int magic){
if(magic == 1){
count_ += size;
inflate_->Append(data,size);
}else if(magic == 2){
count2_ += size;
}
}
virtual void OnZipEnd(int magic) {
}
int count_;
int count2_;
ZipInflate* inflate_;
};
int main(){
char buf[1000] = {0};
ZipDeflate deflate_;
ZipInflate inflate_;
XXX xxxx_(&inflate_);
assert(deflate_.Init(&xxxx_,1));
assert(inflate_.Init(&xxxx_,2));
assert(deflate_.Append(buf,sizeof(buf)));
assert(deflate_.Fini());
return 0;
}
#endif
|
|