我想在一个块中压缩一个大小大于 64Kb 的缓冲区。
我目前使用 lib 压缩到 LZ4 压缩/解压缩,它适用于低于 64Kb 的缓冲区。假设我从块中剥离了 Apple extras 标头,因为 Apple 添加了文档中描述的额外字节,说明:该帧记录在此处,以便您可以轻松地包装另一个 LZ4 编码器/解码器以在必要时生成/使用相同的数据流。LZ4 编码缓冲区是一个块序列,每个块都以一个标头开头。有三个可能的标题:
1) A compressed block header consists of: a) the octets 0x62, 0x76, 0x34, and 0x31, b) followed by the size in bytes of the decoded (plaintext) data represented by the block c) and the size (in bytes) of the encoded data stored in the block.
不幸的是,由于我没有找到一种仅在一个块中强制压缩的方法(有可能吗?常规的 LZ4 压缩器提供了一个 maxBlockSize 来解决这个问题),它会生成多个块(对于 64Kb 的 maxBlockSize)。如果我剥离所有标题,几乎不可能解压缩,不知道块之间的边界在哪里。
最后,我的问题是:——是否可以强制压缩器只生成一个块?
我在一个块的情况下剥离额外内容的扩展:
import Compression
extension Data {
public func lz4Compress(removeAppleExtras:Bool, compressedBufferSize: Int = 500_000) -> Data? {
func print(_ text: String) {
Swift.print("Data.lz4Compress(): \(text)")
}
// Data to compress is self
let dataToCompress = self
let compressedBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: compressedBufferSize)
guard let compressedSize = withUnsafeBytes ({ (dataToCompressBuffer: UnsafePointer<UInt8>) -> Int? in
return compression_encode_buffer(
compressedBuffer, compressedBufferSize,
dataToCompressBuffer, dataToCompress.count,
nil,
COMPRESSION_LZ4
)
}) else {
print("*** Error: Unable to compress, returned size is 0 ")
return nil
}
// Turn to Data not duplicating buffer
let compressed = Data(bytesNoCopy: compressedBuffer, count: compressedSize, deallocator: .free)
guard removeAppleExtras else {
return compressed
}
// We must remove Apple extra header/footer
let cz = compressedSize
let axHeader = UInt32(bigEndian: compressed.subdata(in: 0 ..< 4).withUnsafeBytes{$0.pointee})
let axUncompressedSize = UInt32(littleEndian: compressed.subdata(in: 4 ..< 8).withUnsafeBytes{$0.pointee})
let axCompressedSize = UInt32(littleEndian: compressed.subdata(in: 8 ..< 12).withUnsafeBytes{$0.pointee})
print("LZ4 Apple extras for compressed size of \(compressedSize.hex()) (\(compressedSize)), uncompressed: \(dataToCompress.count.hex()) (\(dataToCompress.count))")
print("Apple Header: \(axHeader.hex()) (\(compressed.subdata(in: 0..<4).ascii()))")
print("UncompressedSize: \(axUncompressedSize.hex()) (\(axUncompressedSize))")
print("CompressedSize: \(axCompressedSize.hex()) (\(axCompressedSize))")
let bareBonesCompressed = compressed.subdata(in: 12 ..< (cz-4))
let axFooter = UInt32(bigEndian: compressed.subdata(in: cz-4 ..< cz).withUnsafeBytes{$0.pointee})
print("Apple footer: \(axFooter.hex()) (\(compressed.subdata(in: cz-4 ..< cz).ascii()))")
return bareBonesCompressed
} // Data.lz4Compress()
}