A lot of the constants associated with Audio Session programming are really four-character strings (Audio Session Services Reference). The same applies to the OSStatus code returned from functions like AudioSessionGetProperty.
The problem is that when I try to print these things out of the box, they look like 1919902568. I can plug that into Calculator and turn on ASCII output and it'll tell me "roch", but there must be a programmatic way to do this.
I've had limited success in one of my C functions with the following block:
char str[20];
// see if it appears to be a four-character code
*(UInt32 *) (str + 1) = CFSwapInt32HostToBig(error);
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
str[0] = str[5] = '\'';
str[6] = '\0';
} else {
// no, format as integer
sprintf(str, "%d", (int)error);
}
What I want to do is to abstract this feature out of its current function, in order to use it elsewhere. I tried doing
char * fourCharCode(UInt32 code) {
// block
}
void someOtherFunction(UInt32 foo){
printf("%s\n",fourCharCode(foo));
}
but that gives me "à*€/3íT:ê*€/+€/", not "roch". My C fu isn't very strong, but my hunch is that the above code tries to interpret the memory address as a string. Or perhaps there's an encoding issue? Any ideas?
The type you're talking about is a FourCharCode, defined in CFBase.h. It's equivalent to an OSType. The easiest way to convert between OSType and NSString is using NSFileTypeForHFSTypeCode() and NSHFSTypeCodeFromFileType(). These functions, unfortunately, aren't available on iOS.
For iOS and Cocoa-portable code, I like Joachim Bengtsson's FourCC2Str() from his NCCommon.h (plus a little casting cleanup for easier use):
#include <TargetConditionals.h>
#if TARGET_RT_BIG_ENDIAN
# define FourCC2Str(fourcc) (const char[]){*((char*)&fourcc), *(((char*)&fourcc)+1), *(((char*)&fourcc)+2), *(((char*)&fourcc)+3),0}
#else
# define FourCC2Str(fourcc) (const char[]){*(((char*)&fourcc)+3), *(((char*)&fourcc)+2), *(((char*)&fourcc)+1), *(((char*)&fourcc)+0),0}
#endif
FourCharCode code = 'APPL';
NSLog(@"%s", FourCC2Str(code));
NSLog(@"%@", @(FourCC2Str(code));
You could of course throw the @() into the macro for even easier use.
In Swift you would use this function:
func str4 (n: Int) -> String
{
var s: String = ""
var i: Int = n
for var j: Int = 0; j < 4; ++j
{
s = String(UnicodeScalar(i & 255)) + s
i = i / 256
}
return (s)
}
This func will do the same like above in a third of the time:
func str4 (n: Int) -> String
{
var s: String = String (UnicodeScalar((n >> 24) & 255))
s.append(UnicodeScalar((n >> 16) & 255))
s.append(UnicodeScalar((n >> 8) & 255))
s.append(UnicodeScalar(n & 255))
return (s)
}
The reverse way will be:
func val4 (s: String) -> Int
{
var n: Int = 0
var r: String = ""
if (countElements(s) > 4)
{
r = s.substringToIndex(advance(s.startIndex, 4))
}
else
{
r = s + " "
r = r.substringToIndex(advance(r.startIndex, 4))
}
for UniCodeChar in r.unicodeScalars
{
n = (n << 8) + (Int(UniCodeChar.value) & 255)
}
return (n)
}
char str[5];
str[4] = '\0';
long *code = (long *)str;
*code = 1919902568;
printf("%s\n", str);
I wrote this C function for my audio code ... it might be a tad naive, but it does the job for well enough for me:
NSString* fourCharNSStringForFourCharCode(FourCharCode aCode){
char fourChar[5] = {(aCode >> 24) & 0xFF, (aCode >> 16) & 0xFF, (aCode >> 8) & 0xFF, aCode & 0xFF, 0};
NSString *fourCharString = [NSString stringWithCString:fourChar encoding:NSUTF8StringEncoding];
return fourCharString; }
Integer = 4 bytes = 4 chars. So to convert from integer to char * you can simply write:
char st[5] = {0};
st[0] = yourInt & 0xff;
st[1] = (yourInt >> 8) & 0xff;
st[2] = (yourInt >> 16) & 0xff;
st[3] = (yourInt >> 24) & 0xff;
To convert it back:
yourInt = st[0] | (st[1] << 8) | (st[2] << 16) | (st[3] << 24);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With