Objective-C では文字列リテラルは @"abesi" のように @"" で囲んで表現します。このリテラルは(あくまで推測で確定ではないのですが)コンパイラによってコンパイル時に CFSTR("abesi") に置換され、 CFStringRef 型としてプログラム中に定義されているようです。さて問題はここからで、 Xcode 4.0 が内部的に構文解析のために使っている LLVM がこのリテラル中に \0 、要するにNULL文字が含まれていると以下のような警告を出すようになってしまったのです
CFString literal contains NUL character普通はNULL文字をリテラル中に含めたいということはまず無いのですが、SMTPの通信部分を書いたりしていると通信プロトコル自体が命令を \0 で区切れみたいな要件を求めてくるため、どうしてもリテラルの中に \0 を含めたいときが出てきます。 まぁ、具体的には以下のライブラリなんですけどね。
http://code.google.com/p/skpsmtpmessage/source/browse/trunk/SMTPSender/Classes/SKPSMTPMessage.m
sendState = kSKPSMTPWaitingAuthSuccess;そして私と同じライブラリの同じ箇所でぶつかった人を発見。
NSString *loginString = [NSString stringWithFormat:@"\000%@\000%@", login, pass];
NSString *authString = [NSString stringWithFormat:@"AUTH PLAIN %@\r\n", [[loginString dataUsingEncoding:NSUTF8StringEncoding] encodeBase64ForData]];
NSLog(@"C: %@", authString);
if (CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[authString UTF8String], [authString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) < 0)
{
error = [outputStream streamError];
encounteredError = YES;
}
else
{
[self startShortWatchdog];
}
http://stackoverflow.com/questions/5814520/how-do-i-create-a-login-string-that-contains-2-embedded-nulls-and-the-login-an
さて回避方法はないものかと探してみたところ、ちょうど良い回避策が発見できました。
http://stackoverflow.com/questions/6211908/nsstring-with-0
NSStringのstringWithFormat:に %C を埋め込んで、そこに 0 を渡せばうまくいくみたいです!
int main() {さっきの例だと、
NSString *string = [NSString stringWithFormat: @"Hello%CWorld!", 0];
NSData *bytes = [string dataUsingEncoding: NSUTF8StringEncoding];
NSLog(@"string: %@", string);
NSLog(@"bytes: %@", bytes);
return 0;
}
sendState = kSKPSMTPWaitingAuthSuccess;このようにすればばっちり上手く回避できました!
NSString *loginString = [NSString stringWithFormat:@"%C%@%C%@", 0, login, 0, pass];
NSString *authString = [NSString stringWithFormat:@"AUTH PLAIN %@\r\n", [[loginString dataUsingEncoding:NSUTF8StringEncoding] encodeBase64ForData]];
NSLog(@"C: %@", authString);
if (CFWriteStreamWriteFully((CFWriteStreamRef)outputStream, (const uint8_t *)[authString UTF8String], [authString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]) < 0)
{
error = [outputStream streamError];
encounteredError = YES;
}
else
{
[self startShortWatchdog];
}