我们如何区分deflate流和deflateRaw流?

6
2个回答

17
如果十六进制的第一个字节的低半字节为8,则它是一个zlib流。否则它是一个未经处理的deflate流。(假设您事先知道唯一可能的选择是有效的zlib流或有效的deflate流)。未经处理的deflate流永远不会在第一个半字节中有8,但zlib流总是会有。
背景: zlib头格式将压缩方法放在第一个字节的低半字节中。该压缩方法对于deflate总是8。 原始deflate流中的位序列从字节的最低有效位开始。 如果前三位是000(如8),那么表示是存储块(即未压缩块),并且它不是最后一个块。 存储块将输入字节放置在字节边界上。 因此,在写入000位之后,压缩器执行的下一件事情是用零位填充其余的位以到达下一个字节边界。 因此,下一个位永远不会是1,因此有效的deflate流不可能使前四位为1000或第一个半字节为8。(请注意,位是从下往上读取的。) 有效的deflate流的第一个(即低)半字节只能为0..5a..d。 如果看到6..9ef,则不是有效的deflate流。

RFC 1951表示,对于存储块(BTYPE=00),将忽略输入数据中直到下一个字节边界的任何位。这意味着0x78可以是有效原始deflate流的起始位置。例如,require('node:zlib').inflateRawSync(Buffer.from([0x78, 1, 0, 0xfe, 0xff, 0x13, 0x79, 1, 0, 0xfe, 0xff, 0x37]))返回<Buffer 13 37> - Victor
@Victor 你完全正确。然而,我坚称没有任何压缩器会产生那样的结果。跳过的位始终填充为零。 - Mark Adler

1
理论上,不可能区分这两者。在下面的示例中,buf既是有效的原始deflate流,也是有效的zlib流。
const zlib = require('node:zlib')

const buf = Buffer.from([
    0x08, 0x1d, 0x79, 0xe2, 0x86, 0x1d, 0x79,
    ...Array(31003).fill(0),
    0x09, 0xc6, 0x0d, 0x39, 0xf2,
    ...Array(3522).fill(0),
    0x71, 0xa4, 0x02, 0x08,
])

console.log(zlib.inflateRawSync(buf))
// <Buffer 1d 79 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 34481 more bytes>

console.log(zlib.inflateSync(buf))
// <Buffer 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 34480 more bytes>

实际上,大多数压缩器的实现在对齐到字节边界时会插入零位,因此可以通过检查第一个字节的低4位来区分,就像其他答案中所描述的那样。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接