// // Extensions.swift // Clover // // Created by vector sigma on 19/10/2019. // Copyright © 2019 CloverHackyColor. All rights reserved. // import Cocoa extension String { public func noSpaces() -> String { return self.trimmingCharacters(in: CharacterSet.whitespaces) } var lastPath: String { return (self as NSString).lastPathComponent } var fileExtension: String { return (self as NSString).pathExtension } var deletingLastPath: String { return (self as NSString).deletingLastPathComponent } var deletingFileExtension: String { return (self as NSString).deletingPathExtension } var componentsPath: [String] { return (self as NSString).pathComponents } func addPath(_ path: String) -> String { let nsSt = self as NSString return nsSt.appendingPathComponent(path) } func appendingFileExtension(ext: String) -> String? { let nsSt = self as NSString return nsSt.appendingPathExtension(ext) } // https://stackoverflow.com/questions/25554986/how-to-convert-string-to-unsafepointeruint8-and-length# func toPointer() -> UnsafePointer? { guard let data = self.data(using: String.Encoding.utf8) else { return nil } let buffer = UnsafeMutablePointer.allocate(capacity: data.count) let stream = OutputStream(toBuffer: buffer, capacity: data.count) stream.open() let value = data.withUnsafeBytes { $0.baseAddress?.assumingMemoryBound(to: UInt8.self) } guard let val = value else { return nil } stream.write(val, maxLength: data.count) stream.close() return UnsafePointer(buffer) } } extension NSNumber { var hexString: String { if (self.intValue > 0xFFFF) { return String(format: "0x%08llx", self.intValue) } else { return String(format: "0x%04llx", self.intValue) } } } extension Int { var data: Data { var num = self return Data(bytes: &num, count: MemoryLayout.size) } } extension UInt8 { var data: Data { var num = self return Data(bytes: &num, count: MemoryLayout.size) } } extension UInt16 { var data: Data { var num = self return Data(bytes: &num, count: MemoryLayout.size) } } extension UInt32 { var data: Data { var num = self return Data(bytes: &num, count: MemoryLayout.size) } } extension Data { func toPointer() -> UnsafePointer? { let buffer = UnsafeMutablePointer.allocate(capacity: self.count) let stream = OutputStream(toBuffer: buffer, capacity: self.count) stream.open() let value = self.withUnsafeBytes { $0.baseAddress?.assumingMemoryBound(to: UInt8.self) } guard let val = value else { return nil } stream.write(val, maxLength: self.count) stream.close() return UnsafePointer(buffer) } } extension URL { // https://stackoverflow.com/questions/38343186/write-extend-file-attributes-swift-example?answertab=active#tab-top /// Get extended attribute. func extendedAttribute(forName name: String) throws -> Data { let data = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> Data in // Determine attribute size: let length = getxattr(fileSystemPath, name, nil, 0, 0, 0) guard length >= 0 else { throw URL.posixError(errno) } // Create buffer with required size: var data = Data(count: length) // Retrieve attribute: let result = data.withUnsafeMutableBytes { [count = data.count] in getxattr(fileSystemPath, name, $0.baseAddress, count, 0, 0) } guard result >= 0 else { throw URL.posixError(errno) } return data } return data } /// Set extended attribute. func setExtendedAttribute(data: Data, forName name: String) throws { try self.withUnsafeFileSystemRepresentation { fileSystemPath in let result = data.withUnsafeBytes { setxattr(fileSystemPath, name, $0.baseAddress, data.count, 0, 0) } guard result >= 0 else { throw URL.posixError(errno) } } } /// Remove extended attribute. func removeExtendedAttribute(forName name: String) throws { try self.withUnsafeFileSystemRepresentation { fileSystemPath in let result = removexattr(fileSystemPath, name, 0) guard result >= 0 else { throw URL.posixError(errno) } } } /// Get list of all extended attributes. func listExtendedAttributes() throws -> [String] { let list = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> [String] in let length = listxattr(fileSystemPath, nil, 0, 0) guard length >= 0 else { throw URL.posixError(errno) } // Create buffer with required size: var namebuf = Array(repeating: 0, count: length) // Retrieve attribute list: let result = listxattr(fileSystemPath, &namebuf, namebuf.count, 0) guard result >= 0 else { throw URL.posixError(errno) } // Extract attribute names: let list = namebuf.split(separator: 0).compactMap { $0.withUnsafeBufferPointer { $0.withMemoryRebound(to: UInt8.self) { String(bytes: $0, encoding: .utf8) } } } return list } return list } /// Helper function to create an NSError from a Unix errno. private static func posixError(_ err: Int32) -> NSError { return NSError(domain: NSPOSIXErrorDomain, code: Int(err), userInfo: [NSLocalizedDescriptionKey: String(cString: strerror(err))]) } } extension io_object_t { /// - Returns: The device's name. func name() -> String? { let buf = UnsafeMutablePointer.allocate(capacity: 1) defer { buf.deallocate() } return buf.withMemoryRebound(to: CChar.self, capacity: MemoryLayout.size) { if IORegistryEntryGetName(self, $0) == KERN_SUCCESS { return String(cString: $0) } return nil } } func info() -> NSDictionary? { var serviceDictionary : Unmanaged? if IORegistryEntryCreateCFProperties(self, &serviceDictionary, kCFAllocatorDefault, 0) == KERN_SUCCESS { if let info : NSDictionary = serviceDictionary?.takeRetainedValue() { return info } } return nil } } extension NSBitmapImageRep { var png: Data? { representation(using: .png, properties: [:]) } }