I am trying to decompress some JSON (representing a Codable
type) that was compressed on an iPhone, using the NSData
instance method .compressed(using: .zlib)
. Note .zlib
is the format recommended by Apple for portability.
The output bytes are not recognized by tools like Python 3's zlib
library (on macOS 12.2 or Ubuntu Linux 21.10) or the command-line uncompress
(on macOS).
Question: how can I decompress this data on other devices/not in Swift on Apple?
Here's a basic example which can be thrown into compressor.swift
and compiled/run to produce the compressed data, following this guide
import Foundation
struct SomeThing: Codable {
var thing: String
init(thing: String) {
self.thing = thing
}
}
let thing = SomeThing(thing: "abc")
let encoder = JSONEncoder()
let encodedThing = try encoder.encode(thing)
let compressedEncodedThing = try (encodedThing as NSData).compressed(using: .zlib)
try compressedEncodedThing.write(to: URL(fileURLWithPath: "/path/to/somewhere/abc.Z"),
options: [])
Compiling and running that on macOS produces abc.Z
as expected.
This code will decompress the file we just wrote, so long as we compile on macOS:
import Foundation
let readBytes = try! Data(contentsOf: URL(fileURLWithPath: "/path/to/somewhere/abc.Z"))
let decompressed = try! (readBytes as NSData).decompressed(using: .zlib) as Data
let decompString = String(decoding: decompressed, as: UTF8.self)
print(decompString) // prints {"thing": "abc"}
Trying the same thing on Linux (Ubuntu 21.10 with Swift 5.5.3 Release toolchain),
$ swiftc decompressor.swift
decompressor.swift:5:47: error: value of type 'NSData' has no member 'decompressed'
let decompressed = try! (readBytes as NSData).decompressed(using: .zlib) as Data
~~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~
decompressor.swift:5:68: error: cannot infer contextual base in reference to member 'zlib'
let decompressed = try! (readBytes as NSData).decompressed(using: .zlib) as Data
which suggests that the open sourced NSData
lacks some methods it has on Apple hardware/OS.
Other things I've tried that strongly suggest true ZLib encoding is not being used:
- Calling
(from the same macOS computer that produceduncompress abc.Z
abc.Z
) returns
I've also tried usinguncompress: abc.Z: Inappropriate file type or format
gunzip
, to similar failure message. - Tried
zlib.decompress
in Python 3. The Python failure is perhaps the most informative: this script crashes with errorerror: Error -3 while decompressing data: incorrect header check
import zlib with open("/path/to/somewhere/abc.Z", "rb") as f: bytesRead = f.read() decompressed = zlib.decompress(bytesRead) print(decompressed)
- The first 20 bytes of the file, in hexadecimal, are:
$ od -x -N 20 abc.Z 0000000 56ab c92a ccc8 574b 52b2 4c4a 564a 05aa 0000020 0000 0000021
CodePudding user response:
Your data appears to be a raw deflate stream. In python you can try zlib.decompress(bytesRead, wbits=-15)
.