Skip to main content

3.1.1.3. Compressed Blocks (压缩块)

要解压缩压缩块,必须从 Block_Header 内的 Block_Size 字段提供压缩大小。

压缩块由两部分组成:Literals_Section(字面量段,第 3.1.1.3.1 节)和 Sequences_Section(序列段,第 3.1.1.3.2 节)。然后将这两部分的结果组合以在序列执行(第 3.1.1.4 节)中生成解压缩数据。

要解码压缩块,需要以下元素:

  • 先前解码的数据,最多到 Window_Size 的距离,或帧的开头,以较小者为准。在后一种情况下将设置 Single_Segment_Flag。

  • "最近偏移量" 列表,来自先前的 Compressed_Block。

  • 先前的 Huffman 树,Treeless_Literals_Block 类型需要。

  • 先前的有限状态熵(FSE)解码表,Repeat_Mode 需要,用于每种符号类型(字面量长度代码、匹配长度代码、偏移量代码)。

请注意,解码表并不总是来自先前的 Compressed_Block:

  • 每个解码表都可以来自字典。
  • Huffman 树来自先前的 Compressed_Literals_Block。

3.1.1.3.1. Literals_Section_Header (字面量段头部)

所有字面量都重新组合在块的第一部分中。它们可以首先解码,然后在序列执行(参见第 3.1.1.4 节)期间复制,或者它们可以在序列执行期间即时解码。

字面量可以未压缩存储或使用 Huffman 前缀码压缩。压缩时,可以存在可选的树描述,后跟 1 或 4 个流。

+----------------------------+
| Literals_Section_Header |
+----------------------------+
| [Huffman_Tree_Description] |
+----------------------------+
| [Jump_Table] |
+----------------------------+
| Stream_1 |
+----------------------------+
| [Stream_2] |
+----------------------------+
| [Stream_3] |
+----------------------------+
| [Stream_4] |
+----------------------------+

表 11: 压缩字面量

3.1.1.3.1.1. Literals_Section_Header (字面量段头部)

此字段描述字面量如何打包。它是一个字节对齐的可变大小位字段,范围从 1 到 5 字节,使用小端约定。

字段大小
Literals_Block_Type2 bits
Size_Format1-2 bits
Regenerated_Size5-20 bits
[Compressed_Size]0-18 bits

表 12: Literals_Section_Header

在此表示中,顶部的位是最低位。

Literals_Block_Type 字段使用第一个字节的两个最低位,描述四种不同的块类型:

Literals_Block_Type (字面量块类型)Value (值)
Raw_Literals_Block (原始字面量块)0
RLE_Literals_Block (RLE字面量块)1
Compressed_Literals_Block (压缩字面量块)2
Treeless_Literals_Block (无树字面量块)3

表 13: Literals_Block_Type

Raw_Literals_Block (原始字面量块) : 字面量未压缩存储。Literals_Section_Content 为 Regenerated_Size。

RLE_Literals_Block (RLE字面量块) : 字面量由重复 Regenerated_Size 次的单字节值组成。Literals_Section_Content 为 1。

Compressed_Literals_Block (压缩字面量块) : 这是标准的 Huffman 压缩块,以 Huffman 树描述开始。详见下文。Literals_Section_Content 为 Compressed_Size。

Treeless_Literals_Block (无树字面量块) : 这是一个 Huffman 压缩块,使用来自先前 Compressed_Literals_Block 的 Huffman 树,或者如果没有先前的 Huffman 压缩字面量块,则使用字典。将跳过 Huffman_Tree_Description。请注意,如果在帧(或字典,根据第 5 节)中没有任何先前的 Huffman 表的情况下触发此模式,则应将其视为数据损坏。Literals_Section_Content 为 Compressed_Size。

Size_Format 分为两个系列:

  • 对于 Raw_Literals_Block 和 RLE_Literals_Block,只需解码 Regenerated_Size。没有 Compressed_Size 字段。

  • 对于 Compressed_Block 和 Treeless_Literals_Block,需要解码 Compressed_Size 和 Regenerated_Size(解压缩大小)。还需要解码流的数量(1 或 4)。

对于跨越多个字节的值,约定是小端。

Raw_Literals_Block 和 RLE_Literals_Block 的 Size_Format 使用 1 或 2 位。其值为 (Literals_Section_Header[0]>>2) & 0x3

  • Size_Format == 00 或 10: Size_Format 使用 1 位。Regenerated_Size 使用 5 位(值 0-31)。Literals_Section_Header 使用 1 字节。Regenerated_Size = Literal_Section_Header[0]>>3

  • Size_Format == 01: Size_Format 使用 2 位。Regenerated_Size 使用 12 位(值 0-4095)。Literals_Section_Header 使用 2 字节。Regenerated_Size = (Literals_Section_Header[0]>>4) + (Literals_Section_Header[1]<<4)

  • Size_Format == 11: Size_Format 使用 2 位。Regenerated_Size 使用 20 位(值 0-1048575)。Literals_Section_Header 使用 3 字节。Regenerated_Size = (Literals_Section_Header[0]>>4) + (Literals_Section_Header[1]<<4) + (Literals_Section_Header[2]<<12)

对于这些情况,仅存在 Stream_1。请注意,即使效率较低,也允许使用长格式表示短值(例如,13)。

Compressed_Literals_Block 和 Treeless_Literals_Block 的 Size_Format 始终使用 2 位。

  • Size_Format == 00: 单个流。Regenerated_Size 和 Compressed_Size 都使用 10 位(值 0-1023)。Literals_Section_Header 使用 3 字节。

  • Size_Format == 01: 4 个流。Regenerated_Size 和 Compressed_Size 都使用 10 位(值 0-1023)。Literals_Section_Header 使用 3 字节。

  • Size_Format == 10: 4 个流。Regenerated_Size 和 Compressed_Size 都使用 14 位(值 0-16383)。Literals_Section_Header 使用 4 字节。

  • Size_Format == 11: 4 个流。Regenerated_Size 和 Compressed_Size 都使用 18 位(值 0-262143)。Literals_Section_Header 使用 5 字节。

Compressed_Size 和 Regenerated_Size 字段都遵循小端约定。请注意,Compressed_Size 在存在时包括 Huffman_Tree_Description 的大小。

3.1.1.3.1.2. Raw_Literals_Block (原始字面量块)

Stream_1 中的数据长度为 Regenerated_Size 字节。它包含在序列执行(第 3.1.1.3.2 节)期间使用的原始字面量数据。

3.1.1.3.1.3. RLE_Literals_Block (RLE字面量块)

Stream_1 由应重复 Regenerated_Size 次以生成解码字面量的单个字节组成。

3.1.1.3.1.4. Compressed_Literals_Block and Treeless_Literals_Block (压缩字面量块和无树字面量块)

这两种模式都包含 Huffman 编码数据。对于 Treeless_Literals_Block,Huffman 表来自先前压缩的字面量块或字典;参见第 5 节。

3.1.1.3.1.5. Huffman_Tree_Description (Huffman树描述)

仅当 Literals_Block_Type 类型为 Compressed_Literals_Block (2) 时,此部分才存在。Huffman_Tree_Description 的格式可以在第 4.2.1 节中找到。Huffman_Tree_Description 的大小在解码过程中确定。必须使用它来确定流从哪里开始。

Total_Streams_Size = Compressed_Size - Huffman_Tree_Description_Size

3.1.1.3.1.6. Jump_Table (跳转表)

仅当有 4 个 Huffman 编码流时,才存在 Jump_Table。

(提醒:Huffman 压缩数据由 1 或 4 个 Huffman 编码流组成。)

如果只有 1 个流存在,它是占据字面量块剩余整个部分的单个位流,如第 4.2.2 节中所述进行编码。

如果有 4 个流,Literals_Section_Header 仅提供足够的信息来了解所有 4 个流组合的解压缩和压缩大小。每个流的解压缩大小等于 (Regenerated_Size+3)/4,除了最后一个流,它最多可以小 3 个字节,以达到 Regenerated_Size 中指定的总解压缩大小。