Skip to content

Instantly share code, notes, and snippets.

@MaddTheSane
Forked from mwaterfall/gist:543667
Last active August 29, 2015 14:08
Show Gist options
  • Save MaddTheSane/6144600aef468a72929a to your computer and use it in GitHub Desktop.
Save MaddTheSane/6144600aef468a72929a to your computer and use it in GitHub Desktop.
Get/set the NSString text encoding of a file using xattr.
//
// 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