puff.c霍夫曼解码是如何工作的?



我试图解压缩一个原始DEFLATE数据流,以了解DEFLATE解压缩是如何工作的。我现在不关心表现。我只是想详细地了解解压缩算法,所以我在网上搜索了一些例子,偶然发现了Mark Adler的程序puff.c

我想解压缩这段原始DEFLATE数据:

05 C1 01 01 00 00 08 C3 20 6E FF CE 13 44 D2 4D C2 03

它是用动态霍夫曼码压缩的单个块。RFC-1951对块的整体结构给出了一个很好的概述。在块头之后,有4-19个3位整数,它们定义了码长字母表的码长;之后是文字/长度和距离字母的代码长度,最后是实际压缩的数据。到目前为止一切都好……

我看了看puff.c,看看霍夫曼解码过程的实现应该是什么样子的。

在函数construct(第340-379行)中,创建了字母表的符号表,然后在解码过程中使用。在函数decode(第235-255行)中,使用符号表和码长频率表对单个符号进行解码。这个函数让我头疼。我不明白符号、码长频率和实际输入比特流之间的关系。还有检查

if (code - count < first)       /* if length len, return symbol */

247行的对我来说纯粹是巫术。我在网上搜索解码过程的详细解释,但我没有找到任何解释如此深刻。

你能解释一下这个过程/解码功能吗?

这里是puff.c的链接,如果你想看一下。

关键是要理解deflate中使用的霍夫曼码是规范的,这意味着分配给符号的0和1的序列完全取决于代码的位长度和符号的顺序。顺序在RFC中指定,例如,文字/长度代码从0到255的顺序的文字字节开始,然后是单个块结束码,然后是长度代码从最短到最长的顺序。对于任何给定的,例如,动态头文件中描述的文字/长度代码,通常只有这些符号的一个子集会在块中实际使用,并且为它们定义了代码。

deflate中的约定是将最短代码的第一个有序符号赋值为全零。然后,对于该长度的剩余符号,按顺序将代码作为整数(这是键)递增。为了升到下一个长度,在前一个长度的最后一个符号后面加一个0位(即加倍)。

对于解码,我所需要的是a)按位长度顺序编码的符号列表,并且在每个位长度内,按符号顺序排序,b)每个位长度的符号数量,它们必须加起来等于列表中的符号数量。

puff.c中使用的解码方案是从比特长度列表中最短的比特长度开始,并获得那么多比特。现在我检查这些位的值,作为整数,是否小于或等于该长度的最后一个代码。如果是这样,我就有了当前代码的所有位,并且我可以通过索引a)中的符号列表来返回相应的符号。如果整数的值大于,那么我知道我需要更多的位来存储这段代码。我从流中再向整型追加一位,并对下一个代码长度重复此过程。

这有点复杂,因为比特在流中是以相反的顺序存储的。当我从连续的位建立整数时,我需要翻转顺序,以便我可以将结果解释为可以比较的整数。

因此,if (code - count < first)可以读为if (code < first + count)if (code <= first + count - 1),即code是否小于或等于该长度的最后一个代码。如果是,我们有代码,对应的符号是h->symbol[index + (code - first)],其中index是当前长度的第一个符号在符号列表中的位置。

最新更新