DEFLATE:如何处理 "no distance codes" 的情况?

DEFLATE: how to handle "no distance codes" case?

我主要了解 RFC 1951,但是我不太清楚如何管理(使用动态霍夫曼表时)不需要或不存在距离代码的情况。例如,让我们输入:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890987654321ZYXWVUTSR

因为没有长度 >= 3 的重复,所以不可能有反向引用。 根据 RFC 1951,无论如何都必须至少存在一个距离代码,否则将无法对 HDIST - 1 进行编码。根据参考文献,我理解这样的代码应该是零位以表示“无距离代码” ".

One distance code of zero bits means that there are no distance codes used at all (the data is all literals).

在 infgen 符号中,我希望看到 dist 0 0

分析 gzip 对 infgen 的作用,但是,我看到为上述输入发出了两个距离代码(每个 1 位长)(即使当时实际使用了 none):

! infgen 2.4 output
!
gzip
!
last
dynamic
litlen 48 6
litlen 49 6
litlen 50 6
...cut...
litlen 121 6
litlen 122 6
litlen 256 6
dist 0 1
dist 1 1
literal 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890987654321Z
literal 'YXWVUTSR
end
!
crc
length

那么在这些情况下正确的行为是什么?

如果 deflate 块中没有匹配项,length/literal 代码将没有长度,因此解码器永远不会寻找距离代码。在那种情况下,最有意义的是根本不提供任何关于距离代码的信息。

但是格式不允许这样做,因为 header 中的 5 位 HDIST 值被解释为 1 到 32 个距离代码,必须在 header。您必须在 header 中至少提供一个距离代码长度,即使它永远不会被使用。

在这种情况下,您可以做几件有效的事情。 RFC 1951 说明您可以提供长度为零的单个距离代码(HDIST == 0,表示一个长度),这在长度列表中只是一个零。

也允许提供一个长度为1的代码,或者你也可以像zlib做的那样,提供两个长度为1的代码。实际上,您可以在那里放置任何您喜欢的有效距离代码描述,它仍然会被接受。

至于为什么 zlib 的 deflate 选择在那里定义两个代码,我只能猜测 Jean-loup 是保守的,写了一些他知道即使是 over-simplified 充气机也必须接受的东西。 gzip 和 zopfli 做同样的事情。当只使用一个距离代码时,它们都做同样的事情。根据 RFC,它们可以仅发出单个 one-bit 距离代码,但它们发出两个 single-bit 距离代码,其中一个从未使用过。

真正正确的做法是写一个零长度,如 RFC 中所述,这将占用 header 中最少的位数。我会考虑更新 zlib 来做到这一点,以增加一些压缩。