3.1.1.3.2. Sequences_Section (序列段)
压缩块是一系列序列的连续体。序列是一个字面量复制命令,后跟一个匹配复制命令。字面量复制命令指定长度。它是要从 Literals_Section 复制(或提取)的字节数。匹配复制命令指定偏移量和长度。
当所有序列都已解码后,如果 Literals_Section 中还有剩余字面量,则这些字节将添加到块的末尾。
这在第 3.1.1.4 节中有更详细的描述。
Sequences_Section 重新组合解码命令所需的所有符号。有三种符号类型:字面量长度代码、偏移量代码和匹配长度代码。它们在单个 "位流" 中交错编码在一起。
Sequences_Section 以头部开始,然后是每种符号类型的可选概率表,然后是位流。
Sequences_Section_Header
[Literals_Length_Table]
[Offset_Table]
[Match_Length_Table]
bitStream
要解码 Sequences_Section,必须知道其大小。此大小从 Literals_Section 的大小推导出来:
Sequences_Section_Size = Block_Size - Literals_Section_Header
- Literals_Section_Content
3.1.1.3.2.1. Sequences_Section_Header (序列段头部)
此头部由两个项目组成:
- Number_of_Sequences (序列数量)
- Symbol_Compression_Modes (符号压缩模式)
Number_of_Sequences
Number_of_Sequences 是一个可变大小字段,使用 1 到 3 个字节。如果第一个字节是 "byte0":
-
if (byte0 == 0): 没有序列。序列部分在此停止。解压缩内容完全定义为 Literals_Section 内容。Repeat_Mode 中使用的 FSE 表不会更新。
-
if (byte0 < 128): Number_of_Sequences = byte0。使用 1 字节。
-
if (byte0 < 255): Number_of_Sequences =
((byte0 - 128) << 8) + byte1。使用 2 字节。 -
if (byte0 == 255): Number_of_Sequences =
byte1 + (byte2 << 8) + 0x7F00。使用 3 字节。
Symbol_Compression_Modes
Symbol_Compression_Modes 是一个单字节,定义每种符号类型的压缩模式。
| 比特号 (Bit Number) | 字段名称 (Field Name) |
|---|---|
| 7-6 | Literal_Lengths_Mode |
| 5-4 | Offsets_Mode |
| 3-2 | Match_Lengths_Mode |
| 1-0 | Reserved (保留) |
表 14: Symbol_Compression_Modes
最后一个字段 Reserved 必须全部为零。
Literals_Lengths_Mode、Offsets_Mode 和 Match_Lengths_Mode 分别定义字面量长度代码、偏移量代码和匹配长度代码的 Compression_Mode。它们遵循相同的枚举:
| Value (值) | Compression_Mode (压缩模式) |
|---|---|
| 0 | Predefined_Mode (预定义模式) |
| 1 | RLE_Mode (RLE模式) |
| 2 | FSE_Compressed_Mode (FSE压缩模式) |
| 3 | Repeat_Mode (重复模式) |
表 15: Literals_Lengths_Mode, Offsets_Mode, and Match_Lengths_Mode
Predefined_Mode (预定义模式) : 使用预定义的 FSE(参见第 4.1 节)分布表,如第 3.1.1.3.2.2 节中所定义。不会存在分布表。
RLE_Mode (RLE模式) : 表描述由一个字节组成,其中包含符号的值。此符号将用于所有序列。
FSE_Compressed_Mode (FSE压缩模式) : 标准 FSE 压缩。将存在分布表。此分布表的格式在第 4.1.1 节中描述。请注意,字面量长度代码和匹配长度代码表的最大允许精度日志为 9,偏移量代码表的最大精度日志为 8。当只有一个符号存在时,不得使用此模式;应改用 RLE_Mode(尽管任何其他模式也可以工作)。
Repeat_Mode (重复模式) : 将再次使用先前 Number_Of_Sequences > 0 的 Compressed_Block 中使用的表,或者如果这是第一个块,则使用字典中的表。请注意,这包括 RLE_Mode,因此如果 Repeat_Mode 跟随 RLE_Mode,则将重复相同的符号。它还包括 Predefined_Mode,在这种情况下,Repeat_Mode 将与 Predefined_Mode 具有相同的结果。不会存在分布表。如果在帧(或字典;参见第 5 节)中没有任何先前的序列表可重复的情况下使用此模式,则应将其视为损坏。
3.1.1.3.2.1.1. Sequence Codes for Lengths and Offsets (长度和偏移量的序列代码)
每个符号都是其自己上下文中的代码,它指定 Baseline(基线)和要添加的 Number_of_Bits(比特数)。代码经过 FSE 压缩,并在同一位流中与原始附加位交错。
字面量长度代码 (Literals Length Codes)
字面量长度代码是从 0 到 35(含)的值。它们定义从 0 到 131071 字节的长度。字面量长度等于解码的 Baseline 加上从位流中读取 Number_of_Bits 位的结果(作为小端值)。
| Literals_Length_Code | Baseline | Number_of_Bits |
|---|---|---|
| 0-15 | length | 0 |
| 16 | 16 | 1 |
| 17 | 18 | 1 |
| 18 | 20 | 1 |
| 19 | 22 | 1 |
| 20 | 24 | 2 |
| 21 | 28 | 2 |
| 22 | 32 | 3 |
| 23 | 40 | 3 |
| 24 | 48 | 4 |
| 25 | 64 | 6 |
| 26 | 128 | 7 |
| 27 | 256 | 8 |
| 28 | 512 | 9 |
| 29 | 1024 | 10 |
| 30 | 2048 | 11 |
| 31 | 4096 | 12 |
| 32 | 8192 | 13 |
| 33 | 16384 | 14 |
| 34 | 32768 | 15 |
| 35 | 65536 | 16 |
表 16: 字面量长度代码
匹配长度代码 (Match Length Codes)
匹配长度代码是从 0 到 52(含)的值。它们定义从 3 到 131074 字节的长度。匹配长度等于解码的 Baseline 加上从位流中读取 Number_of_Bits 位的结果(作为小端值)。
| Match_Length_Code | Baseline | Number_of_Bits |
|---|---|---|
| 0-31 | Match_Length_Code + 3 | 0 |
| 32 | 35 | 1 |
| 33 | 37 | 1 |
| 34 | 39 | 1 |
| 35 | 41 | 1 |
| 36 | 43 | 2 |
| 37 | 47 | 2 |
| 38 | 51 | 3 |
| 39 | 59 | 3 |
| 40 | 67 | 4 |
| 41 | 83 | 4 |
| 42 | 99 | 5 |
| 43 | 131 | 7 |
| 44 | 259 | 8 |
| 45 | 515 | 9 |
| 46 | 1027 | 10 |
| 47 | 2051 | 11 |
| 48 | 4099 | 12 |
| 49 | 8195 | 13 |
| 50 | 16387 | 14 |
| 51 | 32771 | 15 |
| 52 | 65539 | 16 |
表 17: 匹配长度代码
偏移量代码 (Offset Codes)
偏移量代码是从 0 到 N 的值。
解码器可以自由限制其最大支持的 N 值。建议至少支持 22 的值。在撰写本文时,参考解码器支持的最大 N 值为 31。
偏移量代码也是以小端方式读取的附加位数,可以使用以下公式转换为 Offset_Value:
Offset_Value = (1 << offsetCode) + readNBits(offsetCode);
if (Offset_Value > 3) Offset = Offset_Value - 3;
这意味着最大 Offset_Value 为 (2^(N+1)) - 1,支持最多 (2^(N+1)) - 4 的后向引用距离,但受最大后向引用距离限制(参见第 3.1.1.1.2 节)。
从 1 到 3 的 Offset_Value 是特殊的:它们定义 "重复代码"。这在第 3.1.1.5 节中有更详细的描述。
3.1.1.3.2.2. Default Distributions (默认分布)
如果为符号类型选择了 Predefined_Mode,则其 FSE 解码表是从此处定义的预定义分布表生成的。有关如何将此分布转换为解码表的详细信息,请参见第 4.1 节。
3.1.1.3.2.2.1. Literals Length Codes (字面量长度代码)
解码表使用 6 位的精度日志(64 个状态)。
short literalsLength_defaultDistribution[36] =
{ 4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
-1,-1,-1,-1
};
3.1.1.3.2.2.2. Match Length Codes (匹配长度代码)
解码表使用 6 位的精度日志(64 个状态)。
short matchLengths_defaultDistribution[53] =
{ 1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,
-1,-1,-1,-1,-1
};
3.1.1.3.2.2.3. Offset Codes (偏移量代码)
解码表使用 5 位的精度日志(32 个状态),支持最大 N 值为 28,允许最多 536,870,908 的偏移值。
如果压缩块中的任何序列需要比此更大的偏移量,则无法使用默认分布来表示它。
short offsetCodes_defaultDistribution[29] =
{ 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1
};