CloverBootloader/CloverApp/Clover/Plist Editor/PEFormatters.swift
vectorsigma72 c8969630f3 Plist Editor for Cover.app
Introduced a real Property List Editor.
Fixed Theme manager engine.
Other minor fixes
2020-04-07 13:48:12 +02:00

249 lines
7.3 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 Cocoa
//MARK: UTC Date formatters
func utcDateFormatter() -> DateFormatter {
let formatter = DateFormatter()
formatter.timeZone = TimeZone(abbreviation: "UTC")
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
return formatter
}
func utcStringToDate(_ str: String) -> Date {
return utcDateFormatter().date(from: str)!
}
func utcDateToString(_ str: Date) -> String {
return utcDateFormatter().string(from: str)
}
//MARK: localized Date formatters to return current timezone and custom date style
func localizedDateFormatter() -> DateFormatter {
let formatter = DateFormatter()
formatter.timeZone = TimeZone.current
formatter.locale = Locale.current
formatter.dateStyle = .medium
formatter.timeStyle = .medium
return formatter
}
func localizedStringToDate(_ str: String) -> Date {
return localizedDateFormatter().date(from: str)!
}
func localizedStringToDateS(_ str: String) -> Date? { /* safe version that can safely be nil */
return localizedDateFormatter().date(from: str)
}
func localizedDateToString(_ date: Date) -> String {
return localizedDateFormatter().string(from: date)
}
func funcyDateFromUser(_ str: String) -> Date? {
let detector = try? NSDataDetector(types: NSTextCheckingResult.CheckingType.date.rawValue)
let result: NSTextCheckingResult? = detector?.firstMatch(in: str, options: [], range: NSRange(location: 0, length: str.count))
if result?.resultType == .date {
let date: Date? = result?.date
if date != nil {
return date!
}
}
return nil
}
//MARK: Number formatters
func localizedNumberFormatter() -> NumberFormatter {
let formatter = NumberFormatter()
formatter.locale = Locale.current
formatter.numberStyle = .decimal
//formatter.groupingSeparator = formatter.locale.groupingSeparator
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 8
return formatter
}
func localizedStringFrom(number: NSNumber) -> String {
return localizedNumberFormatter().string(from: number)!
}
/*
what will goes in the Outlineview cell is a localized string that use custom decimal/thousand separator
*/
func numberFromLocalizedString(string: String) -> NSNumber {
// check if is an hex string
if string.hasPrefix("0x") || string.hasPrefix("0X") {
//get string after 0x
let comp = string.lowercased().components(separatedBy: "0x")
if comp.count == 2 && stringContainsOnlyHexChars(string: comp[1]) {
let scanner = Scanner(string: string)
var value: UInt64 = 0
if scanner.scanHexInt64(&value) {
return NSNumber(value: value)
}
}
}
let nf = localizedNumberFormatter()
let separator = nf.decimalSeparator
var isNegative : Bool = false
var str : String = string
if str.count == 0 {
return NSNumber(value: 0) // length is 0 .. number is 0
}
// check if is a negative number
if str.hasPrefix("-") {
isNegative = true
}
// if the first char is the decimal separator insert a 0 (e.g. ",2" to "0,2")
if str.hasPrefix(separator!) {
str = "0" + str
}
// clean the string from non numerical part (but keep the decimal separator)
let setToKeep = CharacterSet.init(charactersIn: "0123456789" + separator!).inverted
str = str.components(separatedBy: setToKeep).joined()
// check the lenght again..
if str.count == 0 {
return NSNumber(value: 0)
}
// remove the separator if is the last char
if str.hasSuffix(separator!) {
str = String(str.dropLast())
}
// check the lenght again..
if str.count == 0 {
return NSNumber(value: 0)
}
/*
check if we have 0 or at least one separator
(if more than one truncate before the second!)
*/
if (str.range(of: separator!) != nil) {
let arr = str.components(separatedBy: separator!)
if arr.count > 1 {
str = arr[0] + "." + arr[1]
}
}
// readd the subtraction operator if was there
if str != "0" && isNegative {
str = "-" + str
}
//determine if is integer or double
var num : NSNumber? = nil
if (str.range(of: ".") != nil) {
num = NSNumber(value: (str as NSString).doubleValue)
} else {
num = NSNumber(value: (str as NSString).integerValue)
}
if (num != nil) {
return num!
}
return NSNumber(value: 0)
}
//MARK: Data to string/string to Data
/*
We expect the data enclosed in "<>", must have valid hex characters,
must be multiple of 2
*/
func isHexStringValid(string: String) -> String {
var hex = string.lowercased()
if hex.count == 0 {
return DataEmptyString
}
let hexSet : CharacterSet = CharacterSet(charactersIn: "0123456789abcdef")
// remove blank spaces
hex = hex.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
hex = hex.replacingOccurrences(of: " ", with: "")
if hex.count == 0 {
return DataEmptyString
}
// first char must be '<'
if !hex.hasPrefix("<") {
return DataMissingOpenTag
}
// well, is still >=2? (like "<>")
if hex.count < 2 {
return DataMissingEndTag
}
// last char must be '>'
if !hex.hasSuffix(">") {
return DataMissingEndTag
}
// contains only valid hex characters? testw/o "<>"
var copy : String = String(hex.dropFirst(1))
copy = String(copy.dropLast(1))
if copy.trimmingCharacters(in: hexSet).count > 0 {
return DataIllegalHex
}
if copy.count % 2 != 0 { // ----> w/o considering "<>"
return DataOddBytes
}
return "HexSuccess"
}
func stringContainsOnlyHexChars(string: String) -> Bool {
var hex = string.lowercased()
if hex.count == 0 {
return false
}
let hexSet : CharacterSet = CharacterSet(charactersIn: "0123456789abcdef")
// remove blanck spaces
hex = hex.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
if hex.count == 0 {
return false
}
// contains only valid hex characters?
if (hex.rangeOfCharacter(from: hexSet) == nil) {
return false
}
return true
}