Created
August 22, 2010 11:26
-
-
Save mwaterfall/543667 to your computer and use it in GitHub Desktop.
Handling the text encoding attribute in text files
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 | |
+ (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 UTF8String]; | |
// 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 UTF8String]; | |
// 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); | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You should consider replacing
-UTF8String
with-fileSystemRepresentation
. See http://cocoadev.com/StringWithCString