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,130 @@
1
+ //
2
+ // FileManager+ZIP.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 FileManager {
14
+
15
+ /// The default permissions for newly added entries.
16
+ static let defaultFilePermissions = UInt16(0o644)
17
+
18
+ class func attributes(from entry: ZipEntry) -> [FileAttributeKey: Any] {
19
+ let centralDirectoryStructure = entry.centralDirectoryStructure
20
+ let fileTime = centralDirectoryStructure.lastModFileTime
21
+ let fileDate = centralDirectoryStructure.lastModFileDate
22
+ let defaultPermissions = defaultFilePermissions
23
+ var attributes = [.posixPermissions: defaultPermissions] as [FileAttributeKey: Any]
24
+ // Certain keys are not yet supported in swift-corelibs
25
+ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
26
+ attributes[.modificationDate] = Date(dateTime: (fileDate, fileTime))
27
+ #endif
28
+ let externalFileAttributes = centralDirectoryStructure.externalFileAttributes
29
+ let permissions = permissions(for: externalFileAttributes)
30
+ attributes[.posixPermissions] = NSNumber(value: permissions)
31
+ return attributes
32
+ }
33
+
34
+ class func permissions(for externalFileAttributes: UInt32) -> UInt16 {
35
+ let permissions = mode_t(externalFileAttributes >> 16) & ~S_IFMT
36
+ let defaultPermissions = defaultFilePermissions
37
+ return permissions == 0 ? defaultPermissions : UInt16(permissions)
38
+ }
39
+
40
+ /// Unzips the contents at the specified source URL to the destination URL.
41
+ ///
42
+ /// - Parameters:
43
+ /// - sourceURL: The file URL pointing to an existing ZIP file.
44
+ /// - destinationURL: The file URL that identifies the destination directory of the unzip operation.
45
+ /// - Throws: Throws an error if the source item does not exist or the destination URL is not writable.
46
+ func unzipItem(at sourceURL: URL, to destinationURL: URL) throws {
47
+ guard (try? sourceURL.checkResourceIsReachable()) == true else {
48
+ throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: sourceURL.path])
49
+ }
50
+ guard let archive = ZipArchive(url: sourceURL) else {
51
+ throw ZipArchive.ArchiveError.unreadableArchive
52
+ }
53
+
54
+ for entry in archive {
55
+ let path = entry.path
56
+ let entryURL = destinationURL.appendingPathComponent(path)
57
+ guard entryURL.isContained(in: destinationURL) else {
58
+ throw CocoaError(
59
+ .fileReadInvalidFileName,
60
+ userInfo: [NSFilePathErrorKey: entryURL.path])
61
+ }
62
+ let crc32: UInt32 = try archive.extract(entry, to: entryURL)
63
+
64
+ func verifyChecksumIfNecessary() throws {
65
+ if crc32 != entry.checksum {
66
+ throw ZipArchive.ArchiveError.invalidCRC32
67
+ }
68
+ }
69
+ try verifyChecksumIfNecessary()
70
+ }
71
+ }
72
+
73
+ // MARK: - Helpers
74
+
75
+ func createParentDirectoryStructure(for url: URL) throws {
76
+ let parentDirectoryURL = url.deletingLastPathComponent()
77
+ try createDirectory(at: parentDirectoryURL, withIntermediateDirectories: true, attributes: nil)
78
+ }
79
+
80
+ }
81
+
82
+ extension Date {
83
+ fileprivate init(dateTime: (UInt16, UInt16)) {
84
+ var msdosDateTime = Int(dateTime.0)
85
+ msdosDateTime <<= 16
86
+ msdosDateTime |= Int(dateTime.1)
87
+ var unixTime = tm()
88
+ unixTime.tm_sec = Int32((msdosDateTime & 31) * 2)
89
+ unixTime.tm_min = Int32((msdosDateTime >> 5) & 63)
90
+ unixTime.tm_hour = Int32((Int(dateTime.1) >> 11) & 31)
91
+ unixTime.tm_mday = Int32((msdosDateTime >> 16) & 31)
92
+ unixTime.tm_mon = Int32((msdosDateTime >> 21) & 15)
93
+ unixTime.tm_mon -= 1 // UNIX time struct month entries are zero based.
94
+ unixTime.tm_year = Int32(1980 + (msdosDateTime >> 25))
95
+ unixTime.tm_year -= 1900 // UNIX time structs count in "years since 1900".
96
+ let time = timegm(&unixTime)
97
+ self = Date(timeIntervalSince1970: TimeInterval(time))
98
+ }
99
+ }
100
+
101
+ #if swift(>=4.2)
102
+ #else
103
+
104
+ #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
105
+ #else
106
+
107
+ // The swift-corelibs-foundation version of NSError.swift was missing a convenience method to create
108
+ // error objects from error codes. (https://github.com/apple/swift-corelibs-foundation/pull/1420)
109
+ // We have to provide an implementation for non-Darwin platforms using Swift versions < 4.2.
110
+
111
+ extension CocoaError {
112
+ fileprivate static func error(_ code: CocoaError.Code, userInfo: [AnyHashable: Any]? = nil, url: URL? = nil) -> Error {
113
+ var info: [String: Any] = userInfo as? [String: Any] ?? [:]
114
+ if let url = url {
115
+ info[NSURLErrorKey] = url
116
+ }
117
+ return NSError(domain: NSCocoaErrorDomain, code: code.rawValue, userInfo: info)
118
+ }
119
+ }
120
+
121
+ #endif
122
+ #endif
123
+
124
+ extension URL {
125
+ fileprivate func isContained(in parentDirectoryURL: URL) -> Bool {
126
+ // Ensure this URL is contained in the passed in URL
127
+ let parentDirectoryURL = URL(fileURLWithPath: parentDirectoryURL.path, isDirectory: true).standardized
128
+ return standardized.absoluteString.hasPrefix(parentDirectoryURL.absoluteString)
129
+ }
130
+ }
@@ -0,0 +1,474 @@
1
+ //
2
+ // Archive.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: - ZipArchive
14
+
15
+ final class ZipArchive: Sequence {
16
+
17
+ // MARK: Lifecycle
18
+
19
+ /// Initializes a new ZIP `Archive`.
20
+ ///
21
+ /// You can use this initalizer to create new archive files or to read and update existing ones.
22
+ /// - Parameters:
23
+ /// - url: File URL to the receivers backing file.
24
+ /// - Returns: An archive initialized with a backing file at the passed in file URL and the given access mode
25
+ /// or `nil` if the following criteria are not met:
26
+ init?(url: URL) {
27
+ self.url = url
28
+ guard let config = ZipArchive.makeBackingConfiguration(for: url) else { return nil }
29
+ archiveFile = config.file
30
+ endOfCentralDirectoryRecord = config.endOfCentralDirectoryRecord
31
+ zip64EndOfCentralDirectory = config.zip64EndOfCentralDirectory
32
+ setvbuf(archiveFile, nil, _IOFBF, Int(Self.defaultPOSIXBufferSize))
33
+ }
34
+
35
+ deinit {
36
+ fclose(self.archiveFile)
37
+ }
38
+
39
+ // MARK: Internal
40
+
41
+ typealias LocalFileHeader = ZipEntry.LocalFileHeader
42
+ typealias DataDescriptor = ZipEntry.DefaultDataDescriptor
43
+ typealias ZIP64DataDescriptor = ZipEntry.ZIP64DataDescriptor
44
+ typealias CentralDirectoryStructure = ZipEntry.CentralDirectoryStructure
45
+
46
+ /// An error that occurs during reading, creating or updating a ZIP file.
47
+ enum ArchiveError: Error {
48
+ /// Thrown when an archive file is either damaged or inaccessible.
49
+ case unreadableArchive
50
+ /// Thrown when an archive is either opened with AccessMode.read or the destination file is unwritable.
51
+ case unwritableArchive
52
+ /// Thrown when the path of an `Entry` cannot be stored in an archive.
53
+ case invalidEntryPath
54
+ /// Thrown when an `Entry` can't be stored in the archive with the proposed compression method.
55
+ case invalidCompressionMethod
56
+ /// Thrown when the stored checksum of an `Entry` doesn't match the checksum during reading.
57
+ case invalidCRC32
58
+ /// Thrown when an extract, add or remove operation was canceled.
59
+ case cancelledOperation
60
+ /// Thrown when an extract operation was called with zero or negative `bufferSize` parameter.
61
+ case invalidBufferSize
62
+ /// Thrown when uncompressedSize/compressedSize exceeds `Int64.max` (Imposed by file API).
63
+ case invalidEntrySize
64
+ /// Thrown when the offset of local header data exceeds `Int64.max` (Imposed by file API).
65
+ case invalidLocalHeaderDataOffset
66
+ /// Thrown when the size of local header exceeds `Int64.max` (Imposed by file API).
67
+ case invalidLocalHeaderSize
68
+ /// Thrown when the offset of central directory exceeds `Int64.max` (Imposed by file API).
69
+ case invalidCentralDirectoryOffset
70
+ /// Thrown when the size of central directory exceeds `UInt64.max` (Imposed by ZIP specification).
71
+ case invalidCentralDirectorySize
72
+ /// Thrown when number of entries in central directory exceeds `UInt64.max` (Imposed by ZIP specification).
73
+ case invalidCentralDirectoryEntryCount
74
+ /// Thrown when an archive does not contain the required End of Central Directory Record.
75
+ case missingEndOfCentralDirectoryRecord
76
+ }
77
+
78
+ struct EndOfCentralDirectoryRecord: DataSerializable {
79
+ let endOfCentralDirectorySignature = UInt32(endOfCentralDirectoryStructSignature)
80
+ let numberOfDisk: UInt16
81
+ let numberOfDiskStart: UInt16
82
+ let totalNumberOfEntriesOnDisk: UInt16
83
+ let totalNumberOfEntriesInCentralDirectory: UInt16
84
+ let sizeOfCentralDirectory: UInt32
85
+ let offsetToStartOfCentralDirectory: UInt32
86
+ let zipFileCommentLength: UInt16
87
+ let zipFileCommentData: Data
88
+ static let size = 22
89
+ }
90
+
91
+ // MARK: - Helpers
92
+
93
+ typealias EndOfCentralDirectoryStructure = (EndOfCentralDirectoryRecord, ZIP64EndOfCentralDirectory?)
94
+
95
+ struct BackingConfiguration {
96
+ let file: FILEPointer
97
+ let endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord
98
+ let zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory?
99
+
100
+ init(
101
+ file: FILEPointer,
102
+ endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord,
103
+ zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory?)
104
+ {
105
+ self.file = file
106
+ self.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
107
+ self.zip64EndOfCentralDirectory = zip64EndOfCentralDirectory
108
+ }
109
+ }
110
+
111
+ static let defaultPOSIXBufferSize = Int(16 * 1024)
112
+ static let minEndOfCentralDirectoryOffset = Int64(22)
113
+ static let endOfCentralDirectoryStructSignature = 0x06054b50
114
+
115
+ /// The default chunk size when reading entry data from an archive.
116
+ static let defaultReadChunkSize = Int(16 * 1024)
117
+
118
+ /// URL of an Archive's backing file.
119
+ let url: URL
120
+ var archiveFile: FILEPointer
121
+ var endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord
122
+ var zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory?
123
+
124
+ var totalNumberOfEntriesInCentralDirectory: UInt64 {
125
+ zip64EndOfCentralDirectory?.record.totalNumberOfEntriesInCentralDirectory
126
+ ?? UInt64(endOfCentralDirectoryRecord.totalNumberOfEntriesInCentralDirectory)
127
+ }
128
+
129
+ var sizeOfCentralDirectory: UInt64 {
130
+ zip64EndOfCentralDirectory?.record.sizeOfCentralDirectory
131
+ ?? UInt64(endOfCentralDirectoryRecord.sizeOfCentralDirectory)
132
+ }
133
+
134
+ var offsetToStartOfCentralDirectory: UInt64 {
135
+ zip64EndOfCentralDirectory?.record.offsetToStartOfCentralDirectory
136
+ ?? UInt64(endOfCentralDirectoryRecord.offsetToStartOfCentralDirectory)
137
+ }
138
+
139
+ static func scanForEndOfCentralDirectoryRecord(in file: FILEPointer)
140
+ -> EndOfCentralDirectoryStructure?
141
+ {
142
+ var eocdOffset: UInt64 = 0
143
+ var index = minEndOfCentralDirectoryOffset
144
+ fseeko(file, 0, SEEK_END)
145
+ let archiveLength = Int64(ftello(file))
146
+ while eocdOffset == 0, index <= archiveLength {
147
+ fseeko(file, off_t(archiveLength - index), SEEK_SET)
148
+ var potentialDirectoryEndTag = UInt32()
149
+ fread(&potentialDirectoryEndTag, 1, MemoryLayout<UInt32>.size, file)
150
+ if potentialDirectoryEndTag == UInt32(endOfCentralDirectoryStructSignature) {
151
+ eocdOffset = UInt64(archiveLength - index)
152
+ guard let eocd: EndOfCentralDirectoryRecord = Data.readStruct(from: file, at: eocdOffset) else {
153
+ return nil
154
+ }
155
+ let zip64EOCD = scanForZIP64EndOfCentralDirectory(in: file, eocdOffset: eocdOffset)
156
+ return (eocd, zip64EOCD)
157
+ }
158
+ index += 1
159
+ }
160
+ return nil
161
+ }
162
+
163
+ static func makeBackingConfiguration(for url: URL) -> BackingConfiguration? {
164
+ let fileManager = FileManager()
165
+ let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
166
+ guard
167
+ let archiveFile = fopen(fileSystemRepresentation, "rb"),
168
+ let (eocdRecord, zip64EOCD) = ZipArchive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else
169
+ {
170
+ return nil
171
+ }
172
+ return BackingConfiguration(
173
+ file: archiveFile,
174
+ endOfCentralDirectoryRecord: eocdRecord,
175
+ zip64EndOfCentralDirectory: zip64EOCD)
176
+ }
177
+
178
+ func makeIterator() -> AnyIterator<ZipEntry> {
179
+ let totalNumberOfEntriesInCD = totalNumberOfEntriesInCentralDirectory
180
+ var directoryIndex = offsetToStartOfCentralDirectory
181
+ var index = 0
182
+ return AnyIterator {
183
+ guard index < totalNumberOfEntriesInCD else { return nil }
184
+ guard
185
+ let centralDirStruct: CentralDirectoryStructure = Data.readStruct(
186
+ from: self.archiveFile,
187
+ at: directoryIndex) else
188
+ {
189
+ return nil
190
+ }
191
+ let offset = UInt64(centralDirStruct.effectiveRelativeOffsetOfLocalHeader)
192
+ guard
193
+ let localFileHeader: LocalFileHeader = Data.readStruct(
194
+ from: self.archiveFile,
195
+ at: offset) else { return nil }
196
+ var dataDescriptor: DataDescriptor?
197
+ var zip64DataDescriptor: ZIP64DataDescriptor?
198
+ if centralDirStruct.usesDataDescriptor {
199
+ let additionalSize = UInt64(localFileHeader.fileNameLength) + UInt64(localFileHeader.extraFieldLength)
200
+ let isCompressed = centralDirStruct.compressionMethod != 0
201
+ let dataSize = isCompressed
202
+ ? centralDirStruct.effectiveCompressedSize
203
+ : centralDirStruct.effectiveUncompressedSize
204
+ let descriptorPosition = offset + UInt64(LocalFileHeader.size) + additionalSize + dataSize
205
+ if centralDirStruct.isZIP64 {
206
+ zip64DataDescriptor = Data.readStruct(from: self.archiveFile, at: descriptorPosition)
207
+ } else {
208
+ dataDescriptor = Data.readStruct(from: self.archiveFile, at: descriptorPosition)
209
+ }
210
+ }
211
+ defer {
212
+ directoryIndex += UInt64(CentralDirectoryStructure.size)
213
+ directoryIndex += UInt64(centralDirStruct.fileNameLength)
214
+ directoryIndex += UInt64(centralDirStruct.extraFieldLength)
215
+ directoryIndex += UInt64(centralDirStruct.fileCommentLength)
216
+ index += 1
217
+ }
218
+ return ZipEntry(
219
+ centralDirectoryStructure: centralDirStruct,
220
+ localFileHeader: localFileHeader,
221
+ dataDescriptor: dataDescriptor,
222
+ zip64DataDescriptor: zip64DataDescriptor)
223
+ }
224
+ }
225
+
226
+ /// Retrieve the ZIP `Entry` with the given `path` from the receiver.
227
+ ///
228
+ /// - Note: The ZIP file format specification does not enforce unique paths for entries.
229
+ /// Therefore an archive can contain multiple entries with the same path. This method
230
+ /// always returns the first `Entry` with the given `path`.
231
+ ///
232
+ /// - Parameter path: A relative file path identifying the corresponding `Entry`.
233
+ /// - Returns: An `Entry` with the given `path`. Otherwise, `nil`.
234
+ subscript(path: String) -> ZipEntry? {
235
+ first { $0.path == path }
236
+ }
237
+
238
+ /// Read a ZIP `Entry` from the receiver and write it to `url`.
239
+ ///
240
+ /// - Parameters:
241
+ /// - entry: The ZIP `Entry` to read.
242
+ /// - url: The destination file URL.
243
+ /// - bufferSize: The maximum size of the read buffer and the decompression buffer (if needed).
244
+ /// - Returns: The checksum of the processed content or 0 if the `skipCRC32` flag was set to `true`.
245
+ /// - Throws: An error if the destination file cannot be written or the entry contains malformed content.
246
+ func extract(_ entry: ZipEntry, to url: URL, bufferSize: Int = defaultReadChunkSize) throws -> UInt32 {
247
+ guard bufferSize > 0 else { throw ArchiveError.invalidBufferSize }
248
+ let fileManager = FileManager()
249
+ try fileManager.createParentDirectoryStructure(for: url)
250
+ let destinationRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
251
+ guard let destinationFile: FILEPointer = fopen(destinationRepresentation, "wb+") else {
252
+ throw CocoaError(.fileNoSuchFile)
253
+ }
254
+ defer { fclose(destinationFile) }
255
+
256
+ guard bufferSize > 0 else { throw ArchiveError.invalidBufferSize }
257
+ guard entry.dataOffset <= .max else { throw ArchiveError.invalidLocalHeaderDataOffset }
258
+ fseeko(archiveFile, off_t(entry.dataOffset), SEEK_SET)
259
+
260
+ let attributes = FileManager.attributes(from: entry)
261
+ try fileManager.setAttributes(attributes, ofItemAtPath: url.path)
262
+
263
+ let size = entry.centralDirectoryStructure.effectiveCompressedSize
264
+ guard size <= .max else { throw ArchiveError.invalidEntrySize }
265
+ return try Data.decompress(size: Int64(size), bufferSize: bufferSize, provider: { _, chunkSize -> Data in
266
+ try Data.readChunk(of: chunkSize, from: self.archiveFile)
267
+ }, consumer: { data in
268
+ _ = try Data.write(chunk: data, to: destinationFile)
269
+ })
270
+ }
271
+
272
+ // MARK: Private
273
+
274
+ private static func scanForZIP64EndOfCentralDirectory(in file: FILEPointer, eocdOffset: UInt64)
275
+ -> ZIP64EndOfCentralDirectory?
276
+ {
277
+ guard UInt64(ZIP64EndOfCentralDirectoryLocator.size) < eocdOffset else {
278
+ return nil
279
+ }
280
+ let locatorOffset = eocdOffset - UInt64(ZIP64EndOfCentralDirectoryLocator.size)
281
+
282
+ guard UInt64(ZIP64EndOfCentralDirectoryRecord.size) < locatorOffset else {
283
+ return nil
284
+ }
285
+ let recordOffset = locatorOffset - UInt64(ZIP64EndOfCentralDirectoryRecord.size)
286
+ guard
287
+ let locator: ZIP64EndOfCentralDirectoryLocator = Data.readStruct(from: file, at: locatorOffset),
288
+ let record: ZIP64EndOfCentralDirectoryRecord = Data.readStruct(from: file, at: recordOffset) else
289
+ {
290
+ return nil
291
+ }
292
+ return ZIP64EndOfCentralDirectory(record: record, locator: locator)
293
+ }
294
+ }
295
+
296
+ // MARK: - Zip64
297
+
298
+ extension ZipArchive {
299
+
300
+ struct ZIP64EndOfCentralDirectory {
301
+ let record: ZIP64EndOfCentralDirectoryRecord
302
+ let locator: ZIP64EndOfCentralDirectoryLocator
303
+ }
304
+
305
+ struct ZIP64EndOfCentralDirectoryRecord: DataSerializable {
306
+ let zip64EOCDRecordSignature = UInt32(zip64EOCDRecordStructSignature)
307
+ let sizeOfZIP64EndOfCentralDirectoryRecord: UInt64
308
+ let versionMadeBy: UInt16
309
+ let versionNeededToExtract: UInt16
310
+ let numberOfDisk: UInt32
311
+ let numberOfDiskStart: UInt32
312
+ let totalNumberOfEntriesOnDisk: UInt64
313
+ let totalNumberOfEntriesInCentralDirectory: UInt64
314
+ let sizeOfCentralDirectory: UInt64
315
+ let offsetToStartOfCentralDirectory: UInt64
316
+ let zip64ExtensibleDataSector: Data
317
+ static let size = 56
318
+ }
319
+
320
+ struct ZIP64EndOfCentralDirectoryLocator: DataSerializable {
321
+ let zip64EOCDLocatorSignature = UInt32(zip64EOCDLocatorStructSignature)
322
+ let numberOfDiskWithZIP64EOCDRecordStart: UInt32
323
+ let relativeOffsetOfZIP64EOCDRecord: UInt64
324
+ let totalNumberOfDisk: UInt32
325
+ static let size = 20
326
+ }
327
+
328
+ static let zip64EOCDRecordStructSignature = 0x06064b50
329
+ static let zip64EOCDLocatorStructSignature = 0x07064b50
330
+ }
331
+
332
+ extension ZipArchive.ZIP64EndOfCentralDirectoryRecord {
333
+
334
+ // MARK: Lifecycle
335
+
336
+ init?(data: Data, additionalDataProvider _: (Int) throws -> Data) {
337
+ guard data.count == ZipArchive.ZIP64EndOfCentralDirectoryRecord.size else { return nil }
338
+ guard data.scanValue(start: 0) == zip64EOCDRecordSignature else { return nil }
339
+ sizeOfZIP64EndOfCentralDirectoryRecord = data.scanValue(start: 4)
340
+ versionMadeBy = data.scanValue(start: 12)
341
+ versionNeededToExtract = data.scanValue(start: 14)
342
+ // Version Needed to Extract: 4.5 - File uses ZIP64 format extensions
343
+ guard versionNeededToExtract >= 45 else { return nil }
344
+ numberOfDisk = data.scanValue(start: 16)
345
+ numberOfDiskStart = data.scanValue(start: 20)
346
+ totalNumberOfEntriesOnDisk = data.scanValue(start: 24)
347
+ totalNumberOfEntriesInCentralDirectory = data.scanValue(start: 32)
348
+ sizeOfCentralDirectory = data.scanValue(start: 40)
349
+ offsetToStartOfCentralDirectory = data.scanValue(start: 48)
350
+ zip64ExtensibleDataSector = Data()
351
+ }
352
+
353
+ init(
354
+ record: ZipArchive.ZIP64EndOfCentralDirectoryRecord,
355
+ numberOfEntriesOnDisk: UInt64,
356
+ numberOfEntriesInCD: UInt64,
357
+ sizeOfCentralDirectory: UInt64,
358
+ offsetToStartOfCD: UInt64)
359
+ {
360
+ sizeOfZIP64EndOfCentralDirectoryRecord = record.sizeOfZIP64EndOfCentralDirectoryRecord
361
+ versionMadeBy = record.versionMadeBy
362
+ versionNeededToExtract = record.versionNeededToExtract
363
+ numberOfDisk = record.numberOfDisk
364
+ numberOfDiskStart = record.numberOfDiskStart
365
+ totalNumberOfEntriesOnDisk = numberOfEntriesOnDisk
366
+ totalNumberOfEntriesInCentralDirectory = numberOfEntriesInCD
367
+ self.sizeOfCentralDirectory = sizeOfCentralDirectory
368
+ offsetToStartOfCentralDirectory = offsetToStartOfCD
369
+ zip64ExtensibleDataSector = record.zip64ExtensibleDataSector
370
+ }
371
+
372
+ // MARK: Internal
373
+
374
+ var data: Data {
375
+ var zip64EOCDRecordSignature = zip64EOCDRecordSignature
376
+ var sizeOfZIP64EOCDRecord = sizeOfZIP64EndOfCentralDirectoryRecord
377
+ var versionMadeBy = versionMadeBy
378
+ var versionNeededToExtract = versionNeededToExtract
379
+ var numberOfDisk = numberOfDisk
380
+ var numberOfDiskStart = numberOfDiskStart
381
+ var totalNumberOfEntriesOnDisk = totalNumberOfEntriesOnDisk
382
+ var totalNumberOfEntriesInCD = totalNumberOfEntriesInCentralDirectory
383
+ var sizeOfCD = sizeOfCentralDirectory
384
+ var offsetToStartOfCD = offsetToStartOfCentralDirectory
385
+ var data = Data()
386
+ withUnsafePointer(to: &zip64EOCDRecordSignature) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
387
+ withUnsafePointer(to: &sizeOfZIP64EOCDRecord) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
388
+ withUnsafePointer(to: &versionMadeBy) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
389
+ withUnsafePointer(to: &versionNeededToExtract) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
390
+ withUnsafePointer(to: &numberOfDisk) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
391
+ withUnsafePointer(to: &numberOfDiskStart) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
392
+ withUnsafePointer(to: &totalNumberOfEntriesOnDisk) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
393
+ withUnsafePointer(to: &totalNumberOfEntriesInCD) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
394
+ withUnsafePointer(to: &sizeOfCD) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
395
+ withUnsafePointer(to: &offsetToStartOfCD) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
396
+ data.append(zip64ExtensibleDataSector)
397
+ return data
398
+ }
399
+
400
+ }
401
+
402
+ extension ZipArchive.ZIP64EndOfCentralDirectoryLocator {
403
+
404
+ // MARK: Lifecycle
405
+
406
+ init?(data: Data, additionalDataProvider _: (Int) throws -> Data) {
407
+ guard data.count == ZipArchive.ZIP64EndOfCentralDirectoryLocator.size else { return nil }
408
+ guard data.scanValue(start: 0) == zip64EOCDLocatorSignature else { return nil }
409
+ numberOfDiskWithZIP64EOCDRecordStart = data.scanValue(start: 4)
410
+ relativeOffsetOfZIP64EOCDRecord = data.scanValue(start: 8)
411
+ totalNumberOfDisk = data.scanValue(start: 16)
412
+ }
413
+
414
+ // MARK: Internal
415
+
416
+ var data: Data {
417
+ var zip64EOCDLocatorSignature = zip64EOCDLocatorSignature
418
+ var numberOfDiskWithZIP64EOCD = numberOfDiskWithZIP64EOCDRecordStart
419
+ var offsetOfZIP64EOCDRecord = relativeOffsetOfZIP64EOCDRecord
420
+ var totalNumberOfDisk = totalNumberOfDisk
421
+ var data = Data()
422
+ withUnsafePointer(to: &zip64EOCDLocatorSignature) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
423
+ withUnsafePointer(to: &numberOfDiskWithZIP64EOCD) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
424
+ withUnsafePointer(to: &offsetOfZIP64EOCDRecord) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
425
+ withUnsafePointer(to: &totalNumberOfDisk) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
426
+ return data
427
+ }
428
+
429
+ }
430
+
431
+ extension ZipArchive.EndOfCentralDirectoryRecord {
432
+
433
+ // MARK: Lifecycle
434
+
435
+ init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
436
+ guard data.count == ZipArchive.EndOfCentralDirectoryRecord.size else { return nil }
437
+ guard data.scanValue(start: 0) == endOfCentralDirectorySignature else { return nil }
438
+ numberOfDisk = data.scanValue(start: 4)
439
+ numberOfDiskStart = data.scanValue(start: 6)
440
+ totalNumberOfEntriesOnDisk = data.scanValue(start: 8)
441
+ totalNumberOfEntriesInCentralDirectory = data.scanValue(start: 10)
442
+ sizeOfCentralDirectory = data.scanValue(start: 12)
443
+ offsetToStartOfCentralDirectory = data.scanValue(start: 16)
444
+ zipFileCommentLength = data.scanValue(start: 20)
445
+ guard let commentData = try? provider(Int(zipFileCommentLength)) else { return nil }
446
+ guard commentData.count == Int(zipFileCommentLength) else { return nil }
447
+ zipFileCommentData = commentData
448
+ }
449
+
450
+ // MARK: Internal
451
+
452
+ var data: Data {
453
+ var endOfCDSignature = endOfCentralDirectorySignature
454
+ var numberOfDisk = numberOfDisk
455
+ var numberOfDiskStart = numberOfDiskStart
456
+ var totalNumberOfEntriesOnDisk = totalNumberOfEntriesOnDisk
457
+ var totalNumberOfEntriesInCD = totalNumberOfEntriesInCentralDirectory
458
+ var sizeOfCentralDirectory = sizeOfCentralDirectory
459
+ var offsetToStartOfCD = offsetToStartOfCentralDirectory
460
+ var zipFileCommentLength = zipFileCommentLength
461
+ var data = Data()
462
+ withUnsafePointer(to: &endOfCDSignature) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
463
+ withUnsafePointer(to: &numberOfDisk) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
464
+ withUnsafePointer(to: &numberOfDiskStart) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
465
+ withUnsafePointer(to: &totalNumberOfEntriesOnDisk) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
466
+ withUnsafePointer(to: &totalNumberOfEntriesInCD) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
467
+ withUnsafePointer(to: &sizeOfCentralDirectory) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
468
+ withUnsafePointer(to: &offsetToStartOfCD) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
469
+ withUnsafePointer(to: &zipFileCommentLength) { data.append(UnsafeBufferPointer(start: $0, count: 1)) }
470
+ data.append(zipFileCommentData)
471
+ return data
472
+ }
473
+
474
+ }