Search code examples
swiftzlibdeflate

Compress and decompress zlib (RFC 1950) using DEFLATE (RFC 1951) functions


On iOS 13 and macOS 10.15 Apple ships some nice functions to compress and decompress in one line of code.

However they only support DEFLATE (RFC 1951) and I have data compressed with ZLIB (RFC 1950).

I have experimentally found that if I remove the first 2 bytes then decompress works:

let output = try NSData(data: input[2...]).decompressed(using: .zlib)

Is this a reliable method?

For compression I've tried adding a 2 byte header:

let output = try Data([0x78, 0x9c]) + input.compressed(using: .zlib)

This works in a few simple cases but definitely fails in others. Is there any way to make this work?


Solution

  • Adding a 2 byte header 0x78, 0x9c will not (as you observed) and should not reliably work. Because RFC1950 expects a 4 byte checksum at the end of the compressed data. Your compressed data will not be portable. Decompressors may complain that the data is corrupt.

    Checksum is the adler32 function described here https://www.rfc-editor.org/rfc/rfc1950#section-2.2. You can get adler32 from the zlib source package and run your raw data through it and append the 4 byte to the end.

    But I am surprised that macOS supports rfc1951 but doesn't support rfc1950. Because 1950 is a trivial extension of 1951 which defines a wrapper around 1950 formatted data. Look for the functions named inflate() deflate() which may do the trick.