gzip-1.2.4程式分析 (轉)

themoney發表於2007-10-01
gzip-1.2.4程式分析 (轉)[@more@]

-1.2.4分析
一點說明:
 在gzip.c中:
DECLARE(uch, inbuf,  INBUFSIZ +INBUF_EXTRA);
DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA);
DECLARE(ush, d_buf,  DIST_BUFSIZE);
DECLARE(uch, window, 2L*WSIZE);
#ifndef MAXSEG_64K
  DECLARE(ush, tab_prefix, 1L<#else
  DECLARE(ush, tab_prefix0, 1L<  DECLARE(ush, tab_prefix1, 1L<#endif
 實際上定義了一些陣列:inbuf,outbuf,d_buf,window,tab_prefix,tab_prefix0,tabfix1.
1/
==================================================================================
入口程式:gzip-1.2.4/gzip.c
: int main (argc, argv)
   int argc;
   char **argv;
功能: 1)透過命令內容(gzip,gunzip,unzip等),設定操作型別(或是解壓縮)。
 2)透過引數,設定一些全域性變數的值,對我們而言,有用的是:ascii(表示
為文字,可以根據本地的換行符來代替解壓後的檔案中的換行符)、decompress(表示進行解壓操作)和level(轉換操作的級別-進行更快
的轉換還是進行更大壓縮比的轉換,當然,這隻對壓縮而言)。
 3)為輸入、輸出及視窗的緩衝分配。
 4)treat_file(argv[optind++]);對檔案進行操作。


2/
==================================================================================
函式: local void treat_file(iname)
   char *iname;
引數: 為檔名稱;
功能: 1)得到輸入的檔案的狀態:name,size,time,mode等。
 2)建立輸出檔案的名稱。
 3)當進行解壓操作時,呼叫 local int get_method(in) 來得到gz檔案的壓縮方法。
 4)如果命令列中的引數-l,則呼叫do_list()顯示檔案資訊。
 5)呼叫local int create_outfile()建立輸出檔案。
 6) 呼叫(*work)(ifd, ofd)進行壓縮、解壓縮的操作。這時的work指標被get_method()
函式置為unzip()函式(解壓時),或是為預設的zip()函式。在解壓縮時,
這個過程是在迴圈中的,因為可能會包含多個檔案。


3/
==================================================================================
函式: local int get_method(in)
   int in;  /* input file descriptor */
引數: 檔名稱
功能: 1)驗證第一第二位元組是否為0x1F,0x8B。
 2)驗證第三位元組是否為0x08(deflate)。
 3)設定函式指標work = unzip。(work的預設值是zip)
 4)得到做為flags的第四位元組。
 5)如果設定了第1、5、6、7位,則給出錯誤提示。(編號0到7是從最低位開始)
 6)將第5到8位元組中的時間值儲存在全域性變數time_stamp中。
 7)跳過第9位元組(壓縮時採用的演算法-更快或是比例更高)和
第10位元組(壓縮時的操作)。
 8)如果設定了flags的第1位,則得到當前檔案的編號
 9)如果設定了flags的第2位(存在有附加的內容),則得到附加內容的長度,
並跳過這部分內容。
 10)如果設定了flags的第3位(存在有原始檔案的名稱),則得到原始檔案的名稱。
 11)如果設定了flags的第4位(存在一段不用解析的內容,是給人提供可讀資訊的),
跳過這部分可讀資訊。
 12) 設定頭部資訊的長度:header_bytes,包括了最後的CRC及檔案長度部分。
返回: 函式壓縮方法(一般為“deflate”,程式中的返回值為8)


4/
==================================================================================
在檔案gzip-1.2.4/unzip.c中:
函式: int unzip(in, out)
   int in, out;  /* input and output file descriptors */
引數:為輸入、輸出檔案。
功能: 1)初始化全域性變數crc。
 2)呼叫函式inflate()進行解碼操作。
 3)得到原來檔案中儲存的CRC及長度值。如果與當前計算出的值不同,則產生提示。


5/
==================================================================================
在檔案gzip-1.2.4/inflate.c中:
函式: int inflate()
說明: ulg bb;  /* 是 bit buffer */
unsigned bk;  /* 是bit buffer中還有多少位,即剩餘的位數 */
功能: 1) 迴圈呼叫inflate_block(&e),一塊一塊的解壓資料。
 2)若bk>-8,即bb中有完整的位元組,則將此位元組放回輸入中。
 3)輸出解壓得到的內容。


6/
==================================================================================
在檔案gzip-1.2.4/inflate.c中:
函式: int inflate_block(e)
int *e;  /* last block flag */
引數:如果是1,是說明當前塊是最後一塊。
功能: 1)得到第一位,這一位說明當前塊是否為最後一塊(0,不是;1,是)並相應的設定引數。
 2)得到下兩位的值: 
0,本塊沒有壓縮,
1,用固定的Huffman編碼壓縮,見1951的3.2.6節。
2,用動態的Huffman編碼壓縮,見RFC1951的3.2.7節。
 3)根據前面得到的值,呼叫不同的函式解壓:
 inflate_stored(); 對於未壓縮的資料,呼叫這個函式。
 inflate_fixed(); 對於用固定的Huffman編碼壓縮的資料,呼叫這個函式。
 inflate_dynamic(); 對於用動態的Huffman編碼壓縮的資料,呼叫這個函式。


7/ 
==================================================================================
在檔案gzip-1.2.4/inflate.c中:
函式: int inflate_stored()
功能: 處理非壓縮的資料內容
1)丟棄不足一位元組的位。由於非壓縮的資料中,內容都是以位元組為單位的,所以原來按
 位讀取的時候,會剩餘不足一位元組位內容,現在要去掉這些位。
 2)讀入兩位元組的內容,其值是未壓縮的資料長度。再讀入兩位元組的內容,其值應該是前
 兩位元組所表示的長度的補碼,若不是,則錯誤。
 3)逐位元組的讀入內容,並輸出到輸出檔案中。


8/
==================================================================================
在檔案gzip-1.2.4/inflate.c中:
函式: int inflate_fixed()
功能: 用固定的Huffman編碼壓縮的資料
1) 為0至287的文字/length值設定編碼長度:
  Lit Value  Bits  Codes
  ---------  ----  -----
  0 - 143  8  00110000 through
  10111111
  144 - 255  9  110010000 through
  111111111
  256 - 279  7  0000000 through
  0010111
  280 - 287  8  11000000 through
  11000111
2) 呼叫huft_build()建造文字/length值的Huffman樹
3) 設定所有distance值(從0至29)的編碼長度為5。
4) 呼叫huft_build()建造distance值的Huffman樹
5) 呼叫函式inflate_codes()進行解碼。


9/
==================================================================================
在檔案gzip-1.2.4/inflate.c中:
函式: int inflate_dynamic()
功能: 用動態的Huffman編碼壓縮的資料
1) 讀入5位的值HLIT,算出nl = 257+HLIT。這是需要編碼的最大值。
2) 讀入5位的值HDIST,算出nd = 1+HDIST。這是distance的最大值。
3) 讀入4位的值HCLEN,算出nb = 4+HCLEN。說明有多少種編碼長度。
4) 再讀入3*nb位,每三位的值表示用多少位來表示所對應的編碼長度。
5) 呼叫huft_build()建造編碼長度的Huffman樹。
6) 利用這個Huffman樹,對接下來的若干位解碼出nl+nd個值,這些值依次是0~nl-1
的編碼長度(對於文字/length平說),及0~nd-1的編碼長度(對於distance來說)。
7) 利用上面解碼出的兩組長度值,兩次呼叫huft_build()函式,建造兩個Huffman樹
(一個是為文字/length,另一個是為distance)。
8) 呼叫函式inflate_codes()進行解碼。


10/
==================================================================================
在檔案gzip-1.2.4/inflate.c中:
函式: int inflate_codes(tl, td, bl, bd)
struct huft *tl, *td; /* literal/length and distance decoder tables */
int bl, bd;  /* number of bits decoded by tl[] and td[] */
引數: tl,td是進行Huffman編碼解碼時用到的結構體,由於length和distance用不同的編碼
方式,所以要有兩個指標進行解碼。
 在兩種編碼中,用struct huft結構編碼時,分別以bl,bd位進行編碼。
功能: 用兩個以經做好的連結串列來進行解碼。
1) 解碼一個值X,如果0<=X<=255,則X是一個字元,輸出,迴圈1)。
2) 如果X==255,則說明塊結束,函式返回。
3) X>255,則說明讀到的是一個length值,根據這個值,及其後的附加位,得到真實的
length值。
4) 繼續讀入一個值,這個值是distance的標誌值,根據這個值及其後的附加位得到真實
的distance。
5) 在已經輸出的串中,向前查詢distance個位元組,複製length個位元組到輸出串的末尾。
6) 迴圈1)


11/
==================================================================================
在檔案gzip-1.2.4/inflate.c中:
函式: int huft_build() 和函式int huft_free()比較獨立,可以直接引用,不再分析。
功能: int huft_build() :建立Huffman解碼連結串列。
int huft_free() :清除連結串列。
12/
==================================================================================
在檔案gzip-1.2.4/zip.c中:
函式: int zip(in, out)
   int in, out;  /* input and output file descriptors */
引數:為輸入、輸出檔案。
功能: 
1) 向輸出寫入三位元組:0x1F 0x8B 0x08。
2) 向輸出寫入一個含有8個標誌位的位元組。
3) 向輸出寫入4位元組的系統時間。
4) 初始化CRC的值。
5) 呼叫bi_init(out)初始化讀入位串的程式。
6) 呼叫ct_init()進行分配記憶體,初始化變數表,儲存原始檔案資訊的
操作。
7) 呼叫lm_init()為新檔案初始化“最長匹配”的程式。
8) 再向輸出寫入2位元組,一個為額外的標誌,一個為系統型別。
9) 如果需要,則儲存原始檔名稱。
10) 儲存頭部資訊的長度。
11) 呼叫函式deflate()壓縮。
12) 寫入4位元組的CRC值。
13)  寫入4位元組的原始內容長度值。
14)修改前面儲存的頭部資訊長度的值。


13/
==================================================================================
在檔案gzip-1.2.4/deflate.c中:
函式: ulg deflate()
功能: 壓縮資料。此函式透過一些複雜的演算法來進行壓縮操作,可以直接引用。
1) 如果需要壓縮,則呼叫函式deflate_fast(),然後返回。
2) 將當前內容插入到雜湊表中,並查詢最長匹配。
3) 若找到匹配內容,則輸出對的編碼,否則輸出字元編碼。

 

 :namespace prefix = o ns = "urn:schemas--com::office" />


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10794571/viewspace-974312/,如需轉載,請註明出處,否則將追究法律責任。

相關文章