gzip-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<<BITS);
#else
DECLARE(ush, tab_prefix0, 1L<<(BITS-1));
DECLARE(ush, tab_prefix1, 1L<<(BITS-1));
#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编码压缩,见RFC1951的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) 若找到匹配内容,则输出<length,distence>对的编码,否则输出字符编码。