Skip to content

Instantly share code, notes, and snippets.

@memfrag
Last active September 23, 2018 21:33
Show Gist options
  • Save memfrag/d9a817ab9546b11b63ea to your computer and use it in GitHub Desktop.
Save memfrag/d9a817ab9546b11b63ea to your computer and use it in GitHub Desktop.
import Foundation
import Compression
/// A convenience class for compressing an NSData object.
///
/// Example:
/// ```
/// let compression = Compression(algorithm: .ZLIB)
/// let compressedData = compression.compressData(data)
/// let decompressedData = compresison.decompressData(compressedData)
/// ```
///
public final class Compression {
public enum Algorithm {
case LZ4
case LZFSE
case LZMA
case ZLIB
public func algorithm() -> compression_algorithm {
switch self {
case .LZ4: return COMPRESSION_LZ4
case .LZFSE: return COMPRESSION_LZFSE
case .LZMA: return COMPRESSION_LZMA
case .ZLIB: return COMPRESSION_ZLIB
}
}
}
private let algorithm: Algorithm
private let bufferSize: Int
public init(algorithm: Algorithm, bufferSize: Int = 0x20000) {
self.algorithm = algorithm
self.bufferSize = bufferSize
}
public func compressData(data: NSData) -> NSData? {
return processData(data, algorithm: algorithm, bufferSize: bufferSize, compress: true)
}
public func decompressData(data: NSData) -> NSData? {
return processData(data, algorithm: algorithm, bufferSize: bufferSize, compress: true)
}
private func processData(inputData: NSData, algorithm: Algorithm, bufferSize: Int, compress: Bool) -> NSData? {
guard inputData.length > 0 else { return nil }
var stream = UnsafeMutablePointer<compression_stream>.alloc(1).memory
let initStatus = compression_stream_init(&stream, compress ? COMPRESSION_STREAM_ENCODE : COMPRESSION_STREAM_DECODE, algorithm.algorithm())
guard initStatus != COMPRESSION_STATUS_ERROR else {
print("[Compression] \(compress ? "Compression" : "Decompression") with \(algorithm) failed to init stream with status \(initStatus).")
return nil
}
defer {
compression_stream_destroy(&stream)
}
stream.src_ptr = UnsafePointer<UInt8>(inputData.bytes)
stream.src_size = inputData.length
let buffer = UnsafeMutablePointer<UInt8>.alloc(bufferSize)
stream.dst_ptr = buffer
stream.dst_size = bufferSize
let outputData = NSMutableData()
while true {
let status = compression_stream_process(&stream, Int32(compress ? COMPRESSION_STREAM_FINALIZE.rawValue : 0))
if status == COMPRESSION_STATUS_OK {
guard stream.dst_size == 0 else { continue }
outputData.appendBytes(buffer, length: bufferSize)
stream.dst_ptr = buffer
stream.dst_size = bufferSize
} else if status == COMPRESSION_STATUS_END {
guard stream.dst_ptr > buffer else { continue }
outputData.appendBytes(buffer, length: stream.dst_ptr - buffer)
return outputData
} else if status == COMPRESSION_STATUS_ERROR {
print("[Compression] \(compress ? "Compression" : "Decompression") with \(algorithm) failed with status \(status).")
return nil
}
}
}
}
@parthjdabhi
Copy link

Hey @brototyp, yeah you are right as we are decoding stream we have to set them false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment