【发布时间】:2021-10-12 02:13:58
【问题描述】:
我有一个压缩文件,它是一个 CAB,我希望从 Linux 中提取一个文件。由于 Linux 上没有任何本地 CAB 提取器,我想我会尝试完成一个。
虽然我已经看过 MSZIP 文档 [0] 以及 [1] 和 [2],但我在解压缩它时遇到了困难,即使每个 Block 都是使用修改后的 DEFLATE 压缩器压缩的。虽然我确实使用 [3] 来解压缩块,但除了第一个块之外,其余块有很多丢失的数据 [完全无效的数据 [即0x00 填充]。
所以我相信我需要手动解决。
很遗憾,我无法理解 [2]。所以, 使用以下数据:
ED 9D 79 70 1C C7 75 87 07 E0 4D 88 24 EE 8B 94
04 1E A2 44 51 04 81 05 08 2D 11 4A C2 5E 00 96
...
以及下面的代码来剖析数据:
#!/bin/env python
import os
def to_bin(in_item):
b = ord(chr(in_item))
retval = bin(b).replace("0b", "")
if len(retval) < 8:
lx = 8 - len(retval)
q = "0" * lx
retval = q + retval
return retval
def swapbytes(in_bit_str):
p = in_bit_str[:4]
q = in_bit_str[4:]
return q + p
pth = os.path.join("comp", "test_0.dat")
fp = open(pth, 'rb')
fpd = fp.read(10)
fp.close()
dx = ""
for item in fpd:
cx = to_bin(item)
scx = swapbytes(cx)
dx += scx
print(cx)
print("---> %s" % scx)
print("Final: %s" % dx)
bfinal = dx[0]
btype = dx[1:3]
print("Bfinal: %s" % bfinal)
print("Btype: %s" % btype)
rest = dx[3:]
hlit = rest[:5]
hdist = rest[5:11]
hclen = rest[11:15]
hlitd = int(hlit, 2)
hdistd = int(hdist, 2)
hclend = int(hclen, 2)
print("HLIT: %s [%d]" % (hlit, hlitd))
print("HDIST: %s [%d]" % (hdist, hdistd))
print("HCLEN: %s [%d]" % (hclen, hclend))
我得到以下输出:
$ python tstdcmp.py
11101101
---> 11011110
10011101
---> 11011001
01111001
---> 10010111
01110000
---> 00000111
00011100
---> 11000001
11000111
---> 01111100
01110101
---> 01010111
10000111
---> 01111000
00000111
---> 01110000
11100000
---> 00001110
Final: 1101111011011001100101110000011111000001011111000101011101111000011100000
0001110
Bfinal: 1
Btype: 10
HLIT: 11110 [30]
HDIST: 11011 [27]
HCLEN: 0011 [3]
所以我从 RFC1951 [2] 中得到的基本概念是,在一个字节中,它是从最高位到最低位。即 7 6 5 4 3 2 1 0 但是对于多个字节,即 AB CD,字节被交换到 CD AB。
所以通过代码,我确定前两个字节ED 9D
实际上应该是9D ED。
并且以位为单位:
11011110 11011001
这意味着 BFinal == 1 和 BTYPE == 10(因此是动态霍夫曼编码)。
删除前三位后,我得到:
11110 11011001
所以从 [2] 的 3.2.7 开始,我应该有以下几组位的以下信息:
5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286)
5 Bits: HDIST, # of Distance codes - 1 (1 - 32)
4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19)
所以,HLIT = 11110 [30] HDIST = 11011 [27] HCLEN = 0011 [3]
但是从上面看,HLIT 应该在 257 到 286 之间 和 HCLEN 在 4 和 9 之间;但我得到 HLIT = 30 和 HCLEN = 3。
也就是说,3.2.7 中的文档:
For even greater compactness, the code length sequences
themselves are compressed using a Huffman code.
那么这是用霍夫曼代码进一步压缩的例子吗? 我曾希望了解这个 RFC1951[2];但这非常令人困惑。
我看过一些关于 DEFLATE 压缩的 Youtube 视频;但它们主要展示的是算法,而不是字节是如何打包到文件中的。
非常感谢任何帮助。
谢谢
[1] - How to decompress MSZIP files with c#?
[2] - https://datatracker.ietf.org/doc/html/rfc1951
[3] - https://www.nayuki.io/page/simple-deflate-decompressor
【问题讨论】:
标签: python compression deflate