c语言lzma算法,在C中使用C-LZMA-SDK解压缩LZMA返回SZ_ERROR_DATA,因为输入流的第一个字节是!= 0...

我有一个文件,根据它的拥有者LZMA压缩.

lzmadecode.exe(程序)没有问题解码它,所以文件没有损坏,似乎确实是LZMA编码.

这是我将文件读取到缓冲区并调用UnCompress函数的代码:int main()

{

::std::ifstream lReplayFileStream("C:\\tmp\\COMPRESSED_FILE", ::std::ios::binary);

if (lReplayFileStream)

{

lReplayFileStream.seekg(0, lReplayFileStream.end);

std::streamoff lFileSize = lReplayFileStream.tellg();

lReplayFileStream.seekg(0, lReplayFileStream.beg);

char * lReplayBuffer = new char[lFileSize];

lReplayFileStream.read(lReplayBuffer, lFileSize);

if (lReplayFileStream.gcount() != lFileSize)

{

// Error

}

lReplayFileStream.close();

::std::vector inBuf(lFileSize);

::std::vector outBuf;

memcpy(&inBuf[0], lReplayBuffer, lFileSize);

UNCOMPRESSED_SIZE = lFileSize + lFileSize * 3;

UnCompress(outBuf, inBuf);

delete[] lReplayBuffer;

}

return EXIT_SUCCESS;

}

这是UnCompress功能(不是我写的,是我从互联网上获得的一个例子):static void UnCompress(std::vector &outBuf, const std::vector &inBuf)

{

outBuf.resize(UNCOMPRESSED_SIZE);

unsigned dstLen = outBuf.size();

unsigned srcLen = inBuf.size() - LZMA_PROPS_SIZE;

SRes res = LzmaUncompress(&outBuf[0], &dstLen, &inBuf[LZMA_PROPS_SIZE], &srcLen, &inBuf[0], LZMA_PROPS_SIZE);

outBuf.resize(dstLen); // If uncompressed data can be smaller

}

该文件以以下字节开头:

5D 00 00 20 00 B6 EC 07 00

或者用ASCII:]. . . ¶ 一世 . .

LZMA_PROPS_SIZE始终为5.

正如您在UnCompress函数中看到的那样,inBuf被传递给LzmaUncompress()函数,偏移量为LZMA_PROP_SIZE,可能是标题?

我调试了代码并发现,在LzmaUncompress()的子例程中,如果inBuf [0]!= 0则检查它,如果是,则返回SZ_ERROR_DATA.

如您所见,p-> tmpBuf [0]的字节(即inBuf)是¶,它是十六进制B6.这是inBuf的第6个字节,因为inBuf LZMA_PROP_SIZE(5).

我真的不太了解LZMA,但为什么LZMA_PROP_SIZE之后的第一个字节必须为0,为什么lzmadecompress.exe解压缩它,当它使用相同的功能?

我究竟做错了什么?

最佳答案 解

LZMA_PROP_SIZE之后的下一个8字节是未压缩数据的大小,因此是标头的一部分.程序失败,因为我试图解码文件,前8个字节是标题的一部分.

要解决这个问题,我只需要编辑这两行:unsigned srcLen = inBuf.size() - LZMA_PROPS_SIZE - 8;

SRes res = LzmaUncompress(&outBuf[0], &dstLen, &inBuf[LZMA_PROPS_SIZE + 8], &srcLen, &inBuf[0], LZMA_PROPS_SIZE);

>从srcLen中减去8个字节

>将8字节添加到LzmaUncompress()开始解码的偏移量.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用LZMA SDK对7z文件进行解压缩,需要先了解7z文件的结构。7z文件实际上是一个压缩文件,其包含多个压缩数据块和一个头文件,头文件包含了每个压缩数据块的信息。因此,我们需要先读取头文件,然后逐个解压数据块。 以下是一个简略的C语言例程,用于对7z文件进行解压缩: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <lzma.h> #define LZMA_PROPERTIES_SIZE 5 int main(int argc, char *argv[]) { if (argc < 3) { printf("Usage: %s input_file output_dir\n", argv[0]); return 1; } char *input_filename = argv[1]; char *output_dirname = argv[2]; // 打开输入文件 FILE *input_file = fopen(input_filename, "rb"); if (input_file == NULL) { printf("Error: Failed to open input file.\n"); return 1; } // 读取7z头文件 uint8_t header[32]; if (fread(header, 1, 32, input_file) != 32) { printf("Error: Failed to read 7z header.\n"); fclose(input_file); return 1; } // 验证7z头文件 if (memcmp(header, "\x37\x7A\xBC\xAF\x27\x1C", 6) != 0) { printf("Error: Invalid 7z header.\n"); fclose(input_file); return 1; } // 获取7z头文件信息 uint8_t properties[LZMA_PROPERTIES_SIZE]; uint64_t header_size; lzma_stream_flags flags; memcpy(properties, header + 6, LZMA_PROPERTIES_SIZE); header_size = *(uint64_t *)(header + 13); flags = *(lzma_stream_flags *)(header + 21); // 初始化LZMA解压缩lzma_stream lzma_strm = LZMA_STREAM_INIT; lzma_ret ret = lzma_stream_decoder(&lzma_strm, UINT64_MAX, LZMA_CONCATENATED); if (ret != LZMA_OK) { printf("Error: Failed to initialize LZMA decoder.\n"); fclose(input_file); return 1; } // 创建输出目录 char output_filename[256]; sprintf(output_filename, "%s/", output_dirname); mkdir(output_filename, 0777); // 分配输入输出缓冲区 uint8_t *input_buf = malloc(flags.dict_size); uint8_t *output_buf = malloc(LZMA_BUFLEN); if (input_buf == NULL || output_buf == NULL) { printf("Error: Failed to allocate memory.\n"); free(input_buf); free(output_buf); lzma_end(&lzma_strm); fclose(input_file); return 1; } // 解压缩数据块 uint64_t offset = header_size; uint64_t uncompressed_size = 0; while (1) { // 读取数据块头信息 uint8_t block_header[17]; if (fread(block_header, 1, 17, input_file) != 17) { printf("Error: Failed to read block header.\n"); break; } // 获取数据块信息 uint64_t block_size = *(uint64_t *)(block_header + 1); uint8_t block_type = block_header[9]; // 设置LZMA输入缓冲区 lzma_strm.next_in = input_buf; lzma_strm.avail_in = block_size; // 设置LZMA输出缓冲区 lzma_strm.next_out = output_buf; lzma_strm.avail_out = LZMA_BUFLEN; // 解压数据块 while (1) { ret = lzma_code(&lzma_strm, LZMA_RUN); if (ret != LZMA_OK && ret != LZMA_STREAM_END) { printf("Error: Failed to decode LZMA data.\n"); free(input_buf); free(output_buf); lzma_end(&lzma_strm); fclose(input_file); return 1; } fwrite(output_buf, 1, lzma_strm.next_out - output_buf, output_file); lzma_strm.next_out = output_buf; lzma_strm.avail_out = LZMA_BUFLEN; if (ret == LZMA_STREAM_END) { break; } } // 更新偏移量和解压缩大小 offset += block_size + 17; uncompressed_size += *(uint64_t *)(block_header + 10); // 如果解压缩大小等于文件大小,则说明解压缩完成 if (uncompressed_size >= flags.uncompressed_size) { break; } } // 释放资源 free(input_buf); free(output_buf); lzma_end(&lzma_strm); fclose(input_file); printf("Done.\n"); return 0; } ``` 这个例程通过LZMA SDK提供的API实现了7z文件的解压缩功能。在解压缩过程,我们需要先读取7z头文件,然后逐个解压缩数据块。在解压缩数据块时,我们需要先读取数据块头信息,然后设置LZMA输入输出缓冲区,调用`lzma_code`函数解压缩数据,最后写入输出文件。在解压缩完成后,我们需要调用`lzma_end`函数释放资源。 注意:这个例程仅适用于对单个7z文件进行解压缩。如果需要解压缩多个7z文件,需要先读取7z头文件,然后逐个解压缩7z文件的数据块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值