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.
- package/.github/workflows/main.yml +27 -9
- package/Lottie.xcodeproj/project.pbxproj +158 -70
- package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +2 -2
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/IDEFindNavigatorScopes.plist +5 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +258 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +13 -2
- package/Package.swift +2 -1
- package/README.md +3 -3
- package/Rakefile +8 -4
- package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +16 -2
- package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +6 -6
- package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +76 -7
- package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +66 -102
- package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +2 -2
- package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +3 -3
- package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +66 -17
- package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +55 -32
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +16 -12
- package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +3 -3
- package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +24 -11
- package/Sources/Private/CoreAnimation/Layers/ImageLayer.swift +2 -2
- package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +13 -2
- package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +9 -1
- package/Sources/Private/CoreAnimation/ValueProviderStore.swift +22 -11
- package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +1 -1
- package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +13 -2
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +16 -7
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +20 -8
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +28 -9
- package/Sources/Private/Model/Assets/ImageAsset.swift +4 -3
- package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +2 -8
- package/Sources/Private/Model/DotLottie/DotLottieManifest.swift +3 -14
- package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +11 -1
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+BackingConfiguration.swift +147 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Helpers.swift +351 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+MemoryFile.swift +183 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Progress.swift +66 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Reading.swift +144 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+ReadingDeprecated.swift +49 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Writing.swift +385 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+WritingDeprecated.swift +91 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+ZIP64.swift +170 -0
- package/Sources/Private/Model/DotLottie/{Zip/ZipArchive.swift → ZipFoundation/Archive.swift} +150 -227
- package/Sources/Private/Model/DotLottie/ZipFoundation/Data+Compression.swift +403 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/Data+CompressionDeprecated.swift +44 -0
- package/Sources/Private/Model/DotLottie/{Zip → ZipFoundation}/Data+Serialization.swift +62 -0
- package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+Serialization.swift → ZipFoundation/Entry+Serialization.swift} +7 -7
- package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+ZIP64.swift → ZipFoundation/Entry+ZIP64.swift} +13 -19
- package/Sources/Private/Model/DotLottie/{Zip/ZipEntry.swift → ZipFoundation/Entry.swift} +141 -10
- package/Sources/Private/Model/DotLottie/ZipFoundation/FileManager+ZIP.swift +368 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/README.md +24 -0
- package/Sources/Private/Model/DotLottie/ZipFoundation/URL+ZIP.swift +32 -0
- package/Sources/Private/Model/Extensions/Bundle.swift +5 -14
- package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +31 -8
- package/Sources/Private/Model/Objects/Transform.swift +58 -17
- package/Sources/Private/Model/ShapeItems/Repeater.swift +41 -7
- package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +61 -7
- package/Sources/Private/Model/Text/TextAnimator.swift +37 -5
- package/Sources/Private/RootAnimationLayer.swift +3 -1
- package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +12 -4
- package/Sources/Private/Utility/Extensions/DataExtension.swift +14 -4
- package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +11 -0
- package/Sources/Private/Utility/Primitives/ColorExtension.swift +10 -13
- package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +28 -6
- package/Sources/Public/Animation/LottieAnimationHelpers.swift +12 -10
- package/Sources/Public/Animation/LottieAnimationView.swift +213 -186
- package/Sources/Public/DotLottie/DotLottieFile.swift +11 -34
- package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +101 -74
- package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +90 -0
- package/Sources/Public/iOS/LottieAnimationViewBase.swift +1 -1
- package/Sources/Public/macOS/LottieAnimationViewBase.macOS.swift +1 -1
- package/lottie-ios.podspec +1 -1
- package/package.json +1 -1
- package/LottieAnimation/LottieAnimation.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/LottieAnimation/LottieAnimation.xcodeproj/project.xcworkspace/xcuserdata/valentinperignon.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/valentinperignon.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
- package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/valentinperignon.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/Sources/Private/Model/DotLottie/Zip/Data+Compression.swift +0 -134
- package/Sources/Private/Model/DotLottie/Zip/FileManager+ZIP.swift +0 -130
- 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
|
|
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 ==
|
|
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 =
|
|
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
|
|
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 ==
|
|
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 =
|
|
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
|
|
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)
|
package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+ZIP64.swift → ZipFoundation/Entry+ZIP64.swift}
RENAMED
|
@@ -17,13 +17,7 @@ protocol ExtensibleDataField {
|
|
|
17
17
|
var dataSize: UInt16 { get }
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
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 =
|
|
40
|
+
typealias Field = Entry.ZIP64ExtendedInformation.Field
|
|
47
41
|
|
|
48
|
-
extension
|
|
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
|
|
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:
|
|
68
|
-
extraFields?.compactMap { $0 as?
|
|
61
|
+
var zip64ExtendedInformation: Entry.ZIP64ExtendedInformation? {
|
|
62
|
+
extraFields?.compactMap { $0 as? Entry.ZIP64ExtendedInformation }.first
|
|
69
63
|
}
|
|
70
64
|
}
|
|
71
65
|
|
|
72
|
-
extension
|
|
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
|
|
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:
|
|
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 >=
|
|
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]) ->
|
|
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(
|
|
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
|
|
167
|
+
return Entry.ZIP64ExtendedInformation(data: data.subdata(in: offset..<nextOffset), fields: fields)
|
|
174
168
|
}
|
|
175
169
|
offset = nextOffset
|
|
176
170
|
}
|