stringEncodingForData:encodingOptions:convertedString:usedLossyConversion:是否可以返回NSUTF16StringEncoding或NSUTF32StringEncoding?

时间:2018-10-29 10:48:36

标签: objective-c nsdata c-strings nsstringencoding

我想知道调用stringEncodingForData:encodingOptions:convertedString:usedLossyConversion:是否可以返回NSUTF16StringEncodingNSUTF32StringEncoding或它们的任何变体吗?

我要问的原因是因为这个documentation note on cStringUsingEncoding:

  

特殊注意事项

     

UTF-16和UTF-32不被视为C字符串编码,不应与this method(传递NSUTF16StringEncodingNSUTF32StringEncoding或以下任何一种的结果)一起使用它们的变体是不确定的。

因此,我了解不支持使用UTF-16或UTF-32创建C字符串,但是我不确定是否尝试使用stringEncodingForData:encodingOptions:convertedString:usedLossyConversion:进行字符串编码检测是否会返回UTF- 16和是否为UTF-32。

一个示例场景(改编自SSZipArchive.m)可能是:

// name is a null-terminated C string built with `fread` from stdio.h:
char *name = (char *)malloc(size_name + 1);
size_t read = fread(name, 1, size_name + 1, file);
name[size_name] = '\0';

// dataName is the data object of name
NSData *dataName = [NSData dataWithBytes:(const void *)name length:sizeof(unsigned char) * size_name];

// stringName is the string object of dataName
NSString *stringName = nil;
NSStringEncoding encoding = [NSString stringEncodingForData:dataName encodingOptions:nil convertedString:&stringName usedLossyConversion:nil];

在上面的代码中,encodingNSUTF16StringEncodingNSUTF32StringEncoding还是它们的任何变体?


平台:macOS 10.10 +,iOS 8.0 +,watchOS 2.0 +,tvOS 9.0 +。

1 个答案:

答案 0 :(得分:3)

是,如果使用这些编码之一对字符串进行编码。有关C字符串的注释特定于C字符串。 NSString不是C字符串,并且您描述的方法不适用于C字符串。它适用于可以以多种方式编码的任意数据。

例如:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSData *data = [@"test" dataUsingEncoding:NSUTF16StringEncoding];
        NSStringEncoding encoding = [NSString stringEncodingForData:data
                                                    encodingOptions:nil
                                                    convertedString:nil
                                                usedLossyConversion:nil];
        NSLog(@"%ld == %ld", (unsigned long)encoding, 
                             (unsigned long)NSUTF16StringEncoding);
    }
    return 0;
}
// Output:   10 == 10

在您的特定示例中,这表示如果name确实是“空终止的C字符串”,则它永远不可能是UTF-16,因为C字符串无法在UTF-16。 C字符串以\ 0结尾,并且\ 0是UTF-16中非常常见的字符。但是,如果看不到更多代码,我不会赌博该评论是否正确。

如果您的真正问题是“给予任意c字符串安全编码,stringEncodingForData:是否会返回非c字符串安全编码”,那么答案是“是的,它可能,而且即使今天不是今天,也绝对不会承诺不会。”如果您需要防止这种情况,建议您使用NSStringEncodingDetectionSuggestedEncodingsKey...UseOnlySuggestedEncodingsKey强制使其成为您可以处理的编码。 (您也可以使用...DisallowedEncodingsKey来防止特定的多字节编码,但这并不那么可靠。)