lottie-ios 3.4.4 → 4.0.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/.gitattributes +1 -0
- package/.github/workflows/main.yml +7 -7
- package/Gemfile.lock +1 -1
- package/Lottie.xcodeproj/project.pbxproj +286 -68
- package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +18 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +3 -24
- package/Package.swift +2 -2
- package/README.md +10 -3
- package/Rakefile +1 -1
- package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +6 -9
- package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +42 -3
- package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +5 -17
- package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +25 -17
- package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +2 -2
- package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +1 -1
- package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +9 -20
- package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +39 -25
- package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +13 -32
- package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +4 -4
- package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +13 -13
- package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +4 -4
- package/Sources/Private/CoreAnimation/Extensions/KeyframeGroup+exactlyOneKeyframe.swift +4 -12
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +222 -0
- package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +8 -6
- package/Sources/Private/CoreAnimation/Layers/GradientRenderLayer.swift +13 -10
- package/Sources/Private/CoreAnimation/Layers/InfiniteOpaqueAnimationLayer.swift +56 -0
- package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -1
- package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +2 -3
- package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +9 -9
- package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +9 -3
- package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +7 -18
- package/Sources/Private/CoreAnimation/ValueProviderStore.swift +2 -3
- package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +5 -5
- package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +3 -3
- package/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift +2 -2
- package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +7 -6
- package/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift +1 -3
- package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +10 -10
- package/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +7 -0
- package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/ValueProviders/GroupInterpolator.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/RoundedCornersNode.swift +85 -0
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +4 -4
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +11 -12
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +10 -11
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +1 -1
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +5 -5
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +3 -3
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +9 -9
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +14 -14
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +2 -2
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +3 -3
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +10 -10
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +14 -14
- package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +11 -11
- package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +1 -1
- package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +52 -0
- package/Sources/Private/Model/DotLottie/DotLottieConfiguration.swift +15 -0
- package/Sources/Private/Model/DotLottie/DotLottieImageProvider.swift +73 -0
- package/Sources/Private/Model/DotLottie/DotLottieManifest.swift +53 -0
- package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +58 -0
- package/Sources/Private/Model/DotLottie/Zip/Data+Compression.swift +134 -0
- package/Sources/Private/Model/DotLottie/Zip/Data+Serialization.swift +87 -0
- package/Sources/Private/Model/DotLottie/Zip/FileManager+ZIP.swift +130 -0
- package/Sources/Private/Model/DotLottie/Zip/ZipArchive.swift +474 -0
- package/Sources/Private/Model/DotLottie/Zip/ZipEntry+Serialization.swift +189 -0
- package/Sources/Private/Model/DotLottie/Zip/ZipEntry+ZIP64.swift +179 -0
- package/Sources/Private/Model/DotLottie/Zip/ZipEntry.swift +227 -0
- package/Sources/Private/Model/Extensions/Bundle.swift +26 -0
- package/Sources/Private/Model/Keyframes/KeyframeData.swift +12 -12
- package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +9 -2
- package/Sources/Private/Model/Layers/LayerModel.swift +1 -1
- package/Sources/Private/Model/Layers/PreCompLayerModel.swift +3 -3
- package/Sources/Private/Model/Layers/TextLayerModel.swift +1 -1
- package/Sources/Private/Model/Objects/DashPattern.swift +2 -2
- package/Sources/Private/Model/Objects/Mask.swift +10 -8
- package/Sources/Private/Model/Objects/Transform.swift +39 -35
- package/Sources/Private/Model/ShapeItems/Ellipse.swift +6 -6
- package/Sources/Private/Model/ShapeItems/Fill.swift +6 -6
- package/Sources/Private/Model/ShapeItems/GradientFill.swift +15 -15
- package/Sources/Private/Model/ShapeItems/GradientStroke.swift +19 -19
- package/Sources/Private/Model/ShapeItems/Rectangle.swift +9 -9
- package/Sources/Private/Model/ShapeItems/Repeater.swift +37 -32
- package/Sources/Private/Model/ShapeItems/RoundedCorners.swift +47 -0
- package/Sources/Private/Model/ShapeItems/ShapeItem.swift +4 -0
- package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +34 -28
- package/Sources/Private/Model/ShapeItems/Star.swift +21 -21
- package/Sources/Private/Model/ShapeItems/Stroke.swift +10 -10
- package/Sources/Private/Model/ShapeItems/Trim.swift +9 -9
- package/Sources/Private/Model/Text/Font.swift +1 -1
- package/Sources/Private/Model/Text/TextAnimator.swift +33 -33
- package/Sources/Private/Model/Text/TextDocument.swift +8 -8
- package/Sources/Private/RootAnimationLayer.swift +4 -4
- package/Sources/Private/Utility/Debugging/LayerDebugging.swift +12 -18
- package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +2 -2
- package/Sources/Private/Utility/Extensions/CGColor+RGB.swift +12 -7
- package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +1 -1
- package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +4 -4
- package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +147 -0
- package/Sources/Private/Utility/Primitives/ColorExtension.swift +8 -11
- package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +22 -22
- package/Sources/{Private/Model/Animation.swift → Public/Animation/LottieAnimation.swift} +8 -8
- package/Sources/Public/Animation/{AnimationPublic.swift → LottieAnimationHelpers.swift} +62 -27
- package/Sources/Public/Animation/{AnimationView.swift → LottieAnimationView.swift} +122 -26
- package/Sources/Public/Animation/LottieAnimationViewInitializers.swift +222 -0
- package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +4 -4
- package/Sources/Public/AnimationCache/DefaultAnimationCache.swift +54 -0
- package/Sources/Public/AnimationCache/LRUAnimationCache.swift +4 -52
- package/Sources/Public/AnimationCache/LottieAnimationCache.swift +15 -0
- package/Sources/Public/DotLottie/Cache/DotLottieCache.swift +53 -0
- package/Sources/Public/DotLottie/Cache/DotLottieCacheProvider.swift +23 -0
- package/Sources/Public/DotLottie/DotLottieFile.swift +161 -0
- package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +265 -0
- package/Sources/Public/DynamicProperties/AnimationKeypath.swift +3 -3
- package/Sources/Public/DynamicProperties/AnyValueProvider.swift +2 -2
- package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +10 -10
- package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +4 -4
- package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +5 -5
- package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +2 -2
- package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +2 -2
- package/Sources/Public/FontProvider/AnimationFontProvider.swift +1 -1
- package/Sources/Public/ImageProvider/AnimationImageProvider.swift +2 -2
- package/Sources/Public/Keyframes/Interpolatable.swift +17 -17
- package/Sources/Public/Keyframes/Keyframe.swift +10 -10
- package/Sources/Public/LottieConfiguration.swift +25 -7
- package/Sources/Public/Primitives/{Color.swift → LottieColor.swift} +3 -3
- package/Sources/Public/Primitives/Vectors.swift +4 -4
- package/Sources/Public/TextProvider/AnimationTextProvider.swift +1 -1
- package/Sources/Public/iOS/AnimatedButton.swift +1 -1
- package/Sources/Public/iOS/AnimatedControl.swift +6 -6
- package/Sources/Public/iOS/AnimatedSwitch.swift +1 -1
- package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +8 -8
- package/Sources/Public/iOS/{AnimationViewBase.swift → LottieAnimationViewBase.swift} +4 -4
- package/Sources/Public/iOS/UIColorExtension.swift +2 -2
- package/Sources/Public/macOS/{AnimationViewBase.macOS.swift → LottieAnimationViewBase.macOS.swift} +4 -4
- package/Tests/AnimationCacheProviderTests.swift +40 -0
- package/Tests/AnimationKeypathTests.swift +20 -13
- package/Tests/AnimationViewTests.swift +64 -0
- package/Tests/AutomaticEngineTests.swift +11 -2
- package/Tests/ParsingTests.swift +4 -2
- package/Tests/PerformanceTests.swift +9 -9
- package/Tests/SnapshotConfiguration.swift +7 -7
- package/Tests/SnapshotTests.swift +57 -27
- package/Tests/ValueProvidersTests.swift +9 -6
- package/lottie-ios.podspec +4 -4
- package/package.json +2 -2
- package/script/test-carthage/Cartfile +1 -1
- package/script/test-carthage/CarthageTest/ViewController.swift +1 -1
- package/script/test-carthage/CarthageTest-macOS/ViewController.swift +1 -1
- package/Sources/Private/CoreAnimation/Extensions/Keyframes+combinedIfPossible.swift +0 -154
- package/Sources/Public/Animation/AnimationViewInitializers.swift +0 -109
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +0 -1
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~7IO4FqH8-VUsSfuA0_wMGUgfGdV7MwzpkzjwWbiB50jXZKQRHtU4G0A7ZXTvsR4mDdrWiawpNC_eriOALfZ7Og== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~ClRW5-6rvrgZHHbrPS1VEREaxelpVcKlERPzSa3f2rtFNXdoqATxFCsPge3a_nO4mhhtpmTmbYvyfI-obAu8Qg== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Jr2dFGcJc1188nMoMha82z9wM99lCLm4MKzhjfVVjIxKeCZVGWGZH3HgJFNkTpozdk5p1u5o91dCiY4-cR1Zhg== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~MBDeCFoahVzzmtSQrVhhy9VMJV6CmcnUkFya_qwe0XsMFscmY2nS8dxrTEYkY16sH68sEH7WVCCzTuW1z1Hocw== +0 -1
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~U4plJajEDM_uSZdglhDyj6gQO63mbeKxYP9X94aIaOtL0yErtfQnGz5SgsqQ0ToSZcJj6Ao9Wx-nesZVwBTRuw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~UsLY5O-vDMEHEe3bF8XJvkKkYxdsKlIytgJW7zgNuetw53fG3SssfZiiMfbuYnOtvvvYBXTwpbz07V6Czp029Q== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~cpg4cb7H0TaehHy4a-xINJMFfBM2_AEHal_0tIX8ymNVJPsjlCysi3-Cad0Ca_SvuGwVM7ONF55OBUuC9YKZvA== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~cuHjdTCuciVumvEpvozxwDj2wAdgWe13bzd1pUAGN45-WOgY0kIid9aUlBX675OnS-xNEc_pyQWo0RO1dKAjcw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~f_-bfn-KRHHFg39_MtwgBulEAuWH6F05yqGYydXhil6kqZ51eAoRX6tsiqOr0Oa6eL3dK1tcCBD1bWX5orCZhw== +0 -1
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~jdIx7vWS6ej1cqYcbCS4KyZErSMF13ELR95YwClVc98tIXcsglh7KuGvI1gIxEPDtPXQpfC3XijIAGn1quL8Dw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~lz3e0YeBa8TvMBSSymToh--gc6zznUIdH2jO0AJ4so5OPNdw6wpYmJebhaENGsRoD3beUXvlyD5f7_WeZrzyNQ== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~u_5dWbliYJ__YkyUCDFjdxiFds9M8Epr_RvbU1rIRCbBQdhRJ_TUBXXcL_Qq-wVp4umNLTOzud4OpQItSpO6Rg== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~v-YGzhC2l_icsAsyp1XAbEWYwxNook-rARAWlVZINioEsgT9LGvhg2oh78nYqoeH78m1fihr5HCcGNfF7SQj0g== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~7IO4FqH8-VUsSfuA0_wMGUgfGdV7MwzpkzjwWbiB50jXZKQRHtU4G0A7ZXTvsR4mDdrWiawpNC_eriOALfZ7Og== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~ClRW5-6rvrgZHHbrPS1VEREaxelpVcKlERPzSa3f2rtFNXdoqATxFCsPge3a_nO4mhhtpmTmbYvyfI-obAu8Qg== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Jr2dFGcJc1188nMoMha82z9wM99lCLm4MKzhjfVVjIxKeCZVGWGZH3HgJFNkTpozdk5p1u5o91dCiY4-cR1Zhg== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~MBDeCFoahVzzmtSQrVhhy9VMJV6CmcnUkFya_qwe0XsMFscmY2nS8dxrTEYkY16sH68sEH7WVCCzTuW1z1Hocw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~U4plJajEDM_uSZdglhDyj6gQO63mbeKxYP9X94aIaOtL0yErtfQnGz5SgsqQ0ToSZcJj6Ao9Wx-nesZVwBTRuw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~UsLY5O-vDMEHEe3bF8XJvkKkYxdsKlIytgJW7zgNuetw53fG3SssfZiiMfbuYnOtvvvYBXTwpbz07V6Czp029Q== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~cpg4cb7H0TaehHy4a-xINJMFfBM2_AEHal_0tIX8ymNVJPsjlCysi3-Cad0Ca_SvuGwVM7ONF55OBUuC9YKZvA== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~cuHjdTCuciVumvEpvozxwDj2wAdgWe13bzd1pUAGN45-WOgY0kIid9aUlBX675OnS-xNEc_pyQWo0RO1dKAjcw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~f_-bfn-KRHHFg39_MtwgBulEAuWH6F05yqGYydXhil6kqZ51eAoRX6tsiqOr0Oa6eL3dK1tcCBD1bWX5orCZhw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~jdIx7vWS6ej1cqYcbCS4KyZErSMF13ELR95YwClVc98tIXcsglh7KuGvI1gIxEPDtPXQpfC3XijIAGn1quL8Dw== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~lz3e0YeBa8TvMBSSymToh--gc6zznUIdH2jO0AJ4so5OPNdw6wpYmJebhaENGsRoD3beUXvlyD5f7_WeZrzyNQ== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~u_5dWbliYJ__YkyUCDFjdxiFds9M8Epr_RvbU1rIRCbBQdhRJ_TUBXXcL_Qq-wVp4umNLTOzud4OpQItSpO6Rg== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~v-YGzhC2l_icsAsyp1XAbEWYwxNook-rARAWlVZINioEsgT9LGvhg2oh78nYqoeH78m1fihr5HCcGNfF7SQj0g== +0 -0
- package/Tests/Artifacts/LottieTests.xcresult/Info.plist +0 -29
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Entry+Serialization.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 ZipEntry.LocalFileHeader {
|
|
14
|
+
|
|
15
|
+
// MARK: Lifecycle
|
|
16
|
+
|
|
17
|
+
init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
|
|
18
|
+
guard data.count == ZipEntry.LocalFileHeader.size else { return nil }
|
|
19
|
+
guard data.scanValue(start: 0) == localFileHeaderSignature else { return nil }
|
|
20
|
+
versionNeededToExtract = data.scanValue(start: 4)
|
|
21
|
+
generalPurposeBitFlag = data.scanValue(start: 6)
|
|
22
|
+
compressionMethod = data.scanValue(start: 8)
|
|
23
|
+
lastModFileTime = data.scanValue(start: 10)
|
|
24
|
+
lastModFileDate = data.scanValue(start: 12)
|
|
25
|
+
crc32 = data.scanValue(start: 14)
|
|
26
|
+
compressedSize = data.scanValue(start: 18)
|
|
27
|
+
uncompressedSize = data.scanValue(start: 22)
|
|
28
|
+
fileNameLength = data.scanValue(start: 26)
|
|
29
|
+
extraFieldLength = data.scanValue(start: 28)
|
|
30
|
+
let additionalDataLength = Int(fileNameLength) + Int(extraFieldLength)
|
|
31
|
+
guard let additionalData = try? provider(additionalDataLength) else { return nil }
|
|
32
|
+
guard additionalData.count == additionalDataLength else { return nil }
|
|
33
|
+
var subRangeStart = 0
|
|
34
|
+
var subRangeEnd = Int(fileNameLength)
|
|
35
|
+
fileNameData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
|
|
36
|
+
subRangeStart += Int(fileNameLength)
|
|
37
|
+
subRangeEnd = subRangeStart + Int(extraFieldLength)
|
|
38
|
+
extraFieldData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
|
|
39
|
+
if
|
|
40
|
+
let zip64ExtendedInformation = ZipEntry.ZIP64ExtendedInformation.scanForZIP64Field(
|
|
41
|
+
in: extraFieldData,
|
|
42
|
+
fields: validFields)
|
|
43
|
+
{
|
|
44
|
+
extraFields = [zip64ExtendedInformation]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// MARK: Internal
|
|
49
|
+
|
|
50
|
+
var data: Data {
|
|
51
|
+
var localFileHeaderSignature = localFileHeaderSignature
|
|
52
|
+
var versionNeededToExtract = versionNeededToExtract
|
|
53
|
+
var generalPurposeBitFlag = generalPurposeBitFlag
|
|
54
|
+
var compressionMethod = compressionMethod
|
|
55
|
+
var lastModFileTime = lastModFileTime
|
|
56
|
+
var lastModFileDate = lastModFileDate
|
|
57
|
+
var crc32 = crc32
|
|
58
|
+
var compressedSize = compressedSize
|
|
59
|
+
var uncompressedSize = uncompressedSize
|
|
60
|
+
var fileNameLength = fileNameLength
|
|
61
|
+
var extraFieldLength = extraFieldLength
|
|
62
|
+
var data = Data()
|
|
63
|
+
withUnsafePointer(to: &localFileHeaderSignature) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
64
|
+
withUnsafePointer(to: &versionNeededToExtract) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
65
|
+
withUnsafePointer(to: &generalPurposeBitFlag) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
66
|
+
withUnsafePointer(to: &compressionMethod) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
67
|
+
withUnsafePointer(to: &lastModFileTime) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
68
|
+
withUnsafePointer(to: &lastModFileDate) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
69
|
+
withUnsafePointer(to: &crc32) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
70
|
+
withUnsafePointer(to: &compressedSize) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
71
|
+
withUnsafePointer(to: &uncompressedSize) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
72
|
+
withUnsafePointer(to: &fileNameLength) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
73
|
+
withUnsafePointer(to: &extraFieldLength) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
74
|
+
data.append(fileNameData)
|
|
75
|
+
data.append(extraFieldData)
|
|
76
|
+
return data
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
extension ZipEntry.CentralDirectoryStructure {
|
|
82
|
+
|
|
83
|
+
// MARK: Lifecycle
|
|
84
|
+
|
|
85
|
+
init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
|
|
86
|
+
guard data.count == ZipEntry.CentralDirectoryStructure.size else { return nil }
|
|
87
|
+
guard data.scanValue(start: 0) == centralDirectorySignature else { return nil }
|
|
88
|
+
versionMadeBy = data.scanValue(start: 4)
|
|
89
|
+
versionNeededToExtract = data.scanValue(start: 6)
|
|
90
|
+
generalPurposeBitFlag = data.scanValue(start: 8)
|
|
91
|
+
compressionMethod = data.scanValue(start: 10)
|
|
92
|
+
lastModFileTime = data.scanValue(start: 12)
|
|
93
|
+
lastModFileDate = data.scanValue(start: 14)
|
|
94
|
+
crc32 = data.scanValue(start: 16)
|
|
95
|
+
compressedSize = data.scanValue(start: 20)
|
|
96
|
+
uncompressedSize = data.scanValue(start: 24)
|
|
97
|
+
fileNameLength = data.scanValue(start: 28)
|
|
98
|
+
extraFieldLength = data.scanValue(start: 30)
|
|
99
|
+
fileCommentLength = data.scanValue(start: 32)
|
|
100
|
+
diskNumberStart = data.scanValue(start: 34)
|
|
101
|
+
internalFileAttributes = data.scanValue(start: 36)
|
|
102
|
+
externalFileAttributes = data.scanValue(start: 38)
|
|
103
|
+
relativeOffsetOfLocalHeader = data.scanValue(start: 42)
|
|
104
|
+
let additionalDataLength = Int(fileNameLength) + Int(extraFieldLength) + Int(fileCommentLength)
|
|
105
|
+
guard let additionalData = try? provider(additionalDataLength) else { return nil }
|
|
106
|
+
guard additionalData.count == additionalDataLength else { return nil }
|
|
107
|
+
var subRangeStart = 0
|
|
108
|
+
var subRangeEnd = Int(fileNameLength)
|
|
109
|
+
fileNameData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
|
|
110
|
+
subRangeStart += Int(fileNameLength)
|
|
111
|
+
subRangeEnd = subRangeStart + Int(extraFieldLength)
|
|
112
|
+
extraFieldData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
|
|
113
|
+
subRangeStart += Int(extraFieldLength)
|
|
114
|
+
subRangeEnd = subRangeStart + Int(fileCommentLength)
|
|
115
|
+
fileCommentData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
|
|
116
|
+
if
|
|
117
|
+
let zip64ExtendedInformation = ZipEntry.ZIP64ExtendedInformation.scanForZIP64Field(
|
|
118
|
+
in: extraFieldData,
|
|
119
|
+
fields: validFields)
|
|
120
|
+
{
|
|
121
|
+
extraFields = [zip64ExtendedInformation]
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// MARK: Internal
|
|
126
|
+
|
|
127
|
+
var data: Data {
|
|
128
|
+
var centralDirectorySignature = centralDirectorySignature
|
|
129
|
+
var versionMadeBy = versionMadeBy
|
|
130
|
+
var versionNeededToExtract = versionNeededToExtract
|
|
131
|
+
var generalPurposeBitFlag = generalPurposeBitFlag
|
|
132
|
+
var compressionMethod = compressionMethod
|
|
133
|
+
var lastModFileTime = lastModFileTime
|
|
134
|
+
var lastModFileDate = lastModFileDate
|
|
135
|
+
var crc32 = crc32
|
|
136
|
+
var compressedSize = compressedSize
|
|
137
|
+
var uncompressedSize = uncompressedSize
|
|
138
|
+
var fileNameLength = fileNameLength
|
|
139
|
+
var extraFieldLength = extraFieldLength
|
|
140
|
+
var fileCommentLength = fileCommentLength
|
|
141
|
+
var diskNumberStart = diskNumberStart
|
|
142
|
+
var internalFileAttributes = internalFileAttributes
|
|
143
|
+
var externalFileAttributes = externalFileAttributes
|
|
144
|
+
var relativeOffsetOfLocalHeader = relativeOffsetOfLocalHeader
|
|
145
|
+
var data = Data()
|
|
146
|
+
withUnsafePointer(to: ¢ralDirectorySignature) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
147
|
+
withUnsafePointer(to: &versionMadeBy) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
148
|
+
withUnsafePointer(to: &versionNeededToExtract) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
149
|
+
withUnsafePointer(to: &generalPurposeBitFlag) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
150
|
+
withUnsafePointer(to: &compressionMethod) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
151
|
+
withUnsafePointer(to: &lastModFileTime) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
152
|
+
withUnsafePointer(to: &lastModFileDate) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
153
|
+
withUnsafePointer(to: &crc32) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
154
|
+
withUnsafePointer(to: &compressedSize) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
155
|
+
withUnsafePointer(to: &uncompressedSize) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
156
|
+
withUnsafePointer(to: &fileNameLength) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
157
|
+
withUnsafePointer(to: &extraFieldLength) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
158
|
+
withUnsafePointer(to: &fileCommentLength) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
159
|
+
withUnsafePointer(to: &diskNumberStart) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
160
|
+
withUnsafePointer(to: &internalFileAttributes) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
161
|
+
withUnsafePointer(to: &externalFileAttributes) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
162
|
+
withUnsafePointer(to: &relativeOffsetOfLocalHeader) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
163
|
+
data.append(fileNameData)
|
|
164
|
+
data.append(extraFieldData)
|
|
165
|
+
data.append(fileCommentData)
|
|
166
|
+
return data
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
extension ZipEntry.DataDescriptor {
|
|
172
|
+
init?(data: Data, additionalDataProvider _: (Int) throws -> Data) {
|
|
173
|
+
guard data.count == Self.size else { return nil }
|
|
174
|
+
let signature: UInt32 = data.scanValue(start: 0)
|
|
175
|
+
// The DataDescriptor signature is not mandatory so we have to re-arrange the input data if it is missing.
|
|
176
|
+
var readOffset = 0
|
|
177
|
+
if signature == dataDescriptorSignature { readOffset = 4 }
|
|
178
|
+
crc32 = data.scanValue(start: readOffset)
|
|
179
|
+
readOffset += MemoryLayout<UInt32>.size
|
|
180
|
+
compressedSize = data.scanValue(start: readOffset)
|
|
181
|
+
readOffset += Self.memoryLengthOfSize
|
|
182
|
+
uncompressedSize = data.scanValue(start: readOffset)
|
|
183
|
+
// Our add(_ entry:) methods always maintain compressed & uncompressed
|
|
184
|
+
// sizes and so we don't need a data descriptor for newly added entries.
|
|
185
|
+
// Data descriptors of already existing entries are manually preserved
|
|
186
|
+
// when copying those entries to the tempArchive during remove(_ entry:).
|
|
187
|
+
self.data = Data()
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Entry+ZIP64.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
|
+
// MARK: - ExtensibleDataField
|
|
14
|
+
|
|
15
|
+
protocol ExtensibleDataField {
|
|
16
|
+
var headerID: UInt16 { get }
|
|
17
|
+
var dataSize: UInt16 { get }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// MARK: - ExtraFieldHeaderID
|
|
21
|
+
|
|
22
|
+
private enum ExtraFieldHeaderID: UInt16 {
|
|
23
|
+
case zip64ExtendedInformation = 0x0001
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
extension ZipEntry {
|
|
27
|
+
enum EntryError: Error {
|
|
28
|
+
case invalidDataError
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
struct ZIP64ExtendedInformation: ExtensibleDataField {
|
|
32
|
+
let headerID: UInt16 = ExtraFieldHeaderID.zip64ExtendedInformation.rawValue
|
|
33
|
+
let dataSize: UInt16
|
|
34
|
+
static let headerSize: UInt16 = 4
|
|
35
|
+
let uncompressedSize: UInt64
|
|
36
|
+
let compressedSize: UInt64
|
|
37
|
+
let relativeOffsetOfLocalHeader: UInt64
|
|
38
|
+
let diskNumberStart: UInt32
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
var zip64ExtendedInformation: ZIP64ExtendedInformation? {
|
|
42
|
+
centralDirectoryStructure.zip64ExtendedInformation
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
typealias Field = ZipEntry.ZIP64ExtendedInformation.Field
|
|
47
|
+
|
|
48
|
+
extension ZipEntry.LocalFileHeader {
|
|
49
|
+
var validFields: [Field] {
|
|
50
|
+
var fields: [Field] = []
|
|
51
|
+
if uncompressedSize == .max { fields.append(.uncompressedSize) }
|
|
52
|
+
if compressedSize == .max { fields.append(.compressedSize) }
|
|
53
|
+
return fields
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
extension ZipEntry.CentralDirectoryStructure {
|
|
58
|
+
var validFields: [Field] {
|
|
59
|
+
var fields: [Field] = []
|
|
60
|
+
if uncompressedSize == .max { fields.append(.uncompressedSize) }
|
|
61
|
+
if compressedSize == .max { fields.append(.compressedSize) }
|
|
62
|
+
if relativeOffsetOfLocalHeader == .max { fields.append(.relativeOffsetOfLocalHeader) }
|
|
63
|
+
if diskNumberStart == .max { fields.append(.diskNumberStart) }
|
|
64
|
+
return fields
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var zip64ExtendedInformation: ZipEntry.ZIP64ExtendedInformation? {
|
|
68
|
+
extraFields?.compactMap { $0 as? ZipEntry.ZIP64ExtendedInformation }.first
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
extension ZipEntry.ZIP64ExtendedInformation {
|
|
73
|
+
|
|
74
|
+
// MARK: Lifecycle
|
|
75
|
+
|
|
76
|
+
init?(data: Data, fields: [Field]) {
|
|
77
|
+
let headerLength = 4
|
|
78
|
+
guard fields.reduce(0, { $0 + $1.size }) + headerLength == data.count else { return nil }
|
|
79
|
+
var readOffset = headerLength
|
|
80
|
+
func value<T>(of field: Field) throws -> T where T: BinaryInteger {
|
|
81
|
+
if fields.contains(field) {
|
|
82
|
+
defer {
|
|
83
|
+
readOffset += MemoryLayout<T>.size
|
|
84
|
+
}
|
|
85
|
+
guard readOffset + field.size <= data.count else {
|
|
86
|
+
throw ZipEntry.EntryError.invalidDataError
|
|
87
|
+
}
|
|
88
|
+
return data.scanValue(start: readOffset)
|
|
89
|
+
} else {
|
|
90
|
+
return 0
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
do {
|
|
94
|
+
dataSize = data.scanValue(start: 2)
|
|
95
|
+
uncompressedSize = try value(of: .uncompressedSize)
|
|
96
|
+
compressedSize = try value(of: .compressedSize)
|
|
97
|
+
relativeOffsetOfLocalHeader = try value(of: .relativeOffsetOfLocalHeader)
|
|
98
|
+
diskNumberStart = try value(of: .diskNumberStart)
|
|
99
|
+
} catch {
|
|
100
|
+
return nil
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
init?(zip64ExtendedInformation: ZipEntry.ZIP64ExtendedInformation?, offset: UInt64) {
|
|
105
|
+
// Only used when removing entry, if no ZIP64 extended information exists,
|
|
106
|
+
// then this information will not be newly added either
|
|
107
|
+
guard let existingInfo = zip64ExtendedInformation else { return nil }
|
|
108
|
+
relativeOffsetOfLocalHeader = offset >= UInt32.max ? offset : 0
|
|
109
|
+
uncompressedSize = existingInfo.uncompressedSize
|
|
110
|
+
compressedSize = existingInfo.compressedSize
|
|
111
|
+
diskNumberStart = existingInfo.diskNumberStart
|
|
112
|
+
let tempDataSize = [relativeOffsetOfLocalHeader, uncompressedSize, compressedSize]
|
|
113
|
+
.filter { $0 != 0 }
|
|
114
|
+
.reduce(UInt16(0)) { $0 + UInt16(MemoryLayout.size(ofValue: $1)) }
|
|
115
|
+
dataSize = tempDataSize + (diskNumberStart > 0 ? UInt16(MemoryLayout.size(ofValue: diskNumberStart)) : 0)
|
|
116
|
+
if dataSize == 0 { return nil }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// MARK: Internal
|
|
120
|
+
|
|
121
|
+
enum Field {
|
|
122
|
+
case uncompressedSize
|
|
123
|
+
case compressedSize
|
|
124
|
+
case relativeOffsetOfLocalHeader
|
|
125
|
+
case diskNumberStart
|
|
126
|
+
|
|
127
|
+
var size: Int {
|
|
128
|
+
switch self {
|
|
129
|
+
case .uncompressedSize, .compressedSize, .relativeOffsetOfLocalHeader:
|
|
130
|
+
return 8
|
|
131
|
+
case .diskNumberStart:
|
|
132
|
+
return 4
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var data: Data {
|
|
138
|
+
var headerID = headerID
|
|
139
|
+
var dataSize = dataSize
|
|
140
|
+
var uncompressedSize = uncompressedSize
|
|
141
|
+
var compressedSize = compressedSize
|
|
142
|
+
var relativeOffsetOfLFH = relativeOffsetOfLocalHeader
|
|
143
|
+
var diskNumberStart = diskNumberStart
|
|
144
|
+
var data = Data()
|
|
145
|
+
withUnsafePointer(to: &headerID) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
146
|
+
withUnsafePointer(to: &dataSize) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
147
|
+
if uncompressedSize != 0 || compressedSize != 0 {
|
|
148
|
+
withUnsafePointer(to: &uncompressedSize) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
149
|
+
withUnsafePointer(to: &compressedSize) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
150
|
+
}
|
|
151
|
+
if relativeOffsetOfLocalHeader != 0 {
|
|
152
|
+
withUnsafePointer(to: &relativeOffsetOfLFH) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
153
|
+
}
|
|
154
|
+
if diskNumberStart != 0 {
|
|
155
|
+
withUnsafePointer(to: &diskNumberStart) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
|
|
156
|
+
}
|
|
157
|
+
return data
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static func scanForZIP64Field(in data: Data, fields: [Field]) -> ZipEntry.ZIP64ExtendedInformation? {
|
|
161
|
+
guard data.isEmpty == false else { return nil }
|
|
162
|
+
var offset = 0
|
|
163
|
+
var headerID: UInt16
|
|
164
|
+
var dataSize: UInt16
|
|
165
|
+
let extraFieldLength = data.count
|
|
166
|
+
let headerSize = Int(ZipEntry.ZIP64ExtendedInformation.headerSize)
|
|
167
|
+
while offset < extraFieldLength - headerSize {
|
|
168
|
+
headerID = data.scanValue(start: offset)
|
|
169
|
+
dataSize = data.scanValue(start: offset + 2)
|
|
170
|
+
let nextOffset = offset + headerSize + Int(dataSize)
|
|
171
|
+
guard nextOffset <= extraFieldLength else { return nil }
|
|
172
|
+
if headerID == ExtraFieldHeaderID.zip64ExtendedInformation.rawValue {
|
|
173
|
+
return ZipEntry.ZIP64ExtendedInformation(data: data.subdata(in: offset..<nextOffset), fields: fields)
|
|
174
|
+
}
|
|
175
|
+
offset = nextOffset
|
|
176
|
+
}
|
|
177
|
+
return nil
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Entry.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 CoreFoundation
|
|
12
|
+
import Foundation
|
|
13
|
+
|
|
14
|
+
// MARK: - ZipEntry
|
|
15
|
+
|
|
16
|
+
/// A value that represents a file, a directory or a symbolic link within a ZIP `Archive`.
|
|
17
|
+
///
|
|
18
|
+
/// You can retrieve instances of `Entry` from an `Archive` via subscripting or iteration.
|
|
19
|
+
/// Entries are identified by their `path`.
|
|
20
|
+
struct ZipEntry: Equatable {
|
|
21
|
+
|
|
22
|
+
// MARK: Lifecycle
|
|
23
|
+
|
|
24
|
+
init?(
|
|
25
|
+
centralDirectoryStructure: CentralDirectoryStructure,
|
|
26
|
+
localFileHeader: LocalFileHeader,
|
|
27
|
+
dataDescriptor: DefaultDataDescriptor? = nil,
|
|
28
|
+
zip64DataDescriptor: ZIP64DataDescriptor? = nil)
|
|
29
|
+
{
|
|
30
|
+
// We currently don't support encrypted archives
|
|
31
|
+
guard !centralDirectoryStructure.isEncrypted else { return nil }
|
|
32
|
+
self.centralDirectoryStructure = centralDirectoryStructure
|
|
33
|
+
self.localFileHeader = localFileHeader
|
|
34
|
+
self.dataDescriptor = dataDescriptor
|
|
35
|
+
self.zip64DataDescriptor = zip64DataDescriptor
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// MARK: Internal
|
|
39
|
+
|
|
40
|
+
struct LocalFileHeader: DataSerializable {
|
|
41
|
+
let localFileHeaderSignature = UInt32(localFileHeaderStructSignature)
|
|
42
|
+
let versionNeededToExtract: UInt16
|
|
43
|
+
let generalPurposeBitFlag: UInt16
|
|
44
|
+
let compressionMethod: UInt16
|
|
45
|
+
let lastModFileTime: UInt16
|
|
46
|
+
let lastModFileDate: UInt16
|
|
47
|
+
let crc32: UInt32
|
|
48
|
+
let compressedSize: UInt32
|
|
49
|
+
let uncompressedSize: UInt32
|
|
50
|
+
let fileNameLength: UInt16
|
|
51
|
+
let extraFieldLength: UInt16
|
|
52
|
+
static let size = 30
|
|
53
|
+
let fileNameData: Data
|
|
54
|
+
let extraFieldData: Data
|
|
55
|
+
var extraFields: [ExtensibleDataField]?
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
struct DataDescriptor<T: BinaryInteger>: DataSerializable {
|
|
59
|
+
let data: Data
|
|
60
|
+
let dataDescriptorSignature = UInt32(dataDescriptorStructSignature)
|
|
61
|
+
let crc32: UInt32
|
|
62
|
+
// For normal archives, the compressed and uncompressed sizes are 4 bytes each.
|
|
63
|
+
// For ZIP64 format archives, the compressed and uncompressed sizes are 8 bytes each.
|
|
64
|
+
let compressedSize: T
|
|
65
|
+
let uncompressedSize: T
|
|
66
|
+
static var memoryLengthOfSize: Int { MemoryLayout<T>.size }
|
|
67
|
+
static var size: Int { memoryLengthOfSize * 2 + 8 }
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
typealias DefaultDataDescriptor = DataDescriptor<UInt32>
|
|
71
|
+
typealias ZIP64DataDescriptor = DataDescriptor<UInt64>
|
|
72
|
+
|
|
73
|
+
struct CentralDirectoryStructure: DataSerializable {
|
|
74
|
+
static let size = 46
|
|
75
|
+
|
|
76
|
+
let centralDirectorySignature = UInt32(centralDirectoryStructSignature)
|
|
77
|
+
let versionMadeBy: UInt16
|
|
78
|
+
let versionNeededToExtract: UInt16
|
|
79
|
+
let generalPurposeBitFlag: UInt16
|
|
80
|
+
let compressionMethod: UInt16
|
|
81
|
+
let lastModFileTime: UInt16
|
|
82
|
+
let lastModFileDate: UInt16
|
|
83
|
+
let crc32: UInt32
|
|
84
|
+
let compressedSize: UInt32
|
|
85
|
+
let uncompressedSize: UInt32
|
|
86
|
+
let fileNameLength: UInt16
|
|
87
|
+
let extraFieldLength: UInt16
|
|
88
|
+
let fileCommentLength: UInt16
|
|
89
|
+
let diskNumberStart: UInt16
|
|
90
|
+
let internalFileAttributes: UInt16
|
|
91
|
+
let externalFileAttributes: UInt32
|
|
92
|
+
let relativeOffsetOfLocalHeader: UInt32
|
|
93
|
+
let fileNameData: Data
|
|
94
|
+
let extraFieldData: Data
|
|
95
|
+
let fileCommentData: Data
|
|
96
|
+
|
|
97
|
+
var extraFields: [ExtensibleDataField]?
|
|
98
|
+
|
|
99
|
+
var usesDataDescriptor: Bool { (generalPurposeBitFlag & (1 << 3)) != 0 }
|
|
100
|
+
var usesUTF8PathEncoding: Bool { (generalPurposeBitFlag & (1 << 11)) != 0 }
|
|
101
|
+
var isEncrypted: Bool { (generalPurposeBitFlag & (1 << 0)) != 0 }
|
|
102
|
+
var isZIP64: Bool {
|
|
103
|
+
// If ZIP64 extended information is existing, try to treat cd as ZIP64 format
|
|
104
|
+
// even if the version needed to extract is lower than 4.5
|
|
105
|
+
UInt8(truncatingIfNeeded: versionNeededToExtract) >= 45 || zip64ExtendedInformation != nil
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static let localFileHeaderStructSignature = 0x04034b50
|
|
110
|
+
static let dataDescriptorStructSignature = 0x08074b50
|
|
111
|
+
static let centralDirectoryStructSignature = 0x02014b50
|
|
112
|
+
|
|
113
|
+
let centralDirectoryStructure: CentralDirectoryStructure
|
|
114
|
+
let localFileHeader: LocalFileHeader
|
|
115
|
+
let dataDescriptor: DefaultDataDescriptor?
|
|
116
|
+
let zip64DataDescriptor: ZIP64DataDescriptor?
|
|
117
|
+
|
|
118
|
+
/// The `path` of the receiver within a ZIP `Archive`.
|
|
119
|
+
var path: String {
|
|
120
|
+
let dosLatinUS = 0x400
|
|
121
|
+
let dosLatinUSEncoding = CFStringEncoding(dosLatinUS)
|
|
122
|
+
let dosLatinUSStringEncoding = CFStringConvertEncodingToNSStringEncoding(dosLatinUSEncoding)
|
|
123
|
+
let codepage437 = String.Encoding(rawValue: dosLatinUSStringEncoding)
|
|
124
|
+
let encoding = centralDirectoryStructure.usesUTF8PathEncoding ? .utf8 : codepage437
|
|
125
|
+
return self.path(using: encoding)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/// The file attributes of the receiver as key/value pairs.
|
|
129
|
+
///
|
|
130
|
+
/// Contains the modification date and file permissions.
|
|
131
|
+
var fileAttributes: [FileAttributeKey: Any] {
|
|
132
|
+
FileManager.attributes(from: self)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/// The `CRC32` checksum of the receiver.
|
|
136
|
+
///
|
|
137
|
+
/// - Note: Always returns `0` for entries of type `EntryType.directory`.
|
|
138
|
+
var checksum: UInt32 {
|
|
139
|
+
if centralDirectoryStructure.usesDataDescriptor {
|
|
140
|
+
return zip64DataDescriptor?.crc32 ?? dataDescriptor?.crc32 ?? 0
|
|
141
|
+
}
|
|
142
|
+
return centralDirectoryStructure.crc32
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/// Indicates whether or not the receiver is compressed.
|
|
146
|
+
var isCompressed: Bool {
|
|
147
|
+
localFileHeader.compressionMethod != 0
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/// The size of the receiver's compressed data.
|
|
151
|
+
var compressedSize: UInt64 {
|
|
152
|
+
if centralDirectoryStructure.isZIP64 {
|
|
153
|
+
return zip64DataDescriptor?.compressedSize ?? centralDirectoryStructure.effectiveCompressedSize
|
|
154
|
+
}
|
|
155
|
+
return UInt64(dataDescriptor?.compressedSize ?? centralDirectoryStructure.compressedSize)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/// The size of the receiver's uncompressed data.
|
|
159
|
+
var uncompressedSize: UInt64 {
|
|
160
|
+
if centralDirectoryStructure.isZIP64 {
|
|
161
|
+
return zip64DataDescriptor?.uncompressedSize ?? centralDirectoryStructure.effectiveUncompressedSize
|
|
162
|
+
}
|
|
163
|
+
return UInt64(dataDescriptor?.uncompressedSize ?? centralDirectoryStructure.uncompressedSize)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// The combined size of the local header, the data and the optional data descriptor.
|
|
167
|
+
var localSize: UInt64 {
|
|
168
|
+
let localFileHeader = localFileHeader
|
|
169
|
+
var extraDataLength = Int(localFileHeader.fileNameLength)
|
|
170
|
+
extraDataLength += Int(localFileHeader.extraFieldLength)
|
|
171
|
+
var size = UInt64(LocalFileHeader.size + extraDataLength)
|
|
172
|
+
size += isCompressed ? compressedSize : uncompressedSize
|
|
173
|
+
if centralDirectoryStructure.isZIP64 {
|
|
174
|
+
size += zip64DataDescriptor != nil ? UInt64(ZIP64DataDescriptor.size) : 0
|
|
175
|
+
} else {
|
|
176
|
+
size += dataDescriptor != nil ? UInt64(DefaultDataDescriptor.size) : 0
|
|
177
|
+
}
|
|
178
|
+
return size
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
var dataOffset: UInt64 {
|
|
182
|
+
var dataOffset = centralDirectoryStructure.effectiveRelativeOffsetOfLocalHeader
|
|
183
|
+
dataOffset += UInt64(LocalFileHeader.size)
|
|
184
|
+
dataOffset += UInt64(localFileHeader.fileNameLength)
|
|
185
|
+
dataOffset += UInt64(localFileHeader.extraFieldLength)
|
|
186
|
+
return dataOffset
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static func == (lhs: ZipEntry, rhs: ZipEntry) -> Bool {
|
|
190
|
+
lhs.path == rhs.path
|
|
191
|
+
&& lhs.localFileHeader.crc32 == rhs.localFileHeader.crc32
|
|
192
|
+
&& lhs.centralDirectoryStructure.effectiveRelativeOffsetOfLocalHeader
|
|
193
|
+
== rhs.centralDirectoryStructure.effectiveRelativeOffsetOfLocalHeader
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/// Returns the `path` of the receiver within a ZIP `Archive` using a given encoding.
|
|
197
|
+
///
|
|
198
|
+
/// - Parameters:
|
|
199
|
+
/// - encoding: `String.Encoding`
|
|
200
|
+
func path(using encoding: String.Encoding) -> String {
|
|
201
|
+
String(data: centralDirectoryStructure.fileNameData, encoding: encoding) ?? ""
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
extension ZipEntry.CentralDirectoryStructure {
|
|
207
|
+
var effectiveCompressedSize: UInt64 {
|
|
208
|
+
if isZIP64, let compressedSize = zip64ExtendedInformation?.compressedSize, compressedSize > 0 {
|
|
209
|
+
return compressedSize
|
|
210
|
+
}
|
|
211
|
+
return UInt64(compressedSize)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
var effectiveUncompressedSize: UInt64 {
|
|
215
|
+
if isZIP64, let uncompressedSize = zip64ExtendedInformation?.uncompressedSize, uncompressedSize > 0 {
|
|
216
|
+
return uncompressedSize
|
|
217
|
+
}
|
|
218
|
+
return UInt64(uncompressedSize)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
var effectiveRelativeOffsetOfLocalHeader: UInt64 {
|
|
222
|
+
if isZIP64, let offset = zip64ExtendedInformation?.relativeOffsetOfLocalHeader, offset > 0 {
|
|
223
|
+
return offset
|
|
224
|
+
}
|
|
225
|
+
return UInt64(relativeOffsetOfLocalHeader)
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -19,6 +19,22 @@ extension Bundle {
|
|
|
19
19
|
return nil
|
|
20
20
|
#endif
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
func dotLottieData(_ name: String, subdirectory: String? = nil) throws -> Data? {
|
|
24
|
+
// Check for files in the bundle at the given path
|
|
25
|
+
let name = name.removingDotLottieSuffix()
|
|
26
|
+
if let url = url(forResource: name, withExtension: "lottie", subdirectory: subdirectory) {
|
|
27
|
+
return try Data(contentsOf: url)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check for data assets (not available on macOS)
|
|
31
|
+
#if os(iOS) || os(tvOS) || os(watchOS) || targetEnvironment(macCatalyst)
|
|
32
|
+
let assetKey = subdirectory != nil ? "\(subdirectory ?? "")/\(name)" : name
|
|
33
|
+
return NSDataAsset(name: assetKey, bundle: self)?.data
|
|
34
|
+
#else
|
|
35
|
+
return nil
|
|
36
|
+
#endif
|
|
37
|
+
}
|
|
22
38
|
}
|
|
23
39
|
|
|
24
40
|
extension String {
|
|
@@ -31,4 +47,14 @@ extension String {
|
|
|
31
47
|
|
|
32
48
|
return (self as NSString).deletingPathExtension
|
|
33
49
|
}
|
|
50
|
+
|
|
51
|
+
fileprivate func removingDotLottieSuffix() -> String {
|
|
52
|
+
// Allow filenames to be passed with a ".lottie" extension (but not other extensions)
|
|
53
|
+
// to keep the behavior from Lottie 2.x - instead of failing to load the file
|
|
54
|
+
guard hasSuffix(".lottie") else {
|
|
55
|
+
return self
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return (self as NSString).deletingPathExtension
|
|
59
|
+
}
|
|
34
60
|
}
|
|
@@ -24,10 +24,10 @@ final class KeyframeData<T> {
|
|
|
24
24
|
endValue: T?,
|
|
25
25
|
time: AnimationFrameTime?,
|
|
26
26
|
hold: Int?,
|
|
27
|
-
inTangent:
|
|
28
|
-
outTangent:
|
|
29
|
-
spatialInTangent:
|
|
30
|
-
spatialOutTangent:
|
|
27
|
+
inTangent: LottieVector2D?,
|
|
28
|
+
outTangent: LottieVector2D?,
|
|
29
|
+
spatialInTangent: LottieVector3D?,
|
|
30
|
+
spatialOutTangent: LottieVector3D?)
|
|
31
31
|
{
|
|
32
32
|
self.startValue = startValue
|
|
33
33
|
self.endValue = endValue
|
|
@@ -62,14 +62,14 @@ final class KeyframeData<T> {
|
|
|
62
62
|
let hold: Int?
|
|
63
63
|
|
|
64
64
|
/// The in tangent for the time interpolation curve.
|
|
65
|
-
let inTangent:
|
|
65
|
+
let inTangent: LottieVector2D?
|
|
66
66
|
/// The out tangent for the time interpolation curve.
|
|
67
|
-
let outTangent:
|
|
67
|
+
let outTangent: LottieVector2D?
|
|
68
68
|
|
|
69
69
|
/// The spacial in tangent of the vector.
|
|
70
|
-
let spatialInTangent:
|
|
70
|
+
let spatialInTangent: LottieVector3D?
|
|
71
71
|
/// The spacial out tangent of the vector.
|
|
72
|
-
let spatialOutTangent:
|
|
72
|
+
let spatialOutTangent: LottieVector3D?
|
|
73
73
|
|
|
74
74
|
var isHold: Bool {
|
|
75
75
|
if let hold = hold {
|
|
@@ -95,10 +95,10 @@ extension KeyframeData: DictionaryInitializable where T: AnyInitializable {
|
|
|
95
95
|
let endValue = try? dictionary[CodingKeys.endValue.rawValue].flatMap(T.init)
|
|
96
96
|
let time: AnimationFrameTime? = try? dictionary.value(for: CodingKeys.time)
|
|
97
97
|
let hold: Int? = try? dictionary.value(for: CodingKeys.hold)
|
|
98
|
-
let inTangent:
|
|
99
|
-
let outTangent:
|
|
100
|
-
let spatialInTangent:
|
|
101
|
-
let spatialOutTangent:
|
|
98
|
+
let inTangent: LottieVector2D? = try? dictionary.value(for: CodingKeys.inTangent)
|
|
99
|
+
let outTangent: LottieVector2D? = try? dictionary.value(for: CodingKeys.outTangent)
|
|
100
|
+
let spatialInTangent: LottieVector3D? = try? dictionary.value(for: CodingKeys.spatialInTangent)
|
|
101
|
+
let spatialOutTangent: LottieVector3D? = try? dictionary.value(for: CodingKeys.spatialOutTangent)
|
|
102
102
|
|
|
103
103
|
self.init(
|
|
104
104
|
startValue: startValue,
|