GZIP文件格式解析和Inflate静态Huffman解压缩

news2025/1/11 0:29:22

GZIP是封装了Deflate压缩的格式文件;Deflate使用了无压缩、Huffman+LZ77进行压缩;解压是Inflate,Huffman包括静态Huffman压缩和动态Huffman压缩两种模式。

Java语言实现了GZIP格式解析、Inflate的静态Huffman解压缩、CRC32校验 算法。

gzip文件格式解析代码

	    BinaryInputStream bis = new BinaryInputStream(bytes); // 二进制字节流读取类
	
		Header header = new Header();  // 读取GZIP header
		header.ID1 = bis.ReadUInt8();  // GZIP ID1
		header.ID2 = bis.ReadUInt8();  // GzIP ID2
		header.CM = bis.ReadUInt8();  
		header.Flag = bis.ReadUInt8();
		header.Time = bis.ReadUnix32TimeStamp(); 
		header.Xfl = bis.ReadUInt8();
		header.OS = bis.ReadUInt8();
		
		gzip.header = header;
		
		Console.printlnf("ID=%xb%xb", header.ID1, header.ID2); // 打印
		Console.printlnf("CM=%xb", header.CM);
		Console.printlnf("Flag=%xb", header.Flag);
		Console.printlnf("MTime=%S", header.Time);
		Console.printlnf("XFL=%xb", header.Xfl);
		Console.printlnf("OS=%xb", header.OS);
		
		if ( (header.Flag & 0b00001000) != 0) {  // 如果标志位是文件名
			String filename = bis.ReadCString(); // 读取字节流until 0->char[]->string
			Console.printlnf("filename=%S", filename);
		}
		else // 其他待实现
			throw new java.lang.IllegalArgumentException(header.Flag +"");
		
		byte[] result ; // 解压后的字节
		int data_len ;  // 解压前数据长度
		int crc;        // 程序计算解压后的CRC32(见上篇文章)
		
		if (header.CM == 8) { // deflate 
			data_len = bytes.length - bis.GetPosition() - 8;			
			byte[] data = bis.ReadBytes(data_len); // 解压缩前数据	
			result = Deflate.uncompress(data);  // 解压缩,返回解压后字节流
			
			crc = CRC.CRC32(result); // 计算循环冗余码
		}
		else // 待实现
			throw new java.lang.IllegalArgumentException(header.CM +""); 
		
		gzip.crc = bis.ReadUInt32(); // gzip文件自身存储的crc32值
		gzip.isize = bis.ReadInt32(); 
		
		System.out.println("gzip crc="+ Long.toHexString(gzip.crc) +",calc-crc=" + Integer.toHexString( crc) );

解析结果如下:

显示了GZIP标志、压缩方法、压缩时间、原始文件名、操作系统类型、CRC校验值

GZIP中存储的CRC32值(gzip crc)==解压后计算的CRC32值(calc crc)。(0xa93145a2)

Inflate -静态Huffman解压缩:

	// 读取扩展Code
	private static int ReadExtCode(BitsInputStream bis, int len) {
		bis.setOrder(BitOrder.LeftIsHigh);
		return bis.ReadBits(len);
	}
	
	// 读取距离
	private static int ReadDistance(BitsInputStream bis) {
		bis.setOrder(BitOrder.RightIsHigh);
		return bis.ReadBits(5);
	}
	
	// 读取Code
	private static int ReadCode(BitsInputStream bis) {
		bis.setOrder(BitOrder.RightIsHigh);
		int code = bis.ReadBits(7);
		Integer value = FixHuffmanTable_7.get(code); // 7位长查表
		
		if (value == null) {
			int ext = bis.ReadBit();
			code = (code << 1 | ext);
			
			value = FixHuffmanTable_8.get(code); // 8位长查表
			
			if (value == null) {
				ext = bis.ReadBit();
				code = (code << 1 | ext);
				value = FixHuffmanTable_9.get(code); // 9位长查表
				
				if (value == -1)
					throw new java.lang.IllegalArgumentException(code + "");
			}
		}

		return value;
	}
	
	// Deflate解压缩
	public static byte[] uncompress(final byte[] _input) throws IOException {
		IntArrayBuffer baos = new IntArrayBuffer(); // 输出窗口
		
		// 位流读取类
		BitsInputStream bis = new BitsInputStream(_input);
		
		while (true) {
		    int bFinal = bis.ReadBits(1); // 读取Deflate头,0 – 还有后续子块;1 – 该子块是最后一块。
		    int bType = bis.ReadBits(2);  // 读取Deflate头,00 – 不压缩;01 – 静态Huffman编码压缩;10 – 动态Huffman编码压缩;11 – 保留

			if (bType == 0) { // 无压缩,未实现
				int len = bis.ReadBits(16);
				int nlen = bis.ReadBits(16);
				
				assert len + nlen == 65535;
				throw new java.lang.UnsupportedOperationException(bType + ""); 
			}
			else if (bType == 1) { // fixed Huffman
				while (true) {
					int value = ReadCode(bis); // 读取Huffman code
					
                    // 根据literal范围判断
					if (value >= 0 && value <= 255) // literal
						baos.Write(value);
					else if (value == 256) // 结束标志
						break ;
					else if (value >= 257 && value <= 285) { // 距离或长度
						int length = LengthExtraCodeLengthsTable.get(value);
						int bits = LengthExtraCodeBitsTable.get(value); 
						
						if (bits != 0) {
							int ext =  ReadExtCode(bis, bits); // 读取长度
							length = length + ext; 
						}
						
						value = ReadDistance(bis); // 读取距离
						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();
						}
						
					}
					else 
						throw new java.lang.IllegalArgumentException(value+ "");

				}
			}
			else if (bType == 2) { // dynamic huffman 动态Huffman待实现
				throw new java.lang.UnsupportedOperationException(bType + "");
			}
			else 
				throw new java.lang.IllegalArgumentException(bType + "");
			
			if (bFinal == 1) // 最后一个块
				break ;
		}
		
        // 结果
		int[] b = baos.GetInts();
		byte[] result = new byte[b.length];
		for (int i=0; i<b.length; i++) 
			result[i] = (byte) b[i];
		
		return result;

测试结果如下:

将字符串"abcabcabcabcabcabcabcabcabcabcabcabc1111"写入到文件,

运行gzip程序(系统程序)压缩,

使用Java程序对gzip文件解析并显示解压后的内容。 (gzip使用了静态huffman)。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7-AMCA Mal,可通过与蛋白质上的巯基反应生成具有荧光的标记物

【产品概述】 7-AMCA Mal&#xff0c;也被称为7-AMCA maleimide&#xff0c;是一种在生物医学领域中常用的荧光染料。 中文名称&#xff1a;7-AMCA 马来酰亚胺 英文名称&#xff1a;7-AMCA Mal&#xff0c;7-AMCA maleimide CAS号&#xff1a;N/A 分子式&#xff1a;C18H17N3…

STEP BY STEP带你使用Docker搭建MySql-MGR高可用集群

数据的重要性 数据已成为当今数字时代最重要的资产之一&#xff0c;对于企业的成功至关重要。它可以帮助企业了解客户、市场和自身运营&#xff0c;提高运营效率&#xff0c;做出明智决策&#xff0c;推动创新&#xff0c;并获得竞争优势。 数据的采集&#xff0c;存储&#…

解析源代码安全的防泄密解决途径

随着各行各业业务数据信息化发展&#xff0c;各类产品研发及设计等行业&#xff0c;都有关乎自身发展的核心数据&#xff0c;包括业务数据、代码数据、机密文档、用户数据等敏感信息&#xff0c;这些信息数据有以下共性&#xff1a; 属于核心机密资料&#xff0c;万一泄密会对…

TCP四次挥手中为什么 TIME_WAIT 等待的时间是 2MSL?

TCP 连接断开 1、TCP 四次挥手过程是怎样的&#xff1f;如下图 2、为什么 TIME_WAIT 等待的时间是 2MSL&#xff1f; MSL 是 Maximum Segment Lifetime&#xff0c;报文最大生存时间&#xff0c;它是任何报文在网络上存在的最长时间&#xff0c;超过这个时间报文将被丢弃。因…

JavaEE技术之MySql高级-ShardingSphere5(SpringBoot版本:3.0.5)

文章目录 1 ShardingSphere-JDBC读写分离1.1 创建SpringBoot程序1.1.1、创建项目1.1.2、添加依赖1.1.3、创建实体类1.1.4、创建Mapper1.1.5、配置 Spring Boot1.1.6、配置shardingsphere 1.2 测试1.2.1 读写分离测试1.2.2 负载均衡测试1.2.3 事务测试常见错误 2 ShardingSphere…

电子商务对应的职业有哪些?10年互联网人透底行业秘密!

电子商务对应的职业有哪些&#xff1f;10年互联网人透底行业秘密&#xff01; 事实说话&#xff0c;实事求是&#xff0c;不要再把美颜滤镜下的市场&#xff0c;传给新人小伙伴了&#xff01; 大家好&#xff0c;我是微三云胡佳东&#xff0c;一家软件公司负责人&#xff01; …

20240508在RK3588的Buildroot系统下播放MP4视频

20240508在RK3588的Buildroot系统下播放MP4视频 2024/5/8 18:09 开发板&#xff1a;飞凌的OK3588-C SDK&#xff1a;Linux/Buildroot R4版本 4.4.2.5 播放 H264 格式视频 [rootok3588:/]# gst-launch-1.0 filesrc location13850_h264.mp4 ! qtdemux ! queue ! h264parse ! mpp…

3D模型素材有哪些常见的用途?

3D模型素材已经成为了设计、游戏开发、电影制作和建筑等领域的重要工具。它们以其独特的形式和丰富的细节&#xff0c;为这些领域的专业人士提供了无尽的创作可能性。 1.建筑和室内设计&#xff1a;在建筑设计中&#xff0c;3D模型可以帮助建筑师更直观地展示设计方案&#xff…

WiFi原理

一、引言 简介&#xff1a;WiFi&#xff0c;全称Wireless Fidelity&#xff0c;是一种允许电子设备连接到一个无线局域网&#xff08;WLAN&#xff09;的技术&#xff0c;通常使用2.4GHz或5GHz UHF&#xff08;特高频&#xff09;和SHF&#xff08;超高频&#xff09;ISM&…

游戏辅助 -- 三种分析角色坐标方法(CE、xdbg、龙龙遍历工具)

所用工具下载地址&#xff1a; https://pan.quark.cn/s/d54e7cdc55e6 在上次课程中&#xff0c;我们成功获取了人物对象的基址&#xff1a;[[[0xd75db8]1C]28]&#xff0c;而人物血量的地址则是基址再加上偏移量278。 接下来&#xff0c;我们需要执行以下步骤来进一步操作&a…

SpringCloud 集成consul,消费者报I/O error on GET request for...

创建消费者微服务&#xff0c;去调用生产者微服务的请求过程中&#xff0c;出现以下错误&#xff1a; 报错原因 因为在使用SpringCloudAlibaba中的Nacos框架时&#xff0c;自动整合了SpringCloud中的Ribbon框架中的负载均衡&#xff0c;因为微服务提供者有两个&#xff0c;在消…

taos数据库服务器安装

涛思数据库服务器安装分为两种情况 一。新服务器直接安装&#xff08;非常好&#xff09; 二。旧服务器删除后删除干净再安装&#xff08;麻烦得很&#xff09; 先来讲解一下情况一&#xff1a; 找需要的taos安装版本链接&#xff1a;https://docs.taosdata.com/releases/tde…

STM32、GD32驱动PCA9685控制舵机源码分享

一、PCA9685介绍 PCA9685是一种16通道PWM&#xff08;脉宽调制&#xff09;控制器芯片&#xff0c;由NXP Semiconductors公司生产。它具有高速I2C总线接口&#xff0c;可以通过I2C总线与微控制器或其他设备进行通信。PCA9685广泛应用于各种需要精确控制多路PWM信号的应用&…

【启明智显技术分享】基于ESP32-S3方案的彩屏固件烧录指南

前言&#xff1a; 【启明智显】专注于HMI&#xff08;人机交互&#xff09;及AIoT&#xff08;人工智能物联网&#xff09;产品和解决方案的提供商&#xff0c;我们深知彩屏显示方案在现代物联网应用中的重要性。为此&#xff0c;我们一直致力于为客户提供彩屏显示方案相关的技…

ThreeJS:补间动画与Tween.JS

补间动画 补间动画指的是做FLASH动画时&#xff0c;在两个关键帧中间需要做“补间动画”&#xff0c;才能实现图画的运动&#xff1b;插入补间动画后两个关键帧之间的插补帧是由计算机自动运算而得到的。 ——摘自《百度百科&#xff1a;补间动画_百度百科》 Tween.js Tween.js…

JRT失控处理打印和演示

基于JRT完备的脚本化和打印基础&#xff0c;基于JRT的业务可以轻松的实现想要的打效果&#xff0c;这次以质控图的失控处理打印和月报打印来分享基于JRT的打印业务实现。 演示视频链接 失控报告打印 失控处理打印的虚拟M import JRT.Core.DataGrid.GridDto; import JRT.Co…

数据结构(十二)----查找

目录 一.查找的概念 二.查找算法 1.顺序查找 顺序查找的查找效率&#xff1a; 顺序查找的优化&#xff1a; •有序表的优化&#xff08;缩短查找失败的平均查找长度&#xff09; •被查概率不相等的表的优化&#xff08;缩短查找成功的平均查找长度&#xff09; 2.折半…

[Redis] 使用布隆过滤器和分布式锁实现用户注册

布隆过滤器&#xff08;Bloom Filter&#xff09;是一种数据结构&#xff0c;用于快速判断一个元素是否可能存在于一个集合中。它通过使用多个哈希函数和一个位数组来表示一个集合&#xff0c;当一个元素被加入到集合时&#xff0c;通过哈希函数计算出多个哈希值&#xff0c;并…

「网络流 24 题」最小路径覆盖 【最小路径覆盖】

「网络流 24 题」最小路径覆盖 思路 具体可以看 这篇博客 对于有向无环图&#xff0c;我们只需要将假装将点裂成左点和右点&#xff08;实际没有裂开&#xff09;&#xff0c;然后连边&#xff1b; 在上面跑二分图最大匹配后&#xff0c;剩下没有匹配的左点就是终点&#xff…

【linuxC语言】获取进程信息

文章目录 前言一、getrusage函数二、示例代码总结 前言 在Linux环境下&#xff0c;了解和获取进程的信息对于系统监控、性能优化以及调试等任务至关重要。C语言作为Linux系统编程的主要语言之一&#xff0c;提供了丰富的系统调用和库函数&#xff0c;可以帮助我们轻松地获取进…