如何用一个非常旧的 zlib 给 gzip 充气?

How to inflate a gzip with a really old zlib?

我使用的是移植了旧版本 zlib 的 PPC 平台。是否可以使用 zlib 1.1.3 来扩充使用 gzip 1.5 制作的存档?

$ gzip --list --verbose vmlinux.z
method  crc     date  time           compressed        uncompressed  ratio uncompressed_name
defla 12169518 Apr 29 13:00             4261643             9199404  53.7% vmlinux

存档的前 32 个字节是

00000000  1f 8b 08 08 29 f4 8a 60  00 03 76 6d 6c 69 6e 75  |....)..`..vmlinu|
00000010  78 00 ec 9a 7f 54 1c 55  96 c7 6f 75 37 d0 fc 70  |x....T.U..ou7..p|

我已经尝试使用此代码(其中源是指向 1f 8b 处第一个字节的指针)和三个选项 A、B 和 C 来进行 WBIT 初始化。

int ZEXPORT gunzip (dest, destLen, source, sourceLen)
    Bytef *dest;
    uLongf *destLen;
    const Bytef *source;
    uLong sourceLen;
{
    z_stream stream;
    int err;

    stream.next_in = (Bytef*)source;
    stream.avail_in = (uInt)sourceLen;
    /* Check for source > 64K on 16-bit machine: */
    if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;

    stream.next_out = dest;
    stream.avail_out = (uInt)*destLen;
    if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;

    stream.zalloc = (alloc_func)my_alloc;
    stream.zfree = (free_func)my_free;

    /* option A */
    err = inflateInit(&stream);
    /* option B */
    err = inflateInit2(&stream, 15 + 16);
    /* option C */
    err = inflateInit2(&stream, -MAX_WBITS);
 
    if (err != Z_OK) return err;

    err = inflate(&stream, Z_FINISH);
    if (err != Z_STREAM_END) {
        inflateEnd(&stream);
        return err == Z_OK ? Z_BUF_ERROR : err;
    }
    *destLen = stream.total_out;

    err = inflateEnd(&stream);
    return err;
}

选项A:

zlib inflate() 失败并出现错误 Z_DATA_ERROR。 "unknown compression method"
z_stream.avail_in  = 4261640
z_stream.total_in  = 1
z_stream.avail_out = 134152192
z_stream.total_out = 0

选项 B:

zlib inflateInit2_() 在第 118 行失败并显示 Z_STREAM_ERROR。
  /* set window size */
  if (w < 8 || w > 15)
  {
    inflateEnd(z);
    return Z_STREAM_ERROR;
  }

选项 C:

zlib inflate() 失败并出现错误 Z_DATA_ERROR。 "invalid block type"
z_stream.avail_in  = 4261640
z_stream.total_in  = 1
z_stream.avail_out = 134152192
z_stream.total_out = 0

您的选项 B 适用于 zlib 1.2.1 或更高版本。

对于 zlib 1.1.3,有两种方法。

  1. 使用 gzopen()gzread()gzclose() 从文件中读取 gzip 流并解压缩到内存中。

  2. 要从内存中的 gzip 流解压缩,请使用选项 C,raw inflate,after 手动解码 gzip header。使用 crc32() 来计算解压缩数据的 CRC-32,因为你膨胀它。 inflation 完成后,手动解码 gzip 尾部,检查 CRC-32 和解压缩数据的大小。

手动解码 gzip header 和预告片很容易实现。有关 header 和预告片的说明,请参阅 RFC 1952