嵌入式设备中MINIZ库tinfl_decompress解压数据损坏问题排查
嵌入式设备中MINIZ库解压字节损坏问题排查
我在嵌入式设备中使用MINIZ库,除了解压环节外其余功能正常。问题表现为:仅当解压后数据大小小于输出缓冲区时代码正常运行,否则会出现字节损坏。我知道需要处理TINFL_STATUS_HAS_MORE_OUTPUT返回码,但多次尝试后仍未解决,问题和Stack Exchange上的相关提问情况类似。
问题代码
int i=0; tinfl_decompressor decomp; tinfl_status status; uint8_t ibuf[256],obuf[TINFL_LZ_DICT_SIZE]; size_t src_buf_len,out_buf_len; int out_buf_ofs; *crc=0xffffffff; *len=0; tinfl_init(&decomp); out_buf_ofs=0; src_buf_len=sizeof(ibuf); do { src_buf_len=SuperFileRead(f1,ibuf,min(totbytes,sizeof(ibuf))); out_buf_len=TINFL_LZ_DICT_SIZE-out_buf_ofs; status = tinfl_decompress(&decomp,ibuf,&src_buf_len, obuf, ((uint8_t*)obuf)+out_buf_ofs, &out_buf_len, (totbytes>0 ? TINFL_FLAG_HAS_MORE_INPUT : 0)); totbytes-=src_buf_len; if(status != TINFL_STATUS_DONE) SuperFileSeek(f1,src_buf_len-sizeof(ibuf),SEEK_CUR); // occhio alla fine... //ovvero SuperFileSeek(f1, ,SEEK_SET); if(out_buf_len) { if(SuperFileWrite(f2,((uint8_t*)obuf)+out_buf_ofs,out_buf_len) != out_buf_len) break; *len+=out_buf_len; } *crc=crc32array(((uint8_t*)obuf)+out_buf_ofs,out_buf_len,*crc); out_buf_ofs = (out_buf_ofs+out_buf_len) & (TINFL_LZ_DICT_SIZE-1); if(!totbytes) // safety cmq break; } while(status==TINFL_STATUS_NEEDS_MORE_INPUT || status == TINFL_STATUS_HAS_MORE_OUTPUT); *crc=~Reflect32(*crc);
(尝试过不同的输出缓冲区大小,问题依旧)
我已查阅并研究示例代码,尝试调整缓冲区大小、指针管理方式及配置参数/常量,但上述问题始终存在。参考的帖子提到“问题已解决”,但未说明具体解决方法。
代码中的错误点及修正方案
核心错误分析
- 错误的文件指针调整:当解压未完成时,
src_buf_len是实际被消耗的输入字节数,剩余未消耗的字节还在ibuf中,此时调用SuperFileSeek会跳过后续文件数据,导致输入丢失。 - 未保留未处理的输入数据:每次循环都重新读取新输入,未处理完的
ibuf数据被覆盖,丢失了部分压缩数据。 - 提前退出循环:当
totbytes为0时直接break,忽略了可能存在的TINFL_STATUS_HAS_MORE_OUTPUT状态,导致最后一部分解压数据未被输出。 - 输入输出处理顺序错误:应该优先处理完所有待输出的数据(
TINFL_STATUS_HAS_MORE_OUTPUT),再读取新的输入,避免环形缓冲区覆盖。
修正后的代码
int i=0; tinfl_decompressor decomp; tinfl_status status; uint8_t ibuf[256], obuf[TINFL_LZ_DICT_SIZE]; size_t src_avail = 0; // 记录ibuf中未处理的字节数 size_t out_buf_len; int out_buf_ofs = 0; *crc = 0xffffffff; *len = 0; tinfl_init(&decomp); do { // 仅当输入缓冲区无剩余数据时,才读取新的输入 if (src_avail == 0 && totbytes > 0) { src_avail = SuperFileRead(f1, ibuf, min(totbytes, sizeof(ibuf))); totbytes -= src_avail; } out_buf_len = TINFL_LZ_DICT_SIZE - out_buf_ofs; status = tinfl_decompress(&decomp, ibuf + (sizeof(ibuf) - src_avail), &src_avail, obuf, ((uint8_t*)obuf) + out_buf_ofs, &out_buf_len, (totbytes > 0 || src_avail > 0) ? TINFL_FLAG_HAS_MORE_INPUT : 0); // 处理输出数据 if (out_buf_len > 0) { if (SuperFileWrite(f2, ((uint8_t*)obuf) + out_buf_ofs, out_buf_len) != out_buf_len) { break; } *len += out_buf_len; *crc = crc32array(((uint8_t*)obuf) + out_buf_ofs, out_buf_len, *crc); out_buf_ofs = (out_buf_ofs + out_buf_len) & (TINFL_LZ_DICT_SIZE - 1); } // 当输出缓冲区已满且还有更多输出时,先处理完输出再读取新输入 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT || status == TINFL_STATUS_HAS_MORE_OUTPUT); *crc = ~Reflect32(*crc);
关键修正说明
- 新增
src_avail变量跟踪输入缓冲区中未被消耗的字节数,避免丢失未处理的压缩数据。 - 仅当输入缓冲区为空时才读取新数据,确保未处理的数据被保留并在下一次解压时使用。
- 调整
TINFL_FLAG_HAS_MORE_INPUT的判断条件,只要还有剩余输入(文件未读完或缓冲区有剩余)就标记该标志。 - 移除错误的
SuperFileSeek调用,不再手动调整文件指针,由src_avail管理输入缓冲区的剩余数据。 - 修正循环退出逻辑,确保所有待输出的数据都被处理完毕。
内容的提问来源于stack exchange,提问作者dario
相关产品推荐
相关产品推荐

