VBA解压缩ZIP文件10——解压-动态Huffman
时间:2022-07-22
本文章向大家介绍VBA解压缩ZIP文件10——解压-动态Huffman,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
使用动态Huffman压缩的数据块,在数据块的开头仍然是3个bit的Header,第2个bit是0、第3个bit是1,因为读取过程是先读取低位,再读取高位,所以结果应该是二进制10。
01
解析h3 Huffman树
接下来的压缩数据块的bit流分别是:
- HLIT:5比特,记录literal/length码树中码长序列(CL1)个数的一个变量。
- HDIST:5比特,记录distance码树中码长序列(CL2)个数的一个变量。
- HCLEN:4比特,记录Huffman码表3中码长序列(CCL)个数的一个变量。
- 接下来是每3个比特编码一个CCL,一共HCLEN+4个,用以构造Huffman码表3
读取到这里的时候,CCL数组的数据就读取到了,然后使用CCL数组去创建h3(编码SQ1和SQ2)Huffman树。
02
解析h1、h2 Huffman树
得到了h3后,继续读取压缩数据块后面的bit流,并使用h3进行解码,得到SQ1,使用行程编码进行解析,得到CL1,然后创建h1(编码literal和length)Huffman树。
继续读取压缩数据块后面的bit流,并使用h3进行解码,得到SQ2,使用行程编码进行解析,得到CL2,然后创建h2(编码distance)Huffman树。
解析h3、h1、h2 Huffman树的代码实现:
'解析h1和h2
'参数h1和h2是用来返回Huffman树的
Private Function parseH1AndH2(h1 As CHuffmanTree, h2 As CHuffmanTree, ByRef cpByte() As Byte, ByRef bitIndex As Long) As Long
Dim bValue As Long
Dim i As Long
'HLIT:5比特,记录literal/length码树中码长序列(CL1)个数的一个变量。
'后面CL1个数等于HLIT+257(因为至少有0-255总共256个literal,还有一个256表示解码结束,但length的个数不定)。
bValue = GetBits(cpByte, bitIndex, 5)
bitIndex = bitIndex + 5
Dim iCL1 As Long
iCL1 = bValue + 257
'HDIST:5比特,记录distance码树中码长序列(CL2)个数的一个变量。
'后面CL2个数等于HDIST+1。哪怕没有1个重复字符串,distance都为0也是一个CL。
bValue = GetBits(cpByte, bitIndex, 5)
bitIndex = bitIndex + 5
Dim iCL2 As Long
iCL2 = bValue + 1
'HCLEN:4比特,记录Huffman码表3中码长序列(CCL)个数的一个变量。
'后面CCL个数等于HCLEN+4。PK认为CCL个数不会低于4个,即使对于整个文件只有1个字符的情况。
bValue = GetBits(cpByte, bitIndex, 4)
bitIndex = bitIndex + 4
Dim iCCL As Long
iCCL = bValue + 4
'接下来是3比特编码的CCL,一共HCLEN+4个,用以构造Huffman码表3
'针对SQ1、SQ2,PK用了第三个Huffman码表来对这两个序列进行编码。
'通过统计各个整数(0-18范围内)的出现次数,按照相同的思路,
'对SQ1和SQ2进行了Huffman编码,得到的码流记为SQ1 bits和SQ2 bits。同时,这里又需要记录第三个码表,称为Huffman码表3。
'同理,这个码表也用相同的方法记录,也等效为一个码长序列,称为CCL,因为至多有0-18个,PK认为树的深度至多为7,于是CCL的范围是0-7。
Dim CCL() As Long
'标准的CCL长度为19
ReDim CCL(18) As Long
For i = 0 To iCCL - 1
bValue = GetBits(cpByte, bitIndex, 3)
bitIndex = bitIndex + 3
'当得到了CCL序列后,即000代表0,111代表7。
'这个序列如果全部记录,那就需要19*3=57个比特,PK认为CL序列里面CL范围为0-15,
'特殊的几个值是16、17、18,如果把CCL序列位置置换一下,把16、17、18这些放前面,
'那么这个CCL序列就很可能最后面跟着一串0(因为CL=14,15这些很可能没有),所以最后还引入了一个置换
CCL(CCLSwapValue(i)) = bValue
Next
Dim htCCL As CHuffmanTree
Set htCCL = CreateHuffman(CCL)
' htCCL.PrintOut
Dim CL1() As Long
ReDim CL1(iCL1 - 1) As Long
parseByHuffman3 htCCL, cpByte, bitIndex, CL1
'得到literal/length码表(Huffman码表1),构造Huffman树,解析LIT比特流
Set h1 = CreateHuffman(CL1)
Dim CL2() As Long
ReDim CL2(iCL2 - 1) As Long
parseByHuffman3 htCCL, cpByte, bitIndex, CL2
'得到Distance码表(Huffman码表2),构造Huffman树,解析DIST比特流
Set h2 = CreateHuffman(CL2)
Set htCCL = Nothing
End Function
解压数据
h1、h2创建之后,继续读取压缩数据块后面的bit流,使用h1、h2进行解码,解压出原始数据。
'ZIP里的压缩算法称为Deflate算法
'对应的解压缩算法称为Inflate
Private Function InflateByHuffman(h1 As CHuffmanTree, h2 As CHuffmanTree, ByRef cpByte() As Byte, ByRef uncpByte() As Byte, ByRef bitIndex As Long, ByRef pUncp As Long) As Long
Dim ilen As Long
Dim iDistance As Long
Dim i As Long
Dim bValue As Long
'按h1解码一个数字
bValue = h1.GetLeafKey(cpByte, bitIndex)
Do Until bValue = 256
If bValue < 256 Then
' Debug.Print pUncp, VBA.Chr(bValue)
uncpByte(pUncp) = bValue
pUncp = pUncp + 1
Else
ilen = bValue - 257
ilen = ExtraValue(ilen, LengthCode, cpByte, bitIndex)
'按h2解码distance
iDistance = h2.GetLeafKey(cpByte, bitIndex)
iDistance = ExtraValue(iDistance, DistanceCode, cpByte, bitIndex)
'根据长度和距离复制数据
'一个复制的参考串可能指向前一个块,如:向后的distnace可能
'穿过一个或几个块边界,但是distance不可能越过输出串的开始
For i = 1 To ilen
uncpByte(pUncp) = uncpByte(pUncp - iDistance)
pUncp = pUncp + 1
Next
End If
bValue = h1.GetLeafKey(cpByte, bitIndex)
Loop
Set h1 = Nothing
Set h2 = Nothing
End Function
- BZOJ 1207: [HNOI2004]打鼹鼠【妥妥的n^2爆搜,dp】
- HDU 1711 Number Sequence(KMP裸题,板子题,有坑点)
- BZOJ 2222: [Cqoi2006]猜数游戏【神奇的做法,傻逼题,猜结论】
- BZOJ 1257: [CQOI2007]余数之和sum【神奇的做法,思维题】
- 洛谷 P1019 单词接龙【经典DFS,温习搜索】
- MVCforum 支持多国语言
- BZOJ 1012: [JSOI2008]最大数maxnumber【线段树单点更新求最值,单调队列,多解】
- BZOJ 1303: [CQOI2009]中位数图【前缀和】
- 高斯消元模版
- HDU 1728 逃离迷宫(DFS经典题,比赛手残写废题)
- 洛谷 P1219 八皇后【经典DFS,温习搜索】
- KVM基于内核的虚拟机概念理解与客户机浅析
- 洛谷 P1972 [SDOI2009]HH的项链【莫队算法学习】
- BZOJ 2257: [Jsoi2009]瓶子和燃料【数论:裴蜀定理】
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 免费代理池的实现与优化
- 基于Django和clean-blog前端框架的博客系统
- 应急响应笔记之Linux篇
- Access数据库相关知识
- 11个技巧让你编写出更好的Python代码
- 芯片探针到基因组区段坐标的映射
- CDH5升级到CDP7.1
- 底层架构真的折磨死个人(急,在线等)
- Python基础语法(五)—常用模块和模块的安装和导入
- Python计算文件或字符串的MD5/SHA
- .NETCore中实现ObjectId反解
- GSE16561数据集的文章图表复现,小众的illumina表达量芯片
- 数据挖掘课程能带给你什么收获
- AkShare-股票数据-龙虎榜-机构席位成交明细
- AkShare-股票数据-龙虎榜-机构席位追踪