Theoretically, it is impossible to distinguish between the two. In the example below, buf
is both a valid raw deflate stream and a valid zlib stream.
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>
Practically, most compressor implementations would insert zero bits when aligning to a byte boundary, so it is possible to distinguish by checking the lower 4 bits of the first byte, as described in the other answer.