Entry tags:
[Code Friday] The Last Jackass Problem
Readers of this blog may recall a situation I refer to as the Next Jackass Problem. In brief: if you find yourself doing something particularly clever or esoteric in your code, you'd better be damn sure you document it thoroughly -- not only why you did it, but what you did and how, so that the next jackass who has to maintain your code can understand it, because 99% of the time, the next jackass is you, six months later.
I've run into an interesting (as in "may you live in ~ times") variant on this, which I call the Last Jackass Problem: when you're supporting a legacy library/OS/what-have-you, and there's a nice way to handle it with the current tools but no nice way to do so with the legacy ones.
In this case, I needed to programmatically tell iTunes to open a file. This is presumably pretty easy in Leopard, thanks to the magic of the Scripting Bridge. However, I'm also supporting Tiger, which does not have this magic. Happily, there's appscript, a nifty event bridge which encapsulates all the gory Apple Events foo that talking to scriptable apps requires. So presumably, if you have a file path, you can do the following:
ITApplication *iTunes = [[ITApplication alloc] initWithName:@"iTunes.app"];
[[iTunes play:filePath] send];
This programmatically constructs a reference to iTunes to which you can send commands, then constructs a command to play the file at filePath and dispatches it. Easy? Should be. Except for one thing: on OS X, there's more than one type of path: POSIX paths and HFS paths. POSIX paths are the ones anyone who's spent five minutes with UNIX should know: /path/to/file.ext. HFS paths are the old-school ones that you probably haven't seen unless you've been playing with Macs for a long time or actually use AppleScript: Macintosh HD:path:to:file.ext. And at least under Tiger, some scriptable apps expect HFS paths. (iTunes is one of them. I hear Finder is, too.)
Unfortunately, there does not seem to be any straightforward Cocoa way to convert POSIX paths to HFS paths. But you can tap into the guts of Core Foundation and do the following:
NSURL *ref = [NSURL URLWithString:filePath];
NSString *converted = (NSString*) CFURLCopyFileSystemPath((CFURLRef)ref, kCFURLHFSPathStyle);
That looks like a lot of typecasting, and frankly, for two lines of code, it is. Happily, though, it's safe: NSURL and CFURL are toll-free bridged for no-hassle conversion, as are NSString and CFString (what CFURLCopyFileSystemPath returns).
Nota bene: I have not actually tried the Scripting Bridge approach to this problem. I sincerely hope it silently converts POSIX paths to HFS paths where necessary, in order to prevent headaches of this sort. (
chanson, any remarks there?) But for those of you doing any kind of Cocoa-based application scripting without the help of the Scripting Bridge, at least now you know. (And do please document your code for the next jackass.)
I've run into an interesting (as in "may you live in ~ times") variant on this, which I call the Last Jackass Problem: when you're supporting a legacy library/OS/what-have-you, and there's a nice way to handle it with the current tools but no nice way to do so with the legacy ones.
In this case, I needed to programmatically tell iTunes to open a file. This is presumably pretty easy in Leopard, thanks to the magic of the Scripting Bridge. However, I'm also supporting Tiger, which does not have this magic. Happily, there's appscript, a nifty event bridge which encapsulates all the gory Apple Events foo that talking to scriptable apps requires. So presumably, if you have a file path, you can do the following:
ITApplication *iTunes = [[ITApplication alloc] initWithName:@"iTunes.app"];
[[iTunes play:filePath] send];
This programmatically constructs a reference to iTunes to which you can send commands, then constructs a command to play the file at filePath and dispatches it. Easy? Should be. Except for one thing: on OS X, there's more than one type of path: POSIX paths and HFS paths. POSIX paths are the ones anyone who's spent five minutes with UNIX should know: /path/to/file.ext. HFS paths are the old-school ones that you probably haven't seen unless you've been playing with Macs for a long time or actually use AppleScript: Macintosh HD:path:to:file.ext. And at least under Tiger, some scriptable apps expect HFS paths. (iTunes is one of them. I hear Finder is, too.)
Unfortunately, there does not seem to be any straightforward Cocoa way to convert POSIX paths to HFS paths. But you can tap into the guts of Core Foundation and do the following:
NSURL *ref = [NSURL URLWithString:filePath];
NSString *converted = (NSString*) CFURLCopyFileSystemPath((CFURLRef)ref, kCFURLHFSPathStyle);
That looks like a lot of typecasting, and frankly, for two lines of code, it is. Happily, though, it's safe: NSURL and CFURL are toll-free bridged for no-hassle conversion, as are NSString and CFString (what CFURLCopyFileSystemPath returns).
Nota bene: I have not actually tried the Scripting Bridge approach to this problem. I sincerely hope it silently converts POSIX paths to HFS paths where necessary, in order to prevent headaches of this sort. (
![[livejournal.com profile]](https://www.dreamwidth.org/img/external/lj-userinfo.gif)
HFS vs POSIX
(Anonymous) 2008-04-10 05:21 pm (UTC)(link)I don't think there are any commands in iTunes or Finder that absolutely require HFS paths, although they may accept them in some places as a convenience to AppleScript users. There is the odd Carbon app that does force you to use HFS strings for some things; e.g. IIRC, Excel and Illustrator both require their use in 'save' commands due to poor/buggy design. A few older Carbon apps such as Finder may also have problems with file URLs, used to specify files that don't already exist, which may require you to use HFS strings instead if they'll accept them.
As for using path strings vs file objects in general, Apple's Scripting Interface Guidelines do advise developers always to use the latter, thereby avoiding all the HFS vs POSIX hassles to begin with. (Though if you've been around AppleScript for a while you'll already know what scriptable application developers - including Apple - are like for following guidelines.)
Re: HFS vs POSIX
Interesting; the reason I ended up on this tangent in the first place was that it wouldn't respond to a path of the "file:///localhost/path/to/file.ext" variety. The NSURL suggestion works fine though -- thanks!