如何在python中膨胀这个zlib字节字符串?

2024-09-30 14:36:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在编写一个与流行的数据仓库SaaS交互的工具。他们的在线sql编辑器将sql工作表序列化为JSON,但sql工作表的主体使用pako.js进行了zlib压缩。 我试图从python中读取并扩展这些zlib字符串,但我只能对包含短字符串的ByTestRing进行解码

sql文本的一个示例是字母a

bytestring = b'x\xef\xbf\xbdK\x04\x00\x00b\x00b\n'
zlib.decompress(bytestring[4:-4], -15).decode('utf-8')
>>> "a"

如果包含分号a;,则无法解压缩:

bytestring = b'x\xef\xbf\xbdK\xef\xbf\xbd\x06\x00\x00\xef\xbf\xbd\x00\xef\xbf\xbd\n'
zlib.decompress(bytestring[4:-4], -15).decode('utf-8')
*** UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8f in position 1: invalid start byte

注意:我还尝试了使用“punycode”解码这些示例,我在javascript实现中找到了引用

我对zlib的理解非常有限,但我发现zlib字符串的前两个和最后四个字节是页眉/页脚,如果我们使用神奇的数字-15运行zlib,则可以对其进行修剪。完全有可能存在zlib magic number,它可以解压这些字符串,而不需要去掉页眉和页脚,但是当从-64循环到64时,我无法得到任何组合

我中断了联机sql工作表编辑器的保存和加载函数,发现它们使用的是pako zlib库pako.deflate(a, {to: 'string'})pako.inflate(b['body'], {to: 'string'}),我可以使用pako库在浏览器中膨胀/收缩sql字符串,但无法在python中再现相同的结果


Tags: 字符串示例sql编辑器解码utfdecodexbd
2条回答

\xef\xbf\xbd的每个序列表示原始数据的损坏实例

在第一个示例中,第一个也是唯一的\xef\xbf\xbd应该是一个单字节,它是zlib头的第二个字节。在第二个示例中,第一个\xef\xbf\xbd应该是zlib头的第二个字节,第二个实例应该是\b4,第三个实例应该是\ff,第四个实例应该是\9b

在这条路上的某个地方有一些UTF-8处理不应该发生。每当它遇到一个设置了高位的字节时,它就会失败。在这些情况下,它用三字节UTF-8序列U+FFFD替换字节,这是用于表示未知字符的“替换”字符

归根结底,您的数据已损坏,无法修复。你需要修复上游发生的一切。您是否正在尝试使用复制和粘贴来获取数据?如果你在黑钻石上看到一个问号,那就是UTF-8字符

我同意这是一个数据损坏问题zlibpako应该能够读取彼此的数据,而无需删除任何字段或添加幻数

为了证明这一点,我收集了两个演示脚本,一个使用pako压缩数据,另一个使用zlib再次压缩数据:

// deflate.js
var pako = require("./pako.js");
console.log(escape(pako.deflate(process.argv[2], {to: "string"})));
# inflate.py
import urllib.parse, zlib, sys
print(zlib.decompress(urllib.parse.unquote_to_bytes(sys.stdin.read())).decode("utf-8"))

使用node deflate.js "Here is some example text" | inflate.py在命令行上运行它们。预期的输出是传递给node deflate.js的参数

关于pako值得指出的一点是使用to: "string"选项时的行为。此选项的documentation如下所示:

to (String) - if equal to 'string', then result will be "binary string" (each char code [0..255])

正是出于这个原因,我在上面的JavaScript函数中使用了escape。使用escape可以确保JavaScript和Python之间传递的字符串不包含任何非ASCII字符。(请注意,encodeURIComponent工作,因为字符串包含二进制数据。)然后我在Python中使用urllib.parse.unquote_to_bytes来撤消此转义

如果您可以在浏览器中escape压缩pako的数据,那么您可能会将其传递给Python以再次对其进行膨胀

相关问题 更多 >