重启后恢复解压缩时inflate()报Z_DATA_ERROR问题咨询
错误根源
该Z_DATA_ERROR触发在STORED块处理分支,核心原因是恢复解压缩时的位对齐错误,导致zlib读取到的STORED块长度字段为错位的无效值。
恢复逻辑与状态保存的问题点
1. streamBits的获取方式完全错误
根据zlib官方文档,z_stream.data_type的高3位表示输入流中当前字节未处理的位数(范围0-7)。你目前用stream.data_type & (~0x1C0)清除第8、7、6位,实际保留的是低5位,完全不符合需求。
正确的streamBits获取方式:
streamBits = (stream.data_type >> 5) & 0x07; // 提取高3位作为未处理位数
错误的streamBits会导致后续inflatePrime传入错误的位数,直接破坏字节流的位对齐,进而解析STORED块长度时出现错误。
2. inflatePrime调用参数错误
inflatePrime的函数签名为:
int inflatePrime(z_streamp strm, int bits, int value);
- 第二个参数
bits:要插入到输入流开头的未处理位数(即你保存的streamBits) - 第三个参数
value:这些位的实际值,仅低bits位有效
你的代码中inflatePrime(, streamBits, 8 - streamBits)完全错误,正确操作流程为:
- 若streamBits>0,需读取streamCurrentPos前一个位置的字节(该字节是之前未处理完的字节)
- 将该字节的低streamBits位作为value传入inflatePrime
修正后的代码片段:
if (streamBits > 0) { // 跳转到上一个未处理完的字节位置 ZSEEK64(, , streamCurrentPos - 1, ZLIB_FILEFUNC_SEEK_SET); unz64local_getByte(, , &aByte); // 插入剩余的有效位 inflatePrime(strm, streamBits, aByte & ((1 << streamBits) - 1)); // 跳转回原本的当前字节位置 ZSEEK64(, , streamCurrentPos, ZLIB_FILEFUNC_SEEK_SET); }
3. inflateSetDictionary的调用需谨慎
只有当原解压缩过程确实使用了自定义字典(即调用过inflateSetDictionary,或压缩流由deflateSetDictionary生成)时,才需要在恢复时调用该接口。若未使用字典,此调用会引发不必要的错误。
同时需确保传入的dictionary_buf内容和dictLength与原解压缩时完全一致,否则也会导致解压缩失败。
修正后的完整恢复逻辑示例
// 初始化inflate上下文 inflateInit2(strm, ...); // 跳转到保存的字节偏移位置 ZSEEK64(, , streamCurrentPos, ZLIB_FILEFUNC_SEEK_SET); if (streamBits > 0) { // 读取上一个未处理完的字节 ZSEEK64(, , streamCurrentPos - 1, ZLIB_FILEFUNC_SEEK_SET); unz64local_getByte(, , &aByte); // 插入剩余的有效位 inflatePrime(strm, streamBits, aByte & ((1 << streamBits) - 1)); // 跳转回正确的当前位置 ZSEEK64(, , streamCurrentPos, ZLIB_FILEFUNC_SEEK_SET); } // 仅当原流使用了字典时执行此步骤 if (dictLength > 0) { inflateSetDictionary(strm, dictionary_buf, dictLength); } // 继续执行解压缩操作 inflate(strm, ...);
状态保存结构的确认
你的uncompression_state_info结构字段设计合理,但需修正streamBits的获取逻辑。另外需确认streamCurrentPos是下一个待读取字节的偏移量,若unzGetCurrentFileZStreamPos64()返回的是当前正在处理的字节偏移,保存时需加1调整。
内容的提问来源于stack exchange,提问作者Anton Fernando

