关于结构:zlib标头是什么样的?

What does a zlib header look like?

在我的项目中,我需要知道zlib标头的外观。 我听说这很简单,但是找不到zlib标头的任何描述。

例如,它是否包含一个幻数?


zlib魔术头

1
2
3
78 01 - No Compression/low
78 9C - Default Compression
78 DA - Best Compression


链接到RFC

1
2
3
4
0   1
+---+---+
|CMF|FLG|
+---+---+

CMF(压缩方法和标志)
该字节分为4位压缩方法和4位压缩方法。
位信息字段取决于压缩方法。

1
2
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为底的对数
大小减去八(CINFO = 7表示32K窗口大小)。价值观
此版本的版本中不允许CINFO超过7
规格。本规范中未针对以下情况定义CINFO:
CM不等于8。

实际上,这意味着第一个字节几乎总是78(十六进制)

FLG(FLaGs)
该标志字节划分如下:

1
2
3
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)将这些标志设置为
如下:

1
2
3
4
        0 - compressor used fastest algorithm
        1 - compressor used fast algorithm
        2 - compressor used default algorithm
        3 - compressor used maximum compression, slowest algorithm


ZLIB / GZIP标头

1
2
3
4
5
6
7
8
9
10
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压缩数据格式。

1
2
3
4
5
6
7
8
9
10
11
12
 +---+---+
 |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个字节。

没有字典的标头值(CMFFLG)定义如下。

1
2
3
4
 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)
    指示是否使用预设字典。通常是01在技术上是允许的,但我不知道定义预设词典的任何Deflate格式。

  • FCHECK(位0-4)
    校验和(5位,0 .. 31),其值计算为使整个值除以31后没有余数。

通常,只能自由更改CINFOFLEVEL字段,并且必须根据最终值计算FCHECK。*假设没有预设字典,则其他字段所包含的内容均无选择,因此总计32个可能的标头有效。他们来了:

1
2
3
4
5
6
7
8
9
10
      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-标头如下所示:

1
2
    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-未压缩的文件大小-在流的末尾查找以下字节:

1
2
    putLong (s->file, s->crc);
    putLong (s->file, (uLong)(s->in & 0xffffffff));