lottie-ios 4.1.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/.github/workflows/main.yml +27 -9
  2. package/Lottie.xcodeproj/project.pbxproj +158 -70
  3. package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +2 -2
  4. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/IDEFindNavigatorScopes.plist +5 -0
  5. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +258 -0
  7. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +13 -2
  8. package/Package.swift +2 -1
  9. package/README.md +3 -3
  10. package/Rakefile +8 -4
  11. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +16 -2
  12. package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +1 -1
  13. package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +1 -1
  14. package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +1 -1
  15. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +6 -6
  16. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +76 -7
  17. package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +1 -1
  18. package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +1 -1
  19. package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +66 -102
  20. package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +2 -2
  21. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +3 -3
  22. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +66 -17
  23. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +55 -32
  24. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +16 -12
  25. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +3 -3
  26. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +24 -11
  27. package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +2 -2
  28. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +1 -1
  29. package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +13 -2
  30. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +9 -1
  31. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +22 -11
  32. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +1 -1
  33. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +13 -2
  34. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +16 -7
  35. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +1 -1
  36. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +2 -2
  37. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +1 -1
  38. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +2 -2
  39. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +20 -8
  40. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +1 -1
  41. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +1 -1
  42. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +1 -1
  43. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +1 -1
  44. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +28 -9
  45. package/Sources/Private/Model/Assets/ImageAsset.swift +4 -3
  46. package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +2 -8
  47. package/Sources/Private/Model/DotLottie/DotLottieManifest.swift +3 -14
  48. package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +11 -1
  49. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+BackingConfiguration.swift +147 -0
  50. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Helpers.swift +351 -0
  51. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+MemoryFile.swift +183 -0
  52. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Progress.swift +66 -0
  53. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Reading.swift +144 -0
  54. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+ReadingDeprecated.swift +49 -0
  55. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Writing.swift +385 -0
  56. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+WritingDeprecated.swift +91 -0
  57. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+ZIP64.swift +170 -0
  58. package/Sources/Private/Model/DotLottie/{Zip/ZipArchive.swift → ZipFoundation/Archive.swift} +150 -227
  59. package/Sources/Private/Model/DotLottie/ZipFoundation/Data+Compression.swift +403 -0
  60. package/Sources/Private/Model/DotLottie/ZipFoundation/Data+CompressionDeprecated.swift +44 -0
  61. package/Sources/Private/Model/DotLottie/{Zip → ZipFoundation}/Data+Serialization.swift +62 -0
  62. package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+Serialization.swift → ZipFoundation/Entry+Serialization.swift} +7 -7
  63. package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+ZIP64.swift → ZipFoundation/Entry+ZIP64.swift} +13 -19
  64. package/Sources/Private/Model/DotLottie/{Zip/ZipEntry.swift → ZipFoundation/Entry.swift} +141 -10
  65. package/Sources/Private/Model/DotLottie/ZipFoundation/FileManager+ZIP.swift +368 -0
  66. package/Sources/Private/Model/DotLottie/ZipFoundation/README.md +24 -0
  67. package/Sources/Private/Model/DotLottie/ZipFoundation/URL+ZIP.swift +32 -0
  68. package/Sources/Private/Model/Extensions/Bundle.swift +5 -14
  69. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +31 -8
  70. package/Sources/Private/Model/Objects/Transform.swift +58 -17
  71. package/Sources/Private/Model/ShapeItems/Repeater.swift +41 -7
  72. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +61 -7
  73. package/Sources/Private/Model/Text/TextAnimator.swift +37 -5
  74. package/Sources/Private/RootAnimationLayer.swift +3 -1
  75. package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +12 -4
  76. package/Sources/Private/Utility/Extensions/DataExtension.swift +14 -4
  77. package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +11 -0
  78. package/Sources/Private/Utility/Primitives/ColorExtension.swift +10 -13
  79. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +28 -6
  80. package/Sources/Public/Animation/LottieAnimationHelpers.swift +12 -10
  81. package/Sources/Public/Animation/LottieAnimationView.swift +213 -186
  82. package/Sources/Public/DotLottie/DotLottieFile.swift +11 -34
  83. package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +101 -74
  84. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +90 -0
  85. package/Sources/Public/iOS/LottieAnimationViewBase.swift +1 -1
  86. package/Sources/Public/macOS/LottieAnimationViewBase.macOS.swift +1 -1
  87. package/lottie-ios.podspec +1 -1
  88. package/package.json +1 -1
  89. package/LottieAnimation/LottieAnimation.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  90. package/LottieAnimation/LottieAnimation.xcodeproj/project.xcworkspace/xcuserdata/valentinperignon.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  91. package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  92. package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/valentinperignon.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
  93. package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/valentinperignon.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  94. package/Sources/Private/Model/DotLottie/Zip/Data+Compression.swift +0 -134
  95. package/Sources/Private/Model/DotLottie/Zip/FileManager+ZIP.swift +0 -130
  96. package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +0 -59
@@ -0,0 +1,403 @@
1
+ //
2
+ // Data+Compression.swift
3
+ // ZIPFoundation
4
+ //
5
+ // Copyright © 2017-2021 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
6
+ // Released under the MIT License.
7
+ //
8
+ // See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
9
+ //
10
+
11
+ import Foundation
12
+
13
+ #if canImport(zlib)
14
+ import zlib
15
+ #endif
16
+
17
+ // MARK: - CompressionMethod
18
+
19
+ /// The compression method of an `Entry` in a ZIP `Archive`.
20
+ enum CompressionMethod: UInt16 {
21
+ /// Indicates that an `Entry` has no compression applied to its contents.
22
+ case none = 0
23
+ /// Indicates that contents of an `Entry` have been compressed with a zlib compatible Deflate algorithm.
24
+ case deflate = 8
25
+ }
26
+
27
+ /// An unsigned 32-Bit Integer representing a checksum.
28
+ typealias CRC32 = UInt32
29
+ /// A custom handler that consumes a `Data` object containing partial entry data.
30
+ /// - Parameters:
31
+ /// - data: A chunk of `Data` to consume.
32
+ /// - Throws: Can throw to indicate errors during data consumption.
33
+ typealias Consumer = (_ data: Data) throws -> Void
34
+ /// A custom handler that receives a position and a size that can be used to provide data from an arbitrary source.
35
+ /// - Parameters:
36
+ /// - position: The current read position.
37
+ /// - size: The size of the chunk to provide.
38
+ /// - Returns: A chunk of `Data`.
39
+ /// - Throws: Can throw to indicate errors in the data source.
40
+ typealias Provider = (_ position: Int64, _ size: Int) throws -> Data
41
+
42
+ extension Data {
43
+ enum CompressionError: Error {
44
+ case invalidStream
45
+ case corruptedData
46
+ }
47
+
48
+ /// Compress the output of `provider` and pass it to `consumer`.
49
+ /// - Parameters:
50
+ /// - size: The uncompressed size of the data to be compressed.
51
+ /// - bufferSize: The maximum size of the compression buffer.
52
+ /// - provider: A closure that accepts a position and a chunk size. Returns a `Data` chunk.
53
+ /// - consumer: A closure that processes the result of the compress operation.
54
+ /// - Returns: The checksum of the processed content.
55
+ static func compress(size: Int64, bufferSize: Int, provider: Provider, consumer: Consumer) throws -> CRC32 {
56
+ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
57
+ return try process(
58
+ operation: COMPRESSION_STREAM_ENCODE,
59
+ size: size,
60
+ bufferSize: bufferSize,
61
+ provider: provider,
62
+ consumer: consumer)
63
+ #else
64
+ return try encode(size: size, bufferSize: bufferSize, provider: provider, consumer: consumer)
65
+ #endif
66
+ }
67
+
68
+ /// Decompress the output of `provider` and pass it to `consumer`.
69
+ /// - Parameters:
70
+ /// - size: The compressed size of the data to be decompressed.
71
+ /// - bufferSize: The maximum size of the decompression buffer.
72
+ /// - skipCRC32: Optional flag to skip calculation of the CRC32 checksum to improve performance.
73
+ /// - provider: A closure that accepts a position and a chunk size. Returns a `Data` chunk.
74
+ /// - consumer: A closure that processes the result of the decompress operation.
75
+ /// - Returns: The checksum of the processed content.
76
+ static func decompress(
77
+ size: Int64,
78
+ bufferSize: Int,
79
+ skipCRC32: Bool,
80
+ provider: Provider,
81
+ consumer: Consumer)
82
+ throws -> CRC32
83
+ {
84
+ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
85
+ return try process(
86
+ operation: COMPRESSION_STREAM_DECODE,
87
+ size: size,
88
+ bufferSize: bufferSize,
89
+ skipCRC32: skipCRC32,
90
+ provider: provider,
91
+ consumer: consumer)
92
+ #else
93
+ return try decode(bufferSize: bufferSize, skipCRC32: skipCRC32, provider: provider, consumer: consumer)
94
+ #endif
95
+ }
96
+
97
+ /// Calculate the `CRC32` checksum of the receiver.
98
+ ///
99
+ /// - Parameter checksum: The starting seed.
100
+ /// - Returns: The checksum calculated from the bytes of the receiver and the starting seed.
101
+ func crc32(checksum: CRC32) -> CRC32 {
102
+ #if canImport(zlib)
103
+ return withUnsafeBytes { bufferPointer in
104
+ let length = UInt32(count)
105
+ return CRC32(zlib.crc32(UInt(checksum), bufferPointer.bindMemory(to: UInt8.self).baseAddress, length))
106
+ }
107
+ #else
108
+ return builtInCRC32(checksum: checksum)
109
+ #endif
110
+ }
111
+
112
+ }
113
+
114
+ // MARK: - Apple Platforms
115
+
116
+ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
117
+ import Compression
118
+
119
+ extension Data {
120
+
121
+ static func process(
122
+ operation: compression_stream_operation,
123
+ size: Int64,
124
+ bufferSize: Int,
125
+ skipCRC32: Bool = false,
126
+ provider: Provider,
127
+ consumer: Consumer)
128
+ throws -> CRC32
129
+ {
130
+ var crc32 = CRC32(0)
131
+ let destPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
132
+ defer { destPointer.deallocate() }
133
+ let streamPointer = UnsafeMutablePointer<compression_stream>.allocate(capacity: 1)
134
+ defer { streamPointer.deallocate() }
135
+ var stream = streamPointer.pointee
136
+ var status = compression_stream_init(&stream, operation, COMPRESSION_ZLIB)
137
+ guard status != COMPRESSION_STATUS_ERROR else { throw CompressionError.invalidStream }
138
+ defer { compression_stream_destroy(&stream) }
139
+ stream.src_size = 0
140
+ stream.dst_ptr = destPointer
141
+ stream.dst_size = bufferSize
142
+ var position: Int64 = 0
143
+ var sourceData: Data?
144
+ repeat {
145
+ let isExhausted = stream.src_size == 0
146
+ if isExhausted {
147
+ do {
148
+ sourceData = try provider(position, Int(Swift.min(size - position, Int64(bufferSize))))
149
+ position += Int64(stream.prepare(for: sourceData))
150
+ } catch { throw error }
151
+ }
152
+ if let sourceData = sourceData {
153
+ sourceData.withUnsafeBytes { rawBufferPointer in
154
+ if let baseAddress = rawBufferPointer.baseAddress {
155
+ let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
156
+ stream.src_ptr = pointer.advanced(by: sourceData.count - stream.src_size)
157
+ let flags = sourceData.count < bufferSize ? Int32(COMPRESSION_STREAM_FINALIZE.rawValue) : 0
158
+ status = compression_stream_process(&stream, flags)
159
+ }
160
+ }
161
+ if
162
+ operation == COMPRESSION_STREAM_ENCODE,
163
+ isExhausted, skipCRC32 == false { crc32 = sourceData.crc32(checksum: crc32) }
164
+ }
165
+ switch status {
166
+ case COMPRESSION_STATUS_OK, COMPRESSION_STATUS_END:
167
+ let outputData = Data(bytesNoCopy: destPointer, count: bufferSize - stream.dst_size, deallocator: .none)
168
+ try consumer(outputData)
169
+ if operation == COMPRESSION_STREAM_DECODE, !skipCRC32 { crc32 = outputData.crc32(checksum: crc32) }
170
+ stream.dst_ptr = destPointer
171
+ stream.dst_size = bufferSize
172
+ default: throw CompressionError.corruptedData
173
+ }
174
+ } while status == COMPRESSION_STATUS_OK
175
+ return crc32
176
+ }
177
+ }
178
+
179
+ extension compression_stream {
180
+
181
+ fileprivate mutating func prepare(for sourceData: Data?) -> Int {
182
+ guard let sourceData = sourceData else { return 0 }
183
+
184
+ src_size = sourceData.count
185
+ return sourceData.count
186
+ }
187
+ }
188
+
189
+ // MARK: - Linux
190
+
191
+ #else
192
+ import CZlib
193
+
194
+ extension Data {
195
+ static func encode(size: Int64, bufferSize: Int, provider: Provider, consumer: Consumer) throws -> CRC32 {
196
+ var stream = z_stream()
197
+ let streamSize = Int32(MemoryLayout<z_stream>.size)
198
+ var result = deflateInit2_(
199
+ &stream,
200
+ Z_DEFAULT_COMPRESSION,
201
+ Z_DEFLATED,
202
+ -MAX_WBITS,
203
+ 9,
204
+ Z_DEFAULT_STRATEGY,
205
+ ZLIB_VERSION,
206
+ streamSize)
207
+ defer { deflateEnd(&stream) }
208
+ guard result == Z_OK else { throw CompressionError.invalidStream }
209
+ var flush = Z_NO_FLUSH
210
+ var position: Int64 = 0
211
+ var zipCRC32 = CRC32(0)
212
+ repeat {
213
+ let readSize = Int(Swift.min(size - position, Int64(bufferSize)))
214
+ var inputChunk = try provider(position, readSize)
215
+ zipCRC32 = inputChunk.crc32(checksum: zipCRC32)
216
+ stream.avail_in = UInt32(inputChunk.count)
217
+ try inputChunk.withUnsafeMutableBytes { rawBufferPointer in
218
+ if let baseAddress = rawBufferPointer.baseAddress {
219
+ let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
220
+ stream.next_in = pointer
221
+ flush = position + Int64(bufferSize) >= size ? Z_FINISH : Z_NO_FLUSH
222
+ } else if rawBufferPointer.count > 0 {
223
+ throw CompressionError.corruptedData
224
+ } else {
225
+ stream.next_in = nil
226
+ flush = Z_FINISH
227
+ }
228
+ var outputChunk = Data(count: bufferSize)
229
+ repeat {
230
+ stream.avail_out = UInt32(bufferSize)
231
+ try outputChunk.withUnsafeMutableBytes { rawBufferPointer in
232
+ guard let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 else {
233
+ throw CompressionError.corruptedData
234
+ }
235
+ let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
236
+ stream.next_out = pointer
237
+ result = deflate(&stream, flush)
238
+ }
239
+ guard result >= Z_OK else { throw CompressionError.corruptedData }
240
+
241
+ outputChunk.count = bufferSize - Int(stream.avail_out)
242
+ try consumer(outputChunk)
243
+ } while stream.avail_out == 0
244
+ }
245
+ position += Int64(readSize)
246
+ } while flush != Z_FINISH
247
+ return zipCRC32
248
+ }
249
+
250
+ static func decode(bufferSize: Int, skipCRC32: Bool, provider: Provider, consumer: Consumer) throws -> CRC32 {
251
+ var stream = z_stream()
252
+ let streamSize = Int32(MemoryLayout<z_stream>.size)
253
+ var result = inflateInit2_(&stream, -MAX_WBITS, ZLIB_VERSION, streamSize)
254
+ defer { inflateEnd(&stream) }
255
+ guard result == Z_OK else { throw CompressionError.invalidStream }
256
+ var unzipCRC32 = CRC32(0)
257
+ var position: Int64 = 0
258
+ repeat {
259
+ stream.avail_in = UInt32(bufferSize)
260
+ var chunk = try provider(position, bufferSize)
261
+ position += Int64(chunk.count)
262
+ try chunk.withUnsafeMutableBytes { rawBufferPointer in
263
+ if let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 {
264
+ let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
265
+ stream.next_in = pointer
266
+ repeat {
267
+ var outputData = Data(count: bufferSize)
268
+ stream.avail_out = UInt32(bufferSize)
269
+ try outputData.withUnsafeMutableBytes { rawBufferPointer in
270
+ if let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 {
271
+ let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
272
+ stream.next_out = pointer
273
+ } else {
274
+ throw CompressionError.corruptedData
275
+ }
276
+ result = inflate(&stream, Z_NO_FLUSH)
277
+ guard
278
+ result != Z_NEED_DICT,
279
+ result != Z_DATA_ERROR,
280
+ result != Z_MEM_ERROR else
281
+ {
282
+ throw CompressionError.corruptedData
283
+ }
284
+ }
285
+ let remainingLength = UInt32(bufferSize) - stream.avail_out
286
+ outputData.count = Int(remainingLength)
287
+ try consumer(outputData)
288
+ if !skipCRC32 { unzipCRC32 = outputData.crc32(checksum: unzipCRC32) }
289
+ } while stream.avail_out == 0
290
+ }
291
+ }
292
+ } while result != Z_STREAM_END
293
+ return unzipCRC32
294
+ }
295
+ }
296
+
297
+ #endif
298
+
299
+ /// The lookup table used to calculate `CRC32` checksums when using the built-in
300
+ /// CRC32 implementation.
301
+ private let crcTable: [CRC32] = [
302
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,
303
+ 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
304
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
305
+ 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
306
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
307
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
308
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
309
+ 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
310
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,
311
+ 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
312
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,
313
+ 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
314
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,
315
+ 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
316
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
317
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
318
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
319
+ 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
320
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,
321
+ 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
322
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
323
+ 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
324
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7,
325
+ 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
326
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
327
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
328
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330,
329
+ 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
330
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
331
+ ]
332
+
333
+ extension Data {
334
+
335
+ /// Lookup table-based CRC32 implenetation that is used
336
+ /// if `zlib` isn't available.
337
+ /// - Parameter checksum: Running checksum or `0` for the initial run.
338
+ /// - Returns: The calculated checksum of the receiver.
339
+ func builtInCRC32(checksum: CRC32) -> CRC32 {
340
+ // The typecast is necessary on 32-bit platforms because of
341
+ // https://bugs.swift.org/browse/SR-1774
342
+ let mask = 0xffffffff as CRC32
343
+ var result = checksum ^ mask
344
+ #if swift(>=5.0)
345
+ crcTable.withUnsafeBufferPointer { crcTablePointer in
346
+ self.withUnsafeBytes { bufferPointer in
347
+ var bufferIndex = 0
348
+ while bufferIndex < self.count {
349
+ let byte = bufferPointer[bufferIndex]
350
+ let index = Int((result ^ CRC32(byte)) & 0xff)
351
+ result = (result >> 8) ^ crcTablePointer[index]
352
+ bufferIndex += 1
353
+ }
354
+ }
355
+ }
356
+ #else
357
+ withUnsafeBytes { bytes in
358
+ let bins = stride(from: 0, to: self.count, by: 256)
359
+ for bin in bins {
360
+ for binIndex in 0..<256 {
361
+ let byteIndex = bin + binIndex
362
+ guard byteIndex < self.count else { break }
363
+
364
+ let byte = bytes[byteIndex]
365
+ let index = Int((result ^ CRC32(byte)) & 0xff)
366
+ result = (result >> 8) ^ crcTable[index]
367
+ }
368
+ }
369
+ }
370
+ #endif
371
+ return result ^ mask
372
+ }
373
+ }
374
+
375
+ #if !swift(>=5.0)
376
+
377
+ // Since Swift 5.0, `Data.withUnsafeBytes()` passes an `UnsafeRawBufferPointer` instead of an `UnsafePointer<UInt8>`
378
+ // into `body`.
379
+ // We provide a compatible method for targets that use Swift 4.x so that we can use the new version
380
+ // across all language versions.
381
+
382
+ extension Data {
383
+ func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
384
+ let count = count
385
+ return try withUnsafeBytes { (pointer: UnsafePointer<UInt8>) throws -> T in
386
+ try body(UnsafeRawBufferPointer(start: pointer, count: count))
387
+ }
388
+ }
389
+
390
+ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
391
+ #else
392
+ mutating func withUnsafeMutableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T {
393
+ let count = count
394
+ guard count > 0 else {
395
+ return try body(UnsafeMutableRawBufferPointer(start: nil, count: count))
396
+ }
397
+ return try withUnsafeMutableBytes { (pointer: UnsafeMutablePointer<UInt8>) throws -> T in
398
+ try body(UnsafeMutableRawBufferPointer(start: pointer, count: count))
399
+ }
400
+ }
401
+ #endif
402
+ }
403
+ #endif
@@ -0,0 +1,44 @@
1
+ //
2
+ // Data+CompressionDeprecated.swift
3
+ // ZIPFoundation
4
+ //
5
+ // Copyright © 2017-2021 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
6
+ // Released under the MIT License.
7
+ //
8
+ // See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
9
+ //
10
+
11
+ import Foundation
12
+
13
+ extension Data {
14
+
15
+ @available(*, deprecated, message: "Please use `Int64` for `size` and provider `position`.")
16
+ static func compress(
17
+ size: Int,
18
+ bufferSize: Int,
19
+ provider: (_ position: Int, _ size: Int) throws -> Data,
20
+ consumer: Consumer)
21
+ throws -> CRC32
22
+ {
23
+ let newProvider: Provider = { try provider(Int($0), $1) }
24
+ return try compress(size: Int64(size), bufferSize: bufferSize, provider: newProvider, consumer: consumer)
25
+ }
26
+
27
+ @available(*, deprecated, message: "Please use `Int64` for `size` and provider `position`.")
28
+ static func decompress(
29
+ size: Int,
30
+ bufferSize: Int,
31
+ skipCRC32: Bool,
32
+ provider: (_ position: Int, _ size: Int) throws -> Data,
33
+ consumer: Consumer)
34
+ throws -> CRC32
35
+ {
36
+ let newProvider: Provider = { try provider(Int($0), $1) }
37
+ return try decompress(
38
+ size: Int64(size),
39
+ bufferSize: bufferSize,
40
+ skipCRC32: skipCRC32,
41
+ provider: newProvider,
42
+ consumer: consumer)
43
+ }
44
+ }
@@ -10,7 +10,11 @@
10
10
 
11
11
  import Foundation
12
12
 
13
+ #if os(Android)
14
+ typealias FILEPointer = OpaquePointer
15
+ #else
13
16
  typealias FILEPointer = UnsafeMutablePointer<FILE>
17
+ #endif
14
18
 
15
19
  // MARK: - DataSerializable
16
20
 
@@ -40,6 +44,36 @@ extension Data {
40
44
  return structure
41
45
  }
42
46
 
47
+ static func consumePart(
48
+ of size: Int64,
49
+ chunkSize: Int,
50
+ skipCRC32: Bool = false,
51
+ provider: Provider,
52
+ consumer: Consumer)
53
+ throws -> CRC32
54
+ {
55
+ var checksum = CRC32(0)
56
+ guard size > 0 else {
57
+ try consumer(Data())
58
+ return checksum
59
+ }
60
+
61
+ let readInOneChunk = (size < chunkSize)
62
+ var chunkSize = readInOneChunk ? Int(size) : chunkSize
63
+ var bytesRead: Int64 = 0
64
+ while bytesRead < size {
65
+ let remainingSize = size - bytesRead
66
+ chunkSize = remainingSize < chunkSize ? Int(remainingSize) : chunkSize
67
+ let data = try provider(bytesRead, chunkSize)
68
+ try consumer(data)
69
+ if !skipCRC32 {
70
+ checksum = data.crc32(checksum: checksum)
71
+ }
72
+ bytesRead += Int64(chunkSize)
73
+ }
74
+ return checksum
75
+ }
76
+
43
77
  static func readChunk(of size: Int, from file: FILEPointer) throws -> Data {
44
78
  let alignment = MemoryLayout<UInt>.alignment
45
79
  #if swift(>=4.1)
@@ -75,6 +109,34 @@ extension Data {
75
109
  return sizeWritten
76
110
  }
77
111
 
112
+ static func writeLargeChunk(
113
+ _ chunk: Data,
114
+ size: UInt64,
115
+ bufferSize: Int,
116
+ to file: FILEPointer)
117
+ throws -> UInt64
118
+ {
119
+ var sizeWritten: UInt64 = 0
120
+ chunk.withUnsafeBytes { rawBufferPointer in
121
+ if let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 {
122
+ let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
123
+
124
+ while sizeWritten < size {
125
+ let remainingSize = size - sizeWritten
126
+ let chunkSize = Swift.min(Int(remainingSize), bufferSize)
127
+ let curPointer = pointer.advanced(by: Int(sizeWritten))
128
+ fwrite(curPointer, 1, chunkSize, file)
129
+ sizeWritten += UInt64(chunkSize)
130
+ }
131
+ }
132
+ }
133
+ let error = ferror(file)
134
+ if error > 0 {
135
+ throw DataError.unwritableFile
136
+ }
137
+ return sizeWritten
138
+ }
139
+
78
140
  func scanValue<T>(start: Int) -> T {
79
141
  let subdata = subdata(in: start..<start + MemoryLayout<T>.size)
80
142
  #if swift(>=5.0)
@@ -10,12 +10,12 @@
10
10
 
11
11
  import Foundation
12
12
 
13
- extension ZipEntry.LocalFileHeader {
13
+ extension Entry.LocalFileHeader {
14
14
 
15
15
  // MARK: Lifecycle
16
16
 
17
17
  init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
18
- guard data.count == ZipEntry.LocalFileHeader.size else { return nil }
18
+ guard data.count == Entry.LocalFileHeader.size else { return nil }
19
19
  guard data.scanValue(start: 0) == localFileHeaderSignature else { return nil }
20
20
  versionNeededToExtract = data.scanValue(start: 4)
21
21
  generalPurposeBitFlag = data.scanValue(start: 6)
@@ -37,7 +37,7 @@ extension ZipEntry.LocalFileHeader {
37
37
  subRangeEnd = subRangeStart + Int(extraFieldLength)
38
38
  extraFieldData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
39
39
  if
40
- let zip64ExtendedInformation = ZipEntry.ZIP64ExtendedInformation.scanForZIP64Field(
40
+ let zip64ExtendedInformation = Entry.ZIP64ExtendedInformation.scanForZIP64Field(
41
41
  in: extraFieldData,
42
42
  fields: validFields)
43
43
  {
@@ -78,12 +78,12 @@ extension ZipEntry.LocalFileHeader {
78
78
 
79
79
  }
80
80
 
81
- extension ZipEntry.CentralDirectoryStructure {
81
+ extension Entry.CentralDirectoryStructure {
82
82
 
83
83
  // MARK: Lifecycle
84
84
 
85
85
  init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
86
- guard data.count == ZipEntry.CentralDirectoryStructure.size else { return nil }
86
+ guard data.count == Entry.CentralDirectoryStructure.size else { return nil }
87
87
  guard data.scanValue(start: 0) == centralDirectorySignature else { return nil }
88
88
  versionMadeBy = data.scanValue(start: 4)
89
89
  versionNeededToExtract = data.scanValue(start: 6)
@@ -114,7 +114,7 @@ extension ZipEntry.CentralDirectoryStructure {
114
114
  subRangeEnd = subRangeStart + Int(fileCommentLength)
115
115
  fileCommentData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
116
116
  if
117
- let zip64ExtendedInformation = ZipEntry.ZIP64ExtendedInformation.scanForZIP64Field(
117
+ let zip64ExtendedInformation = Entry.ZIP64ExtendedInformation.scanForZIP64Field(
118
118
  in: extraFieldData,
119
119
  fields: validFields)
120
120
  {
@@ -168,7 +168,7 @@ extension ZipEntry.CentralDirectoryStructure {
168
168
 
169
169
  }
170
170
 
171
- extension ZipEntry.DataDescriptor {
171
+ extension Entry.DataDescriptor {
172
172
  init?(data: Data, additionalDataProvider _: (Int) throws -> Data) {
173
173
  guard data.count == Self.size else { return nil }
174
174
  let signature: UInt32 = data.scanValue(start: 0)
@@ -17,13 +17,7 @@ protocol ExtensibleDataField {
17
17
  var dataSize: UInt16 { get }
18
18
  }
19
19
 
20
- // MARK: - ExtraFieldHeaderID
21
-
22
- private enum ExtraFieldHeaderID: UInt16 {
23
- case zip64ExtendedInformation = 0x0001
24
- }
25
-
26
- extension ZipEntry {
20
+ extension Entry {
27
21
  enum EntryError: Error {
28
22
  case invalidDataError
29
23
  }
@@ -43,9 +37,9 @@ extension ZipEntry {
43
37
  }
44
38
  }
45
39
 
46
- typealias Field = ZipEntry.ZIP64ExtendedInformation.Field
40
+ typealias Field = Entry.ZIP64ExtendedInformation.Field
47
41
 
48
- extension ZipEntry.LocalFileHeader {
42
+ extension Entry.LocalFileHeader {
49
43
  var validFields: [Field] {
50
44
  var fields: [Field] = []
51
45
  if uncompressedSize == .max { fields.append(.uncompressedSize) }
@@ -54,7 +48,7 @@ extension ZipEntry.LocalFileHeader {
54
48
  }
55
49
  }
56
50
 
57
- extension ZipEntry.CentralDirectoryStructure {
51
+ extension Entry.CentralDirectoryStructure {
58
52
  var validFields: [Field] {
59
53
  var fields: [Field] = []
60
54
  if uncompressedSize == .max { fields.append(.uncompressedSize) }
@@ -64,12 +58,12 @@ extension ZipEntry.CentralDirectoryStructure {
64
58
  return fields
65
59
  }
66
60
 
67
- var zip64ExtendedInformation: ZipEntry.ZIP64ExtendedInformation? {
68
- extraFields?.compactMap { $0 as? ZipEntry.ZIP64ExtendedInformation }.first
61
+ var zip64ExtendedInformation: Entry.ZIP64ExtendedInformation? {
62
+ extraFields?.compactMap { $0 as? Entry.ZIP64ExtendedInformation }.first
69
63
  }
70
64
  }
71
65
 
72
- extension ZipEntry.ZIP64ExtendedInformation {
66
+ extension Entry.ZIP64ExtendedInformation {
73
67
 
74
68
  // MARK: Lifecycle
75
69
 
@@ -83,7 +77,7 @@ extension ZipEntry.ZIP64ExtendedInformation {
83
77
  readOffset += MemoryLayout<T>.size
84
78
  }
85
79
  guard readOffset + field.size <= data.count else {
86
- throw ZipEntry.EntryError.invalidDataError
80
+ throw Entry.EntryError.invalidDataError
87
81
  }
88
82
  return data.scanValue(start: readOffset)
89
83
  } else {
@@ -101,11 +95,11 @@ extension ZipEntry.ZIP64ExtendedInformation {
101
95
  }
102
96
  }
103
97
 
104
- init?(zip64ExtendedInformation: ZipEntry.ZIP64ExtendedInformation?, offset: UInt64) {
98
+ init?(zip64ExtendedInformation: Entry.ZIP64ExtendedInformation?, offset: UInt64) {
105
99
  // Only used when removing entry, if no ZIP64 extended information exists,
106
100
  // then this information will not be newly added either
107
101
  guard let existingInfo = zip64ExtendedInformation else { return nil }
108
- relativeOffsetOfLocalHeader = offset >= UInt32.max ? offset : 0
102
+ relativeOffsetOfLocalHeader = offset >= maxOffsetOfLocalFileHeader ? offset : 0
109
103
  uncompressedSize = existingInfo.uncompressedSize
110
104
  compressedSize = existingInfo.compressedSize
111
105
  diskNumberStart = existingInfo.diskNumberStart
@@ -157,20 +151,20 @@ extension ZipEntry.ZIP64ExtendedInformation {
157
151
  return data
158
152
  }
159
153
 
160
- static func scanForZIP64Field(in data: Data, fields: [Field]) -> ZipEntry.ZIP64ExtendedInformation? {
154
+ static func scanForZIP64Field(in data: Data, fields: [Field]) -> Entry.ZIP64ExtendedInformation? {
161
155
  guard data.isEmpty == false else { return nil }
162
156
  var offset = 0
163
157
  var headerID: UInt16
164
158
  var dataSize: UInt16
165
159
  let extraFieldLength = data.count
166
- let headerSize = Int(ZipEntry.ZIP64ExtendedInformation.headerSize)
160
+ let headerSize = Int(Entry.ZIP64ExtendedInformation.headerSize)
167
161
  while offset < extraFieldLength - headerSize {
168
162
  headerID = data.scanValue(start: offset)
169
163
  dataSize = data.scanValue(start: offset + 2)
170
164
  let nextOffset = offset + headerSize + Int(dataSize)
171
165
  guard nextOffset <= extraFieldLength else { return nil }
172
166
  if headerID == ExtraFieldHeaderID.zip64ExtendedInformation.rawValue {
173
- return ZipEntry.ZIP64ExtendedInformation(data: data.subdata(in: offset..<nextOffset), fields: fields)
167
+ return Entry.ZIP64ExtendedInformation(data: data.subdata(in: offset..<nextOffset), fields: fields)
174
168
  }
175
169
  offset = nextOffset
176
170
  }