views:

128

answers:

1

I am trying to convert an NSString to a ResType, as defined below in MacTypes.h.

FourCharCode // A 32-bit value made by packing four 1 byte characters together
typedef FourCharCode ResType;

I think I could use [aString getCharacters:range:], but is there a more straight forward way to make this conversion?

After trying suggestions from David, here is some further information.

I am using GTResourceFork, a Cocoa wrapper for accessing resource forks. The method I am calling is: - (NSArray *)usedResourcesOfType: (ResType)type;

If I hard code a value of 'RTF ', I get the results I expect. I cannot figure out how to convert an NSString containing "RTF " to the hard-coded value. I created a test case using NSString's getCharacters and getBytes, and they all give me different integer values. How can I convert the NSString to give me the same integer value as the hard-coded one?

 Method used:       Value:  Casted int value:
 Hard Coded(Works): 'RTF ' '1381254688'
 getCharacters:     'RTF ' '5505106'
 getBytes(ASCII):   'RTF ' '541480018'
 getBytes(UTF8):    'RTF ' '541480018'

Thanks in advance, Lance

+1  A: 

The problem with getCharacters:range: is that it gives you UTF-16 characters (unichars), whereas you want ASCII.

*(ResType*)[aString UTF8String] will convert the string to UTF-8 (which is equivalent to ASCII as long as all the characters in the string fit within the ASCII range) and then give you the first four bytes as a ResType value. Whether this is efficient enough depends on how often you want to do these conversions.

Another option is to use getBytes:maxLength:usedLength:encoding:options:range:remainingRange: with the encoding set to NSASCIIStringEncoding or NSUTF8StringEncoding, the destination buffer set to a pointer to an existing ResType variable, and the maximum length set to 4 (or sizeof (ResType)).


Update:

I've figured out why you're not getting the correct result with my suggestion. It turns out that in four-character integer literals, the bytes are stored in the opposite order to how they're written. Here's an example:

#include <Foundation/Foundation.h>

int main() {
    int code = 'RTF ';
    printf("'%c%c%c%c' = %d\n", ((char*)&code)[0], ((char*)&code)[1],
                                ((char*)&code)[2], ((char*)&code)[3],
                                code);
}

The output is ' FTR' = 1381254688. So, if you want to convert from NSStrings to these values, here are a few options:

  • Copy the string into a four-byte buffer (using one of the methods I suggested) and then reverse it by swapping byte 0 with byte 3, and byte 1 with byte 2.
  • The same, but do the reversing using a standard "endianness-swapping" algorithm like the one on this page.
  • Iterate through first (and only) four characters using characterAtIndex:, and insert them into a four-byte buffer in reverse. Remember that characterAtIndex: returns a UTF-16 character, but this can be easily cast to as ASCII character assuming it is within the ASCII range.
David
Thank you for your quick response. These methods did not work for me, however. I will add more information to my original question.
Lance
@Lance: I've figured out what the problem is and updated my answer with a few suggestions.
David
@David: were I needing to swap endianness, I'd use the built-in Cocoa functions for doing it like `NXByteSwap...()`. That way when Apple updates their architecture again (they've had four in recent history) the result is still likely to be correct.
Graham Lee
@Graham: Good idea. For the benefit of the OP, could you post the full name of the function(s), or a documentation link? I would do it myself, but for some reason I can't find it.
David
@David/@Lance: `EndianU32_NtoB()` in Core Endian is one of many APIs to do the conversion.
Graham Lee
Your update worked great David. And I'll take a look at Graham's suggestion to make the code cleaner and future proof. Thank you!
Lance