【问题标题】:The structure of Deflate compressed blockDeflate压缩块的结构
【发布时间】:2015-09-06 01:08:35
【问题描述】:

我无法理解 Deflate 算法 (RFC 1951)。

TL; DR如何解析Deflate压缩块4be4 0200

我创建了一个包含字母和换行符a\n 的文件,然后运行gzip a.txt。结果文件a.txt.gz:

1f8b 0808 fe8b eb55 0003 612e 7478 7400

4be4 0200

07a1 eadd 0200 0000

我知道第一行是带有附加信息的标题,最后一行是 CRC32 加上输入大小 (RFC 1951)。这两个对我没有任何麻烦。

但是我如何解释压缩块本身(中间线)?

这是它的十六进制和二进制表示:

4be4 0200

0100 1011
1110 0100
0000 0010
0000 0000

据我了解,不知何故这些:

每个压缩数据块都以包含以下数据的 3 个标头位开始:

  • 第一位 BFINAL
  • 接下来的 2 位 BTYPE

...实际上结束于第一个字节的end:0100 1011。 (我将跳过这个问题,为什么有人将实际上位于其他事物尾部的事物称为“标题”。)

RFC 包含的内容据我所知应该是对此的解释:

  • 数据元素按顺序打包成字节 增加字节内的位数,即开始 字节的最低有效位。
  • 哈夫曼码以外的数据元素被打包 从数据的最低有效位开始 元素。
  • 霍夫曼编码从最- 代码的重要部分。

换句话说,如果将压缩数据打印为 一个字节序列,从第一个字节开始 right 边距并继续到 left,最- 像往常一样,左侧每个字节的有效位是 能够以固定宽度从右到左解析结果 正确的 MSB 到 LSB 顺序和 Huffman 代码中的元素 位反转顺序(即,与代码的第一位在 相对 LSB 位置)。

但遗憾的是我不明白那个解释。

返回我的数据。 OK,这样BFINAL就设置好了,BTYPE是什么? 10 点还是 01 点?

我如何解释该压缩块中的其余数据?

【问题讨论】:

  • 您的数据不仅仅是字母“a”。它是字母 'a' 后跟换行符,'\n' 或十进制 10。所以那里编码了两个字节,而不仅仅是一个。
  • @MarkAdler 感谢您指出这一点。
  • 您可以使用 infgen,一个 deflate 流反汇编器,帮助您理解 RFC 1951。将流反汇编为可读描述,以及 infgen.c 代码本身进一步说明deflate 格式的构造。
  • @MarkAdler 这个程序很有帮助。您可以添加指向它的链接作为答案。虽然正式它并没有直接回答我的问题,但它是相关的并且非常有用。我不会改变接受的答案,但我一定会给你+1。

标签: unix assembly bit-manipulation gzip deflate


【解决方案1】:

首先让我们将压缩数据的十六进制表示形式视为一系列字节(而不是您问题中的一系列 16 位大端值):

4b e4 02 00

现在让我们将这些十六进制字节转换为二进制:

01001011 11100100 00000010 000000000

根据 RFC,这些位是“从字节的最低有效位开始”打包的。字节的最低有效位是字节的最右边位。所以第一个字节的第一位就是这个:

01001011 11100100 00000010 000000000
       ^
       first bit

第二位是这个:

01001011 11100100 00000010 000000000
      ^
      second bit

第三位:

01001011 11100100 00000010 000000000
     ^
     third bit

等等。一旦你遍历了第一个字节中的所有位,你就可以从第二个字节的最低有效位开始。所以第九位是这个:

01001011 11100100 00000010 000000000
                ^
                ninth bit

最后一位,三十秒位,是这个:

01001011 11100100 00000010 000000000
                           ^
                           last bit

BFINAL 值是压缩数据中的第一位,因此包含在上面标记为“第一位”的单个位中。它的值为1,表示这是压缩数据中的最后一个块。

BTYPE 值存储在数据的下两位中。这些是上面标记为“第二位”和“第三位”的位。唯一的问题是两者中哪一位是最低有效位,哪一位是最高有效位。根据 RFC,“哈夫曼代码以外的数据元素被打包 从数据元素的最低有效位开始。”这意味着这两个位中的第一个,标记为“第二位”的那个是最低有效位。这意味着 BTYPE 的值是二进制的01。所以表示该块是使用固定的霍夫曼码压缩的。

这是最简单的部分。解码压缩块的其余部分更加困难(并且对于更现实的示例来说,更加困难)。正确解释如何做到这一点会使这个网站的答案太长(而且你的问题太宽泛)。不过,我会给你一个提示,数据中接下来的三个元素是霍夫曼代码 10010001('a')、00111010('\n')和 0000000(流结束)。其余 6 位未使用,不属于压缩数据。

注意要了解如何解码压缩数据,您必须了解Huffman codes 是什么。您遵循的 RFC 假定您这样做。您还应该知道 LZ77 compression 的工作原理,尽管该文档或多或少地解释了您需要了解的内容。

【讨论】:

  • 非常感谢!这样就可以了。但是为什么标题位在最右边?我自己用我的编程语言简单实现的 BitStream 将它们从那里取出会有些麻烦,如果它们位于最左边的位置,则可以避免这种情况。其他一些工具更方便吗?
  • @EugZol 这取决于你如何看待事物。标头位从数据的第一位开始。数据的第一位是第一个字节的第一位。字节中的位按最低有效位在前,最高有效位在后进行排序。这与我们通常订购数字的方式相同,最不重要的数字在前,最重要的数字在后。问题是我们将数字的数字倒写,我们把数字的最高有效数字放在第一位,最低有效数字放在最后。如果我们尝试从左到右读取它们,这会翻转二进制数字的顺序。
  • @EugZol 无论您如何看待事物,都不应该使提取位变得更加困难。在 C 语言中,你会做类似bit = byte & 1; byte >>= 1; 的事情。如果按照您预期的方式提取位,首先是一个字节的最右边和最重要的位,那么您将不得不执行类似bit = (byte >> 7) & 1; byte <<= 1; 的操作。
  • @EugZol 人类,至少大多数人类,倒读数字。如果您考虑一下,12 应该是数字 21,而 21 应该是数字 12。 12 应该是 21,因为首先您会看到一个 1,然后您应该增加每个后续数字的位值。每当我们读取数字时,我们实际上会跳过数字的末尾并向后读取。
  • @NickSotiros 我是一个简单的人,我可以向前和向后阅读。但是当我需要来回跳跃时,我必然会感到沮丧。尽管我很喜欢德语(虽然知之甚少)(“ein-und-dreißig”=“one-and-thir-teen”,它是 31,而不是 130 或 131)。
猜你喜欢
  • 2021-02-12
  • 1970-01-01
  • 2019-05-27
  • 2010-12-12
  • 2013-05-05
  • 1970-01-01
  • 2021-09-30
  • 1970-01-01
  • 2011-09-18
相关资源
最近更新 更多