内核自解压分析

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;  
参数: 文件名称 
功能: 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;  
参数:为输入、输出文件。 
功能: 1)初始化全局变量crc。 
2)调用函数inflate()进行解码操作。 
3)得到原来文件中保存的CRC及长度值。如果与当前计算出的值不同,则产生提示。 

5/ 
================================================================================== 
在文件gzip-1.2.4/inflate.c中: 
函数: int inflate() 
说明: ulg bb;  
unsigned bk;  
功能: 1) 循环调用inflate_block(&e),一块一块的解压数据。 
2)若bk>-8,即bb中有完整的字节,则将此字节放回输入中。 
3)输出解压得到的内容。 

6/ 
================================================================================== 
在文件gzip-1.2.4/inflate.c中: 
函数: int inflate_block(e) 
int *e;  
参数:如果是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;  
int bl, bd;  
参数: 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;  
参数:为输入、输出文件。 
功能: 
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>对的编码,否则输出字符编码。
阅读更多
个人分类: 内核编程
博主设置当前文章不允许评论。

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭