Last active
December 2, 2020 08:05
-
-
Save zadr/c664e61e29bea1b7e3a23e88c5ea74cc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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