You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

嵌入式设备中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);

(尝试过不同的输出缓冲区大小,问题依旧)

我已查阅并研究示例代码,尝试调整缓冲区大小、指针管理方式及配置参数/常量,但上述问题始终存在。参考的帖子提到“问题已解决”,但未说明具体解决方法。

代码中的错误点及修正方案

核心错误分析

  1. 错误的文件指针调整:当解压未完成时,src_buf_len是实际被消耗的输入字节数,剩余未消耗的字节还在ibuf中,此时调用SuperFileSeek会跳过后续文件数据,导致输入丢失。
  2. 未保留未处理的输入数据:每次循环都重新读取新输入,未处理完的ibuf数据被覆盖,丢失了部分压缩数据。
  3. 提前退出循环:当totbytes为0时直接break,忽略了可能存在的TINFL_STATUS_HAS_MORE_OUTPUT状态,导致最后一部分解压数据未被输出。
  4. 输入输出处理顺序错误:应该优先处理完所有待输出的数据(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:35:10