7-zip 下lzma数据解压缩方式

来源:互联网 发布:北京数据所 编辑:程序博客网 时间:2024/05/17 16:14

那些踩过得神坑:<备注,这个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/

原创粉丝点击