Skip to content

Instantly share code, notes, and snippets.

@zadr
Last active December 2, 2020 08:05
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zadr/c664e61e29bea1b7e3a23e88c5ea74cc to your computer and use it in GitHub Desktop.
Save zadr/c664e61e29bea1b7e3a23e88c5ea74cc to your computer and use it in GitHub Desktop.
// license: i dunno. pick one that works for you. Apache 2.0? that seems reasonable. Let me know if it doesn't work for some reason.
import Foundation
import Compression // https://developer.apple.com/library/mac/documentation/Performance/Reference/Compression/
public enum Compression {
public enum Algorithm {
case LZFSE
case LZ4
case LZMA
case ZLIB
private var algorithm: compression_algorithm {
switch self {
case LZFSE: return COMPRESSION_LZFSE
case LZ4: return COMPRESSION_LZ4
case LZMA: return COMPRESSION_LZMA
case ZLIB: return COMPRESSION_ZLIB
}
}
}
public enum Operation {
case compress
case decompress
private var operation: compression_stream_operation {
switch self {
case compress: return COMPRESSION_STREAM_ENCODE
case decompress: return COMPRESSION_STREAM_DECODE
}
}
private var flags: Int32 {
switch self {
case compress: return Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
case decompress: return 0
}
}
}
public struct Options {
let bufferSize: Int
let destination: NSMutableData?
init(bufferSize: Int = 4096, destination: NSMutableData? = nil) {
self.bufferSize = bufferSize
self.destination = destination
}
}
}
public enum Result<T, E: ErrorType> {
case success(T)
case failure(E)
public init(_ x: T) {
self = .success(x)
}
public init(_ y: E) {
self = .failure(y)
}
}
extension NSData {
func compression(with algorithm: Compression.Algorithm = .LZFSE, for operation: Compression.Operation, options: Compression.Options = Compression.Options()) -> Result<NSData, String> {
let stream = UnsafeMutablePointer<compression_stream>.alloc(1)
var underlyingStream = stream.memory
underlyingStream.src_ptr = UnsafePointer<UInt8>(bytes)
underlyingStream.src_size = length
let buffer = UnsafeMutablePointer<UInt8>.alloc(options.bufferSize)
underlyingStream.dst_ptr = buffer
underlyingStream.dst_size = options.bufferSize
if compression_stream_init(&underlyingStream, operation.operation, algorithm.algorithm) == COMPRESSION_STATUS_ERROR {
return Result("Unable to initialize compression stream with algorithm \(algorithm) for operation \(operation)")
}
let destination = options.destination ?? NSMutableData()
while true {
switch compression_stream_process(stream, operation.flags) {
case COMPRESSION_STATUS_OK:
destination.appendBytes(buffer, length: options.bufferSize)
underlyingStream.dst_ptr = buffer
underlyingStream.dst_size = options.bufferSize
case COMPRESSION_STATUS_END:
destination.appendBytes(buffer, length: options.bufferSize)
break
case COMPRESSION_STATUS_ERROR: fallthrough
default:
return Result("Error with compression stream with algorithm \(algorithm) for operation \(operation)")
}
}
compression_stream_destroy(stream)
return Result(destination.copy() as! NSData)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment