Skip to content

Instantly share code, notes, and snippets.

@mwaterfall
Created August 22, 2010 11:26
Show Gist options
  • Save mwaterfall/543667 to your computer and use it in GitHub Desktop.
Save mwaterfall/543667 to your computer and use it in GitHub Desktop.
Handling the text encoding attribute in text files
//
// 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
@JanX2
Copy link

JanX2 commented Aug 22, 2014

You should consider replacing -UTF8String with -fileSystemRepresentation. See http://cocoadev.com/StringWithCString

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment