在我的项目中,我需要知道zlib
标题是什么样的。我听说它很简单,但我找不到任何zlib标头的描述。
例如,它是否包含幻数?
0 1
+---+---+
|CMF|FLG|
+---+---+
CMF(压缩方法和标志)根据压缩方法,该字节分为4位压缩方法和4位信息字段。
bits 0 to 3 CM Compression method
bits 4 to 7 CINFO Compression info
CM(压缩方法)这标识文件中使用的压缩方法。 CM = 8
表示“deflate”压缩方法,窗口大小高达32K。这是gzip和PNG以及几乎所有其他方法使用的方法。保留CM = 15。
CINFO(压缩信息)对于CM = 8,CINFO是LZ77窗口大小的基数2对数,减去8(CINFO = 7表示32K窗口大小)。在此版本的规范中不允许CINFO的值高于7。对于CM不等于8,本规范中未定义CINFO。
在实践中,这意味着第一个字节几乎总是78
(十六进制)
FLG(FLaGs)此标志字节分为以下内容:
bits 0 to 4 FCHECK (check bits for CMF and FLG)
bit 5 FDICT (preset dictionary)
bits 6 to 7 FLEVEL (compression level)
FCHECK值必须使得CMF和FLG在被视为以MSB顺序(CMF * 256 + FLG)存储的16位无符号整数时,是31的倍数。
FLEVEL(压缩级别)这些标志可供特定压缩方法使用。 “deflate”方法(CM = 8
)将这些标志设置如下:
0 - compressor used fastest algorithm
1 - compressor used fast algorithm
2 - compressor used default algorithm
3 - compressor used maximum compression, slowest algorithm
zlib魔术头
78 01 - No Compression/low
78 9C - Default Compression
78 DA - Best Compression
ZLIB / GZIP标头
Level | ZLIB | GZIP
1 | 78 01 | 1F 8B
2 | 78 5E | 1F 8B
3 | 78 5E | 1F 8B
4 | 78 5E | 1F 8B
5 | 78 5E | 1F 8B
6 | 78 9C | 1F 8B
7 | 78 DA | 1F 8B
8 | 78 DA | 1F 8B
9 | 78 DA | 1F 8B
Deflate没有通用标头
以下是Zlib压缩数据格式。
+---+---+
|CMF|FLG| (2 bytes - Defines the compression mode - More details below)
+---+---+
+---+---+---+---+
| DICTID | (4 bytes. Present only when FLG.FDICT is set.) - Mostly not set
+---+---+---+---+
+=====================+
|...compressed data...| (variable size of data)
+=====================+
+---+---+---+---+
| ADLER32 | (4 bytes of checksum)
+---+---+---+---+
大多数情况下,没有设置FLG.FDICT
(字典标志)。在这种情况下,DICTID
根本就不存在。因此,总听觉只有2个字节。
没有字典的标题值(CMF
和FLG
)定义如下。
CMF | FLG
0x78 | 0x01 - No Compression/low
0x78 | 0x9C - Default Compression
0x78 | 0xDA - Best Compression
更多在ZLIB RFC
ZLIB头(在RFC1950中定义)是一个16位的大端值。它包含从最重要到最不重要的这些字段:
CINFO
(第12-15位)
表示窗口大小为2的幂,从0
(256字节)到7
(32768字节)。这通常是7
。不允许更高的值。CM
(第8-11位)
压缩方法。只允许Deflate(8
)。FLEVEL
(第6-7位)
大致表示压缩级别,从0
(快/低)到3
(慢/高)FDICT
(第5位)
指示是否使用预设字典。这通常是0
。 1
在技术上是允许的,但我不知道任何定义预设词典的Deflate格式。FCHECK
(位0-4)
校验和(5位,0
..31
),其值的计算使得整个值除以31而没有余数。通常,只有CINFO
和FLEVEL
字段可以自由更改,并且必须根据最终值计算FCHECK
。*假设没有预设字典,则其他字段包含的内容没有选择,因此总共32个可能的标头有效。他们来了:
FLEVEL: 0 1 2 3
CINFO:
0 08 1D 08 5B 08 99 08 D7
1 18 19 18 57 18 95 18 D3
2 28 15 28 53 28 91 28 CF
3 38 11 38 4F 38 8D 38 CB
4 48 0D 48 4B 48 89 48 C7
5 58 09 58 47 58 85 58 C3
6 68 05 68 43 68 81 68 DE
7 78 01 78 5E 78 9C 78 DA
CINFO
字段很少(如果有的话)由压缩器设置为7
以外的任何值(表示最大32KB窗口),因此您可能在野外看到的唯一值是底行中的四个(以78
开头) 。
*(您可能想知道FCHECK
的值是否存在少量余地 - 如果两者都通过了校验和,是否可以将其设置为0或31?实际上,在这种情况下,没有任何有效的标题,所以我们不必担心它。)
这里的所有答案都可能是正确的,但是 - 如果你想直接操作ZLib压缩流,并且它是通过使用gz_open, gzwrite, gzclose
函数生成的 - 那么在zlib压缩蒸汽到来之前还有额外的10个前导字节头 - 这些是由函数gz_open生成的 - 标题看起来像这样:
fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
并导致以下十六进制转储:1F 8B 08 00 00 00 00 00 00 0B
后跟zlib压缩流。
但是还有8个字节 - 它们是整个文件的uLong
- crc,uLong
- 未压缩的文件大小 - 在流的末尾查找后续字节:
putLong (s->file, s->crc);
putLong (s->file, (uLong)(s->in & 0xffffffff));