Be careful with CFStringGetCStringPtr() and its companion calls

Sometimes you would need to use CoreFoundation functions which takes UTF8 char* buffer.
For example, you want to obtain a path for a certain file with help of CoreFoundation or Cocoa call and pass the retrieved path to a Cocoa call which requires UTF8 char * buffer.

Then probably you would call CFStringGetCStringPtr() or CFStringGetCharactersPtr().
Also, you will consider CFStringGetCString() or CFStringGetCharacters().
But be careful. According to the document, it says :

Whether or not this function returns a valid pointer or NULL depends on many factors, all of which depend on how the string was created and its properties. In addition, the function result might change between different releases and on different platforms. So do not count on receiving a non-NULL result from this function under any circumstances

Using CFStringGetCString() and CFStringGetCharacters() can’t guarantee that you get some valid converted string.

Aki Inoue replied like this.

The keyword here is that the function returns non-NULL when it can do so “efficiently”. It all depends on a particular CFString instance’s internal representation and the encoding being passed.

However, the document didn’t mention that it returns non-NULL when it can do so efficiently.
Or maybe it is somewhere else…

What is weird about the CFStringGetCStringPtr() is that it returns NULL when it converts a MacRoman characters, which you will get on an English-as-1st-script Mac OS X as system encoding method, it fails, while a Japanese-as-1st-script Mac OS X gives you a valid address.
In my case, I tried converting a path. The path is in English not Japanese. So, I expected that it would return correct address for a converted string on a English system, because UTF8 is very compatible with ASCII and thus MacRoman.
( At first I just passed kCFStringEncodingUTF8 as the 2nd parameter for the CFStringGetCStringPtr() )

Take a look at this code which works by considering the two cases.

// JongAm : Japanese system crash fix
// When a Japanese script becomes the 1st script on a Mac,
// its encoding method is kCFStringEncodingMacJapanese, which I believe 2 bytes, not 1 byte.
// For the CFStringEtCStringPtr, the 2nd parameter which denotes encoding method to use
// should be something 1 byte. So, it falis calling this function.

// NEW : On a English system, CFStringGetCStringPtr( ..., kCFStringEncodingUTF8)
//		returns NULL.
//		On a Japanese system, the same call returns correct string.
//		On Japanese system, CFStringGetCStringPtr( ..., CFStringGetSystemEncoding()) returns NULL.
//
//		Because the 2nd parameter is a target encoding method, it should also work on English system,
//		but it doesn't work. Is this a bug?
char *fullPath;
char outPath[512];;

Boolean conversionResult;
CFStringEncoding encodingMethod;
// This is for ensuring safer operation. When CFStringGetCStringPtr() fails,
// it tries CFStringGetCString().

encodingMethod = CFStringGetSystemEncoding();

// 1st try for English system
fullPath = (char*)CFStringGetCStringPtr(mstr, encodingMethod);
if( fullPath == NULL )
{
	// 2nd try for Japanese system
	encodingMethod = kCFStringEncodingUTF8;
	fullPath = (char*)CFStringGetCStringPtr(mstr, encodingMethod);
}

// for safer operation.
if( fullPath == NULL )
{
	CFIndex length = CFStringGetLength(mstr);
	fullPath = (char *)malloc( length + 1 );
	conversionResult = CFStringGetCString(mstr, fullPath, length, kCFStringEncodingUTF8 );

	strcpy( outPath, fullPath );

	free( fullPath );
}
else
	strcpy( outPath, fullPath );

Aki Inoue suggested better approach though.
He told me to use CFStringGetFastestEncoding() for this.

2 responses to this post.

  1. Posted by bonnyswan on June 13, 2013 at 2:58 AM

    Hi jongampark,
    Your post helped me solve the same issue I had.
    Thanks a lot!

    Reply

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: