热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Gzip源代码分析(四)

哈弗曼编码首先说明一下涉及到的数据结构:typedefstructct_data{union{ushfreq;*freque
哈弗曼编码

首先说明一下涉及到的数据结构:

typedef struct ct_data {
union {
ush freq; /* frequency count */
ush code; /* bit string */
} fc;
union {
ush dad; /* father node in Huffman tree */
ush len; /* length of bit string */
} dl;
} ct_data;

ushunsigned short int类型)这是一个结构体里面套了两个联合体的数据结构。Gzip用这个ct_data类型定义了五棵树,其实就是数组:dyn_ltree[],dyn_dtree[],static_ltree[],static_dtree[],bl_tree[]。数组的下标表示待编码节点的值,freq字段表示该节点出现的频率,其余字段暂不介绍。

哈弗曼编码的输入

gzip中,哈弗曼编码可看作是LZ77的下一级压缩,但哈弗曼编码并不直接处理LZ77输出的第一手材料,而是做了一步映射。

dyn_dtree对应d_buf,其数据的取值范围在032K之间,gzip将这32K的范围映射到[0, 29]。因为树数组的下标代表节点的取值,所以dyn_dtree数组的长度可以定为30。要是不做映射,dyn_dtree数组的大小就需要32K之多,而且其中很多节点可能频率为0

dyn_ltree对应l_bufl_bufliterallength是混杂的,且两者的取值范围都是0255,完全重叠在一起,如果直接哈弗曼编码,解压时,除非参照flag_buf,否则无法区分。之前第二篇计算最小匹配长度时,曾假设(距离-长度)二元组在上下文中能自说明,不需要额外的描述符(flag_buf)。为了让假设成真,gziplength映射到[257285]这29个节点(用256表示block结束),所以解压时,值大于256的是length,小于256的是literal。所以,dyn_ltree数组需要285的大小存放literallength节点。

那么这个映射是怎么做的呢?这样多对一的映射,解压时又该怎么还原呢?

映射的方法就是将原数值的后几位比特(称为extra bit)截断,这样就映射到了比较小的值了。解压时,先解码映射后的小数值,被截断的比特紧随其后,直接拷贝就行了,具体要拷贝多少比特视小数值而定:

int extra_dbits[30] /* extra bits for each distance code */
= {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};

这是距离extra bit长度的定义;

int extra_lbits[29] /* extra bits for each length code */
= {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};

这是长度extra bit长度的定义。


推荐阅读
author-avatar
林小秋
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有