mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
153 lines
4.1 KiB
Swift
153 lines
4.1 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift open source project
|
|
//
|
|
// Copyright (c) 2014-2024 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import Foundation
|
|
|
|
/// A enum representing data types for legacy PropertyList type.
|
|
/// Note that the `identifier` enum is not strictly necessary,
|
|
/// but useful to semantically distinguish the strings that
|
|
/// represents object identifiers from those that are just data.
|
|
/// see: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/PropertyLists/OldStylePlists/OldStylePLists.html
|
|
public enum PropertyList {
|
|
case identifier(String)
|
|
case string(String)
|
|
case array([PropertyList])
|
|
case dictionary([String: PropertyList])
|
|
|
|
var string: String? {
|
|
if case .string(let string) = self {
|
|
return string
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var array: [PropertyList]? {
|
|
if case .array(let array) = self {
|
|
return array
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
extension PropertyList: CustomStringConvertible {
|
|
public var description: String {
|
|
String(decoding: serialize(), as: UTF8.self)
|
|
}
|
|
}
|
|
|
|
extension PropertyList {
|
|
/// Serializes the Plist enum.
|
|
public func serialize() -> Data {
|
|
var writer = UTF8Writer()
|
|
writePlistRepresentation(to: &writer)
|
|
return Data(writer.bytes)
|
|
}
|
|
}
|
|
|
|
fileprivate extension PropertyList {
|
|
struct UTF8Writer {
|
|
private(set) var level: Int = 0
|
|
private(set) var bytes: [UInt8] = []
|
|
init() {
|
|
self += "// !$*UTF8*$!\n"
|
|
}
|
|
|
|
mutating func withIndent(body: (inout Self) -> Void) {
|
|
level += 1
|
|
body(&self)
|
|
level -= 1
|
|
}
|
|
|
|
mutating func append(_ byte: UInt8) {
|
|
bytes.append(byte)
|
|
}
|
|
|
|
static func += (writer: inout UTF8Writer, str: StaticString) {
|
|
str.withUTF8Buffer { utf8 in
|
|
writer.bytes += utf8
|
|
}
|
|
}
|
|
|
|
@_disfavoredOverload
|
|
static func += (writer: inout UTF8Writer, str: String) {
|
|
writer.bytes += str.utf8
|
|
}
|
|
|
|
mutating func indent() {
|
|
for _ in 0 ..< level {
|
|
self += " "
|
|
}
|
|
}
|
|
|
|
/// Appends the given string, with instances of quote (") and backward slash
|
|
/// (\) characters escaped with a backslash.
|
|
mutating func appendEscaped(_ string: String) {
|
|
for char in string.utf8 {
|
|
if char == UInt8(ascii: "\\") || char == UInt8(ascii: "\"") {
|
|
append(UInt8(ascii: "\\"))
|
|
}
|
|
append(char)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Private function to generate OPENSTEP-style plist representation.
|
|
func writePlistRepresentation(to writer: inout UTF8Writer) {
|
|
// Do the appropriate thing for each type of plist node.
|
|
switch self {
|
|
case .identifier(let ident):
|
|
// FIXME: we should assert that the identifier doesn't need quoting
|
|
writer += ident
|
|
|
|
case .string(let string):
|
|
writer += "\""
|
|
writer.appendEscaped(string)
|
|
writer += "\""
|
|
|
|
case .array(let array):
|
|
writer += "(\n"
|
|
writer.withIndent { writer in
|
|
for (i, item) in array.enumerated() {
|
|
writer.indent()
|
|
item.writePlistRepresentation(to: &writer)
|
|
writer += (i != array.count - 1) ? ",\n" : "\n"
|
|
}
|
|
}
|
|
writer.indent()
|
|
writer += ")"
|
|
|
|
case .dictionary(let dict):
|
|
let dict = dict.sorted(by: {
|
|
// Make `isa` sort first (just for readability purposes).
|
|
switch ($0.key, $1.key) {
|
|
case ("isa", "isa"): return false
|
|
case ("isa", _): return true
|
|
case (_, "isa"): return false
|
|
default: return $0.key < $1.key
|
|
}
|
|
})
|
|
writer += "{\n"
|
|
writer.withIndent { writer in
|
|
for (key, value) in dict {
|
|
writer.indent()
|
|
writer += key
|
|
writer += " = "
|
|
value.writePlistRepresentation(to: &writer)
|
|
writer += ";\n"
|
|
}
|
|
}
|
|
writer.indent()
|
|
writer += "}"
|
|
}
|
|
}
|
|
}
|