Search code examples
javascriptcompressionzlibdeflateshared-directory

Decompress zlib/deflate with a shared dictionary in Javascript


Zlib/deflate doesn't exactly support shared dictionaries but you can "pre-load" the output stream with up to 32kB of data. For example in Python:

>>> from zlib import compressobj
>>> c = compressobj(zdict="abcdefghijklmnopqrstuvwxyz")
>>> c.compress(b"abcdefghijklmnopqrstuvwxyz")
b'x\xbb\x90\x86\x0b '
>>> c.flush()
b'K\xc4)\x03\x00\x90\x86\x0b '

The output is a lot shorter than without the dictionary:

>>> compress(b"abcdefghijklmnopqrstuvwxyz")
b'x\x9cKLJNIMK\xcf\xc8\xcc\xca\xce\xc9\xcd\xcb/(,*.)-+\xaf\xa8\xac\x02\x00\x90\x86\x0b '

The question is: is there any way to decompress the dictionary-compressed output in Javascript using built in web APIs?

I'm 99% sure the answer is no; just checking I haven't missed something.


Solution

  • Here is an example in Python for how to decompress a zlib stream with a dictionary without having to use the zdict option, which hopefully can be adapted to Javascript:

    import zlib
    
    # compress dictionary using dictionary, zlib stream in z
    d = b'abcdefghijklmnopqrstuvwxyz'
    c = zlib.compressobj(zdict=d)
    z = c.compress(d)
    z += c.flush()
    
    # decompress z using dictionary, without having to use zdict, result in r
    u = zlib.decompressobj(wbits=-15)
    h = (b'\0' + len(d).to_bytes(2, 'little') +
                 (65535 - len(d)).to_bytes(2, 'little'))
    u.decompress(h + d)                 # feed dictionary (discarded)
    r = u.decompress(z[6:])             # decompress raw deflate from z
    if int.from_bytes(u.unused_data, 'big') != zlib.adler32(r):
        print('** failed integrity check')