Inflate动态Huffman解压缩

2024-05-05 19:04

本文主要是介绍Inflate动态Huffman解压缩,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上个已经实现GZIP压缩文件格式的Inflate静态Huffman解压,这个实现Inflate的无压缩输出和动态Huffman解压。

Java语言实现,Eclipse下编写。

范式Huffman解码实现,输入huffman编码,输出原始数据

    // 范式huffman解码static class CanonicalCode {Vector<Node> table = new Vector<>();public CanonicalCode(int[] len) {for (int i=0; i<len.length; i++)if (len[i] != 0) // 过滤0-即不使用的节点table.add( new Node(i, len[i]) ); // value, bits Length (值, 待编码的编码长度)// 按编码长度+值排序Collections.sort(table, new Comparator<>() {@Overridepublic int compare(Node o1, Node o2) {return o1.bitLen!=o2.bitLen ? o1.bitLen-o2.bitLen : o1.value - o2.value;}});// 初始化第一个节点,实现规则1table.get(0).code = 1 << table.get(0).bitLen;// 计算每一个值得huffman编码for (int i=1; i<table.size(); i++) {Node node = table.get(i);Node prev = table.get(i-1);if (node.bitLen == prev.bitLen)  // 如果位长相等+1,实现规则2node.code = prev.code + 1;else if (node.bitLen > prev.bitLen)	// 位长不等,实现规则3node.code = ( prev.code + 1) << (node.bitLen - prev.bitLen);  // 左移'位长差'}}// 打印符号和huffman码的对应关系void debug() {for (int i=0; i<table.size(); i++) {Node n = table.get(i);System.out.println( n);}}// 根据传入的huffman编码,得到原始数值Integer findValue(int code) {for (Node node : table)if (node.code == code)return node.value;return null;}}

无压缩数据解码:

	bis.alignByte(); // 对齐字节边界int len = bis.ReadBits(16);int nlen = bis.ReadBits(16);assert len + nlen == 65535;for (int i=0; i<len; i++) {baos.Write(bis.ReadBits(8));}

动态huffman解码:

	else if (bType == 2) { // dynamic huffman// length有29个int hlit = bis.ReadBits(5);  // CL1数量 - 字/长度 码个数, LIT(literal/length)// distance码有30个int hdist = bis.ReadBits(5); // CL2数量 - 距离 码个数, DIST(distance)int hclen = bis.ReadBits(4); // c_len:code lengths for the code lengthint cl1_num = hlit + 257;  // CL1(Code Length 1): 'literal/length' length (literal[0..255]+压缩块结束[256] = 257)int cl2_num = hdist + 1;   // CL2(Code Length 2): 'distance code' lengthint ccl_num = hclen + 4;   // int[] cl1 = new int[cl1_num];int[] cl2 = new int[cl2_num];int[] ccl = new int[19]; // ccl bits// 读取CCLArrays.fill(ccl, 0);int[] PermutationtTable = new int[] {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };for (int i=0; i<ccl_num; i++) { // 读取CCL, 每个3bitint p = PermutationtTable[i];ccl[p] = bis.ReadBits(3);}// 通过CCL构建范式huffman编码CanonicalCode codes = new CanonicalCode(ccl);//读取CL1和CL2,'literal/length' Sequence 码流 + dist流IntBuffer sq = IntBuffer.allocate(cl1_num + cl2_num);int prevValue = -1, cl_decode_num = 0;while (cl_decode_num < cl1_num + cl2_num) {Integer value = null;int code = 1;// 范式huffman解码int bits = 1;while (value == null) {code = (code << 1 ) | bis.ReadBit();  // huffman编码value = codes.findValue( code); // 查找对应的符号if ( (bits++) > 15 )throw new java.lang.IllegalArgumentException();}// 处理value, 实现 0-15,16,17,18 这套规则int[] bs;if (value == 17) { // 标识长度int len = bis.ReadBits(3) + 3;bs = new int[len];Arrays.fill(bs, (byte)0);}else if (value == 18) {int len = bis.ReadBits(7) + 11;bs = new int[len];Arrays.fill(bs, (byte)0);}else if (value == 16) {int len = bis.ReadBits(2) + 3;bs = new int[len];Arrays.fill(bs, (byte) prevValue);}else if (value >=0 && value <= 15){bs = new int[] {  value };prevValue = value;}else throw new java.lang.IllegalArgumentException(value + "");sq.put(bs); // 写入符号cl_decode_num += bs.length; // 增加已得到的码流长度}int[] bs = sq.array();// 分别得到CL1和CL2 System.arraycopy(bs, 0, cl1, 0, cl1.length);System.arraycopy(bs, cl1.length, cl2, 0, cl2.length);CanonicalCode code1 = new CanonicalCode(cl1); // literal/length解码器CanonicalCode code2 = new CanonicalCode(cl2); // distance解码器// 解码Integer value = null;do {// 解literal/length码int code = 1;do {code = (code << 1) | bis.ReadBit(); // 读取Huffman codevalue = code1.findValue(code);} while (value == null);// 判断if (value >= 0 && value <= 255)// literalbaos.Write(value);else if (value == 256) // 结束标志break ;else if (value >= 257 && value <= 285) { // length// 处理长度int length = LengthExtraCodeLengthsTable.get(value);int bits = LengthExtraCodeBitsTable.get(value); // 扩展bit长if (bits != 0) {int ext =  ReadExtCode(bis, bits);length = length + ext;}// 读取huffman编码code = 1;do {code = (code << 1) | bis.ReadBit(); // 读取Huffman codevalue = code2.findValue(code);} while (value == null);// 处理距离int distance = DistanceExtraCodeLengthsTable.get(value);bits = DistanceExtraCodeBitsTable.get(value); // 距离扩展if (bits != 0) {int ext =ReadExtCode(bis , bits);distance = distance + ext;}// LZ77滑动窗口计算获取量int[] arr = baos.GetInts();int d = arr.length - distance;if (d < 0) {d = 0;length = length + distance - arr.length;}// 读取滑动窗口,写入到结果for (int i=0; i<length; i++) {int m = arr[ d + i];baos.Write(m);arr = baos.GetInts();}}} while (value != 256);}

输出结果:

对待压缩文件sample-5.svg 计算md5值,得到:84018a59da62b5af9de4c0843ce5d0b6

使用gzip对文件压缩

使用Java程序对压缩后的文件sample-5.svg.gz解压缩,得到sample.svg

对解压后的文件计算md5值,得到84018a59da62b5af9de4c0843ce5d0b6

解压前文件的md5值==解压后的文件的md5值。

这篇关于Inflate动态Huffman解压缩的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/962434

相关文章

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

C#如何动态创建Label,及动态label事件

《C#如何动态创建Label,及动态label事件》:本文主要介绍C#如何动态创建Label,及动态label事件,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录C#如何动态创建Label,及动态label事件第一点:switch中的生成我们的label事件接着,

SpringCloud动态配置注解@RefreshScope与@Component的深度解析

《SpringCloud动态配置注解@RefreshScope与@Component的深度解析》在现代微服务架构中,动态配置管理是一个关键需求,本文将为大家介绍SpringCloud中相关的注解@Re... 目录引言1. @RefreshScope 的作用与原理1.1 什么是 @RefreshScope1.

MyBatis 动态 SQL 优化之标签的实战与技巧(常见用法)

《MyBatis动态SQL优化之标签的实战与技巧(常见用法)》本文通过详细的示例和实际应用场景,介绍了如何有效利用这些标签来优化MyBatis配置,提升开发效率,确保SQL的高效执行和安全性,感... 目录动态SQL详解一、动态SQL的核心概念1.1 什么是动态SQL?1.2 动态SQL的优点1.3 动态S

mybatis-plus 实现查询表名动态修改的示例代码

《mybatis-plus实现查询表名动态修改的示例代码》通过MyBatis-Plus实现表名的动态替换,根据配置或入参选择不同的表,本文主要介绍了mybatis-plus实现查询表名动态修改的示... 目录实现数据库初始化依赖包配置读取类设置 myBATis-plus 插件测试通过 mybatis-plu

基于Canvas的Html5多时区动态时钟实战代码

《基于Canvas的Html5多时区动态时钟实战代码》:本文主要介绍了如何使用Canvas在HTML5上实现一个多时区动态时钟的web展示,通过Canvas的API,可以绘制出6个不同城市的时钟,并且这些时钟可以动态转动,每个时钟上都会标注出对应的24小时制时间,详细内容请阅读本文,希望能对你有所帮助...

Vue中动态权限到按钮的完整实现方案详解

《Vue中动态权限到按钮的完整实现方案详解》这篇文章主要为大家详细介绍了Vue如何在现有方案的基础上加入对路由的增、删、改、查权限控制,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、数据库设计扩展1.1 修改路由表(routes)1.2 修改角色与路由权限表(role_routes)二、后端接口设计

前端 CSS 动态设置样式::class、:style 等技巧(推荐)

《前端CSS动态设置样式::class、:style等技巧(推荐)》:本文主要介绍了Vue.js中动态绑定类名和内联样式的两种方法:对象语法和数组语法,通过对象语法,可以根据条件动态切换类名或样式;通过数组语法,可以同时绑定多个类名或样式,此外,还可以结合计算属性来生成复杂的类名或样式对象,详细内容请阅读本文,希望能对你有所帮助...

Nginx实现动态封禁IP的步骤指南

《Nginx实现动态封禁IP的步骤指南》在日常的生产环境中,网站可能会遭遇恶意请求、DDoS攻击或其他有害的访问行为,为了应对这些情况,动态封禁IP是一项十分重要的安全策略,本篇博客将介绍如何通过NG... 目录1、简述2、实现方式3、使用 fail2ban 动态封禁3.1 安装 fail2ban3.2 配

Vue3中的动态组件详解

《Vue3中的动态组件详解》本文介绍了Vue3中的动态组件,通过`component:is=动态组件名或组件对象/component`来实现根据条件动态渲染不同的组件,此外,还提到了使用`markRa... 目录vue3动态组件动态组件的基本使用第一种写法第二种写法性能优化解决方法总结Vue3动态组件动态