Decompressing a .gz file in Swift that was compressed in PHP gives me an invalidData error

Viewed 490

My iOS app downloads a .gz file that contains a .sqlite3 file. The app was able to decompress these files without issue for a long time using GzipSwift but now the .gz files are getting bigger and its leading to far more crashes in the app (the issue seems to be with the amount of data being held in memory).

So the new approach was following Apple's guide here

Basically, its gets an input file, creates a destination file, takes an operation (compress or decompress) and an algorithm (.zlib in my case)

    static func streamingCompression(operation: FilterOperation,
                                     sourceFileHandle: FileHandle,
                                     destinationFileHandle: FileHandle,
                                     algorithm: Algorithm {
        let bufferSize = 32_768
        do {
            let outputFilter = try OutputFilter(operation, using: algorithm) { (data: Data?) -> Void in
                    if let data = data {
                        destinationFileHandle.write(data)
                    }
            }

            while true {
                let subdata = sourceFileHandle.readData(ofLength: bufferSize)
          
                try outputFilter.write(subdata)
                if subdata.count < bufferSize {
                    break
                }
            }
        } catch {
            fatalError("Error occurred during decoding: \(error.localizedDescription).")
        }
        sourceFileHandle.closeFile()
        destinationFileHandle.closeFile()
    }

However, when the code gets to the outputFilter.write it throws an error every time straight away.

Fatal error: Error occurred during decoding: The operation couldn’t be completed. (Compression.FilterError error 1.

I can't find anything about this error but its when I print the error with the debugger in xcode it says Compression.FilterError.invalidData

The data is compressed in php like so

    $dbpath = "$dbname.sqlite3"
    $gzpath = "$dbpath.gz";
    // Open the gz file 
    $fp = gzopen($gzpath, 'w9');
    // Compress the file
    gzwrite($fp, file_get_contents($dbpath));
    // Close the gz file and we're done
    gzclose($fp);

I'm compressing with gzip and decompressing with zlib which shouldn't be an issue. I've messed around with the compression level too to see if that fixes it but no joy so far. I've downloaded the whole uncompressed file and that works as expected so the uncompressed data isn't the issue either. The compressed file is used on an Android app also, without issue, so the best solution would be getting this to work rather than trying to use another compression algorithm.

1 Answers

Compression does not want the default gzip header, hence it will bail out. You will have to skip the first two bytes.

Simply add a try? sourceFileHandle.seek(toOffset: 2) before launching your stream processor and it will work.

Related