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