【问题标题】:Am I packing bytes correctly for DEFLATE compression?我是否正确打包字节以进行 DEFLATE 压缩?
【发布时间】:2020-05-19 14:32:01
【问题描述】:

所以,我知道有很多库可用于进行 DEFLATE 压缩。如果我正在开发生产产品,我会使用 zlib 之类的东西。但作为一种爱好,我正在自己实施它来尝试解决它。因此,经过几周的编码、重新编码和调整,我终于能够在合理的时间范围内产生一些我认为不错的输出。但是,如果我尝试将我的输出发布到其中一个在线工具中,我会收到一些错误,这些错误不一定能帮助我找出输出的问题。当我让我的程序生成一个实际的位串并手动解析它时,一切似乎都符合 DEFLATE 标准,我可以重建我的数据。这让我相信我的编码是正确的,但我在打包字节时可能完全误解了不同的位顺序。以下是我的输出的 Base64 编码版本,然后是我的程序生成的 8 位字节列表。如果有人可以帮助我指出数据失败的地方,将不胜感激。

Defective program output (both Base64 and raw bytes):

Base64 Encoded Output:
ZYQhAQAADMKqQBWagELQXz/AzTQX+eAB

Byte List:
01100101
10000100
00100001
00000001
00000000
00000000
00001100
11000010
10101010
01000000
00010101
10011010
10000000
01000010
11010000
01011111
00111111
11000000
11001101
00110100
00010111
11111001
11100000
00000001

作为我对文档理解的概述。标准规定一个块以 1 位开始来声明它是否是最后一个块,然后 2 位来声明使用什么类型的压缩,然后是 5 位 hlit、5 位 hdist、4 位 hclen,然后是 hclen + 4 组 3 位,每组给出代码长度对于用于输出文字/长度代码以及距离代码的代码长度的霍夫曼代码。在这之后是 hlit+257+hdist+1 代码长度的霍夫曼编码字符串,最后是实际压缩数据的霍夫曼编码字符串,在块代码的末尾结束。有趣的部分是霍夫曼代码本身是按相反的顺序打包的......但我感到困惑的地方是一些长度代码(代码 16、17、18)之后以及更高的“额外位”之后长度和距离代码。这些是按照与霍夫曼代码相同的相反顺序打包的,还是被视为“霍夫曼代码以外的数据”?

Looking at first byte in list (byte 0):

*01 = last block bit
*02 = 2bit compression type (10 = dynamic huffman)
*03 = msb of hlit (#of literal/length codes - 257)

 *03                 *02     *01
  v                   v       v
+-------------------------------+
| 0   1   1   0   0   1   0   1 |
+-------------------------------+
| Byte 0                        |



Looking at bytes 8 and 9 (starting with byte 0):

*01 = last bit of hclen + 4 sets of codelen code lengths
*02 = msb of huffman code "10" ("10" = codelen code 18 - repeat 0 11-138 times)
*03 = lsb of 7 "extra bits" for codelen code 18
*04 = msb of 7 "extra bits" for codelen code 18

                  *03     *02 *01                           *04
                   v       v   v                             v
+---------------------------------+---------------------------------+
|  1   0   1   0   1   0   1   0  |  0   1   0   0   0   0   0   0  |
+---------------------------------+---------------------------------+
| Byte 8                          | Byte 9                          |

以下是我的程序的一些附加输出,其中包含实际使用的霍夫曼代码:

--------------------------------------------------------------------------
Literal/Length Bit Codes:  Block: 0    hlit: (269 - 257) = 12
--------------------------------------------------------------------------
Code: 32        Count: 1        BitCode: 000                Bit Length: 3                   
Code: 33        Count: 1        BitCode: 001                Bit Length: 3                   
Code: 66        Count: 1        BitCode: 010                Bit Length: 3                   
Code: 97        Count: 1        BitCode: 011                Bit Length: 3                   
Code: 98        Count: 1        BitCode: 100                Bit Length: 3                   
Code: 104       Count: 1        BitCode: 101                Bit Length: 3                   
Code: 108       Count: 1        BitCode: 110                Bit Length: 3                   
Code: 256       Count: 1        BitCode: 1110               Bit Length: 4                   
Code: 268       Count: 1        BitCode: 1111               Bit Length: 4                   

--------------------------------------------------------------------------
Distance Bit Codes:  Block: 0    hdist: (5 - 1) = 4
--------------------------------------------------------------------------
Code: 4         Count: 1        BitCode: 00                 Bit Length: 2                   

--------------------------------------------------------------------------
CodeLength Bit Codes:  Block: 0    hclen: (16 - 4) = 12
--------------------------------------------------------------------------
Code: 2         Count: 1        BitCode: 110                Bit Length: 3                   
Code: 3         Count: 7        BitCode: 00                 Bit Length: 2                   
Code: 4         Count: 2        BitCode: 111                Bit Length: 3                   
Code: 17        Count: 4        BitCode: 01                 Bit Length: 2                   
Code: 18        Count: 5        BitCode: 10                 Bit Length: 2                   

--------------------------------------------------------------------------
--------------------------------------------------------------------------

【问题讨论】:

  • 我很抱歉...... Base64 字符串不起作用......我提供了它,以便那些希望使用它来帮助我追踪问题的人不必自己生成它。
  • bas64有多种方案。另外,你是在做单个文件还是存档,就像 zip 一样?
  • 我的程序将 std::string 作为输入并输出 deflate 编码的 std::string。因为编码的字符串通常不是人类可读的,所以我对其进行了 Web Base64 编码,以便我可以将其粘贴到其中一个在线工具中,以尝试查看它是否可以普遍解压缩。我的问题不在于 Base64 编码。我知道这行得通……您可以将我的 Base64 字符串与原始字节进行比较以验证这一点……大多数在线工具在我执行时只会给我一个通用的“距离长度错误”错误尝试解压缩输出。我正在尝试追踪我的编码输出中的位导致问题的位置

标签: c++ byte bit huffman-code deflate


【解决方案1】:

多余的位不会反转。

您的问题是不允许使用长度为 2 的单个距离代码。单个距离代码的长度必须为 1。来自 RFC 1951:

如果仅使用一个距离码,则使用一位编码,而不是 零位;在这种情况下,只有一个代码长度为 1,其中一个 未使用的代码。

【讨论】:

  • 太棒了!完全是问题所在。谢谢你指出这一点。我读过 RFC 的那部分,但老实说,我对零这个词感到困惑。我以为我必须人为地将代码膨胀到长度 2,因为长度为 1 的单个距离代码必须用于不使用距离代码的情况......换句话说,我完全误读/误解了......是一个快速修复在我的代码和现在的在线工具中轻松解压缩我的字符串。再次感谢!
猜你喜欢
  • 2016-04-28
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
  • 2013-04-15
  • 1970-01-01
  • 2013-05-05
  • 2016-01-06
  • 1970-01-01
相关资源
最近更新 更多