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.
Files changed (183) hide show
  1. package/.gitattributes +1 -0
  2. package/.github/workflows/main.yml +7 -7
  3. package/Gemfile.lock +1 -1
  4. package/Lottie.xcodeproj/project.pbxproj +286 -68
  5. package/Lottie.xcworkspace/xcshareddata/swiftpm/Package.resolved +18 -0
  6. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  7. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +3 -24
  8. package/Package.swift +2 -2
  9. package/README.md +10 -3
  10. package/Rakefile +1 -1
  11. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +6 -9
  12. package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +42 -3
  13. package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +5 -17
  14. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +25 -17
  15. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +2 -2
  16. package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +1 -1
  17. package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +9 -20
  18. package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +39 -25
  19. package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +13 -32
  20. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +4 -4
  21. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +13 -13
  22. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +4 -4
  23. package/Sources/Private/CoreAnimation/Extensions/KeyframeGroup+exactlyOneKeyframe.swift +4 -12
  24. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combined.swift +222 -0
  25. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +1 -1
  26. package/Sources/Private/CoreAnimation/Layers/CALayer+setupLayerHierarchy.swift +8 -6
  27. package/Sources/Private/CoreAnimation/Layers/GradientRenderLayer.swift +13 -10
  28. package/Sources/Private/CoreAnimation/Layers/InfiniteOpaqueAnimationLayer.swift +56 -0
  29. package/Sources/Private/CoreAnimation/Layers/LayerModel+makeAnimationLayer.swift +1 -1
  30. package/Sources/Private/CoreAnimation/Layers/PreCompLayer.swift +2 -3
  31. package/Sources/Private/CoreAnimation/Layers/RepeaterLayer.swift +9 -9
  32. package/Sources/Private/CoreAnimation/Layers/ShapeItemLayer.swift +9 -3
  33. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +7 -18
  34. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +2 -3
  35. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +5 -5
  36. package/Sources/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.swift +3 -3
  37. package/Sources/Private/MainThread/LayerContainers/CompLayers/SolidCompositionLayer.swift +2 -2
  38. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +7 -6
  39. package/Sources/Private/MainThread/LayerContainers/Utility/InvertedMatteLayer.swift +1 -3
  40. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +10 -10
  41. package/Sources/Private/MainThread/NodeRenderSystem/Extensions/ItemsExtension.swift +7 -0
  42. package/Sources/Private/MainThread/NodeRenderSystem/NodeProperties/ValueProviders/GroupInterpolator.swift +2 -2
  43. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/RoundedCornersNode.swift +85 -0
  44. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/ModifierNodes/TrimPathNode.swift +4 -4
  45. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientFillRenderer.swift +11 -12
  46. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/GradientStrokeRenderer.swift +1 -1
  47. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/LegacyGradientFillRenderer.swift +10 -11
  48. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/OutputNodes/Renderables/StrokeRenderer.swift +1 -1
  49. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +2 -2
  50. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +5 -5
  51. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +3 -3
  52. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +9 -9
  53. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +14 -14
  54. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +2 -2
  55. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +3 -3
  56. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +10 -10
  57. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +14 -14
  58. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +11 -11
  59. package/Sources/Private/MainThread/NodeRenderSystem/RenderLayers/ShapeContainerLayer.swift +1 -1
  60. package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +52 -0
  61. package/Sources/Private/Model/DotLottie/DotLottieConfiguration.swift +15 -0
  62. package/Sources/Private/Model/DotLottie/DotLottieImageProvider.swift +73 -0
  63. package/Sources/Private/Model/DotLottie/DotLottieManifest.swift +53 -0
  64. package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +58 -0
  65. package/Sources/Private/Model/DotLottie/Zip/Data+Compression.swift +134 -0
  66. package/Sources/Private/Model/DotLottie/Zip/Data+Serialization.swift +87 -0
  67. package/Sources/Private/Model/DotLottie/Zip/FileManager+ZIP.swift +130 -0
  68. package/Sources/Private/Model/DotLottie/Zip/ZipArchive.swift +474 -0
  69. package/Sources/Private/Model/DotLottie/Zip/ZipEntry+Serialization.swift +189 -0
  70. package/Sources/Private/Model/DotLottie/Zip/ZipEntry+ZIP64.swift +179 -0
  71. package/Sources/Private/Model/DotLottie/Zip/ZipEntry.swift +227 -0
  72. package/Sources/Private/Model/Extensions/Bundle.swift +26 -0
  73. package/Sources/Private/Model/Keyframes/KeyframeData.swift +12 -12
  74. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +9 -2
  75. package/Sources/Private/Model/Layers/LayerModel.swift +1 -1
  76. package/Sources/Private/Model/Layers/PreCompLayerModel.swift +3 -3
  77. package/Sources/Private/Model/Layers/TextLayerModel.swift +1 -1
  78. package/Sources/Private/Model/Objects/DashPattern.swift +2 -2
  79. package/Sources/Private/Model/Objects/Mask.swift +10 -8
  80. package/Sources/Private/Model/Objects/Transform.swift +39 -35
  81. package/Sources/Private/Model/ShapeItems/Ellipse.swift +6 -6
  82. package/Sources/Private/Model/ShapeItems/Fill.swift +6 -6
  83. package/Sources/Private/Model/ShapeItems/GradientFill.swift +15 -15
  84. package/Sources/Private/Model/ShapeItems/GradientStroke.swift +19 -19
  85. package/Sources/Private/Model/ShapeItems/Rectangle.swift +9 -9
  86. package/Sources/Private/Model/ShapeItems/Repeater.swift +37 -32
  87. package/Sources/Private/Model/ShapeItems/RoundedCorners.swift +47 -0
  88. package/Sources/Private/Model/ShapeItems/ShapeItem.swift +4 -0
  89. package/Sources/Private/Model/ShapeItems/ShapeTransform.swift +34 -28
  90. package/Sources/Private/Model/ShapeItems/Star.swift +21 -21
  91. package/Sources/Private/Model/ShapeItems/Stroke.swift +10 -10
  92. package/Sources/Private/Model/ShapeItems/Trim.swift +9 -9
  93. package/Sources/Private/Model/Text/Font.swift +1 -1
  94. package/Sources/Private/Model/Text/TextAnimator.swift +33 -33
  95. package/Sources/Private/Model/Text/TextDocument.swift +8 -8
  96. package/Sources/Private/RootAnimationLayer.swift +4 -4
  97. package/Sources/Private/Utility/Debugging/LayerDebugging.swift +12 -18
  98. package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +2 -2
  99. package/Sources/Private/Utility/Extensions/CGColor+RGB.swift +12 -7
  100. package/Sources/Private/Utility/Interpolatable/InterpolatableExtensions.swift +1 -1
  101. package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +4 -4
  102. package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +147 -0
  103. package/Sources/Private/Utility/Primitives/ColorExtension.swift +8 -11
  104. package/Sources/Private/Utility/Primitives/VectorsExtensions.swift +22 -22
  105. package/Sources/{Private/Model/Animation.swift → Public/Animation/LottieAnimation.swift} +8 -8
  106. package/Sources/Public/Animation/{AnimationPublic.swift → LottieAnimationHelpers.swift} +62 -27
  107. package/Sources/Public/Animation/{AnimationView.swift → LottieAnimationView.swift} +122 -26
  108. package/Sources/Public/Animation/LottieAnimationViewInitializers.swift +222 -0
  109. package/Sources/Public/AnimationCache/AnimationCacheProvider.swift +4 -4
  110. package/Sources/Public/AnimationCache/DefaultAnimationCache.swift +54 -0
  111. package/Sources/Public/AnimationCache/LRUAnimationCache.swift +4 -52
  112. package/Sources/Public/AnimationCache/LottieAnimationCache.swift +15 -0
  113. package/Sources/Public/DotLottie/Cache/DotLottieCache.swift +53 -0
  114. package/Sources/Public/DotLottie/Cache/DotLottieCacheProvider.swift +23 -0
  115. package/Sources/Public/DotLottie/DotLottieFile.swift +161 -0
  116. package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +265 -0
  117. package/Sources/Public/DynamicProperties/AnimationKeypath.swift +3 -3
  118. package/Sources/Public/DynamicProperties/AnyValueProvider.swift +2 -2
  119. package/Sources/Public/DynamicProperties/ValueProviders/ColorValueProvider.swift +10 -10
  120. package/Sources/Public/DynamicProperties/ValueProviders/FloatValueProvider.swift +4 -4
  121. package/Sources/Public/DynamicProperties/ValueProviders/GradientValueProvider.swift +5 -5
  122. package/Sources/Public/DynamicProperties/ValueProviders/PointValueProvider.swift +2 -2
  123. package/Sources/Public/DynamicProperties/ValueProviders/SizeValueProvider.swift +2 -2
  124. package/Sources/Public/FontProvider/AnimationFontProvider.swift +1 -1
  125. package/Sources/Public/ImageProvider/AnimationImageProvider.swift +2 -2
  126. package/Sources/Public/Keyframes/Interpolatable.swift +17 -17
  127. package/Sources/Public/Keyframes/Keyframe.swift +10 -10
  128. package/Sources/Public/LottieConfiguration.swift +25 -7
  129. package/Sources/Public/Primitives/{Color.swift → LottieColor.swift} +3 -3
  130. package/Sources/Public/Primitives/Vectors.swift +4 -4
  131. package/Sources/Public/TextProvider/AnimationTextProvider.swift +1 -1
  132. package/Sources/Public/iOS/AnimatedButton.swift +1 -1
  133. package/Sources/Public/iOS/AnimatedControl.swift +6 -6
  134. package/Sources/Public/iOS/AnimatedSwitch.swift +1 -1
  135. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +8 -8
  136. package/Sources/Public/iOS/{AnimationViewBase.swift → LottieAnimationViewBase.swift} +4 -4
  137. package/Sources/Public/iOS/UIColorExtension.swift +2 -2
  138. package/Sources/Public/macOS/{AnimationViewBase.macOS.swift → LottieAnimationViewBase.macOS.swift} +4 -4
  139. package/Tests/AnimationCacheProviderTests.swift +40 -0
  140. package/Tests/AnimationKeypathTests.swift +20 -13
  141. package/Tests/AnimationViewTests.swift +64 -0
  142. package/Tests/AutomaticEngineTests.swift +11 -2
  143. package/Tests/ParsingTests.swift +4 -2
  144. package/Tests/PerformanceTests.swift +9 -9
  145. package/Tests/SnapshotConfiguration.swift +7 -7
  146. package/Tests/SnapshotTests.swift +57 -27
  147. package/Tests/ValueProvidersTests.swift +9 -6
  148. package/lottie-ios.podspec +4 -4
  149. package/package.json +2 -2
  150. package/script/test-carthage/Cartfile +1 -1
  151. package/script/test-carthage/CarthageTest/ViewController.swift +1 -1
  152. package/script/test-carthage/CarthageTest-macOS/ViewController.swift +1 -1
  153. package/Sources/Private/CoreAnimation/Extensions/Keyframes+combinedIfPossible.swift +0 -154
  154. package/Sources/Public/Animation/AnimationViewInitializers.swift +0 -109
  155. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +0 -1
  156. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~7IO4FqH8-VUsSfuA0_wMGUgfGdV7MwzpkzjwWbiB50jXZKQRHtU4G0A7ZXTvsR4mDdrWiawpNC_eriOALfZ7Og== +0 -0
  157. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~ClRW5-6rvrgZHHbrPS1VEREaxelpVcKlERPzSa3f2rtFNXdoqATxFCsPge3a_nO4mhhtpmTmbYvyfI-obAu8Qg== +0 -0
  158. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~Jr2dFGcJc1188nMoMha82z9wM99lCLm4MKzhjfVVjIxKeCZVGWGZH3HgJFNkTpozdk5p1u5o91dCiY4-cR1Zhg== +0 -0
  159. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~MBDeCFoahVzzmtSQrVhhy9VMJV6CmcnUkFya_qwe0XsMFscmY2nS8dxrTEYkY16sH68sEH7WVCCzTuW1z1Hocw== +0 -1
  160. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~U4plJajEDM_uSZdglhDyj6gQO63mbeKxYP9X94aIaOtL0yErtfQnGz5SgsqQ0ToSZcJj6Ao9Wx-nesZVwBTRuw== +0 -0
  161. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~UsLY5O-vDMEHEe3bF8XJvkKkYxdsKlIytgJW7zgNuetw53fG3SssfZiiMfbuYnOtvvvYBXTwpbz07V6Czp029Q== +0 -0
  162. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~cpg4cb7H0TaehHy4a-xINJMFfBM2_AEHal_0tIX8ymNVJPsjlCysi3-Cad0Ca_SvuGwVM7ONF55OBUuC9YKZvA== +0 -0
  163. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~cuHjdTCuciVumvEpvozxwDj2wAdgWe13bzd1pUAGN45-WOgY0kIid9aUlBX675OnS-xNEc_pyQWo0RO1dKAjcw== +0 -0
  164. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~f_-bfn-KRHHFg39_MtwgBulEAuWH6F05yqGYydXhil6kqZ51eAoRX6tsiqOr0Oa6eL3dK1tcCBD1bWX5orCZhw== +0 -1
  165. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~jdIx7vWS6ej1cqYcbCS4KyZErSMF13ELR95YwClVc98tIXcsglh7KuGvI1gIxEPDtPXQpfC3XijIAGn1quL8Dw== +0 -0
  166. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~lz3e0YeBa8TvMBSSymToh--gc6zznUIdH2jO0AJ4so5OPNdw6wpYmJebhaENGsRoD3beUXvlyD5f7_WeZrzyNQ== +0 -0
  167. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~u_5dWbliYJ__YkyUCDFjdxiFds9M8Epr_RvbU1rIRCbBQdhRJ_TUBXXcL_Qq-wVp4umNLTOzud4OpQItSpO6Rg== +0 -0
  168. package/Tests/Artifacts/LottieTests.xcresult/Data/data.0~v-YGzhC2l_icsAsyp1XAbEWYwxNook-rARAWlVZINioEsgT9LGvhg2oh78nYqoeH78m1fihr5HCcGNfF7SQj0g== +0 -0
  169. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~4VqMqsI5lOfxRppnud6-VDWcNsU8J7VgFCJfW2dXPwOcAkvU-I8Um5yp9n0Zv6nr3VmcxYggaVMDFfR0U_vjKw== +0 -0
  170. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~7IO4FqH8-VUsSfuA0_wMGUgfGdV7MwzpkzjwWbiB50jXZKQRHtU4G0A7ZXTvsR4mDdrWiawpNC_eriOALfZ7Og== +0 -0
  171. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~ClRW5-6rvrgZHHbrPS1VEREaxelpVcKlERPzSa3f2rtFNXdoqATxFCsPge3a_nO4mhhtpmTmbYvyfI-obAu8Qg== +0 -0
  172. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~Jr2dFGcJc1188nMoMha82z9wM99lCLm4MKzhjfVVjIxKeCZVGWGZH3HgJFNkTpozdk5p1u5o91dCiY4-cR1Zhg== +0 -0
  173. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~MBDeCFoahVzzmtSQrVhhy9VMJV6CmcnUkFya_qwe0XsMFscmY2nS8dxrTEYkY16sH68sEH7WVCCzTuW1z1Hocw== +0 -0
  174. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~U4plJajEDM_uSZdglhDyj6gQO63mbeKxYP9X94aIaOtL0yErtfQnGz5SgsqQ0ToSZcJj6Ao9Wx-nesZVwBTRuw== +0 -0
  175. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~UsLY5O-vDMEHEe3bF8XJvkKkYxdsKlIytgJW7zgNuetw53fG3SssfZiiMfbuYnOtvvvYBXTwpbz07V6Czp029Q== +0 -0
  176. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~cpg4cb7H0TaehHy4a-xINJMFfBM2_AEHal_0tIX8ymNVJPsjlCysi3-Cad0Ca_SvuGwVM7ONF55OBUuC9YKZvA== +0 -0
  177. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~cuHjdTCuciVumvEpvozxwDj2wAdgWe13bzd1pUAGN45-WOgY0kIid9aUlBX675OnS-xNEc_pyQWo0RO1dKAjcw== +0 -0
  178. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~f_-bfn-KRHHFg39_MtwgBulEAuWH6F05yqGYydXhil6kqZ51eAoRX6tsiqOr0Oa6eL3dK1tcCBD1bWX5orCZhw== +0 -0
  179. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~jdIx7vWS6ej1cqYcbCS4KyZErSMF13ELR95YwClVc98tIXcsglh7KuGvI1gIxEPDtPXQpfC3XijIAGn1quL8Dw== +0 -0
  180. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~lz3e0YeBa8TvMBSSymToh--gc6zznUIdH2jO0AJ4so5OPNdw6wpYmJebhaENGsRoD3beUXvlyD5f7_WeZrzyNQ== +0 -0
  181. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~u_5dWbliYJ__YkyUCDFjdxiFds9M8Epr_RvbU1rIRCbBQdhRJ_TUBXXcL_Qq-wVp4umNLTOzud4OpQItSpO6Rg== +0 -0
  182. package/Tests/Artifacts/LottieTests.xcresult/Data/refs.0~v-YGzhC2l_icsAsyp1XAbEWYwxNook-rARAWlVZINioEsgT9LGvhg2oh78nYqoeH78m1fihr5HCcGNfF7SQj0g== +0 -0
  183. 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: &centralDirectorySignature) { 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: Vector2D?,
28
- outTangent: Vector2D?,
29
- spatialInTangent: Vector3D?,
30
- spatialOutTangent: Vector3D?)
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: Vector2D?
65
+ let inTangent: LottieVector2D?
66
66
  /// The out tangent for the time interpolation curve.
67
- let outTangent: Vector2D?
67
+ let outTangent: LottieVector2D?
68
68
 
69
69
  /// The spacial in tangent of the vector.
70
- let spatialInTangent: Vector3D?
70
+ let spatialInTangent: LottieVector3D?
71
71
  /// The spacial out tangent of the vector.
72
- let spatialOutTangent: Vector3D?
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: Vector2D? = try? dictionary.value(for: CodingKeys.inTangent)
99
- let outTangent: Vector2D? = try? dictionary.value(for: CodingKeys.outTangent)
100
- let spatialInTangent: Vector3D? = try? dictionary.value(for: CodingKeys.spatialInTangent)
101
- let spatialOutTangent: Vector3D? = try? dictionary.value(for: CodingKeys.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,