How to work around NSTask calling -[NSString fileSystemRepresentation] for arguments

1.2k Views Asked by At

It seems that NSTask calls -[NSString fileSystemRepresentation] to encode values for each of the arguments you give it.

This can become a problem in some situations due to the fact that -fileSystemRepresentation encodes using decomposed unicode forms: for example, the a-umlaut (ä) would be encoded as U+0061 (Latin small letter a) and U+0308 (Combining diaeresis), as opposed to U+00E4 (Latin small letter a with diaeresis). The -UTF8String method, on the other hand, seems to do the opposite.

I need my NSTask arguments to be encoded using composed forms. How do I work around this issue?

2

There are 2 best solutions below

0
On

A possible solution would be to subclass NSString and provide your own implementation of -fileSystemRepresentation, but unfortunately NSString is a class cluster and thus very difficult to subclass (which is also discouraged by Apple's documentation).

However, we can create a separate class that poses as an NSString, but provides its own implementation of -fileSystemRepresentation.

This can, however, create problems if NSTask does anything with the class identity of the argument objects. Currently I have no evidence that this is the case — this workaround seems to work perfectly.

Header:

// MYTaskArgument.h

@interface MYTaskArgument : NSObject
+ (instancetype) taskArgumentWithString:(NSString *)str;
@end

Implementation:

// MYTaskArgument.m

@interface MYTaskArgument ()
@property(copy) NSString *string;
@end

@implementation MYTaskArgument

+ (instancetype) taskArgumentWithString:(NSString *)str {
    MYTaskArgument *ret = [[MYTaskArgument alloc] init];
    ret.string = str;
    return ret;
}

- (const char *) fileSystemRepresentation {
    return self.string.UTF8String;
}

- (id) forwardingTargetForSelector:(SEL)aSelector {
    return self.string;
}

@end
0
On

We ran in to this trying to execute shortcuts via NSTask, essentially:

shortcuts run "Foréver"

NSTask decomposes the characters (FB10036117), and then shortcuts cannot find the matching shortcut (FB10036113).

Our solution was to pre-convert the argument to UTF8, and then map the characters to octal \123 (because octal works in POSIX and thus bash, dash, and csh), and then expand the parameter within the command using printf:

/usr/bin/shortcuts run "`printf '\106\157\162\303\251\166\145\162'`"

Clearly not an ideal solution, but it works and doesn't depend on trying to fake an NSString (which is very clever, but potentially very fragile).