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
- 使用shell进行日志分析(r2第14天)
- easyui表单提交验证form
- 数据紧急修复之启用错误日志 (r2第12天)
- javascript 模拟按键点击提交
- 微信小程序调用接口返回数据或提交数据
- 巧用shell脚本生成快捷脚本(r2第12天)
- asp.net动态增加服务器端控件并提交表单
- c# asp.net 实现分页(pager)功能
- 一次数据库无法登陆的"问题"及排查(r2第11天)
- popcorn-js视频Video框架简单用法
- 一次数据库响应缓慢的问题排查(r2第9天)
- 通过Ajax方式上传文件(input file),使用FormData进行Ajax请求
- C# 读取指定文件夹下所有文件
- ASP.NET 实现Base64文件流下载PDF
- 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 数组属性和方法
- 腾讯云 Serverless 支撑「新东方」核心业务算力资源
- R代码|基于特征重要性的特征排序代码
- windows-exploit-suggester使用指导
- lcx实现端口转发
- 支付宝二维码脱机认证库测试过程记录(andorid平台adb shell验证)
- R代码|dplyr包的使用示例
- ES 面试题
- 支付宝二维码脱机认证库在android的app下测试过程记录
- 在?进来看看怎么攻击JMX呗
- mysql 中的锁结构
- 我的小工具-远程读卡器web客户端(PHP+LUA)
- Linux下suid提权利用
- scala 类型 的最详细解释
- 【入坑JAVA安全】JAVA反射机制
- 小妹妹,我想握着你的手,不为别的,只为给你讲清楚CVE-2020-5902