@@ -56,7 +56,7 @@ public extension Data
56
56
57
57
/// Please consider the [libcompression documentation](https://developer.apple.com/reference/compression/1665429-data_compression)
58
58
/// for further details. Short info:
59
- /// zlib : Aka deflate. Fast with a good compression rate. Proved itself ofer time and is supported everywhere.
59
+ /// zlib : Aka deflate. Fast with a good compression rate. Proved itself over time and is supported everywhere.
60
60
/// lzfse : Apples custom Lempel-Ziv style compression algorithm. Claims to compress as good as zlib but 2 to 3 times faster.
61
61
/// lzma : Horribly slow. Compression as well as decompression. Compresses better than zlib though.
62
62
/// lz4 : Fast, but compression rate is very bad. Apples lz4 implementation often to not compress at all.
@@ -433,7 +433,7 @@ public struct Adler32: CustomStringConvertible
433
433
434
434
435
435
436
- extension Data
436
+ fileprivate extension Data
437
437
{
438
438
func withUnsafeBytes< ResultType, ContentType> ( _ body: ( UnsafePointer < ContentType > ) throws -> ResultType ) rethrows -> ResultType
439
439
{
@@ -470,8 +470,21 @@ fileprivate func perform(_ config: Config, source: UnsafePointer<UInt8>, sourceS
470
470
let status = compression_stream_init ( & stream, config. operation, config. algorithm)
471
471
guard status != COMPRESSION_STATUS_ERROR else { return nil }
472
472
defer { compression_stream_destroy ( & stream) }
473
-
474
- let bufferSize = Swift . max ( Swift . min ( sourceSize, 64 * 1024 ) , 64 )
473
+
474
+ var result = preload
475
+ var flags : Int32 = Int32 ( COMPRESSION_STREAM_FINALIZE . rawValue)
476
+ let blockLimit = 64 * 1024
477
+ var bufferSize = Swift . max ( sourceSize, 64 )
478
+
479
+ if sourceSize > blockLimit {
480
+ bufferSize = blockLimit
481
+ if config. algorithm == COMPRESSION_LZFSE && config. operation != COMPRESSION_STREAM_ENCODE {
482
+ // This fixes a bug in Apples lzfse decompressor. it will sometimes fail randomly when the input gets
483
+ // splitted into multiple chunks and the flag is not 0. Even though it should always work with FINALIZE...
484
+ flags = 0
485
+ }
486
+ }
487
+
475
488
let buffer = UnsafeMutablePointer< UInt8> . allocate( capacity: bufferSize)
476
489
defer { buffer. deallocate ( ) }
477
490
@@ -480,20 +493,21 @@ fileprivate func perform(_ config: Config, source: UnsafePointer<UInt8>, sourceS
480
493
stream. src_ptr = source
481
494
stream. src_size = sourceSize
482
495
483
- var res = preload
484
- let flags : Int32 = Int32 ( COMPRESSION_STREAM_FINALIZE . rawValue)
485
-
486
496
while true {
487
497
switch compression_stream_process ( & stream, flags) {
488
498
case COMPRESSION_STATUS_OK:
489
499
guard stream. dst_size == 0 else { return nil }
490
- res . append ( buffer, count: stream. dst_ptr - buffer)
500
+ result . append ( buffer, count: stream. dst_ptr - buffer)
491
501
stream. dst_ptr = buffer
492
502
stream. dst_size = bufferSize
503
+
504
+ if flags == 0 && stream. src_size == 0 { // part of the lzfse bugfix above
505
+ flags = Int32 ( COMPRESSION_STREAM_FINALIZE . rawValue)
506
+ }
493
507
494
508
case COMPRESSION_STATUS_END:
495
- res . append ( buffer, count: stream. dst_ptr - buffer)
496
- return res
509
+ result . append ( buffer, count: stream. dst_ptr - buffer)
510
+ return result
497
511
498
512
default :
499
513
return nil
0 commit comments