在我的项目中,我需要知道zlib
标题是什么样的。我听说这很简单,但是找不到zlib标头的任何描述。
例如,它是否包含一个幻数?
Answers:
0 1
+---+---+
|CMF|FLG|
+---+---+
CMF(压缩方法和标志)根据压缩方法,此字节分为4位压缩方法和4位信息字段。
bits 0 to 3 CM Compression method
bits 4 to 7 CINFO Compression info
CM(压缩方法)标识文件中使用的压缩方法。CM = 8
表示窗口大小最大为32K的“压缩”压缩方法。这是gzip和PNG以及几乎所有其他方式使用的方法。
CM = 15保留。
CINFO(压缩信息)对于CM = 8,CINFO是LZ77窗口大小的以2为底的对数,减去8(CINFO = 7表示32K窗口大小)。在此版本的规范中,不允许CINFO的值大于7。在本规范中,对于不等于8的CM,未定义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(压缩级别)这些标志可用于特定的压缩方法。“放气”方法(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压缩数据格式。
+---+---+
|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位的big-endian值。它包含从最高到最低的以下字段:
CINFO
(第12-15位)
以2的幂表示窗口大小,从0
(256字节)到7
(32768字节)。通常是这样7
。不允许更高的值。
CM
(第8-11位)
压缩方法。仅8
允许放气()。
FLEVEL
(6-7位)
大致表示压缩级别,从0
(快速/低)到3
(慢/高)
FDICT
(位5)
指示是否使用预设词典。通常是这样0
。 1
在技术上是允许的,但我不知道定义预设词典的任何Deflate格式。
FCHECK
(位0-4)
一个校验和(5位,0
.. 31
),其计算得出的值是整个值除以31后没有余数。
通常,只有CINFO
andFLEVEL
字段可以自由更改,并且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));