那些踩过得神坑:<备注,这个demo的例子有一处是不对的.>
LzmaDecode中的第四个参数:nCompBufLen 应该给第三个参数的实际缓冲区大小.!!!,我操.分析源码.和返回值,百度没有.
本文章介绍的是 LZMA SDK 9.20
7z LZMA 至少需要这三个源文件
LzmaEnc.c
LzmaDec.c
LzFind.c
和这五个头文件
LzFind.h
LzHash.h
LzmaDec.h
LzmaEnc.h
Types.h
LZMA2 需要在此基础上附加两个源文件
Lzma2Dec.c
Lzma2Enc.c
以及两个头文件
Lzma2Dec.h
Lzma2Enc.h
LZMA 流接口有 6 个函数,参数含义可顾名思义
CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc);
void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig);
SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
CLzmaEncHandle 实为 void *
SRes 为状态返回类型
ISzAlloc、ISeqInStream、ISeqOutStreaem 和 ICompressProgress 为用户需要提供的四个接口,它们的定义如下
typedef struct
{
void *(*Alloc)(void *p, size_t size);
void (*Free)(void *p, void *address); /* address can be 0 */
} ISzAlloc;
typedef struct
{
SRes (*Read)(void *p, void *buf, size_t *size);
/* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
(output(*size) < input(*size)) is allowed */
} ISeqInStream;
typedef struct
{
size_t (*Write)(void *p, const void *buf, size_t size);
/* Returns: result - the number of actually written bytes.
(result < size) means error */
} ISeqOutStream;
typedef struct
{
SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
/* Returns: result. (result != SZ_OK) means break.
Value (UInt64)(Int64)-1 for size means unknown value. */
} ICompressProgress;
另外注意在实现 ISeqInStream 时,除最后两次调用外,必须每次都提交 *size 字节的数据,最后两次中,一次提交所有剩余数据,另一次提交 0 字节表示结束,否则 LZMA Encoder 会崩溃。
还有一个 One-Call 接口,把上面的调用按照常规逻辑包装了一下
SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
LZMA2 的接口与 LZMA 类似,主要不同之处有两点:
- alloc 和 allocBig 接口被放到了构造函数中
- props 中多了一些参数
http://www.7-zip.org/sdk.html
另外值得一提的是,LZMA 单线程在笔记本电池供电时,使用快速模式,对随机数据的压缩速度为 4MB/s,压缩率约为 100%,对全零数据的压缩速度为 70MB/s,压缩率约为 0%。
经过SunOS sun280 5.10验证的实例(该实例为直接调用封装好的函数):
/* * Simple test program for LZMA SDK's "one call" interface. * */
#include <stdio.h>
#include <string.h>
#include "../../LzmaEnc.h"
#include "../../LzmaDec.h"
#include "../../Alloc.h"
#define COMP_BUFLEN 1000
#define UNCOMP_BUFLEN 5000
char* pTestData;
unsigned char pCompBuf[1000]; /* Compressed data */
unsigned char pUnCompBuf[5000]; /* Unompressed data - at the end its contents */
/* should be equal to contents of pTestData */
static void *SzAlloc(void *p, size_t size) { return MyAlloc(size); }
static void SzFree(void *p, void *address) { MyFree(address); }
int main(int argc, char* argv[])
{
pTestData = "DEADBEEF|askjd9827x34bnzkj#%wioeruxo3b84nxijlhwqdzhwerzu39b87r#_3b9p78bznor83y4fr";
size_t nTestDataLen = strlen(pTestData);
size_t nCompBufLen = COMP_BUFLEN;
size_t nUnCompBufLen = UNCOMP_BUFLEN;
unsigned char pPropsBuf[LZMA_PROPS_SIZE];
size_t nPropsBufLen = LZMA_PROPS_SIZE;
ISzAlloc stAllocator = { SzAlloc, SzFree };
CLzmaEncProps stProps;
ELzmaStatus nStatus;
SRes rc;
int err = 0;
memset(pCompBuf, 0, COMP_BUFLEN);
memset(pUnCompBuf, 0, UNCOMP_BUFLEN); /* Initialize compressor (aka encoder) properties... */
LzmaEncProps_Init(&stProps);
stProps.level = 9;
stProps.dictSize = 1 << 24;
/* ... and compress data. */
printf("dest_len:%d,src_len:%d,prop_len:%d\n",nCompBufLen,nTestDataLen,nPropsBufLen);
rc = LzmaEncode(pCompBuf+LZMA_PROPS_SIZE, &nCompBufLen, (unsigned char*)pTestData, nTestDataLen, &stProps, pPropsBuf, &nPropsBufLen, 0, NULL, &stAllocator, &stAllocator);
if ( rc != SZ_OK )
{
printf("\nLZMA compression failed (rc=%d).\n", rc);
err = 1;
}
else
{
printf("dest_address:%p,dest_len:%d,src_len:%d,dest:%s\n",pCompBuf,nCompBufLen,nTestDataLen,pCompBuf+LZMA_PROPS_SIZE+1);
}
/* Decompress compressed data from previous step */
//nCompBufLen += LZMA_PROPS_SIZE;
nUnCompBufLen = nTestDataLen;
rc = LzmaDecode(pUnCompBuf, &nUnCompBufLen, pCompBuf+LZMA_PROPS_SIZE, &nCompBufLen, pPropsBuf, nPropsBufLen, LZMA_FINISH_ANY, &nStatus, &stAllocator);
if ( rc != SZ_OK )
{
printf("\nLZMA decompression failed (rc=%d, status=%d).\n", rc, nStatus);
err = 1;
}
if ((nUnCompBufLen != nTestDataLen) || memcmp(pTestData, pUnCompBuf, nTestDataLen) )
{
printf("Compression and/or decompression failed!\n");
printf("\tInput data length [nTestDataLen] : %d\n", nTestDataLen);
printf("\tCompressed data length [nCompBufLen] : %d\n", nCompBufLen);
printf("\tUncompressed data length [nUnCompBufLen]: %d\n", nUnCompBufLen);
if ( memcmp(pTestData, pUnCompBuf, nTestDataLen) )
printf("\tpTestData and pUnCompBuf contain different data!\n");
else
{
printf("\ndest_len:%d\n,dest_data:%s\n,src_src:%s\n",nUnCompBufLen,pUnCompBuf,pTestData);
}
err = 1;
}
printf("\ndest_len:%d\n,dest_data:%s\n,src_src:%s\n",nUnCompBufLen,pUnCompBuf,pTestData);
if ( !err )
printf("\nOK!\n");
return 0;
}
详情请浏览sdk说明文档或者LZMA官方论坛(http://sourceforge.net/projects/sevenzip/forums/forum/45797/topic/4698263)
备注:
整整三天才搞出来,今天终于可以好好睡觉了。学编程的同学啊,要加强英语的学习啊。
原文转载自:http://blog.163.com/linzhigui1988@126/blog/static/1018865812012499356225/