使用以下命令打开后缀为.gz的文件,显示数据格式如下:
2字节GZIP标志字节:0x1f,0x8b(\037\213)
1字节压缩方式:(0..7, 8 =)
1字节标志:
位 0 设置:该文件可能是 ASCII 文本文件
位 1 设置:附加多个 gzip 文件部分
位 2 设置:存在可选附加内容
位 3 设置:提供原始文件名
位 4 设置:然后提供带有 O 终止的文件内容
位 5 设置:文件已加密
位 6,7:保留
4字节文件更改时间(Unix时间)
确定压缩方法的 1 字节附加标志。 2:使用最大压缩、最慢的算法
4:使用最快的算法
1 字节 该标志指定执行压缩时的系统类型。
0 - FAT(MS-DOS、OS/2、NT/Win32)
1-阿米加
2 - VMS(或)
3-Unix
4-VM/CMS
5-雅达利服务条款
6 - HPFS(OS/2、NT)
7-
8-Z-
9-CP/M
10-TOPS-20
11-NTFS(NT)
12-QDOS
13-橡子
255 -
2字节部分(part=1)可选序列号
? 字节额外字段可选附加内容
? 字节文件名,零
可选的原始文件名,以“\0”结尾
? 字节文件,零
可选文件内容(这部分不被解释,但人类可读,以 '\0' 结尾
12字节
? 字节数据
4字节crc32 这是未压缩数据的循环冗余校验值。
4 字节输入大小 2^32 这是原始数据的长度模 2 的 32 次方。
设计了一种可以单向编码的格式,无需反向查找或预测未压缩的数据和输出
压缩数据的大小。如果输入数据不是文件,则修改时间设置为压缩。
开始时间。
是允许通过任何
寻求,并且其中一个
输入尺寸或介质上的尺寸。 如果输入有
不是来自磁盘文件,文件时间已设置
到 的时间。
时间戳主要用于通过网络传输gzip文件时。这种情况下不需要保存所有
人的属性。 本地传输期间,所有者属性在压缩/解压缩期间由 gzip 保留。忽略该值
时间戳为 0。
时间戳是一个 gzip 文件结束的时间
A。 在这种情况下,保持
.就本地而言,有
通过 gzip 当 / 文件。 时间戳为零
是。
标志位中,值为0的位是可选的,这可以让我们对输入数据有一个初步的了解。在吗?
确定后,清除标志位。 对于具有不同文件格式(文本文件和二进制文件)的系统,
解码时,可以使用标志来选择不同的格式。
标志中的位 0 只是一个 ,可以通过以下方式设置
输入数据中的一个小值。 如有疑问,该标志是
数据。 对于其中有
ascii 文本和数据文件,可以
使用标志到 .
如果有附加内容,则必须包含一个或多个子字段,每个子字段的格式如下:
额外字段,如果 ,必须是一个或多个,
每个都有:
id:2字节子字段ID
大小:2 字节 (-) 子字段长度(小端)
数据子字段内容
子字段 ID 可以包含两个容易记住的字母。 请将一些此类 ID 发送至 jloup@.fr。
第二个字节为 0 的 ID 被保留。 定义了以下ID
id 可以是两个,具有一定的值。
将任何此类 ID 发送至 jloup@.fr。 带零的 ID
字节供使用。 ID 是:
Ap(0x41,0x70):文件类型
子字段长度是子字段内容的长度,不包括ID和子字段长度这四个字节。但是
前面提到的“可选附加内容的长度”包括ID和子字段长度的四个字节。
大小是数据的大小,而不是
id 和大小。 字段“额外字段”是
额外字段、id 和大小的总大小。
必须能够在压缩数据中找到数据的结尾,无论数据的实际长度如何。如果压缩
数据不能放置在文件中(如磁盘的情况)。 每个部分必须以标头字段开头,但仅
最后一部分有CRC32和原始数据的长度。解压程序应该能够提示额外的输入。
多个压缩文件中的数据。这是必要的,但不是绝对的,因为当部分数据损坏时,这是必要的
获取其他部分的内容。
它必须是任何数据的末尾
, 的大小
数据。 如果数据适合一个文件(对于
),每个部分都带有 a 如上所述,但是
只有最后一部分有 crc32 和大小。 A
可能用于文件数据。 这是
但不是那个部分
这样数据可以是如果其中之一
零件是 . 仅当没有状态时才会出现这种情况
保持从一个部分到另一部分。 -type 标志
可以这个。
如果压缩文件的系统不区分大小写,则原始文件名将被强制为小写。
如果从标准输入读取数据,则没有原始文件名。
如果该文件位于带有大小写的文件上
名称,名称字段必须为小写。 有
如果数据来自输入,则没有文件名。
即使压缩后的文件比原始文件大,压缩仍然会完成。
是,即使文件是
比 。 最坏的情况是
gzip 文件的几个字节,加上每 32K 块 5 个字节,
对于大文件,比率为 0.015%。 请注意,
从未使用过的磁盘。
这是 zip 1.9 的。 对于支票,
最后一个字节必须为零。 时间
文件的标记可能会设置为零以避免线索
关于的.
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<-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) 若找到匹配内容,则输出对的编码,否则输出字符编码。
14/
==================================================================================
在文件gzip-1.2.4/deflate.c中:
函数: ulg deflate()
功能: 压缩数据。此函数通过一些稍简单一些的算法来进行压缩操作,可以直接引用。
1)将当前内容插入到哈希表中,并查找最长匹配。
2)若找到匹配内容,则输出对的编码,否则输出字符编码。