1. 程式人生 > >zlib庫記憶體壓縮解壓縮函式的C++便利性封裝

zlib庫記憶體壓縮解壓縮函式的C++便利性封裝

zlib是提供資料壓縮用的函式庫,由Jean-loup Gailly與Mark Adler所開發,初版0.9版在1995年5月1日發表,普遍為許多軟體所使用。
在使用zlib進行記憶體壓縮解壓縮的的時候主要用到的函式就是兩個compress/uncompress。為了在C++中使用更方便,做一些便利性封裝是非常必要的。
下面的程式碼中主要對zlib的記憶體壓縮和解壓縮排行了C++封裝,出錯以異常丟擲。
因為zlib沒辦法估計解壓縮後資料的長度,所以解壓縮的時候,如果不知道源資料壓縮之前的長度,就得估算一個長度來設定輸出緩衝區大小,如果緩衝長度不足導致解壓縮失敗,就增大緩衝區再嘗試直到解壓縮成功。

/*
 * zlib_wrapper.h
 *
 *  Created on: 2016年3月29日
 *      Author: guyadong
 */

#ifndef INCLUDE_ZLIB_WRAPPER_H_
#define INCLUDE_ZLIB_WRAPPER_H_
#include <vector>
#include "zlib.h"
#define _DEF_STRING(x) #x
#define DEF_TO_STRING(x) _DEF_STRING(x)
#define SOURCE_AT __FILE__ ":" DEF_TO_STRING(__LINE__)
#define ERROR_STR(msg) std::string(SOURCE_AT ":").append(msg) #define throw_except_if_msg(except,expression,msg) \ if(expression)\ throw except(ERROR_STR(msg)); #define _CAS_ERROR_MSG_(ERR) case ERR:return #ERR; /* * 以sting形式返回錯誤資訊 */ inline std::string zlib_error_message(int err){ switch
(err){ _CAS_ERROR_MSG_(Z_OK) _CAS_ERROR_MSG_(Z_MEM_ERROR) _CAS_ERROR_MSG_(Z_BUF_ERROR) _CAS_ERROR_MSG_(Z_STREAM_ERROR) }; return "unknow error"; } #undef _CAS_ERROR_MSG_ /* zlib異常類 */ class zlib_exception:public std::logic_error{ // 繼承基類建構函式 using std::logic_error::logic_error; }; /* * 呼叫zlib壓縮資料 */ inline std::vector<uint8_t> zlib_mem_compress (const void *source, size_t sourceLen){ throw_if(nullptr==source||0==sourceLen) std::vector<uint8_t> buffer(compressBound(sourceLen)); auto destLen=uLongf(buffer.size()); auto err=compress(buffer.data(),&destLen,reinterpret_cast<const Bytef *>(source),uLong(sourceLen)); throw_except_if_msg(zlib_exception,err!=Z_OK,zlib_error_message(err)) return std::vector<uint8_t>(buffer.data(),buffer.data()+destLen); } /* * 呼叫zlib壓縮陣列資料 */ inline std::vector<uint8_t> zlib_mem_compress (const std::string &source){ return zlib_mem_compress(source.data(),source.size()); } /* * 呼叫zlib壓縮資料 */ template<typename T> inline std::vector<uint8_t> zlib_mem_compress (const std::vector<T> &source){ return zlib_mem_compress(source.data(),source.size()*sizeof(T)); } /* * 呼叫zlib壓縮物件資料 */ template<typename T> inline typename std::enable_if<std::is_class<T>::value,std::vector<uint8_t>>::type compress_obj (const T &source){ return zlib_mem_compress(std::addressof(source),sizeof(T)); } /* * 呼叫zlib解壓縮資料 * uncompress_bound為壓縮前的資料長度,如果不知道資料來源長度設定為0 * */ inline std::vector<uint8_t> zlib_mem_uncompress (const void *source, size_t sourceLen,size_t uncompress_bound=0){ throw_if(nullptr==source||0==sourceLen) //uncompress_bound為0時將緩衝區設定為sourceLen的8倍長度 if (!uncompress_bound) uncompress_bound = sourceLen << 3; for(;;){ std::vector<uint8_t> buffer(uncompress_bound); auto destLen=uLongf(buffer.size()); auto err=uncompress(buffer.data(),&destLen,reinterpret_cast<const Bytef *>(source),uLong(sourceLen)); if(Z_OK==err) return std::vector<uint8_t>(buffer.data(),buffer.data()+destLen); else if(Z_BUF_ERROR==err){ // 緩衝區不足 uncompress_bound<<=2;// 緩衝區放大4倍再嘗試 continue; } // 其他錯誤丟擲異常 throw zlib_exception(zlib_error_message(err)); } } /* * 呼叫zlib解壓縮資料 * */ inline std::string zlib_mem_uncompress (const std::string &source,size_t uncompress_bound=0){ auto un_data=zlib_mem_uncompress(source.data(),source.size(),uncompress_bound); return std::string((char*)un_data.data(),un_data.size()); } /* * 呼叫zlib解壓縮資料 * */ inline void zlib_mem_uncompress (void *dest,size_t *destLen,const void *source, size_t sourceLen){ throw_if(nullptr==source||0==sourceLen||nullptr==dest||nullptr==destLen||0==*destLen) auto len=uLongf(*destLen); auto err=uncompress(reinterpret_cast<Bytef *>(dest),&len,reinterpret_cast<const Bytef *>(source),uLong(sourceLen)); *destLen=size_t(len); throw_except_if_msg(zlib_exception,err!=Z_OK,zlib_error_message(err)) } /* * 解壓縮資料到物件 */ template<typename T> inline typename std::enable_if<std::is_class<T>::value>::type uncompress_obj (T &dest,const void *source, size_t sourceLen){ auto destLen=sizeof(T); zlib_mem_uncompress(std::addressof(dest),&destLen,source,sourceLen); } #endif /* INCLUDE_ZLIB_WRAPPER_H_ */

程式碼在VS2015和MingW5.2.0下編譯通過