Inflate动态Huffman解压缩

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

Java语言实现,Eclipse下编写。

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

    // 范式huffman解码
	static class CanonicalCode {
		Vector table = new Vector<>();
		
		public CanonicalCode(int[] len) {
			for (int i=0; i() {
				@Override
				public int compare(Node o1, Node o2) {
					return o1.bitLen!=o2.bitLen ? o1.bitLen-o2.bitLen : o1.value - o2.value;
				}
			});
			
			// 初始化第一个节点,实现规则1
			table.get(0).code = 1 << table.get(0).bitLen;
			
			// 计算每一个值得huffman编码
			for (int i=1; i prev.bitLen)	// 位长不等,实现规则3
					node.code = ( prev.code + 1) << (node.bitLen - prev.bitLen);  // 左移'位长差'
			}
		}
		
		// 打印符号和huffman码的对应关系
		void debug() {
			for (int i=0; i

无压缩数据解码:

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

动态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 length
		
		int 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' length
		int ccl_num = hclen + 4;   // 
		
		int[] cl1 = new int[cl1_num];
		int[] cl2 = new int[cl2_num];
		int[] ccl = new int[19]; // ccl bits
		
		// 读取CCL
		Arrays.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 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 code
				value = code1.findValue(code);
			} while (value == null);
			
			// 判断
			if (value >= 0 && value <= 255)// literal
				baos.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 code
					value = 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

输出结果:

Inflate动态Huffman解压缩_第1张图片

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

使用gzip对文件压缩

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

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

原始文件的md5值==解压后的文件的md5值。

你可能感兴趣的:(开发语言,Inflate,Huffman,gzip)