1. 程式人生 > >GZIP壓縮原理分析(04)——第三章 gzip檔案格式詳解(三02) gzip檔案頭

GZIP壓縮原理分析(04)——第三章 gzip檔案格式詳解(三02) gzip檔案頭

檔案頭由固定長度的部分和擴充套件部分組成,擴充套件部分不一定存在,尤其是網路傳輸使用的HTTP壓縮,如果使用了gzip格式,那麼對應的壓縮報文一般都不帶擴充套件部分。gzip檔案格式通過將頭部中定長部分的某些位元位置位來標識頭部是否帶有擴充套件部分,我們一一來看。

以下各欄位的中文含義,我在網上搜了好久也沒找到理想的,這裡我將RFC1952中的英文釋義粗略的翻譯一下,不足之處歡迎吐槽。

1、 檔案以10位元組的定長部分開始

+------+------+------+-------+---+---+---+---+------+-----+

ID1   |  ID2  |   CM  |   FLG

   |       MTIME       |  XFL  |  OS  |

+------+------+------+-------+---+---+---+---+------+-----+

上面兩個“+”之間的內容代表一個位元組,所以上面除了MTIME使用四個位元組之外,其他只佔用一個位元組。

ID1ID2IDentification:這兩個位元組用於標識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)中的字元。換行時應該用一個十進位制換行符。

MTIMEModificationTIME:該欄位給出了那個被壓縮的原始檔案最近被修改的時間。該時間使用Unix格式,即,自1970年1月1日0時起到現在的秒數。注意,對於MS-DOS或其他使用本地時間而不是使用通用時間的系統,這種方式可能會引起問題。如果不是壓縮一個檔案,那麼該欄位就是壓縮工作開始的那個時間。如果該欄位為0,則表示沒有可用的時間戳(這種情況在使用gzip的HTTP壓縮報文中很常見)。

XFLeXtraFLags:這個欄位是專門給gzip檔案中使用的壓縮方法用的,由於當前gzip只使用一種壓縮方法,或壓縮演算法,即deflate,所以針對deflate,該欄位有如下含義,

XFL= 2 – 壓縮率最大但是壓縮速度最慢(的那個壓縮級別);

XFL= 4 – 最快的壓縮(級別);

(注:deflate 是分0~9種壓縮級別的,後續分析壓縮原始碼的章節會專門分析壓縮級別)

OSOperatingSystem:這個欄位表示幹壓縮這件事兒的那個檔案系統。這個欄位對於確定文字檔案的行結束標誌是非常有用的。這個欄位的當前值分別代表如下系統,

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 Gailly[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        |

+-------+-------+

這個後面就是實際的壓縮資料了,也就是蝦的身子部分。