ZLIB 压缩的数据格式规范版本3.3
本备忘录的状态:
本备忘为互联网社区提供信息。本备忘并非指定任何性质的互联网标准。本备忘可以无限制发布。
互联网工程指导小组(Internet Engineering Steering Group,IESG)提示:
互联网工程指导小组 IESG 对于包含于本文中的任何知识产权声明的有效性并无任何立场。
声明:
版权所有(c) 1996 L. Peter Deutsch 和 Jean-Loup Gailly
许可出于任何目的的对本文的复制和分发而无须付费,包括翻译成其它语言以及合并到其它出版物,提供上面的版权声明并保留本声明,以及对原文的任何实质性修改或删除请清楚地注明。
本文最新版本以及相关文档的 HTML 格式的版本的位置请见下面的 URL
< ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html >。
概要:
本规范定义一个无损压缩的数据格式。数据可以被生产或者消费,即使对于任意长度顺序表示的输入数据流,也只是使用预先限定好数量的中间存储。目前使用 DEFLATE 压缩方法的格式可以很容易地进行扩展以使用其它的压缩方法。它可以用不涉及专利权的方式容易地实现。本规范也定义了 ADLER-32 校验和(对 Fletcher 校验和的一个扩展和改进),用于数据损坏的探测,并提供计算校验和的方法。
RFC 1950 ZLIB 压缩的数据格式规范 1996 年 5 月
目录
1. 介绍
1.1. 目的
1.2. 预期的读者
1.3. 范围
1.4. 顺从性
1.5. 用到的术语和约定的定义
1.6. 对前一版的修改
2. 规范细节
2.1. 全文的约定
2.2. 数据格式
2.3. 顺从性
3. 参考资源
4. 源代码
5. 安全性考虑
6. 致谢
7. 作者的地址
8. 附录:基本原理
9. 附录:示例代码
1. 介绍
1.1. 目的
本规范的目的是定义一个无损压缩的数据格式,它:
* 与 CPU 类型、操作系统、文件系统和字符集无关,并因此可以用于交换;
* 可以被生产和消费,即使对于顺序表示的任意长度的输入数据流,只使用预先限定好数量的中间存储,并因此可用于数据通信或者类似于 Unix filter 的结构之中。
* 可以使用许多不同的压缩方法
* 可以用不涉及专利权的方式容易地实现,并因此可以自由地实践。
由本规范定义的数据格式并不允许试图对压缩的数据进行随机访问。
1.2. 预期的读者
本规范打算供将数据压缩成 zlib 格式并/或从 zlib 格式解压缩数据的软件实现者使用。
本规范的内容假定读者在位和其它原语数据表示这一级的编程方面有基础背景。
1.3. 范围
本规范指定一个压缩的数据格式,其可用于一系列任意字节的内存中压缩。
1.4. 顺从性
以下除非另外指明,否则顺从的解压缩程序必须能够接受并解压缩完全遵守在此说明的规范的任何数据集;顺从的压缩程序必须产生完全遵守在此说明的规范的数据集。
1.5. 用到的术语和约定定义
字节(byte):8 位的存储或者传输单元(与八位字节(octet)相同)。(对于本规范,字节严格是 8 位,即使在以不同于 8 位的位数存储一个字符的机器上,也是如此。)在字节中位的编号请参见下面。
1.6. 对前一版的修改
版本 3.1 是本规范的第一个公开版本。在版本 3.2 中,修改了一些术语并为清楚起见重写了 Adler-32 的示例代码。在版本 3.3 中,引入了对预置字典(preset dictionary)的支持,并且规范转换成了 RFC 风格。
2. 规范细节
2.1. 全文的约定
在下面的图中,像这样的框
+---+
| | <-- 垂直的边框可能会丢掉
+---+
代表一个字节;像这样的框
+==============+
| |
+==============+
代表可变数目的字节。
存储在计算机中的字节并没有“位顺序”(bit order),因为它们总是被视为一个单元。不过,一个字节被视为 0 和 255 之间的一个没有最高-(most-)和最低-(least-)位的整数,并且因为我们将最高位数字放在左边来书写数,所我们也使用将最高位写在左边的方式来书写字节。在下面的图中,我们将字节的位进行了编号,让位 0 变成最低位,也就是,这些位按下面这样编号:
+-------------+
|76543210|
+-------------+
在计算机中,一个数可能占多个字节。所有遵守在此说明的格式的多字节的数都以高位字节在先(即在较低内存地址)的方式存储。例如,十进制数 520 存储为:
0 1
+-------------+---------------+
|00000010|000010000|
+-------------+---------------+
^ ^
| |
| + 低位字节 = 8
+ 更高位字节能 = 2 X 256
2.2. 数据格式
Zlib 流有如下的结构:
0 1
+----+-----+
|CMF|FLG| (more-->)
+----+-----+
(if FLG.FDICT set)
0 1 2 3
+-----+-----+-----+-----+
| DICTID | (more-->)
+-----+-----+-----+-----+
+==============+-----+-----+-----+-----+
| ...compressed data... | ADLER32 |
+==============+-----+-----+-----+-----+
任何出现在 ADLER32 之后的数据都不是 zlib 流的一部分。
CMF(Compression Method and flags,压缩方法和标志)
这个字节分为一个 4 位的压缩方法和一个取决于压缩方法的 4 位信息域。
bits 0 to 3 CM Compression method
bits 4 to 7 CINFO Compression info
CM(Compression Method,压缩方法)
它在文件中用于标识压缩方法。CM = 8 表示窗口大小超过 32K 的“deflate”压缩方法。Gzip 和 png (参见下面提供参考文档的第 3 章中参考资源 [1] 和 [2])使用这个方法。CM = 15 保留。它可能在本规范的将来版本中表示出现在压缩数据之前的附加域。
CINFO(Comression Info,压缩信息)
对于 CM = 8,CINFO 是 LZ77 窗口大小的以 2 为底的对数加上 8(CINFO = 7 表示窗口大小为 32 K)。是本规范中,并不允许 CINFO 的值在 7 以上。对于 CM 不等于 8 的 CINFO 在本规范中并没有定义。
FLG(FLaGs)
这个标志字节分为如下几个部分:
bits 0 to 4 FCHECK (检查 CMF 和 FLG 位)
bit 5 FDICT (预置字典)
bits 6 to 7 FLEVEL (压缩级别)
FCHECK 在当 CMF 和 FLG 被视为按 MSB 顺序存储的一个 16 位无符号整数(CMF*256 + FLG)时,必须是 31 的倍数。
FDICT(Preset dictionary,预置字典)
如果设置了 FDICT,DICT 字典标识符立即出现在 FLG 字节之后。字典是最初送到压缩程序而不产生任何压缩输出的一系列字节。DICT 是这一系列字节的 Adler-32 校验和(参见下面对 ADLER32 的定义)。解压缩程序可以使用这个标识符判断压缩程序使用了哪个字典。
FLEVEL(Compression level,压缩级别)
这些标志可用于特定的压缩方法。“Deflate”方法(CM = 8)将这些标志设置如下:
0 - 压缩程序使用最快的算法
1 - 压缩程序使用较快的算法
2 - 压缩程序使用缺少的算法
3 - 压缩程序使用最大的压缩,最慢的算法
对于解压缩程序来说,它并不需要 FLEVEL 中的信息;在解压缩程序中,让它表示是否要重新压缩可能更用价值。
压缩的数据(compressed data)
对于压缩方法 8,压缩的数据按照在由 L. Peter Deutsch 所写的文档“DEFLATE 压缩数据格式规范”(参见下面第 3 章参考资源[3])中说明的 deflate 压缩数据格式存储。
其它压缩的数据格式在 zlib 规范的这个版本中并不做说明。
ADLER32 (Adler-32 校验和,Adler-32 checksum)
这包含了一个按照 Adler-32 算法计算出的未压缩数据(除了任何字典数据)的校验值。这个算法是用在 ITU-T X.224 / ISO 8073 标准中的 Fletcher 算法的 32 位扩展和改进。(请参见下面第 3 章的 [4] 和 [5])。
Alder-32 是由每个字节累积的两个和组成:s1 是所有字节的和,s2 是所有 s1 值的和。这两个和是 65521 取模得来。S1 初始值是 1,s2 是零。Adler-32 校验和按高位字节在先(网络字节序)的顺序存储为 s2*65536 + s1。
2.3. 顺从性
顺从的压缩程序必须产生有正确 CMF、FLG 和 ADLER32 的流,但是不需要支持预置字典。当 zlib 数据格式用作另一个标准数据格式的一部分时,压缩程序只使用由它一其它数据格式指定的预置字典。如果这一其它格式并没有使用预置字典的特性,压缩程序就不能设置 FDICT 标志。
顺从的解压缩程序必须检查 CMF、FLG 和 ADLER32,并且在这些标志值中有任何一个不正确时提供一个错误标识。顺从的解压缩程序在如果 CM 不是定义在本规范中的值的其中之一时必须给出一个错误标识,因为另一个值可能表示出现了会引起后续数据被不正确中断的新特性。顺从的解压缩程序在如果设置了 FDICT 并且 DICTID 并不是一个已知预置字典的标识时必须给出一个错误标识。解压缩程序可能忽略 FLEVEL 并且仍然是顺从的。当 zlib 数据格式用作另一个标准的一部分时,顺从的解压缩程序必须支持所有由其它格式指定的预置字典。当其它格式并不使用预置字典特性时,顺从的解压缩程序必须拒绝任何在其中设置了 FDICT 标志的流。
3. 参考资源
[1] Deutsch, L.P., “GZIP 压缩的数据格式规范”,可在 ftp://ftp.uu.net/pub/archiving/zip/doc中获得。
[2] Thomas Boutell, “PNG(Portable Network Graphics)规范”,可在 ftp://ftp.uu.net/graphics/png/documents/中获得。
[3] Deutsch, L.P.,“DEFLATE 压缩的数据格式规范”,可在 ftp://ftp.uu.net/pub/archiving/zip/doc/中获得。
[4] Fletcher, J.G., “用于系列传输的算术校验和”,IEEE Transactions on Communications,Vol. COM-30, No. 1, January 1982, pp. 247-252。
[5] ITU-T Recommendation X.224, Annex D, “校验和算法”, November, 1993, pp. 144, 145.(可从 gopher://info.itu.ch上获取)。ITU-T X.244 也就是 ISO 8037。
4. 源代码
“Zlib”顺从的库的 C 语言实现的源代码可以从 ftp://ftp.uu.net/pub/archiving/zip/zlib/中获得。
5. 安全方面的考虑
忘记检查 ADLER32 校验和值的解码程序可能会遭受未检测到的数据损坏。
6. 致谢
在本文中引用的商标是它们各自所有者的财产。
Jean-Loup Gailly 和 Mark Adler 设计了 zlib 格式并编写了在本规范中说明的相关软件。Glenn Randers-Pehrson 将本文转换成 RFC 和 HTML 格式。
7. 作者的地址
L. Peter Deutsch
Aladdin Enterprise
203 Santa Margarita Ave.
Menlo Park, CA 94025
电话: (415)322-0103 (只限上午)
传真: (415)322-1734
Email: < [email protected] >
Jean-Loup Gailly
Email:< [email protected]>
关于本规范内容方面的技术问题可以发送 email 到:
Jean-Loup Gailly < [email protected]> 和
Mark Adler < [email protected]>
对本规范的编辑意见可以发送 email 到:
L. Peter Deutsch < [email protected]> 和
Glenn Randers-Pehrson < [email protected]>
8. 附录: 基本原理
8.1. 预置字典
预置字典对于短小的输入序列的压缩特别有用。压缩程序可以利用字典上下文的优点以更紧缩的方式来编码输入。解压缩程序可以通过实际上解压一个压缩版本的字典而不产生任何输出来用适合的上下文进行初始化。不过,对于一些像 deflate 算法等压缩算法,这个操作无需实际地执行任何解压缩就可以完成。
压缩程序和解压缩程序必须严格使用同一字典。字典可能是固定的,或者也可能是从某些预定义的字典中选择出来的。解压缩程序通过检查字典标识符来判断压缩程序选择了哪一个字典。本文并没有说明预定义字典方面的内容,因为最佳字典与应用相关。使用 zlib 规范的这一特性的标准数据格式必须精确地定义所允许的字典。
8.2. Adler-32 算法
Adler-32 算法比仍然提供具有极低未探测错误的概率的 CRC32 算法更快。
在无符号长整型累积数上进行的取模操作可以达到 5552 个字节,因此取模操作时间可以忽略不计。如果字节是 a,b,c,第二个和是 3a + 2b + c + 3,并且因此是位置和顺序敏感的,不像只是校验和的第一个和。65521 是一个素数,这对于避免导致检查不变的两字节大类的可能错误是很重要的。(Fletcher 校验和使用 255,它不是素数并且也使 Fletcher 检查对于单字节改变 0 <-> 255 不敏感。)
和 s1 最初设置为 1 而不是零,以创建序列的 s2 部分的长度,因此长度不必单独检查。(任何零序更的 Fletcher 校验和为零。)
9. 附录:示例代码
下面的 C 代码计算一个数据缓冲区的 Adler-32 校验和。它只是为了说明而不是为了速度缩写的。示例代码是以 ANSI C 编程语言来写的。非 C 用户可以用下面这些提示来读可能更容易:
& AND 位运算操作符。
>> 右移位运算操作符。当应用于无符号的量时,右移在左边插入零。
<< 左移位运算操作符。左移在右边插入零。
++ “n++”递增变量 n。
% 取模操作符: a % b 是 a 除以 b 后的余数。
#define BASE 65521
unsigned long update_adler32(unsigned long adler, unsigned char *buf, int len)
{
unsigned long s1 = adler & 0xffff;
unsigned long s2 = (adler >> 16) & 0xffff;
int n;
for (n = 0; n < len; n++) {
s1 = (s1 + buf[n]) % BASE;
s2 = (s2 + s1) % BASE;
}
return (s2 << 16) + s1;
}
unsigned long adler32(unsigned char *buf, int len)
{
return update_adler32(1L, buf, len);
}