-
-
Save MaddTheSane/6144600aef468a72929a to your computer and use it in GitHub Desktop.
Get/set the NSString text encoding of a file using xattr.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSString+FileTextEncodingAttribute.h | |
// Adapted from http://github.com/scrod/nv/blob/master/NSString_NV.m | |
// | |
#import <Foundation/Foundation.h> | |
#include <sys/xattr.h> | |
@interface NSString (FileTextEncodingAttribute) | |
// See: http://stackoverflow.com/questions/3534729/nsutf8stringencoding-causes-file-to-render-improperly-in-textedit-pages-but-not | |
// Fixes as suggested by https://gist.github.com/mwaterfall/543667#comment-1286524 | |
+ (BOOL)setTextEncodingAttribute:(NSStringEncoding)encoding atPath:(NSString *)filePath; | |
+ (NSStringEncoding)textEncodingAttributeOfPath:(NSString *)filePath; | |
@end | |
@implementation NSString (FileTextEncodingAttribute) | |
+ (BOOL)setTextEncodingAttribute:(NSStringEncoding)encoding atPath:(NSString *)filePath { | |
// Get C string | |
if (!filePath) return NO; | |
const char* path = [filePath fileSystemRepresentation]; | |
// Get correct encoding | |
CFStringEncoding cfStringEncoding = CFStringConvertNSStringEncodingToEncoding(encoding); | |
if (cfStringEncoding == kCFStringEncodingInvalidId) { | |
NSLog(@"%s: encoding %lu is invalid!", _cmd, encoding); | |
return NO; | |
} | |
// Get text encoding string value | |
NSString *textEncStr = [(NSString *)CFStringConvertEncodingToIANACharSetName(cfStringEncoding) | |
stringByAppendingFormat:@";%@", [[NSNumber numberWithInt:cfStringEncoding] stringValue]]; | |
const char *textEncUTF8Str = [textEncStr UTF8String]; | |
// Set attribute | |
if (setxattr(path, "com.apple.TextEncoding", textEncUTF8Str, strlen(textEncUTF8Str), 0, 0) < 0) { | |
NSLog(@"couldn't set text encoding attribute of %s to '%s': %d", path, textEncUTF8Str, errno); | |
return NO; | |
} | |
return YES; | |
} | |
+ (NSStringEncoding)textEncodingAttributeOfPath:(NSString *)filePath { | |
// Get C string | |
if (!filePath) return 0; | |
const char* path = [filePath fileSystemRepresentation]; | |
// We could query the size of the attribute, but that would require a second system call | |
// and the value for this key shouldn't need to be anywhere near this large, anyway. | |
// It could be, but it probably won't. If it is, then we won't get the encoding. Too bad. | |
char xattrValueBytes[128] = { 0 }; | |
if (getxattr(path, "com.apple.TextEncoding", xattrValueBytes, sizeof(xattrValueBytes), 0, 0) < 0) { | |
if (ENOATTR != errno) NSLog(@"couldn't get text encoding attribute of %s: %d", path, errno); | |
return 0; | |
} | |
NSString *encodingStr = [NSString stringWithUTF8String:xattrValueBytes]; | |
if (!encodingStr) { | |
NSLog(@"couldn't make attribute data from %s into a string", path); | |
return 0; | |
} | |
NSArray *segs = [encodingStr componentsSeparatedByString:@";"]; | |
if ([segs count] >= 2 && [(NSString*)[segs objectAtIndex:1] length] > 1) { | |
return CFStringConvertEncodingToNSStringEncoding([[segs objectAtIndex:1] intValue]); | |
} else if ([(NSString*)[segs objectAtIndex:0] length] > 1) { | |
CFStringEncoding theCFEncoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)[segs objectAtIndex:0]); | |
if (theCFEncoding == kCFStringEncodingInvalidId) { | |
NSLog(@"couldn't convert IANA charset"); | |
return 0; | |
} | |
return CFStringConvertEncodingToNSStringEncoding(theCFEncoding); | |
} else { | |
return 0; // error | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment