如何附加到 zlib 流?

How to append to a zlib stream?

我一直在尝试使用 zlib 库提供的 deflatePrime 函数将原始字节附加到现有的 zlib 流。但是,我无法理解 deflatePrime(z_streamp strm,int bits,int value); 的第二个和第三个参数是什么,除了文档中的一个小注释表明它应该小于或等于 16 以及 gzlog.c 示例中的一些提示。 在文件中,它是这样调用的:

deflatePrime(&strm, (8 - log->back) & 7, *buf);

log->back的定义是:

 int back;       /* location of first block id in bits back from first */

初始化如下:

log->back = 3 + (buf[HEAD + 34] & 7);
  1. 什么是block id
  2. 超出 HEAD 范围的 buf[HEAD + 34] 应该指向什么?
  3. 为什么在log->back中添加了一个任意的3

deflate 块是位序列,而不是字节,可以在流中的任何位位置开始和结束。所以一个块可以从一个字节的中间某处开始,也可以在另一个字节的中间某处结束。

您已经使用 deflateInit() 开始了一个新的原始 deflate 流。一旦你开始向 deflate() 提供字节,它就会及时将比特流作为字节序列发出。 但是,在前一个 deflate 块的最后一个完整字节之后还剩下一些位。您想在 before 将要发出的位中插入这些位。这就是 deflatePrime(strm, bits, value) 让你做的。它在 soon-to-be-emitted 位流的开头插入 value 的最低有效位的 bits 位。您需要在第一个 deflate() 调用之前调用它。

在 gzlog 中,这用于在先前的 deflate 块之后附加新的 deflate 块。您首先切掉最后一个块,留下最后一个放气块,其中包含数据。最后一个放气块可能(概率为 0.875)在一个字节的中间某处结束。在这种情况下,您可以保存前一个块的最后几位,以便在下一个块之前插入。您将使用 deflatePrime().

进行插入

区块id是每个deflate区块的前三位。所以块id的位置就是块开始的位置。 log->back 是块开始从存储块中的第一个长度返回的位数,它本身总是在字节边界上。一个存储块是三个 header 位,从一个字节中的任意位置开始,然后是足够的填充零位以到达字节边界,然后是存储块长度和数据,所有这些都在字节边界上。返回的位数至少为三,因为 header 是三位。它可能最早可以追溯到十位,即三位加上七个填充位。它不能再往前了,因为再往前一位并且它以字节边界结束,所以没有填充位。 log->back 因此在 3..10.

那么最后一个完整字节后前一个块中剩余的位数是八减log->back,模八。因此,如果 log->back 是 6,那么在之前的 deflate 块中有两位。如果 log->back 为 10,则 header 的前两位在第二个字节后面,header 的最后一位在最后一个字节,后面是七个填充位。那么前一个deflate块的位数是6.

为了取回位,在额外块中保存的内容上加上三,因为保存时减去三:ext[34] = log->back - 3 + (op << 3);(操作码也保存在该字节的其他位中).那么为什么先减去三再加呢?这样 3..10 的值可以存储在额外字段中的三个位中作为 0..7。我不再解释它是什么,而是从源代码注释中复制:

   - First stored block start as the number of bits back from the final stored
     block first length byte.  This value is in the range of 3..10, and is
     stored as the low three bits of the final byte of the extra field after
     subtracting three (0..7).  This allows the last-block bit of the stored
     block header to be updated when a new stored block is added, for the case
     when the first stored block and the last stored block are the same.  (When
     they are different, the numbers of bits back is known to be eight.)  This
     also allows for new compressed data to be appended to the old compressed
     data in the compress operation, overwriting the previous first stored
     block, or for the compressed data to be terminated and a valid gzip file
     reconstructed on the off chance that a compression operation was
     interrupted and the data to compress in the foo.add file was deleted.

我不知道你所说的“超出 HEAD 范围”是什么意思。即一个字节在额外块中的偏移量。