Getting an Uniform Type Identifier for a given extension
Asked Answered
V

2

22

I'm trying to find some way in Cocoa to translate from file extensions to Uniform Type Identifiers. That is, I want to find some way of doing this:

".jpg" => "public.jpeg"
".html" => "public.html" 
".ttf"=> "public.truetype-font"

I've searched on the NSWorkspace docs but couldn't find anything. The closest I could get was:

- (NSImage *)iconForFileType:(NSString *)fileType

that returns the icon for a file extension, and

– (NSString *)preferredFilenameExtensionForType:(NSString *)typeName

that does exactly the opposite of what I'm trying to do. Do any of you know how to do this?

I really hope I don't have to check for a lot of extensions by hand.

Thanks in advance.

Vivid answered 1/10, 2009 at 20:25 Comment(0)
B
46

I needed this about a week ago:

NSString * UTI = (NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, 
                                                                   (CFStringRef)[myFilePath pathExtension], 
                                                                   NULL);

If I run this on the extensions @"php", @"jpg", @"html", and @"ttf", it prints:

public.php-script
public.jpeg
public.html
public.truetype-ttf-font

Update 11+ years later:

In Swift, there are two ways to do this, depending on your deployment target:

  1. If you want to run on macOS Catalina and earlier (before Big Sur) or iOS 13 and earlier:

    let fileExtension = "html"
    let unmanagedString = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension as CFString,
                                                                fileExtension as CFString, 
                                                                nil)
    
    let typeIdentifier = unmanagedString?.takeRetainedValue() as String?
    

    The UTTypeCreatePreferredIdentifierForTag() func (still part of the CoreServices module) returns an Unmanaged<CFString>?; this is a type that boxes a CFString and you need to indicate (via one of the .take... methods) what the memory management semantics should be.

    Since the function follows the Create Rule naming pattern, it's going to return a CFString to us that we need to take ownership of. Therefore we use .takeRetainedValue() to transfer the ownership of the CFString from the manual memory management world into the ARC world.

    Then there's a decent amount of bridging to go from String to CFString and vice versa.

  2. macOS Big Sur (and iOS 14) got a new UniformTypeIdentifiers module that makes this a whole lot simpler:

    let fileExtension = "html"
    let typeIdentifier = UTType(filenameExtension: fileExtension)
    
Beeck answered 1/10, 2009 at 20:42 Comment(5)
Just don't forget that because the function name has Create in it, you're responsible for releaseing the object.Kerrison
Thanks! It worked. I had some problems initially, but it was because I was not trimming whitespace and newline characters from the path strings. (I am reading them from a command line tool.)Habanera
I needed this just today. :-) It's even cleaner if you wrap it like so: NSString *uti = [NSMakeCollectable(UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)[myFilePath pathExtension], NULL)) autorelease];Crossquestion
You should know, that in order to get this code snippet to work on iOS, you must #import <MobileCoreServices/MobileCoreServices.h>Insistence
what is the Swift 5 equivalent for this?Ruelle
D
17

You can use the Terminal and invoke mdls which gives you all kinds of information on a certain file type including UTIs.

mdls /myPath/to/myFile.ext

mdls will then show you the associated UTIs in kMDItemContentTypeTree (it's also possible to call mdls from within your Cocoa App btw).

Dayle answered 1/1, 2012 at 15:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.