网络游戏在前后端交换的过程中,有可能会有大量的数据,比如说游戏回放功能,这时最好是将数据压缩一下。
比较简单的数据压库就是zlib了。
zlib官方文档,常用的函数都在这里了,解释很详细。
一 C++功能实现部分
下面将代码贴上来。
在ZipUtils中添加下面三个函数:
// ZipUtils.h
<pre name="code" class="cpp">typedef struct{
unsigned str_size;
unsigned buf_size;
char data[];// 柔性数组
}CompressedData;
class ZipUtils
{
public:
// add by XuLidong
static void testFun();
static unsigned getCompressBound(unsigned len);
static bool compressString(const char* str,CompressedData* pdata);
static bool decompressString(CompressedData* pdata, char* str);
};
用到了柔性数组,不动的可以参考我的另一篇文章
下面是相应的实现:
// ZipUtils.cpp
#include <zlib.h>
#include <stdlib.h>
#include "ZipUtils.h"
int test1()
{
char text[] = "zlib compress and uncompress test\nxulidong_china@163.com\n2012-11-05\n";
uLong tlen = strlen(text) + 1; /* 需要把字符串的结束符'\0'也一并处理 */
char* buf = NULL;
uLong blen;
/* 计算缓冲区大小,并为其分配内存 */
blen = compressBound(tlen); /* 压缩后的长度是不会超过blen的 */
printf("compress str_size:%d, buf_size:%d\n", tlen, blen);
if((buf = (char*)malloc(sizeof(char) * blen)) == NULL)
{
printf("no enough memory!\n");
return -1;
}
/* 压缩 */
if(compress((Bytef*)buf, &blen, (const Bytef*)text, tlen) != Z_OK)
{
printf("compress failed!\n");
return -1;
}
/* 解压缩 */
printf("uncompress str_size:%d, buf_size:%d\n", tlen, blen);
if(uncompress((Bytef*)text, &tlen, (const Bytef*)buf, blen) != Z_OK)
{
printf("uncompress failed!\n");
return -1;
}
/* 打印结果,并释放内存 */
printf("%s", text);
if(buf != NULL)
{
free(buf);
buf = NULL;
}
}
void test2()
{
const char* str="abcdefg 中文字符可以吗 ? 》 , >\ ";
unsigned len = strlen(str) + 1;
unsigned long blen = compressBound(len);
CompressedData* pdata = (CompressedData*)malloc(sizeof(CompressedData) + blen * sizeof(char));
pdata->str_size = len;
pdata->buf_size = blen;
ZipUtils::compressString(str, pdata);
char* ustr = (char*)malloc(len);
memset(ustr, 0, len);
ZipUtils::decompressString(pdata, ustr);
free(ustr);
}
void ZipUtils::testFun()
{
//test1();
test2();
}
unsigned ZipUtils::getCompressBound(unsigned len)
{
return (unsigned)compressBound((unsigned long)len);
}
bool ZipUtils::compressString(const char* str, CompressedData* pdata)
{
printf("compress string:%s\n", str);
int res = compress((Bytef*)pdata->data, (unsigned long*)&(pdata->buf_size), (const Bytef*)str, (unsigned long)pdata->str_size);
if( res != Z_OK)
{
printf("compress failed, error code:%d\n", res);
return false;
}
printf("string size %d, buffer size: %d\n", pdata->str_size, pdata->buf_size);
return true;
}
bool ZipUtils::decompressString(CompressedData* pdata, char* str)
{
printf("string size %d, buffer size: %d\n", pdata->str_size, pdata->buf_size);
int res = uncompress((Bytef*)str, (unsigned long *)&(pdata->str_size), (const Bytef *)pdata->data, (unsigned long)pdata->buf_size);
if(res != Z_OK)
{
printf("uncompress failed, error code:%d\n", res);
return false;
}
printf("uncompress string:%s\n", str);
return true;
}
二 C++导出到Lua接口
// ZipUtilsLua.h
#include "tolua++.h"
#include "tolua_event.h"
#include "lauxlib.h"
int tolua_ZipUtils_open(lua_State *L);
// ZipUtilsLua.cpp
#include "support/zip_support/ZipUtils.h"
#include <string>
#include "tolua++.h"
#include "tolua_event.h"
#include "lauxlib.h"
using namespace cocos2d;
int TOLUA_API luaCopressString(lua_State *L)
{
size_t slen = 0;
const char *str = lua_tolstring(L, 1, &slen);
unsigned blen = ZipUtils::getCompressBound((unsigned long)slen);
CompressedData* pdata = (CompressedData*)malloc(sizeof(CompressedData) + blen * sizeof(char));
pdata->str_size = slen;
pdata->buf_size = blen;
if(ZipUtils::compressString(str, pdata)){
lua_pushlstring(L, (char*)pdata, pdata->buf_size+sizeof(CompressedData));
printf("sizeof=%d", sizeof(CompressedData));
}
else{
lua_pushstring(L, "");
}
free(pdata);
return 1;
}
int TOLUA_API luaDecopressString(lua_State *L)
{
const char *strBuf = lua_tostring(L, 1);
CompressedData* pdata = (CompressedData*)strBuf;
unsigned slen = pdata->str_size;
unsigned blen = pdata->buf_size;
char* str = (char*)malloc(pdata->str_size * sizeof(char));
if(ZipUtils::decompressString(pdata, str)){
lua_pushlstring(L, str, slen);
}
else{
lua_pushstring(L, "");
}
free(str);
return 1;
}
int TOLUA_API luaTestFun(lua_State *L)
{
ZipUtils::testFun();
return 1;
}
static luaL_Reg ziplib[] = {
{"compress", luaCopressString},
{"decompress", luaDecopressString},
{"testFun", luaTestFun},
{NULL, NULL}
};
// 函数名必须为luaopen_xxx,其中xxx表示library名称,Lua代码require "xxx"需要与之对应。
int luaopen_ZipUtils(lua_State* L)
{
const char* libName = "ZipUtils";
luaL_register(L, libName, ziplib);// 调用方式libName.函数名
return 1;
}
int tolua_ZipUtils_open(lua_State *L)
{
luaopen_ZipUtils(L);
return 1;
}
注册代码:
// register lua engine
CCLuaEngine* pEngine = CCLuaEngine::defaultEngine();
CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
<span style="font-family: Arial, Helvetica, sans-serif;">tolua_ZipUtils_open</span><span style="font-family: Arial, Helvetica, sans-serif;">(pEngine->getLuaStack()->getLuaState());</span>
三 Lua中调用
require ("ZipUtils")
local string = "hello, world"
local zipData = ZipUtils.compress(string)
if c ~= "" then
print("XXXXXXXXXXXXXXXXX compress", zipData)
else
print("XXXXXXXXXXXXXXXXX error")
end
local str = ZipUtils.decompress(zipData)
if str ~= "" then
print("XXXXXXXXXXXXXXXXX decompress", str)
else
print("XXXXXXXXXXXXXXXXX error")
end