lottie-ios 4.1.3 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.github/workflows/main.yml +27 -9
  2. package/Lottie.xcodeproj/project.pbxproj +158 -70
  3. package/Lottie.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +2 -2
  4. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/IDEFindNavigatorScopes.plist +5 -0
  5. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  6. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +258 -0
  7. package/Lottie.xcworkspace/xcuserdata/calstephens.xcuserdatad/xcdebugger/Expressions.xcexplist +13 -2
  8. package/Package.swift +2 -1
  9. package/README.md +1 -1
  10. package/Rakefile +3 -3
  11. package/Sources/Private/CoreAnimation/Animations/CALayer+addAnimation.swift +16 -2
  12. package/Sources/Private/CoreAnimation/Animations/CombinedShapeAnimation.swift +1 -1
  13. package/Sources/Private/CoreAnimation/Animations/CustomPathAnimation.swift +1 -1
  14. package/Sources/Private/CoreAnimation/Animations/EllipseAnimation.swift +1 -1
  15. package/Sources/Private/CoreAnimation/Animations/GradientAnimations.swift +6 -6
  16. package/Sources/Private/CoreAnimation/Animations/LayerProperty.swift +68 -6
  17. package/Sources/Private/CoreAnimation/Animations/OpacityAnimation.swift +1 -1
  18. package/Sources/Private/CoreAnimation/Animations/RectangleAnimation.swift +1 -1
  19. package/Sources/Private/CoreAnimation/Animations/ShapeAnimation.swift +66 -102
  20. package/Sources/Private/CoreAnimation/Animations/StarAnimation.swift +2 -2
  21. package/Sources/Private/CoreAnimation/Animations/StrokeAnimation.swift +3 -3
  22. package/Sources/Private/CoreAnimation/Animations/TransformAnimations.swift +11 -11
  23. package/Sources/Private/CoreAnimation/CoreAnimationLayer.swift +55 -32
  24. package/Sources/Private/CoreAnimation/Layers/AnimationLayer.swift +3 -3
  25. package/Sources/Private/CoreAnimation/Layers/BaseCompositionLayer.swift +7 -9
  26. package/Sources/Private/CoreAnimation/Layers/ShapeLayer.swift +9 -1
  27. package/Sources/Private/CoreAnimation/ValueProviderStore.swift +22 -11
  28. package/Sources/Private/MainThread/LayerContainers/CompLayers/MaskContainerLayer.swift +1 -1
  29. package/Sources/Private/MainThread/LayerContainers/MainThreadAnimationLayer.swift +13 -2
  30. package/Sources/Private/MainThread/LayerContainers/Utility/LayerTransformNode.swift +4 -4
  31. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/EllipseNode.swift +1 -1
  32. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/PolygonNode.swift +2 -2
  33. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/RectNode.swift +1 -1
  34. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/PathNodes/StarNode.swift +2 -2
  35. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderContainers/GroupNode.swift +4 -4
  36. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/FillNode.swift +1 -1
  37. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientFillNode.swift +1 -1
  38. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/GradientStrokeNode.swift +1 -1
  39. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/RenderNodes/StrokeNode.swift +1 -1
  40. package/Sources/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.swift +4 -4
  41. package/Sources/Private/Model/Assets/ImageAsset.swift +4 -3
  42. package/Sources/Private/Model/DotLottie/DotLottieAnimation.swift +2 -8
  43. package/Sources/Private/Model/DotLottie/DotLottieManifest.swift +3 -14
  44. package/Sources/Private/Model/DotLottie/DotLottieUtils.swift +11 -1
  45. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+BackingConfiguration.swift +147 -0
  46. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Helpers.swift +351 -0
  47. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+MemoryFile.swift +183 -0
  48. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Progress.swift +66 -0
  49. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Reading.swift +144 -0
  50. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+ReadingDeprecated.swift +49 -0
  51. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+Writing.swift +385 -0
  52. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+WritingDeprecated.swift +91 -0
  53. package/Sources/Private/Model/DotLottie/ZipFoundation/Archive+ZIP64.swift +170 -0
  54. package/Sources/Private/Model/DotLottie/{Zip/ZipArchive.swift → ZipFoundation/Archive.swift} +150 -227
  55. package/Sources/Private/Model/DotLottie/ZipFoundation/Data+Compression.swift +403 -0
  56. package/Sources/Private/Model/DotLottie/ZipFoundation/Data+CompressionDeprecated.swift +44 -0
  57. package/Sources/Private/Model/DotLottie/{Zip → ZipFoundation}/Data+Serialization.swift +62 -0
  58. package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+Serialization.swift → ZipFoundation/Entry+Serialization.swift} +7 -7
  59. package/Sources/Private/Model/DotLottie/{Zip/ZipEntry+ZIP64.swift → ZipFoundation/Entry+ZIP64.swift} +13 -19
  60. package/Sources/Private/Model/DotLottie/{Zip/ZipEntry.swift → ZipFoundation/Entry.swift} +141 -10
  61. package/Sources/Private/Model/DotLottie/ZipFoundation/FileManager+ZIP.swift +368 -0
  62. package/Sources/Private/Model/DotLottie/ZipFoundation/README.md +24 -0
  63. package/Sources/Private/Model/DotLottie/ZipFoundation/URL+ZIP.swift +32 -0
  64. package/Sources/Private/Model/Extensions/Bundle.swift +5 -14
  65. package/Sources/Private/Model/Keyframes/KeyframeGroup.swift +31 -8
  66. package/Sources/Private/RootAnimationLayer.swift +3 -1
  67. package/Sources/Private/Utility/Extensions/AnimationKeypathExtension.swift +12 -4
  68. package/Sources/Private/Utility/Extensions/DataExtension.swift +14 -4
  69. package/Sources/Private/Utility/Primitives/BezierPathRoundExtension.swift +11 -0
  70. package/Sources/Public/Animation/LottieAnimationHelpers.swift +12 -10
  71. package/Sources/Public/Animation/LottieAnimationView.swift +52 -27
  72. package/Sources/Public/DotLottie/DotLottieFile.swift +11 -34
  73. package/Sources/Public/DotLottie/DotLottieFileHelpers.swift +92 -71
  74. package/Sources/Public/iOS/Compatibility/CompatibleAnimationView.swift +58 -0
  75. package/lottie-ios.podspec +1 -1
  76. package/package.json +1 -1
  77. package/LottieAnimation/LottieAnimation.xcodeproj/project.xcworkspace/xcuserdata/calstephens.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  78. package/LottieAnimation/LottieAnimation.xcodeproj/project.xcworkspace/xcuserdata/valentinperignon.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  79. package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/calstephens.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  80. package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/valentinperignon.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
  81. package/LottieAnimation/LottieAnimation.xcodeproj/xcuserdata/valentinperignon.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  82. package/Sources/Private/Model/DotLottie/Zip/Data+Compression.swift +0 -134
  83. package/Sources/Private/Model/DotLottie/Zip/FileManager+ZIP.swift +0 -130
  84. package/Sources/Private/Utility/Interpolatable/KeyframeGroup+Extensions.swift +0 -59
@@ -167,7 +167,7 @@ private class MaskNodeProperties: NodePropertyMap {
167
167
  shape = NodeProperty(provider: KeyframeInterpolator(keyframes: mask.shape.keyframes))
168
168
  expansion = NodeProperty(provider: KeyframeInterpolator(keyframes: mask.expansion.keyframes))
169
169
  propertyMap = [
170
- "Opacity" : opacity,
170
+ PropertyName.opacity.rawValue : opacity,
171
171
  "Shape" : shape,
172
172
  "Expansion" : expansion,
173
173
  ]
@@ -23,6 +23,7 @@ final class MainThreadAnimationLayer: CALayer, RootAnimationLayer {
23
23
  imageProvider: AnimationImageProvider,
24
24
  textProvider: AnimationTextProvider,
25
25
  fontProvider: AnimationFontProvider,
26
+ maskAnimationToBounds: Bool,
26
27
  logger: LottieLogger)
27
28
  {
28
29
  layerImageProvider = LayerImageProvider(imageProvider: imageProvider, assets: animation.assetLibrary?.imageAssets)
@@ -31,7 +32,7 @@ final class MainThreadAnimationLayer: CALayer, RootAnimationLayer {
31
32
  animationLayers = []
32
33
  self.logger = logger
33
34
  super.init()
34
- masksToBounds = true
35
+ masksToBounds = maskAnimationToBounds
35
36
  bounds = animation.bounds
36
37
  let layers = animation.layers.initializeCompositionLayers(
37
38
  assetLibrary: animation.assetLibrary,
@@ -146,6 +147,9 @@ final class MainThreadAnimationLayer: CALayer, RootAnimationLayer {
146
147
  /// The animatable Current Frame Property
147
148
  @NSManaged var currentFrame: CGFloat
148
149
 
150
+ /// The parent `LottieAnimationView` that manages this layer
151
+ weak var animationView: LottieAnimationView?
152
+
149
153
  var animationLayers: ContiguousArray<CompositionLayer>
150
154
 
151
155
  var primaryAnimationKey: AnimationKey {
@@ -200,7 +204,14 @@ final class MainThreadAnimationLayer: CALayer, RootAnimationLayer {
200
204
 
201
205
  func logHierarchyKeypaths() {
202
206
  logger.info("Lottie: Logging Animation Keypaths")
203
- animationLayers.forEach { $0.logKeypaths(for: nil, logger: self.logger) }
207
+
208
+ for keypath in allHierarchyKeypaths() {
209
+ logger.info(keypath)
210
+ }
211
+ }
212
+
213
+ func allHierarchyKeypaths() -> [String] {
214
+ animationLayers.flatMap { $0.allKeypaths() }
204
215
  }
205
216
 
206
217
  func setValueProvider(_ valueProvider: AnyValueProvider, keypath: AnimationKeypath) {
@@ -25,12 +25,12 @@ final class LayerTransformProperties: NodePropertyMap, KeypathSearchable {
25
25
 
26
26
  var propertyMap: [String: AnyNodeProperty] = [
27
27
  "Anchor Point" : anchor,
28
- "Scale" : scale,
29
- "Rotation": rotationZ,
28
+ PropertyName.scale.rawValue : scale,
29
+ PropertyName.rotation.rawValue: rotationZ,
30
30
  "Rotation X" : rotationX,
31
31
  "Rotation Y" : rotationY,
32
32
  "Rotation Z" : rotationZ,
33
- "Opacity" : opacity,
33
+ PropertyName.opacity.rawValue : opacity,
34
34
  ]
35
35
 
36
36
  if
@@ -46,7 +46,7 @@ final class LayerTransformProperties: NodePropertyMap, KeypathSearchable {
46
46
  position = nil
47
47
  } else if let positionKeyframes = transform.position?.keyframes {
48
48
  let position: NodeProperty<LottieVector3D> = NodeProperty(provider: KeyframeInterpolator(keyframes: positionKeyframes))
49
- propertyMap["Position"] = position
49
+ propertyMap[PropertyName.position.rawValue] = position
50
50
  self.position = position
51
51
  positionX = nil
52
52
  positionY = nil
@@ -20,7 +20,7 @@ final class EllipseNodeProperties: NodePropertyMap, KeypathSearchable {
20
20
  position = NodeProperty(provider: KeyframeInterpolator(keyframes: ellipse.position.keyframes))
21
21
  size = NodeProperty(provider: KeyframeInterpolator(keyframes: ellipse.size.keyframes))
22
22
  keypathProperties = [
23
- "Position" : position,
23
+ PropertyName.position.rawValue : position,
24
24
  "Size" : size,
25
25
  ]
26
26
  properties = Array(keypathProperties.values)
@@ -23,10 +23,10 @@ final class PolygonNodeProperties: NodePropertyMap, KeypathSearchable {
23
23
  rotation = NodeProperty(provider: KeyframeInterpolator(keyframes: star.rotation.keyframes))
24
24
  points = NodeProperty(provider: KeyframeInterpolator(keyframes: star.points.keyframes))
25
25
  keypathProperties = [
26
- "Position" : position,
26
+ PropertyName.position.rawValue : position,
27
27
  "Outer Radius" : outerRadius,
28
28
  "Outer Roundedness" : outerRoundedness,
29
- "Rotation" : rotation,
29
+ PropertyName.rotation.rawValue : rotation,
30
30
  "Points" : points,
31
31
  ]
32
32
  properties = Array(keypathProperties.values)
@@ -22,7 +22,7 @@ final class RectNodeProperties: NodePropertyMap, KeypathSearchable {
22
22
  cornerRadius = NodeProperty(provider: KeyframeInterpolator(keyframes: rectangle.cornerRadius.keyframes))
23
23
 
24
24
  keypathProperties = [
25
- "Position" : position,
25
+ PropertyName.position.rawValue : position,
26
26
  "Size" : size,
27
27
  "Roundness" : cornerRadius,
28
28
  ]
@@ -33,12 +33,12 @@ final class StarNodeProperties: NodePropertyMap, KeypathSearchable {
33
33
  rotation = NodeProperty(provider: KeyframeInterpolator(keyframes: star.rotation.keyframes))
34
34
  points = NodeProperty(provider: KeyframeInterpolator(keyframes: star.points.keyframes))
35
35
  keypathProperties = [
36
- "Position" : position,
36
+ PropertyName.position.rawValue : position,
37
37
  "Outer Radius" : outerRadius,
38
38
  "Outer Roundedness" : outerRoundedness,
39
39
  "Inner Radius" : innerRadius,
40
40
  "Inner Roundedness" : innerRoundedness,
41
- "Rotation" : rotation,
41
+ PropertyName.rotation.rawValue : rotation,
42
42
  "Points" : points,
43
43
  ]
44
44
  properties = Array(keypathProperties.values)
@@ -40,13 +40,13 @@ final class GroupNodeProperties: NodePropertyMap, KeypathSearchable {
40
40
  }
41
41
  keypathProperties = [
42
42
  "Anchor Point" : anchor,
43
- "Position" : position,
44
- "Scale" : scale,
45
- "Rotation" : rotationZ,
43
+ PropertyName.position.rawValue : position,
44
+ PropertyName.scale.rawValue : scale,
45
+ PropertyName.rotation.rawValue : rotationZ,
46
46
  "Rotation X" : rotationX,
47
47
  "Rotation Y" : rotationY,
48
48
  "Rotation Z" : rotationZ,
49
- "Opacity" : opacity,
49
+ PropertyName.opacity.rawValue : opacity,
50
50
  "Skew" : skew,
51
51
  "Skew Axis" : skewAxis,
52
52
  ]
@@ -20,7 +20,7 @@ final class FillNodeProperties: NodePropertyMap, KeypathSearchable {
20
20
  opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: fill.opacity.keyframes))
21
21
  type = fill.fillRule
22
22
  keypathProperties = [
23
- "Opacity" : opacity,
23
+ PropertyName.opacity.rawValue : opacity,
24
24
  PropertyName.color.rawValue : color,
25
25
  ]
26
26
  properties = Array(keypathProperties.values)
@@ -24,7 +24,7 @@ final class GradientFillProperties: NodePropertyMap, KeypathSearchable {
24
24
  numberOfColors = gradientfill.numberOfColors
25
25
  fillRule = gradientfill.fillRule
26
26
  keypathProperties = [
27
- "Opacity" : opacity,
27
+ PropertyName.opacity.rawValue : opacity,
28
28
  "Start Point" : startPoint,
29
29
  "End Point" : endPoint,
30
30
  "Colors" : colors,
@@ -44,7 +44,7 @@ final class GradientStrokeProperties: NodePropertyMap, KeypathSearchable {
44
44
  dashPhase = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
45
45
  }
46
46
  keypathProperties = [
47
- "Opacity" : opacity,
47
+ PropertyName.opacity.rawValue : opacity,
48
48
  "Start Point" : startPoint,
49
49
  "End Point" : endPoint,
50
50
  "Colors" : colors,
@@ -36,7 +36,7 @@ final class StrokeNodeProperties: NodePropertyMap, KeypathSearchable {
36
36
  dashPhase = NodeProperty(provider: SingleValueProvider(LottieVector1D(0)))
37
37
  }
38
38
  keypathProperties = [
39
- "Opacity" : opacity,
39
+ PropertyName.opacity.rawValue : opacity,
40
40
  PropertyName.color.rawValue : color,
41
41
  "Stroke Width" : width,
42
42
  "Dashes" : dashPattern,
@@ -28,14 +28,14 @@ final class TextAnimatorNodeProperties: NodePropertyMap, KeypathSearchable {
28
28
 
29
29
  if let keyframeGroup = textAnimator.position {
30
30
  position = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
31
- properties["Position"] = position
31
+ properties[PropertyName.position.rawValue] = position
32
32
  } else {
33
33
  position = nil
34
34
  }
35
35
 
36
36
  if let keyframeGroup = textAnimator.scale {
37
37
  scale = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
38
- properties["Scale"] = scale
38
+ properties[PropertyName.scale.rawValue] = scale
39
39
  } else {
40
40
  scale = nil
41
41
  }
@@ -71,14 +71,14 @@ final class TextAnimatorNodeProperties: NodePropertyMap, KeypathSearchable {
71
71
  if let keyframeGroup = textAnimator.rotationZ {
72
72
  rotationZ = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
73
73
  properties["Rotation Z"] = rotationZ
74
- properties["Rotation"] = rotationZ
74
+ properties[PropertyName.rotation.rawValue] = rotationZ
75
75
  } else {
76
76
  rotationZ = nil
77
77
  }
78
78
 
79
79
  if let keyframeGroup = textAnimator.opacity {
80
80
  opacity = NodeProperty(provider: KeyframeInterpolator(keyframes: keyframeGroup.keyframes))
81
- properties["Opacity"] = opacity
81
+ properties[PropertyName.opacity.rawValue] = opacity
82
82
  } else {
83
83
  opacity = nil
84
84
  }
@@ -80,9 +80,10 @@ extension Data {
80
80
  /// - parameter dataString: The data string to parse.
81
81
  /// - parameter options: Options for the string parsing. Default value is `[]`.
82
82
  internal init?(dataString: String, options: DataURLReadOptions = []) {
83
+ let trimmedDataString = dataString.trimmingCharacters(in: .whitespacesAndNewlines)
83
84
  guard
84
85
  dataString.hasPrefix("data:"),
85
- let url = URL(string: dataString)
86
+ let url = URL(string: trimmedDataString)
86
87
  else {
87
88
  return nil
88
89
  }
@@ -90,10 +91,10 @@ extension Data {
90
91
  // with messages since url doesn't have a host. This only fixes flooding logs
91
92
  // when data inside Data URL is base64 encoded.
92
93
  if
93
- let base64Range = dataString.range(of: ";base64,"),
94
+ let base64Range = trimmedDataString.range(of: ";base64,"),
94
95
  !options.contains(DataURLReadOptions.legacy)
95
96
  {
96
- let encodedString = String(dataString[base64Range.upperBound...])
97
+ let encodedString = String(trimmedDataString[base64Range.upperBound...])
97
98
  self.init(base64Encoded: encodedString)
98
99
  } else {
99
100
  try? self.init(contentsOf: url)
@@ -23,9 +23,6 @@ struct DotLottieAnimation: Codable {
23
23
  /// mode - "bounce" | "normal"
24
24
  var mode: String? = "normal"
25
25
 
26
- /// URL to animation, to be set internally
27
- var animationUrl: URL?
28
-
29
26
  /// Loop mode for animation
30
27
  var loopMode: LottieLoopMode {
31
28
  mode == "bounce" ? .autoReverse : ((loop ?? false) ? .loop : .playOnce)
@@ -38,12 +35,9 @@ struct DotLottieAnimation: Codable {
38
35
 
39
36
  /// Loads `LottieAnimation` from `animationUrl`
40
37
  /// - Returns: Deserialized `LottieAnimation`. Optional.
41
- func animation() throws -> LottieAnimation {
42
- guard let animationUrl = animationUrl else {
43
- throw DotLottieError.animationNotAvailable
44
- }
38
+ func animation(url: URL) throws -> LottieAnimation {
39
+ let animationUrl = url.appendingPathComponent("\(id).json")
45
40
  let data = try Data(contentsOf: animationUrl)
46
41
  return try LottieAnimation.from(data: data)
47
42
  }
48
-
49
43
  }
@@ -10,21 +10,10 @@ import Foundation
10
10
  /// Manifest model for .lottie File
11
11
  struct DotLottieManifest: Codable {
12
12
 
13
- // MARK: Lifecycle
14
-
15
- init(animations: [DotLottieAnimation], version: String, author: String, generator: String) {
16
- self.animations = animations
17
- self.version = version
18
- self.author = author
19
- self.generator = generator
20
- }
21
-
22
- // MARK: Internal
23
-
24
13
  var animations: [DotLottieAnimation]
25
- var version: String
26
- var author: String
27
- var generator: String
14
+ var version: String?
15
+ var author: String?
16
+ var generator: String?
28
17
 
29
18
  /// Decodes data to Manifest model
30
19
  /// - Parameter data: Data to decode
@@ -15,7 +15,7 @@ struct DotLottieUtils {
15
15
 
16
16
  /// Temp folder to app directory
17
17
  static var tempDirectoryURL: URL {
18
- if #available(iOS 10.0, *) {
18
+ if #available(iOS 10.0, macOS 10.12, *) {
19
19
  return FileManager.default.temporaryDirectory
20
20
  }
21
21
  return URL(fileURLWithPath: NSTemporaryDirectory())
@@ -52,7 +52,17 @@ extension FileManager {
52
52
  // MARK: - DotLottieError
53
53
 
54
54
  public enum DotLottieError: Error {
55
+ /// URL response has no data.
56
+ case noDataLoaded
57
+ /// Asset with this name was not found in the provided bundle.
58
+ case assetNotFound(name: String, bundle: Bundle?)
59
+ /// Animation loading from asset is not supported on macOS 10.10.
60
+ case loadingFromAssetNotSupported
61
+
62
+ @available(*, deprecated, message: "Unused")
55
63
  case invalidFileFormat
64
+ @available(*, deprecated, message: "Unused")
56
65
  case invalidData
66
+ @available(*, deprecated, message: "Unused")
57
67
  case animationNotAvailable
58
68
  }
@@ -0,0 +1,147 @@
1
+ //
2
+ // Archive+BackingConfiguration.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 Archive {
14
+
15
+ struct BackingConfiguration {
16
+ let file: FILEPointer
17
+ let endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord
18
+ let zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory?
19
+
20
+ #if swift(>=5.0)
21
+ let memoryFile: MemoryFile?
22
+
23
+ init(
24
+ file: FILEPointer,
25
+ endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord,
26
+ zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory? = nil,
27
+ memoryFile: MemoryFile? = nil)
28
+ {
29
+ self.file = file
30
+ self.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
31
+ self.zip64EndOfCentralDirectory = zip64EndOfCentralDirectory
32
+ self.memoryFile = memoryFile
33
+ }
34
+ #else
35
+
36
+ init(
37
+ file: FILEPointer,
38
+ endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord,
39
+ zip64EndOfCentralDirectory: ZIP64EndOfCentralDirectory?)
40
+ {
41
+ self.file = file
42
+ self.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
43
+ self.zip64EndOfCentralDirectory = zip64EndOfCentralDirectory
44
+ }
45
+ #endif
46
+ }
47
+
48
+ static func makeBackingConfiguration(for url: URL, mode: AccessMode)
49
+ -> BackingConfiguration?
50
+ {
51
+ let fileManager = FileManager()
52
+ switch mode {
53
+ case .read:
54
+ let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
55
+ guard
56
+ let archiveFile = fopen(fileSystemRepresentation, "rb"),
57
+ let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else
58
+ {
59
+ return nil
60
+ }
61
+ return BackingConfiguration(
62
+ file: archiveFile,
63
+ endOfCentralDirectoryRecord: eocdRecord,
64
+ zip64EndOfCentralDirectory: zip64EOCD)
65
+ case .create:
66
+ let endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord(
67
+ numberOfDisk: 0,
68
+ numberOfDiskStart: 0,
69
+ totalNumberOfEntriesOnDisk: 0,
70
+ totalNumberOfEntriesInCentralDirectory: 0,
71
+ sizeOfCentralDirectory: 0,
72
+ offsetToStartOfCentralDirectory: 0,
73
+ zipFileCommentLength: 0,
74
+ zipFileCommentData: Data())
75
+ do {
76
+ try endOfCentralDirectoryRecord.data.write(to: url, options: .withoutOverwriting)
77
+ } catch { return nil }
78
+ fallthrough
79
+ case .update:
80
+ let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
81
+ guard
82
+ let archiveFile = fopen(fileSystemRepresentation, "rb+"),
83
+ let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else
84
+ {
85
+ return nil
86
+ }
87
+ fseeko(archiveFile, 0, SEEK_SET)
88
+ return BackingConfiguration(
89
+ file: archiveFile,
90
+ endOfCentralDirectoryRecord: eocdRecord,
91
+ zip64EndOfCentralDirectory: zip64EOCD)
92
+ }
93
+ }
94
+
95
+ #if swift(>=5.0)
96
+ static func makeBackingConfiguration(for data: Data, mode: AccessMode)
97
+ -> BackingConfiguration?
98
+ {
99
+ let posixMode: String
100
+ switch mode {
101
+ case .read: posixMode = "rb"
102
+ case .create: posixMode = "wb+"
103
+ case .update: posixMode = "rb+"
104
+ }
105
+ let memoryFile = MemoryFile(data: data)
106
+ guard let archiveFile = memoryFile.open(mode: posixMode) else { return nil }
107
+
108
+ switch mode {
109
+ case .read:
110
+ guard let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else {
111
+ return nil
112
+ }
113
+
114
+ return BackingConfiguration(
115
+ file: archiveFile,
116
+ endOfCentralDirectoryRecord: eocdRecord,
117
+ zip64EndOfCentralDirectory: zip64EOCD,
118
+ memoryFile: memoryFile)
119
+ case .create:
120
+ let endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord(
121
+ numberOfDisk: 0,
122
+ numberOfDiskStart: 0,
123
+ totalNumberOfEntriesOnDisk: 0,
124
+ totalNumberOfEntriesInCentralDirectory: 0,
125
+ sizeOfCentralDirectory: 0,
126
+ offsetToStartOfCentralDirectory: 0,
127
+ zipFileCommentLength: 0,
128
+ zipFileCommentData: Data())
129
+ _ = endOfCentralDirectoryRecord.data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
130
+ fwrite(buffer.baseAddress, buffer.count, 1, archiveFile) // Errors handled during read
131
+ }
132
+ fallthrough
133
+ case .update:
134
+ guard let (eocdRecord, zip64EOCD) = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else {
135
+ return nil
136
+ }
137
+
138
+ fseeko(archiveFile, 0, SEEK_SET)
139
+ return BackingConfiguration(
140
+ file: archiveFile,
141
+ endOfCentralDirectoryRecord: eocdRecord,
142
+ zip64EndOfCentralDirectory: zip64EOCD,
143
+ memoryFile: memoryFile)
144
+ }
145
+ }
146
+ #endif
147
+ }