OS X または iOS は、MIME Encoded-Wordを解析するための API を提供していますか? これらの素敵な文字列:
=?iso-8859-1?Q?=A1Hola,_se=F1or!?=
あるいは、これを行う既知のオープンソース ライブラリはありますか?
OS X または iOS は、MIME Encoded-Wordを解析するための API を提供していますか? これらの素敵な文字列:
=?iso-8859-1?Q?=A1Hola,_se=F1or!?=
あるいは、これを行う既知のオープンソース ライブラリはありますか?
@NickolayO. の回答を受け取り、 QSStringsでbase-64 サポートを追加し、 componentsSeparatedByString:
andを使用してコードを短縮しましたstringByReplacingOccurrencesOfString:withString:
。
コードをGitHubで利用できるようにしました。便宜上、スニペットを次に示します。
@implementation NSString (MimeEncodedWord)
- (BOOL) isMimeEncodedWord
{
return [self hasPrefix:@"=?"] && [self hasSuffix:@"?="];
}
+ (NSString*) stringWithMimeEncodedWord:(NSString*)word
{ // Example: =?iso-8859-1?Q?=A1Hola,_se=F1or!?=
NSArray *components = [word componentsSeparatedByString:@"?"];
if (components.count < 5) return nil;
NSString *charset = [components objectAtIndex:1];
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)charset)); // TODO: What happens if the encoding is invalid?
NSString *encodingType = [components objectAtIndex:2];
NSString *encodedText = [components objectAtIndex:3];
if ([encodingType isEqualToString:@"Q"])
{ // quoted-printable
encodedText = [encodedText stringByReplacingOccurrencesOfString:@"_" withString:@" "];
encodedText = [encodedText stringByReplacingOccurrencesOfString:@"=" withString:@"%"];
NSString *decoded = [encodedText stringByReplacingPercentEscapesUsingEncoding:encoding];
return decoded;
} else if ([encodingType isEqualToString:@"B"])
{ // base64
NSData *data = [QSStrings decodeBase64WithString:encodedText];
NSString *decoded = [[NSString alloc] initWithData:data encoding:encoding];
return decoded;
} else {
NSLog(@"%@ is not a valid encoding (must be Q or B)", encodingType);
return nil;
}
}
@end
これは引用された印刷可能なバージョンのコードです (Mime Encoded-word は引用された印刷可能なバージョンまたは base-64 でエンコードされたものにすることができます)。base64 エンコードの場合は、引用された印刷可能なデコードを base64 デコードに置き換えて、同様に行う必要があります。おそらく、このコードにはいくつかのテストが必要です。また、NSString のエンコーディングのみをサポートします。
- (NSString*) decodeMimeEncodedWord:(NSString*)word
{
if (![word hasPrefix:@"=?"] || ![word hasSuffix:@"?="])
return nil;
int i = 2;
while ((i < word.length) && ([word characterAtIndex:i] != (unichar)'?'))
i++;
if (i >= word.length - 4)
return nil;
NSString *encodingName = [word substringWithRange:NSMakeRange(2, i - 2)];
NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName));
// warning! can return 'undefined something' if encodingName is invalid or unknown
NSString *encodedString;
if ([[word substringWithRange:NSMakeRange(i + 1, 2)] isEqualToString:@"Q?"])
{
// quoted-printable
encodedString = [word substringWithRange:NSMakeRange(i + 3, word.length - i - 5)];
NSMutableData *binaryString = [[[NSMutableData alloc] initWithLength:encodedString.length] autorelease];
unsigned char *binaryBytes = (unsigned char*)[binaryString mutableBytes];
int j = 0;
char h;
for (i = 0; i < encodedString.length; i++)
{
unichar ch = [encodedString characterAtIndex:i];
if (ch == (unichar)'_')
binaryBytes[j++] = ' ';
else if (ch == (unichar)'=')
{
if (i >= encodedString.length - 2)
return nil;
unsigned char val = 0;
// high-order hex char
h = [encodedString characterAtIndex:++i];
if ((h >= '0') && (h <= '9'))
val += ((int)(h - '0')) << 4;
else if ((h >= 'A') && (h <= 'F'))
val += ((int)(h + 10 - 'A')) << 4;
else
return nil;
// low-order hex char
h = [encodedString characterAtIndex:++i];
if ((h >= '0') && (h <= '9'))
val += (int)(h - '0');
else if ((h >= 'A') && (h <= 'F'))
val += (int)(h + 10 - 'A');
else
return nil;
binaryBytes[j++] = val;
}
else if (ch < 256)
binaryBytes[j++] = ch;
else
return nil;
}
binaryBytes[++j] = 0;
[binaryString setLength:j];
NSString *result = [[NSString alloc] initWithCString:[binaryString mutableBytes] encoding:encoding];
// warning! can return 'undefined something' if encoding is invalid or unknown
return result;
}
else if ([[word substringWithRange:NSMakeRange(i + 1, 2)] isEqualToString:@"B?"])
{
// base64-encoded
return nil;
}
else
return nil;
}