├── .gitignore ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── SwiftUTI │ └── UTI.swift ├── SwiftUTI.podspec └── Tests └── SwiftUTITests └── UTITests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | # 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear on external disk 15 | .Spotlight-V100 16 | .Trashes 17 | 18 | # Directories potentially created on remote AFP share 19 | .AppleDB 20 | .AppleDesktop 21 | Network Trash Folder 22 | Temporary Items 23 | .apdisk 24 | 25 | # Xcode 26 | # 27 | build/ 28 | *.pbxuser 29 | !default.pbxuser 30 | *.mode1v3 31 | !default.mode1v3 32 | *.mode2v3 33 | !default.mode2v3 34 | *.perspectivev3 35 | !default.perspectivev3 36 | xcuserdata 37 | *.xccheckout 38 | *.moved-aside 39 | DerivedData 40 | *.hmap 41 | *.ipa 42 | *.xcuserstate 43 | 44 | # Swift Package Manager 45 | 46 | .swiftpm 47 | .build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "SwiftUTI", 7 | products: [ 8 | .library( 9 | name: "SwiftUTI", 10 | targets: ["SwiftUTI"] 11 | ) 12 | ], 13 | targets: [ 14 | // Our package contains two targets, one for our library 15 | // code, and one for our tests: 16 | .target(name: "SwiftUTI"), 17 | .testTarget( 18 | name: "SwiftUTITests", 19 | dependencies: ["SwiftUTI"] 20 | ) 21 | ] 22 | ) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftUTI 2 | 3 | A swift wrapper around Apples Universal Type Identifier functions. 4 | 5 | ## Usage 6 | 7 | A typical usage might be like that: 8 | 9 | ```Swift 10 | let fileURL = URL(fileURLWithPath: ...) 11 | let fileUTI = UTI(withExtension: fileURL.pathExtension) 12 | 13 | // Check if it is a specific UTI (UTIs are equatable): 14 | 15 | if fileUTI == UTI.pdf { 16 | 17 | // handle PDF document... 18 | } 19 | 20 | // Check if an UTI conforms to a UTI: 21 | 22 | if fileUTI.conforms(to: .image) { 23 | 24 | // Handle image file... 25 | } 26 | ``` 27 | 28 | ## Creating System and Custom UTIs 29 | 30 | All system defined `UTType`s are available as static variables. For example, to access the UTType for PDF documents, simply call `UTI.pdf`. 31 | 32 | To define your own UTI (perhaps for your custom document type), you should make an extension like this: 33 | 34 | ```Swift 35 | public extension UTI { 36 | 37 | static let myDocument = UTI(rawValue: "com.mycompany.mydocument") 38 | } 39 | ``` 40 | 41 | Your custom type is then accessible like this: `UTI.myDocument`. 42 | 43 | ## Working with Tags 44 | 45 | ##### Initializing from tags: 46 | 47 | Initializing an UTI from a file extension: 48 | 49 | ```Swift 50 | let fileURL = URL(fileURLWithPath: ...) 51 | let fileUTI = UTI(withExtension: fileURL.pathExtension) 52 | ``` 53 | 54 | Forcing conformance to another UTI: 55 | 56 | ```Swift 57 | let fileURL = URL(fileURLWithPath: ...) 58 | let fileUTI = UTI(withExtension: fileURL.pathExtension, conformingTo: UTI.package) 59 | ``` 60 | 61 | There are similar APIs to work with MIME types, pasteboard types, and OSTypes. 62 | 63 | ##### Accessing tags: 64 | 65 | You can easily access tags from any UTI instance. For example to get the MIME type of PDFs, simply call `UTI.pdf.mimeType`. 66 | 67 | -------------------------------------------------------------------------------- /Sources/SwiftUTI/UTI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTI.swift 3 | // fseventstool 4 | // 5 | // Created by Matthias Keiser on 09.01.17. 6 | // Copyright © 2017 Tristan Inc. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | #if os(iOS) || os(watchOS) 12 | import MobileCoreServices 13 | #elseif os(macOS) 14 | import CoreServices 15 | #endif 16 | 17 | /// Instances of the UTI class represent a specific Universal Type Identifier, e.g. kUTTypeMPEG4. 18 | 19 | public class UTI: RawRepresentable, Equatable { 20 | 21 | /** 22 | The TagClass enum represents the supported tag classes. 23 | 24 | - fileExtension: kUTTagClassFilenameExtension 25 | - mimeType: kUTTagClassMIMEType 26 | - pbType: kUTTagClassNSPboardType 27 | - osType: kUTTagClassOSType 28 | */ 29 | public enum TagClass: String { 30 | 31 | /// Equivalent to kUTTagClassFilenameExtension 32 | case fileExtension = "public.filename-extension" 33 | 34 | /// Equivalent to kUTTagClassMIMEType 35 | case mimeType = "public.mime-type" 36 | 37 | #if os (macOS) 38 | 39 | /// Equivalent to kUTTagClassNSPboardType 40 | case pbType = "com.apple.nspboard-type" 41 | 42 | /// Equivalent to kUTTagClassOSType 43 | case osType = "com.apple.ostype" 44 | #endif 45 | 46 | /// Convenience variable for internal use. 47 | 48 | fileprivate var rawCFValue: CFString { 49 | return self.rawValue as CFString 50 | } 51 | } 52 | 53 | public typealias RawValue = String 54 | public let rawValue: String 55 | 56 | 57 | /// Convenience variable for internal use. 58 | 59 | private var rawCFValue: CFString { 60 | 61 | return self.rawValue as CFString 62 | } 63 | 64 | // MARK: Initialization 65 | 66 | 67 | /** 68 | 69 | This is the designated initializer of the UTI class. 70 | 71 | - Parameters: 72 | - rawValue: A string that is a Universal Type Identifier, i.e. "com.foobar.baz" or a constant like kUTTypeMP3. 73 | - Returns: 74 | An UTI instance representing the specified rawValue. 75 | - Note: 76 | You should rarely use this method. The preferred way to initialize a known UTI is to use its static variable (i.e. UTI.pdf). You should make an extension to make your own types available as static variables. 77 | 78 | */ 79 | 80 | public required init(rawValue: UTI.RawValue) { 81 | 82 | self.rawValue = rawValue 83 | } 84 | 85 | /** 86 | 87 | Initialize an UTI with a tag of a specified class. 88 | 89 | - Parameters: 90 | - tagClass: The class of the tag. 91 | - value: The value of the tag. 92 | - conformingTo: If specified, the returned UTI must conform to this UTI. If nil is specified, this parameter is ignored. The default is nil. 93 | - Returns: 94 | An UTI instance representing the specified rawValue. If no known UTI with the specified tags is found, a dynamic UTI is created. 95 | - Note: 96 | You should rarely need this method. It's usually simpler to use one of the specialized initialzers like 97 | ```convenience init?(withExtension fileExtension: String, conformingTo conforming: UTI? = nil)``` 98 | */ 99 | 100 | public convenience init(withTagClass tagClass: TagClass, value: String, conformingTo conforming: UTI? = nil) { 101 | 102 | let unmanagedIdentifier = UTTypeCreatePreferredIdentifierForTag(tagClass.rawCFValue, value as CFString, conforming?.rawCFValue) 103 | 104 | // UTTypeCreatePreferredIdentifierForTag only returns nil if the tag class is unknwown, which can't happen to us since we use an 105 | // enum of known values. Hence we can force-cast the result. 106 | 107 | let identifier = (unmanagedIdentifier?.takeRetainedValue() as String?)! 108 | 109 | self.init(rawValue: identifier) 110 | } 111 | 112 | /** 113 | 114 | Initialize an UTI with a file extension. 115 | 116 | - Parameters: 117 | - withExtension: The file extension (e.g. "txt"). 118 | - conformingTo: If specified, the returned UTI must conform to this UTI. If nil is specified, this parameter is ignored. The default is nil. 119 | - Returns: 120 | An UTI corresponding to the specified values. 121 | **/ 122 | 123 | public convenience init(withExtension fileExtension: String, conformingTo conforming: UTI? = nil) { 124 | 125 | self.init(withTagClass:.fileExtension, value: fileExtension, conformingTo: conforming) 126 | } 127 | 128 | /** 129 | 130 | Initialize an UTI with a MIME type. 131 | 132 | - Parameters: 133 | - mimeType: The MIME type (e.g. "text/plain"). 134 | - conformingTo: If specified, the returned UTI must conform to this UTI. If nil is specified, this parameter is ignored. The default is nil. 135 | - Returns: 136 | An UTI corresponding to the specified values. 137 | */ 138 | 139 | public convenience init(withMimeType mimeType: String, conformingTo conforming: UTI? = nil) { 140 | 141 | self.init(withTagClass:.mimeType, value: mimeType, conformingTo: conforming) 142 | } 143 | 144 | #if os(macOS) 145 | 146 | /** 147 | 148 | Initialize an UTI with a pasteboard type. 149 | - Important: **This function is de-facto deprecated!** The old cocoa pasteboard types ( `NSStringPboardType`, `NSPDFPboardType`, etc) have been deprecated in favour of actual UTIs, and the constants are not available anymore in Swift. This function only works correctly with the values of these old constants, but _not_ with the replacement values (like `NSPasteboardTypeString` etc), since these already are UTIs. 150 | - Parameters: 151 | - pbType: The pasteboard type (e.g. NSPDFPboardType). 152 | - conformingTo: If specified, the returned UTI must conform to this UTI. If nil is specified, this parameter is ignored. The default is nil. 153 | - Returns: 154 | An UTI corresponding to the specified values. 155 | */ 156 | public convenience init(withPBType pbType: String, conformingTo conforming: UTI? = nil) { 157 | 158 | self.init(withTagClass:.pbType, value: pbType, conformingTo: conforming) 159 | } 160 | 161 | /** 162 | Initialize an UTI with a OSType. 163 | 164 | - Parameters: 165 | - osType: The OSType type as a string (e.g. "PDF "). 166 | - conformingTo: If specified, the returned UTI must conform to this UTI. If nil is specified, this parameter is ignored. The default is nil. 167 | - Returns: 168 | An UTI corresponding to the specified values. 169 | - Note: 170 | You can use the variable ```OSType.string``` to get a string from an actual OSType. 171 | */ 172 | 173 | public convenience init(withOSType osType: String, conformingTo conforming: UTI? = nil) { 174 | 175 | self.init(withTagClass:.osType, value: osType, conformingTo: conforming) 176 | } 177 | 178 | #endif 179 | 180 | // MARK: Accessing Tags 181 | 182 | /** 183 | 184 | Returns the tag with the specified class. 185 | 186 | - Parameters: 187 | - tagClass: The tag class to return. 188 | - Returns: 189 | The requested tag, or nil if there is no tag of the specified class. 190 | */ 191 | 192 | public func tag(with tagClass: TagClass) -> String? { 193 | 194 | let unmanagedTag = UTTypeCopyPreferredTagWithClass(self.rawCFValue, tagClass.rawCFValue) 195 | 196 | guard let tag = unmanagedTag?.takeRetainedValue() as String? else { 197 | return nil 198 | } 199 | 200 | return tag 201 | } 202 | 203 | /// Return the file extension that corresponds the the UTI. Returns nil if not available. 204 | 205 | public var fileExtension: String? { 206 | 207 | return self.tag(with: .fileExtension) 208 | } 209 | 210 | /// Return the MIME type that corresponds the the UTI. Returns nil if not available. 211 | 212 | public var mimeType: String? { 213 | 214 | return self.tag(with: .mimeType) 215 | } 216 | 217 | #if os(macOS) 218 | 219 | /// Return the pasteboard type that corresponds the the UTI. Returns nil if not available. 220 | 221 | public var pbType: String? { 222 | 223 | return self.tag(with: .pbType) 224 | } 225 | 226 | /// Return the OSType as a string that corresponds the the UTI. Returns nil if not available. 227 | /// - Note: you can use the ```init(with string: String)``` initializer to construct an actual OSType from the returnes string. 228 | 229 | public var osType: String? { 230 | 231 | return self.tag(with: .osType) 232 | } 233 | 234 | #endif 235 | 236 | /** 237 | 238 | Returns all tags of the specified tag class. 239 | 240 | - Parameters: 241 | - tagClass: The class of the requested tags. 242 | - Returns: 243 | An array of all tags of the receiver of the specified class. 244 | */ 245 | 246 | public func tags(with tagClass: TagClass) -> Array { 247 | 248 | let unmanagedTags = UTTypeCopyAllTagsWithClass(self.rawCFValue, tagClass.rawCFValue) 249 | 250 | guard let tags = unmanagedTags?.takeRetainedValue() as? Array else { 251 | return [] 252 | } 253 | 254 | return tags as Array 255 | } 256 | 257 | // MARK: List all UTIs associated with a tag 258 | 259 | 260 | /** 261 | Returns all UTIs that are associated with a specified tag. 262 | 263 | - Parameters: 264 | - tag: The class of the specified tag. 265 | - value: The value of the tag. 266 | - conforming: If specified, the returned UTIs must conform to this UTI. If nil is specified, this parameter is ignored. The default is nil. 267 | - Returns: 268 | An array of all UTIs that satisfy the specified parameters. 269 | */ 270 | 271 | public static func utis(for tag: TagClass, value: String, conformingTo conforming: UTI? = nil) -> Array { 272 | 273 | let unmanagedIdentifiers = UTTypeCreateAllIdentifiersForTag(tag.rawCFValue, value as CFString, conforming?.rawCFValue) 274 | 275 | 276 | guard let identifiers = unmanagedIdentifiers?.takeRetainedValue() as? Array else { 277 | return [] 278 | } 279 | 280 | return identifiers.compactMap { UTI(rawValue: $0 as String) } 281 | } 282 | 283 | // MARK: Equality and Conformance to other UTIs 284 | 285 | /** 286 | 287 | Checks if the receiver conforms to a specified UTI. 288 | 289 | - Parameters: 290 | - otherUTI: The UTI to which the receiver is compared. 291 | - Returns: 292 | ```true``` if the receiver conforms to the specified UTI, ```false```otherwise. 293 | */ 294 | 295 | public func conforms(to otherUTI: UTI) -> Bool { 296 | 297 | return UTTypeConformsTo(self.rawCFValue, otherUTI.rawCFValue) as Bool 298 | } 299 | 300 | public static func ==(lhs: UTI, rhs: UTI) -> Bool { 301 | 302 | return UTTypeEqual(lhs.rawCFValue, rhs.rawCFValue) as Bool 303 | } 304 | 305 | // MARK: Accessing Information about an UTI 306 | 307 | /// Returns the localized, user-readable type description string associated with a uniform type identifier. 308 | 309 | public var description: String? { 310 | 311 | let unmanagedDescription = UTTypeCopyDescription(self.rawCFValue) 312 | 313 | guard let description = unmanagedDescription?.takeRetainedValue() as String? else { 314 | return nil 315 | } 316 | 317 | return description 318 | } 319 | 320 | /// Returns a uniform type’s declaration as a Dictionary, or nil if if no declaration for that type can be found. 321 | 322 | public var declaration: [AnyHashable:Any]? { 323 | 324 | let unmanagedDeclaration = UTTypeCopyDeclaration(self.rawCFValue) 325 | 326 | guard let declaration = unmanagedDeclaration?.takeRetainedValue() as? [AnyHashable:Any] else { 327 | return nil 328 | } 329 | 330 | return declaration 331 | } 332 | 333 | /// Returns the location of a bundle containing the declaration for a type, or nil if the bundle could not be located. 334 | 335 | public var declaringBundleURL: URL? { 336 | 337 | let unmanagedURL = UTTypeCopyDeclaringBundleURL(self.rawCFValue) 338 | 339 | guard let url = unmanagedURL?.takeRetainedValue() as URL? else { 340 | return nil 341 | } 342 | 343 | return url 344 | } 345 | 346 | /// Returns ```true``` if the receiver is a dynamic UTI. 347 | 348 | public var isDynamic: Bool { 349 | 350 | return UTTypeIsDynamic(self.rawCFValue) 351 | } 352 | } 353 | 354 | 355 | // MARK: System defined UTIs 356 | 357 | public extension UTI { 358 | 359 | static let item = UTI(rawValue: kUTTypeItem as String) 360 | static let content = UTI(rawValue: kUTTypeContent as String) 361 | static let compositeContent = UTI(rawValue: kUTTypeCompositeContent as String) 362 | static let message = UTI(rawValue: kUTTypeMessage as String) 363 | static let contact = UTI(rawValue: kUTTypeContact as String) 364 | static let archive = UTI(rawValue: kUTTypeArchive as String) 365 | static let diskImage = UTI(rawValue: kUTTypeDiskImage as String) 366 | static let data = UTI(rawValue: kUTTypeData as String) 367 | static let directory = UTI(rawValue: kUTTypeDirectory as String) 368 | static let resolvable = UTI(rawValue: kUTTypeResolvable as String) 369 | static let symLink = UTI(rawValue: kUTTypeSymLink as String) 370 | static let executable = UTI(rawValue: kUTTypeExecutable as String) 371 | static let mountPoint = UTI(rawValue: kUTTypeMountPoint as String) 372 | static let aliasFile = UTI(rawValue: kUTTypeAliasFile as String) 373 | static let aliasRecord = UTI(rawValue: kUTTypeAliasRecord as String) 374 | static let urlBookmarkData = UTI(rawValue: kUTTypeURLBookmarkData as String) 375 | static let url = UTI(rawValue: kUTTypeURL as String) 376 | static let fileURL = UTI(rawValue: kUTTypeFileURL as String) 377 | static let text = UTI(rawValue: kUTTypeText as String) 378 | static let plainText = UTI(rawValue: kUTTypePlainText as String) 379 | static let utf8PlainText = UTI(rawValue: kUTTypeUTF8PlainText as String) 380 | static let utf16ExternalPlainText = UTI(rawValue: kUTTypeUTF16ExternalPlainText as String) 381 | static let utf16PlainText = UTI(rawValue: kUTTypeUTF16PlainText as String) 382 | static let delimitedText = UTI(rawValue: kUTTypeDelimitedText as String) 383 | static let commaSeparatedText = UTI(rawValue: kUTTypeCommaSeparatedText as String) 384 | static let tabSeparatedText = UTI(rawValue: kUTTypeTabSeparatedText as String) 385 | static let utf8TabSeparatedText = UTI(rawValue: kUTTypeUTF8TabSeparatedText as String) 386 | static let rtf = UTI(rawValue: kUTTypeRTF as String) 387 | static let html = UTI(rawValue: kUTTypeHTML as String) 388 | static let xml = UTI(rawValue: kUTTypeXML as String) 389 | static let sourceCode = UTI(rawValue: kUTTypeSourceCode as String) 390 | static let assemblyLanguageSource = UTI(rawValue: kUTTypeAssemblyLanguageSource as String) 391 | static let cSource = UTI(rawValue: kUTTypeCSource as String) 392 | static let objectiveCSource = UTI(rawValue: kUTTypeObjectiveCSource as String) 393 | @available( OSX 10.11, iOS 9.0, * ) 394 | static let swiftSource = UTI(rawValue: kUTTypeSwiftSource as String) 395 | static let cPlusPlusSource = UTI(rawValue: kUTTypeCPlusPlusSource as String) 396 | static let objectiveCPlusPlusSource = UTI(rawValue: kUTTypeObjectiveCPlusPlusSource as String) 397 | static let cHeader = UTI(rawValue: kUTTypeCHeader as String) 398 | static let cPlusPlusHeader = UTI(rawValue: kUTTypeCPlusPlusHeader as String) 399 | static let javaSource = UTI(rawValue: kUTTypeJavaSource as String) 400 | static let script = UTI(rawValue: kUTTypeScript as String) 401 | static let appleScript = UTI(rawValue: kUTTypeAppleScript as String) 402 | static let osaScript = UTI(rawValue: kUTTypeOSAScript as String) 403 | static let osaScriptBundle = UTI(rawValue: kUTTypeOSAScriptBundle as String) 404 | static let javaScript = UTI(rawValue: kUTTypeJavaScript as String) 405 | static let shellScript = UTI(rawValue: kUTTypeShellScript as String) 406 | static let perlScript = UTI(rawValue: kUTTypePerlScript as String) 407 | static let pythonScript = UTI(rawValue: kUTTypePythonScript as String) 408 | static let rubyScript = UTI(rawValue: kUTTypeRubyScript as String) 409 | static let phpScript = UTI(rawValue: kUTTypePHPScript as String) 410 | static let json = UTI(rawValue: kUTTypeJSON as String) 411 | static let propertyList = UTI(rawValue: kUTTypePropertyList as String) 412 | static let xmlPropertyList = UTI(rawValue: kUTTypeXMLPropertyList as String) 413 | static let binaryPropertyList = UTI(rawValue: kUTTypeBinaryPropertyList as String) 414 | static let pdf = UTI(rawValue: kUTTypePDF as String) 415 | static let rtfd = UTI(rawValue: kUTTypeRTFD as String) 416 | static let flatRTFD = UTI(rawValue: kUTTypeFlatRTFD as String) 417 | static let txnTextAndMultimediaData = UTI(rawValue: kUTTypeTXNTextAndMultimediaData as String) 418 | static let webArchive = UTI(rawValue: kUTTypeWebArchive as String) 419 | static let image = UTI(rawValue: kUTTypeImage as String) 420 | static let jpeg = UTI(rawValue: kUTTypeJPEG as String) 421 | static let jpeg2000 = UTI(rawValue: kUTTypeJPEG2000 as String) 422 | static let tiff = UTI(rawValue: kUTTypeTIFF as String) 423 | static let pict = UTI(rawValue: kUTTypePICT as String) 424 | static let gif = UTI(rawValue: kUTTypeGIF as String) 425 | static let png = UTI(rawValue: kUTTypePNG as String) 426 | static let quickTimeImage = UTI(rawValue: kUTTypeQuickTimeImage as String) 427 | static let appleICNS = UTI(rawValue: kUTTypeAppleICNS as String) 428 | static let bmp = UTI(rawValue: kUTTypeBMP as String) 429 | static let ico = UTI(rawValue: kUTTypeICO as String) 430 | static let rawImage = UTI(rawValue: kUTTypeRawImage as String) 431 | static let scalableVectorGraphics = UTI(rawValue: kUTTypeScalableVectorGraphics as String) 432 | @available(OSX 10.12, iOS 9.1, watchOS 2.1, *) 433 | static let livePhoto = UTI(rawValue: kUTTypeLivePhoto as String) 434 | @available(OSX 10.12, iOS 9.1, *) 435 | static let audiovisualContent = UTI(rawValue: kUTTypeAudiovisualContent as String) 436 | static let movie = UTI(rawValue: kUTTypeMovie as String) 437 | static let video = UTI(rawValue: kUTTypeVideo as String) 438 | static let audio = UTI(rawValue: kUTTypeAudio as String) 439 | static let quickTimeMovie = UTI(rawValue: kUTTypeQuickTimeMovie as String) 440 | static let mpeg = UTI(rawValue: kUTTypeMPEG as String) 441 | static let mpeg2Video = UTI(rawValue: kUTTypeMPEG2Video as String) 442 | static let mpeg2TransportStream = UTI(rawValue: kUTTypeMPEG2TransportStream as String) 443 | static let mp3 = UTI(rawValue: kUTTypeMP3 as String) 444 | static let mpeg4 = UTI(rawValue: kUTTypeMPEG4 as String) 445 | static let mpeg4Audio = UTI(rawValue: kUTTypeMPEG4Audio as String) 446 | static let appleProtectedMPEG4Audio = UTI(rawValue: kUTTypeAppleProtectedMPEG4Audio as String) 447 | static let appleProtectedMPEG4Video = UTI(rawValue: kUTTypeAppleProtectedMPEG4Video as String) 448 | static let aviMovie = UTI(rawValue: kUTTypeAVIMovie as String) 449 | static let audioInterchangeFileFormat = UTI(rawValue: kUTTypeAudioInterchangeFileFormat as String) 450 | static let waveformAudio = UTI(rawValue: kUTTypeWaveformAudio as String) 451 | static let midiAudio = UTI(rawValue: kUTTypeMIDIAudio as String) 452 | static let playlist = UTI(rawValue: kUTTypePlaylist as String) 453 | static let m3UPlaylist = UTI(rawValue: kUTTypeM3UPlaylist as String) 454 | static let folder = UTI(rawValue: kUTTypeFolder as String) 455 | static let volume = UTI(rawValue: kUTTypeVolume as String) 456 | static let package = UTI(rawValue: kUTTypePackage as String) 457 | static let bundle = UTI(rawValue: kUTTypeBundle as String) 458 | static let pluginBundle = UTI(rawValue: kUTTypePluginBundle as String) 459 | static let spotlightImporter = UTI(rawValue: kUTTypeSpotlightImporter as String) 460 | static let quickLookGenerator = UTI(rawValue: kUTTypeQuickLookGenerator as String) 461 | static let xpcService = UTI(rawValue: kUTTypeXPCService as String) 462 | static let framework = UTI(rawValue: kUTTypeFramework as String) 463 | static let application = UTI(rawValue: kUTTypeApplication as String) 464 | static let applicationBundle = UTI(rawValue: kUTTypeApplicationBundle as String) 465 | static let applicationFile = UTI(rawValue: kUTTypeApplicationFile as String) 466 | static let unixExecutable = UTI(rawValue: kUTTypeUnixExecutable as String) 467 | static let windowsExecutable = UTI(rawValue: kUTTypeWindowsExecutable as String) 468 | static let javaClass = UTI(rawValue: kUTTypeJavaClass as String) 469 | static let javaArchive = UTI(rawValue: kUTTypeJavaArchive as String) 470 | static let systemPreferencesPane = UTI(rawValue: kUTTypeSystemPreferencesPane as String) 471 | static let gnuZipArchive = UTI(rawValue: kUTTypeGNUZipArchive as String) 472 | static let bzip2Archive = UTI(rawValue: kUTTypeBzip2Archive as String) 473 | static let zipArchive = UTI(rawValue: kUTTypeZipArchive as String) 474 | static let spreadsheet = UTI(rawValue: kUTTypeSpreadsheet as String) 475 | static let presentation = UTI(rawValue: kUTTypePresentation as String) 476 | static let database = UTI(rawValue: kUTTypeDatabase as String) 477 | static let vCard = UTI(rawValue: kUTTypeVCard as String) 478 | static let toDoItem = UTI(rawValue: kUTTypeToDoItem as String) 479 | static let calendarEvent = UTI(rawValue: kUTTypeCalendarEvent as String) 480 | static let emailMessage = UTI(rawValue: kUTTypeEmailMessage as String) 481 | static let internetLocation = UTI(rawValue: kUTTypeInternetLocation as String) 482 | static let inkText = UTI(rawValue: kUTTypeInkText as String) 483 | static let font = UTI(rawValue: kUTTypeFont as String) 484 | static let bookmark = UTI(rawValue: kUTTypeBookmark as String) 485 | static let _3DContent = UTI(rawValue: kUTType3DContent as String) 486 | static let pkcs12 = UTI(rawValue: kUTTypePKCS12 as String) 487 | static let x509Certificate = UTI(rawValue: kUTTypeX509Certificate as String) 488 | static let electronicPublication = UTI(rawValue: kUTTypeElectronicPublication as String) 489 | static let log = UTI(rawValue: kUTTypeLog as String) 490 | } 491 | 492 | #if os(OSX) 493 | 494 | extension OSType { 495 | 496 | 497 | /// Returns the OSType encoded as a String. 498 | 499 | var string: String { 500 | 501 | let unmanagedString = UTCreateStringForOSType(self) 502 | 503 | return unmanagedString.takeRetainedValue() as String 504 | } 505 | 506 | 507 | /// Initializes a OSType from a String. 508 | /// 509 | /// - Parameter string: A String representing an OSType. 510 | 511 | init(with string: String) { 512 | 513 | self = UTGetOSTypeFromString(string as CFString) 514 | } 515 | } 516 | 517 | #endif 518 | -------------------------------------------------------------------------------- /SwiftUTI.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint SwiftUTI.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'SwiftUTI' 11 | s.version = '2.0.2' 12 | s.swift_version = '5.0' 13 | s.summary = 'A swift wrapper around Apples Universal Type Identifier functions.' 14 | 15 | # This description is used to generate tags and improve search results. 16 | # * Think: What does it do? Why did you write it? What is the focus? 17 | # * Try to keep it short, snappy and to the point. 18 | # * Write the description between the DESC delimiters below. 19 | # * Finally, don't worry about the indent, CocoaPods strips it! 20 | 21 | s.description = <<-DESC 22 | 23 | This module makes it very simple to work with Apples Universal Type Identifiers. 24 | 25 | DESC 26 | 27 | s.homepage = 'https://github.com/mkeiser/SwiftUTI' 28 | s.license = { :type => 'MIT', :file => 'LICENSE' } 29 | s.author = { 'mkeiser' => 'matthias@tristan-inc.com' } 30 | s.source = { :git => 'https://github.com/mkeiser/SwiftUTI.git', :tag => s.version.to_s } 31 | 32 | s.watchos.deployment_target = '2.0' 33 | s.ios.deployment_target = '8.0' 34 | s.osx.deployment_target = '10.10' 35 | 36 | s.source_files = 'Sources/SwiftUTI/*' 37 | 38 | s.osx.framework = 'CoreServices' 39 | s.ios.framework = 'MobileCoreServices' 40 | end 41 | -------------------------------------------------------------------------------- /Tests/SwiftUTITests/UTITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UTI_Tests.swift 3 | // fseventstool 4 | // 5 | // Created by Matthias Keiser on 10.01.17. 6 | // Copyright © 2017 Tristan Inc. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import SwiftUTI 11 | 12 | #if os(iOS) 13 | import MobileCoreServices 14 | #elseif os(macOS) 15 | import CoreServices 16 | import AppKit 17 | #endif 18 | 19 | class UTI_Tests: XCTestCase { 20 | 21 | override func setUp() { 22 | super.setUp() 23 | // Put setup code here. This method is called before the invocation of each test method in the class. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testEquality() { 32 | 33 | let uti1 = UTI(rawValue: kUTTypePDF as String) 34 | let uti2 = UTI.pdf 35 | let uti3 = UTI.rtf 36 | 37 | XCTAssertTrue(uti1 == uti2) 38 | XCTAssertTrue(uti2 == uti1) 39 | XCTAssertFalse(uti1 == uti3) 40 | XCTAssertFalse(uti2 == uti3) 41 | } 42 | 43 | func testConformance() { 44 | 45 | let uti1 = UTI.text 46 | let uti2 = UTI.rtf 47 | let uti3 = UTI.directory 48 | 49 | XCTAssertTrue( uti2.conforms(to: uti1) ) 50 | XCTAssertFalse( uti1.conforms(to: uti2) ) 51 | XCTAssertFalse( uti1.conforms(to: uti3) ) 52 | } 53 | 54 | // MARK: Tags 55 | 56 | func assertUTIIdentical(_ uti1: UTI, _ uti2: UTI) { 57 | 58 | XCTAssertTrue(uti1 == uti2) 59 | XCTAssertEqual(uti1.fileExtension, uti2.fileExtension) 60 | XCTAssertEqual(uti1.mimeType, uti2.mimeType) 61 | 62 | #if os(macOS) 63 | XCTAssertEqual(uti1.pbType, uti2.pbType) 64 | XCTAssertEqual(uti1.osType, uti2.osType) 65 | #endif 66 | } 67 | 68 | func testExtension() { 69 | 70 | let uti = UTI(withExtension: "pdf") 71 | assertUTIIdentical(uti, UTI.pdf) 72 | } 73 | 74 | func testMIMEType() { 75 | 76 | let uti = UTI(withMimeType: "application/pdf") 77 | assertUTIIdentical(uti, UTI.pdf) 78 | } 79 | 80 | #if os(macOS) 81 | 82 | func testPBType() { 83 | // The old Cocoa pasteboard types have been deprecated in favour of actual UTIs. We are using the content of 84 | // the old NSPDFPboardType to do this test. 85 | let uti = UTI(withPBType: "Apple PDF pasteboard type") 86 | assertUTIIdentical(uti, UTI.pdf) 87 | } 88 | 89 | func testOSType() { 90 | let uti = UTI(withOSType: "PDF ") 91 | assertUTIIdentical(uti, UTI.pdf) 92 | } 93 | 94 | #endif 95 | 96 | func testDynamic() { 97 | 98 | XCTAssertFalse(UTI.pdf.isDynamic) 99 | 100 | XCTAssertTrue(UTI(withExtension: "random_unknown_value_xxxxx").isDynamic) 101 | } 102 | 103 | } 104 | --------------------------------------------------------------------------------