Skip to content

Commit

Permalink
Add some serialisation functions to PropertyList too
Browse files Browse the repository at this point in the history
  • Loading branch information
phimage authored and e-marchand committed Oct 22, 2022
1 parent 8cec2af commit 00fe58d
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 96 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.build
.build
.swiftpm
6 changes: 3 additions & 3 deletions Sources/OpenStepSerializer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ class OpenStepSerializer {
let projectFile: XcodeProj
let lineEnding: String

init(projectName: String, lineEnding: String = "\r\n", projectFile: XcodeProj) {
init(projectName: String, lineEnding: String? = "\r\n", projectFile: XcodeProj) {
self.projectName = projectName
self.lineEnding = lineEnding
self.lineEnding = lineEnding ?? "\r\n"
self.projectFile = projectFile
}

Expand Down Expand Up @@ -67,7 +67,7 @@ class OpenStepSerializer {
}
#if os(Linux)
let row: String
if let dict = val as? [AnyHashable: Any], dict.isEmpty {
if let dict = val as? [AnyHashable: Any], dict.isEmpty {
row = "\(key) = {\n}\(comment);" // print on linux give [:] ...
} else {
row = "\(key) = \(val)\(comment);"
Expand Down
145 changes: 145 additions & 0 deletions Sources/PropertyList.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//
// PropertyList.swift
//
//
// Created by emarchand on 22/10/2022.
//

import Foundation

open class PropertyList {

public enum Format {
case binary
case xml
case json
case openStep

public func toPropertyListformat() -> PropertyListSerialization.PropertyListFormat? {
switch self {
case .binary:
return .binary
case .xml:
return .xml
case .openStep:
return .openStep
case .json:
return nil
}
}

public init(_ format: PropertyListSerialization.PropertyListFormat) {
switch format {
case .binary:
self = .binary
case .xml:
self = .xml
case .openStep:
self = .openStep
@unknown default:
fatalError("unknown format")
}
}

public init?(_ format: PropertyListSerialization.PropertyListFormat?) {
if let format = format {
self.init(format)
} else {
return nil
}
}

public init?(string: String) {
switch string.lowercased() {
case "openstep":
self = .openStep
case "xml", "xml1":
self = .xml
case "json":
self = .json
case "binary", "binary1":
self = .binary
default:
return nil
}
}

}

public let dict: PBXObject.Fields
public let format: Format

public init(dict: PBXObject.Fields, format: Format) throws {
self.dict = dict
self.format = format
}

public convenience init(propertyListData data: Data) throws {
let format: Format
let obj: Any
if data.first == 123 { // start with {
obj = try JSONSerialization.jsonObject(with: data)
format = .json
} else {
var propertyListFormat: PropertyListSerialization.PropertyListFormat = .binary
obj = try PropertyListSerialization.propertyList(from: data, options: [], format: &propertyListFormat)
format = .init(propertyListFormat)
}

guard let dict = obj as? PBXObject.Fields else {
throw XcodeProjError.invalidData(object: obj)
}

try self.init(dict: dict, format: format)
}

public convenience init(url: URL) throws {
assert(url.isFileURL)
do {
let data = try Data(contentsOf: url)
try self.init(propertyListData: data)
} catch let error as XcodeProjError {
throw error
} catch {
throw XcodeProjError.failedToReadFile(error: error)
}
}

// MARK: - Write
public func write(to url: URL,
format: Format,
atomic: Bool = true) throws {
if format == .openStep {
throw XcodeProjError.notSupported
} else if let propertyListformat = format.toPropertyListformat() {
let data = try PropertyListSerialization.data(
fromPropertyList: dict,
format: propertyListformat,
options: 0)
#if os(Linux)
try data.write(to: url, options: []) // error no attomic on linux
#else
try data.write(to: url, options: atomic ? [.atomicWrite] : [])
#endif
} else if format == .json {
let data = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
#if os(Linux)
try data.write(to: url, options: []) // error no attomic on linux
#else
try data.write(to: url, options: atomic ? [.atomicWrite] : [])
#endif
}
}

public func data() throws -> Data {
if format == .openStep {
throw XcodeProjError.notSupported
} else if let propertyListformat = format.toPropertyListformat() {
return try PropertyListSerialization.data(fromPropertyList: dict, format: propertyListformat, options: 0)
} else if format == .json {
return try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
}
return Data()
}

}
21 changes: 12 additions & 9 deletions Sources/XcodeProj+Serialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import Foundation

extension XcodeProj {

public func write(to url: URL, format: Format? = nil,
projectName: String? = nil, lineEnding: String? = nil, atomic: Bool = true) throws {
public func write(to url: URL,
format: Format? = nil,
projectName: String? = nil,
lineEnding: String? = nil,
atomic: Bool = true) throws {
let pbxprojURL: URL
let name: String
if url.isDirectoryURL {
Expand All @@ -36,16 +39,17 @@ extension XcodeProj {
if format == .openStep {
let serializer = OpenStepSerializer(projectName: name, lineEnding: lineEnding, projectFile: self)
try serializer.serialize().write(to: pbxprojURL, atomically: atomic, encoding: .utf8)
}
else if let propertyListformat = format.toPropertyListformat() {
let data = try PropertyListSerialization.data(fromPropertyList: dict, format: propertyListformat, options: 0)
} else if let propertyListformat = format.toPropertyListformat() {
let data = try PropertyListSerialization.data(
fromPropertyList: dict,
format: propertyListformat,
options: 0)
#if os(Linux)
try data.write(to: pbxprojURL, options: []) // error no attomic on linux
#else
try data.write(to: pbxprojURL, options: atomic ? [.atomicWrite] : [])
#endif
}
else if format == .json {
} else if format == .json {
let data = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
#if os(Linux)
try data.write(to: pbxprojURL, options: []) // error no attomic on linux
Expand All @@ -62,8 +66,7 @@ extension XcodeProj {
return try serializer.serialize().data(using: .utf8) ?? Data()
} else if let propertyListformat = format.toPropertyListformat() {
return try PropertyListSerialization.data(fromPropertyList: dict, format: propertyListformat, options: 0)
}
else if format == .json {
} else if format == .json {
return try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
}
return Data() // must not occurs
Expand Down
83 changes: 0 additions & 83 deletions Sources/XcodeProj.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,88 +8,6 @@

import Foundation

open class PropertyList {

public enum Format {
case binary
case xml
case json
case openStep

public func toPropertyListformat() -> PropertyListSerialization.PropertyListFormat? {
switch self {
case .binary:
return .binary
case .xml:
return .xml
case .openStep:
return .openStep
case .json:
return nil
}
}

public init(_ format: PropertyListSerialization.PropertyListFormat) {
switch format {
case .binary:
self = .binary
case .xml:
self = .xml
case .openStep:
self = .openStep
}
}

public init?(_ format: PropertyListSerialization.PropertyListFormat?) {
if let format = format {
self.init(format)
} else {
return nil
}
}
}

public let dict: PBXObject.Fields
public let format: Format

public init(dict: PBXObject.Fields, format: Format) throws {
self.dict = dict
self.format = format
}

public convenience init(propertyListData data: Data) throws {
let format: Format
let obj: Any
if data.first == 123 { // start with {
obj = try JSONSerialization.jsonObject(with: data)
format = .json
} else {
var propertyListFormat: PropertyListSerialization.PropertyListFormat = .binary
obj = try PropertyListSerialization.propertyList(from: data, options: [], format: &propertyListFormat)
format = .init(propertyListFormat)
}

guard let dict = obj as? PBXObject.Fields else {
throw XcodeProjError.invalidData(object: obj)
}

try self.init(dict: dict, format: format)
}

public convenience init(url: URL) throws {
assert(url.isFileURL)
do {
let data = try Data(contentsOf: url)
try self.init(propertyListData: data)
} catch let error as XcodeProjError {
throw error
} catch {
throw XcodeProjError.failedToReadFile(error: error)
}
}

}

public class XcodeProj: PropertyList {

public static let pbxprojFileExtension = "pbxproj"
Expand Down Expand Up @@ -150,7 +68,6 @@ public class XcodeProj: PropertyList {

}


// MARK: init
public convenience init(url: URL) throws {
assert(url.isFileURL)
Expand Down
3 changes: 3 additions & 0 deletions Sources/XcodeProjError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ public enum XcodeProjError: Error {
// object missing
case objectMissing(key: String, expectedType: Isa?)

// not supported
case notSupported

}

0 comments on commit 00fe58d

Please sign in to comment.