一直想解码酷狗的krc格式文件,但是苦于没有找到资料,最近在吾爱破解发现了一篇文章讲解码krc文件的(地址),我就打算自己试试。文中解码使用了 zlib 库,所以便看看如何使用Zlib库,也算是积累一点知识吧。
在写这些代码的时候,遇到了一些问题,就包括上一篇讲的Qt断点无法断下,还有QByteArray的对象转char *时会截断'\0'(我最想吐槽这一点,花了我很长时间在解压函数上)。
2015.6.29 Note
ZLibGetDecodeLength被用在ZlibUncompress函数中仍然有空间不足的危险, Zlib建议设置一个固定的缓冲区,且缓冲区大小与解压速度相关联.
/************************************************
* [Qt]简单使用 Zlib 库压缩/解压数据
* DownLoad: http://be18e3.l5.yunpan.cn/lk/cQW55yPJ8b78r (2c5b)
* By sunnysab 2015.6.18 - 6.28
************************************************/
#include <QCoreApplication>
#include <QByteArray>
#include "zlib.h"
/*
* 函 数: ZlibGetDecodeLength
* 功 能: 通过要压缩的数据大小,得到压缩后数据的最大大小
* 以此设置缓冲区
* 参 数: uLong InRawLength 压缩前数据大小
*
*/
int ZlibGetDecodeLength(uLong InRawLength)
{
return compressBound(InRawLength);
}
/*
* 函 数: ZlibGetDecodeLength
* 功 能: 通过要压缩的数据大小,得到压缩后数据的最大大小
* 以此设置缓冲区
* 参 数: QByteArray InRawData 压缩前数据
*
*/
int ZlibGetDecodeLength(QByteArray InRawData)
{
// 注:
// ((QByteArray)"Hello").size() == 5
// 因为当字符串为 QByteArray , '\0' 被忽略
return compressBound(InRawData.length());
}
/*
* 函 数: ZlibCompress
* 功 能: 执行压缩操作
* 参 数: QByteArray &OutEncodeData 压缩后数据
* QByteArray InRawData 要压缩的数据
int * nErrorCode 错误代码
* 说 明: 当 nErrorCode 不为 NULL 时, 若 compress 出错后, 其数据改为
* compress 返回的错误代码. 在 zlib.h 中可以找到.
* 例如: -5 缓冲区长度不够
* 返回值: 类型 long
* 返回压缩后的长度, -1 表示压缩失败, 请检查 *nErrorCode .
*/
long ZlibCompress(QByteArray &OutEncodeData, QByteArray InRawData,
int * nErrorCode = NULL)
{
Bytef *EncodeData = NULL; // 压缩后的数据暂存于此
int nFuncRet = Z_ERRNO; // 随便找个错误代码先填着
long nOutLength = 0;
// 申请最大缓冲区
nOutLength = ZlibGetDecodeLength(InRawData.length());
EncodeData = new Bytef[nOutLength];
if (NULL != EncodeData)
{
// 调用 compress 函数前, nOutLength 要置为缓冲区大小
nFuncRet = compress(EncodeData, (uLongf *)&nOutLength, (Bytef *)InRawData.data(),
InRawData.length());
if (Z_OK == nFuncRet)
{
// 自己设置好长度为好, 省的 '\0' 被截断了
OutEncodeData.append((const char *)EncodeData, nOutLength);
}
else
{
nOutLength = -1;
}
}
delete EncodeData;
// 输出错误代码
if (NULL != nErrorCode)
{
*nErrorCode = nFuncRet;
}
return nOutLength;
}
/*
* 函 数: ZlibUnCompress
* 功 能: 执行解压操作
* 参 数: QByteArray &OutDecodeData 解压后数据
* QByteArray InEncodeData 要解压的数据
int * nErrorCode 错误代码
* 说 明: 当 nErrorCode 不为 NULL 时, 若 uncompress 出错后, 其数据改为
* uncompress 返回的错误代码. 在 zlib.h 中可以找到.
* 例如: -5 缓冲区长度不够
* 返回值: 类型 long
* 返回解压后的长度, -1 表示解压失败, 请检查 *nErrorCode .
*/
long ZlibUncompress(QByteArray &OutDecodeData, QByteArray InEncodeData,
int * nErrorCode = NULL)
{
Bytef *DecodeData = NULL; // 解压后的数据缓冲区
Bytef *EncodeData_Buffer = NULL; // 要解压的数据缓冲区, 后面用memcpy放到这
int nFuncRet = Z_ERRNO;
unsigned long nOutLength = 0;
// 说明:
// 如果压缩后大小比之前小, 缓冲区大小应该设置多少?
// 暂且把 ZlibGetDecodeLength 拿来用用, 确保缓冲区够了.
nOutLength = ZlibGetDecodeLength(InEncodeData.length());
// 为缓冲区申请内存
DecodeData = new Bytef[nOutLength];
EncodeData_Buffer = new Bytef[nOutLength];
if (NULL != DecodeData && NULL != EncodeData_Buffer)
{
// 由于 QByteArray 在 data() 函数中会因为'\0'截断
// (先鄙视一下,那还叫什么字节操作)
// 文档又说,constData() 效率高
// 所以用 constData() 获取地址然后 memcpy 自己复制
memcpy(EncodeData_Buffer, InEncodeData.constData(), InEncodeData.size());
nFuncRet = uncompress(DecodeData, &nOutLength, (Bytef *)EncodeData_Buffer,
InEncodeData.length());
if (Z_OK == nFuncRet)
{
OutDecodeData.append((const char *)DecodeData, nOutLength);
}
else
{
nOutLength = -1;
}
}
else
{
nOutLength = -1;
}
// 清理 new 产生的内存
if (NULL != DecodeData)
{
delete DecodeData;
}
if (NULL != EncodeData_Buffer)
{
delete EncodeData_Buffer;
}
// 输出错误代码
if (NULL != nErrorCode)
{
*nErrorCode = nFuncRet;
}
return nOutLength;
}
int main(int argc, char *argv[])
{
QCoreApplication AppInstance(argc, argv);
QByteArray strEncode;
QByteArray strDecode;
int nFuncRet = 0;
nFuncRet = ZlibCompress(strEncode, (QByteArray)"Hello World");
printf("retCompress = %d\n", nFuncRet);
nFuncRet = ZlibUncompress(strDecode, strEncode);
printf("retUnCompress = %d\n", nFuncRet);
printf("data = %s\n", strDecode.data());
return AppInstance.exec();
}