(转)gzip文件格式详解
一、文件头
文件头由固定长度的部分和扩展部分组成,扩展部分不一定存在,尤其是网络传输使用的HTTP压缩,如果使用了gzip格式,那么对应的压缩报文一般都不带扩展部分。gzip文件格式通过将头部中定长部分的某些比特位置位来标识头部是否带有扩展部分,我们一一来看。
1、 文件以10字节的定长部分开始
+——+——+——+——-+—+—+—+—+——+—–+
| ID1 | ID2 | CM | FLG | MTIME | XFL | OS |
+——+——+——+——-+—+—+—+—+——+—–+
上面两个“+”之间的内容代表一个字节,所以上面除了MTIME使用四个字节之外,其他只占用一个字节。
ID1和ID2(IDentification):这两个字节用于标识gzip文件,其中,ID1 = 31(0x1f,\037),ID2 = 139(0x8b,\213),如果判断某文件以这两个字节开头,那么可以初步认为这是gzip文件,但具体是不是,必须该文件格式完全符合gzip文件格式才行;
CM(CompressionMethod):该字段用于标识当前gzip压缩文件内部的压缩结果所使用的压缩方法,取值范围[0,8](提示,这是一个闭区间),其中,[0,7]保留,目前只用8,即gzip使用deflate压缩方法;
FLG(FLaGs):标记位,该标记位中的每一比特分别代表后面对应扩展位是否存在,各比特位含义如下,
Bit 0 FTEXT
Bit 1 FHCRC
Bit 2 FEXTRA
Bit 3 FNAME
Bit 4 FCOMMENT
Bit 5~7 预留,必须全0
Bit 0 FTEXT,如果置位,则表明文件(应该是指被压缩文件)是ASCII文本文件。这一位是否置位是可选的,压缩工具通过检查少量输入数据中是否含有非ASCII字符来将其置位。一旦怀疑有非ASCII字符,就不置位,表示这是二进制文件。那些对ASCII文本文件和二进制文件使用不同文件格式的系统,解压缩工具会通过这一位是否置位来决定合适的文件格式。我们故意不让压缩所使用的算法来设置这一位,因为压缩工具本身可以选择是否将其置位,而且解压缩工具通常也可以选择忽略这一位并将数据转换的问题抛给其他程序。
Bit 1 FHCRC,如果置位,表示会对gzip文件头部进行CRC16校验,校验结果会放在实际的压缩数据之前,紧挨着实际的压缩数据。CRC16由CRC32的两个低有效字节组成,CRC32用于计算整个gzip头的校验和,但计算时不包括CRC16所占的这两个字节。这一位一般不会被置上。(注意:这里说的这个CRC32与我们后面要说的位于gzip文件尾的那个CRC32不是同一个CRC32!!!但都是用32位循环冗余校验码算法计算得到的,只是作用对象不同。这里的CRC32作用对象是gzip头,完成计算后只取两个低有效字节,构成CRC16;而我们后面要说的位于gzip文件尾的CRC32的作用对象是全部的原始待压缩数据,这两个概念一定要理清)。
Bit 2 FEXTRA,如果置位,表示带着扩展gzip头部部分。扩展部分后续介绍。
Bit 3 FNAME,如果置位,表示携带被压缩文件的文件名(没被压缩),该文件名会以’\0’结束(就是个字符串)。该文件名必须由ISO 8859-1 (LATIN-1) 中的字符组成;在那些使用EBCDIC或其他字符集组成名称的系统中,文件名称必须被转换为ISO LATIN-1 字符集才能让gzip文件携带。这个文件名是被压缩文件的原始文件名,不携带任何的路径信息,只是个文件名而已。如果被压缩文件在一个对名称字母大小写不敏感的文件系统上,则文件名称必须全部小写。如果被压缩数据不是来自一个有文件名称的文件,则不携带文件名称(比如使用gzip压缩HTTP应答报文);例如,被压缩数据来自Unix系统的标准输入,则gzip文件不携带文件名。
Bit 4 FCOMMENT,如果置位,表示携带以‘\0’结尾的文件说明(这个文件说明也是个字符串)。这个说明只是给人们去使用的,类似HTTP应答报文头部中的状态码原因短语。这个文件说明也必须使用ISO 8859-1 (LATIN-1)中的字符。换行时应该用一个十进制换行符。
MTIME(ModificationTIME):该字段给出了那个被压缩的原始文件最近被修改的时间。该时间使用Unix格式,即,自1970年1月1日0时起到现在的秒数。注意,对于MS-DOS或其他使用本地时间而不是使用通用时间的系统,这种方式可能会引起问题。如果不是压缩一个文件,那么该字段就是压缩工作开始的那个时间。如果该字段为0,则表示没有可用的时间戳(这种情况在使用gzip的HTTP压缩报文中很常见)。
XFL(eXtraFLags):这个字段是专门给gzip文件中使用的压缩方法用的,由于当前gzip只使用一种压缩方法,或压缩算法,即deflate,所以针对deflate,该字段有如下含义,
XFL= 2 – 压缩率最大但是压缩速度最慢(的那个压缩级别);
XFL= 4 – 最快的压缩(级别);
(注:deflate 是分0~9种压缩级别的,后续分析压缩源码的章节会专门分析压缩级别)
OS(OperatingSystem):这个字段表示干压缩这件事儿的那个文件系统。这个字段对于确定文本文件的行结束标志是非常有用的。这个字段的当前值分别代表如下系统,
0- FAT filesystem (MS-DOS, OS/2, NT/Win32)
1- Amiga
2- VMS (or OpenVMS)
3- Unix
4- VM/CMS
5- Atari TOS
6- HPFS filesystem (OS/2, NT)
7- Macintosh
8- Z-System
9- CP/M
10- TOPS-20
11- NTFS filesystem (NT)
12- QDOS
13- Acorn RISCOS
255– unknown
2、 头部扩展字段
上面10个字节是无论如何都会存在的,而这里所描述的扩展字段,就是根据上面那10个字节来决定是否存在的。共分为四个部分,
按照顺序依次是:FEXTRA+FNAME+FCOMMENT+FHCRC,
不一定都会存在,但是只要存在,不论存在几个,一定要按照顺序来,例如,FHCRC 和FNAME都存在,那么FNAME 一定要在FHCRC前面!!!下面我们逐个分析。
FEXTRA:
+—–+—–+===============================================+
| XLEN |…………………………XLEN bytes of “extra field”…| (more–>)
+—–+—–+===============================================+
XLEN用两个字节记录,表示extra field部分的大小。而extra field部分又细分为如下结构,
+--------+--------+--------+--------+========================+
| SI1 | SI2 | LEN |…………... LEN bytes ofsubfield data ...|
+--------+--------+--------+--------+========================+
(我将这个部分翻译为次级域)SI1和SI2为这个次级域提供一个ID,这个ID通常由两个便于记忆的ASCII字母表示(这句话不知道是不是应该这么翻译)。Jean-Loup [email protected](gzip源码作者)维护了一张次级域表,你可以将自己的次级域ID发送给他。SI2 = 0 的次级域ID目前保留,未来再用。现在的次级域ID是这样定义的,
SI1 | SI2 | Data
———- ———- ————-
0x41(‘A’) 0x70 (‘P’) Apollo file typeinformation(这个真不知道这么翻译)
LEN给出了次级域数据部分的长度,但是不包括SI1、SI2和LEN这四个字节。
FNAME:
+=========================================+
|…originalfile name, zero-terminated…| (more–>)
+=========================================+
以‘\0’结束,就是个字符串
FCOMMENT:
+===================================+
|…filecomment, zero-terminated…| (more–>)
+===================================+
以‘\0’结束,就是个字符串
FHCRC:
+——-+——-+
| CRC16 |
+——-+——-+
二、文件尾
相比gzip文件头,gzip文件尾较简单,只由四个字节构成,
0 1 2 3 4 5 6 7
+———+———+———+———+———+———+———+———+
| CRC32 | ISIZE |
+———+———+———+———+———+———+———+———+
CRC32(Cyclic Redundancy Check):用标准循环冗余校验算法对原始数据进行计算的结果。
ISIZE(InputSIZE):将原始数据大小对2^32取模的结果(因为只能用四个字节存结果,所以只能对2^32取模)。
三、文件体
上面已经将整个gzip文件的基本文件格式分析完毕,这里简单说下gzip文件的文件体。该文件体本身与gzip没多大关系了,因为只要用到deflate的文件格式,这部分都是一样的,比如gzip的文件体和PKzip的文件体“基本”是一样的,因为它们都使用了deflate。换句话说,这部分的格式就全部由deflate算法(或格式)决定了。