CloverBootloader/CloverApp/Clover/Plist Editor/PE_Utils.swift

163 lines
5.5 KiB
Swift

/*
* vector sigma (https://github.com/vectorsigma72)
* Copyright 2020 vector sigma All Rights Reserved.
*
* The source code contained or described herein and all documents related
* to the source code ("Material") are owned by vector sigma.
* Title to the Material remains with vector sigma or its suppliers and licensors.
* The Material is proprietary of vector sigma and is protected by worldwide copyright.
* No part of the Material may be used, copied, reproduced, modified, published,
* uploaded, posted, transmitted, distributed, or disclosed in any way without
* vector sigma's prior express written permission.
*
* No license under any patent, copyright, trade secret or other intellectual
* property right is granted to or conferred upon you by disclosure or delivery
* of the Materials, either expressly, by implication, inducement, estoppel or
* otherwise. Any license under such intellectual property rights must be
* express and approved by vector sigma in writing.
*
* Unless otherwise agreed by vector sigma in writing, you may not remove or alter
* this notice or any other notice embedded in Materials by vector sigma in any way.
*
* The license is granted for the CloverBootloader project (i.e. https://github.com/CloverHackyColor/CloverBootloader)
* and all the users as long as the Material is used only within the
* source code and for the exclusive use of CloverBootloader, which must
* be free from any type of payment or commercial service for the license to be valid.
*/
import Foundation
/**
Assign a unique name for newNode if parent already contains it.
- Parameter parent: the parent node in which newNode will be inserted.
- Parameter newNode: the new node for which it's key must be unique.
- Discussion: Call this method before insert new nodes in the parent node.
*/
func gDeduplicateKeyInParent(parent: PENode, newNode: PENode) {
/* making an array of existing keys */
var actualKeys = [String]()
for item in parent.mutableChildren {
actualKeys.append(((item as! PENode).tagdata?.key)!)
}
/* new way */
let newKey : String = newNode.tagdata!.key
newNode.tagdata!.key = gProposedNewItem(with: newKey, in: actualKeys)
}
/**
Propose a new key name for a node Dictionary's keys.
- Parameter key: the actual key of the node or the desired one.
- Parameter array: an array of String containing all the keys for the target node's childrens.
- Returns: a `String` with a unique name for the given array. Will return the same string if the given array doesn't contains it.
- Discussion: A dictioanry cannot have duplicate keys. This method ensure that a given key will be unique by adding a numeric suffix (key - n).
*/
func gProposedNewItem(with key: String, in array: [String]) -> String {
var i : Int = 0
var proposed : String = key
repeat {
if !array.contains(proposed) {
break
}
proposed = "\(key) - \(i)"
i+=1
} while true
return proposed
}
/**
A string representation for a given `PlistTag`.
- Parameter tag: a `PlistTag`.
- Returns: a `String` object.
- Discussion: the returned string can be localized which is the main purpose.
*/
func gPlistTagStr(tag: PlistTag) -> String {
switch tag {
case .Dictionary:
return "Dictionary"
case .Array:
return "Array"
case .String:
return "String"
case .Number:
return "Number"
case .Bool:
return "Bool"
case .Date:
return "Date"
case .Data:
return "Data"
}
}
/**
A `PlistTag` representation for a given `PlistTag`.
- Parameter str: a `String` which must be no other than `Dictionary`, `Array`, `String`, `Number`, `Bool`,
`Date` or `Data`.
- Returns: a `String` object.
- Discussion: A `fatalError` occours if the given str is not avalid `PlistTag`.
*/
func gPlistTag(from str: String) -> PlistTag {
switch str {
case "Dictionary":
return .Dictionary
case "Array":
return .Array
case "String":
return .String
case "Number":
return .Number
case "Bool":
return .Bool
case "Date":
return .Date
case "Data":
return .Data
default:
fatalError("plistTag(from str: String): unsupported str parameter \(str)")
}
}
/**
Loading a plist file.
- Parameter path: a `String` representing the path to a loadable plist file.
- Discussion: The insternal Plist Editor is used for loading plist files while in 10.9/10.10, in order, PlistEdit Pro or Xcode are used.
In 10.9/10.10 if mentioned programs aren't present the directory containing the desired file will be opened by the Finder.
*/
func loadPlist(at path: String) {
if #available(OSX 10.11, *) {
let dc = NSDocumentController.shared
dc.openDocument(withContentsOf: URL(fileURLWithPath: path), display: true) {
(document, documentWasAlreadyOpen, error) in
if error != nil {
print(error!.localizedDescription)
NSSound.beep()
} else {
if (document != nil) {
dc.addDocument(document!)
}
}
}
} else {
// check if a document is opened some where
if NSDocumentController.shared.documents.count == 0 {
NSApp.setActivationPolicy(.accessory)
}
// Use reccomended programs (hope) to avoid Text Edit
var success = NSWorkspace.shared.openFile(path, withApplication: "PlistEdit Pro")
if !success {
success = NSWorkspace.shared.openFile(path, withApplication: "Xcode")
}
/* will it be Text Edit???
if !success {
success = NSWorkspace.shared.openFile(path)
}*/
if !success { // open the directory path
success = NSWorkspace.shared.openFile(path.deletingLastPath)
}
}
}