zlib
标头是什么样子的。我听说它相当简单,但我找不到关于 zlib 标头的任何描述。例如,它是否包含一个魔数?
zlib魔术标头
78 01 - No Compression/low
78 9C - Default Compression
78 DA - Best Compression
0 1
+---+---+
|CMF|FLG|
+---+---+
CMF(压缩方法和标志) 该字节按照压缩方法分为4位和依赖于压缩方法的4位信息字段。
bits 0 to 3 CM Compression method
bits 4 to 7 CINFO Compression info
压缩方法CM (Compression method)
该字段标识文件中所使用的压缩方法。当CM = 8
时,表示使用了最大为32K的“deflate”压缩方法,包括gzip和PNG等几乎所有其他文件格式都使用此方法。而CM = 15则保留。
压缩信息CINFO (Compression info) 对于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顺序存储的16位无符号整数(即CMF * 256 + FLG),其值必须是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/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没有常见的头部信息。
1f 8b 08
,这样可以更好地区分。此外,您只展示了64个可能的zlib头文件中的四个。请参阅mwfearnley的回答。 - Mark AdlerZLIB头(如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?实际上,只有在 FDICT = 1
的情况下才会发生这种情况,因此它不出现在上表中。)
(S
、8O
、HK
、XG
、hC
、x^
都是有效的标头。PNGOUT在压缩图像时使用x^
(78 5E
)。 - mwfearnley以下是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压缩流,而它是通过使用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));
78
答案 - 这个答案省略了78 5E
- 它落在无/默认之间。另外还有28个值不太可能被看到,但仍然有效。 - mwfearnley