I'm using the following code to write number in hex to a MIDI file. It's to specify the track length - and the MIDI format requires a 32-bit hex value..
This is the code I'm using, where 'length' stores the number of bytes in the MIDI track -
int length;
char lenShort[3] = { 0x00, 0x00, 0x00 };
char lenLong[2] = { 0x00, 0x00 };
// create length 32-bit hex
if (length>255) {
[contents appendBytes:&lenLong length:2];
[contents appendBytes:&length length:2];
} else {
[contents appendBytes:&lenShort length:3];
[contents appendBytes:&length length:1];
}
It works fine with low numbers - for example, when length=57, it spits out 00000039 in hex, which is fine.
But for higher numbers, such as length=295, it gives me this - 00002701, which is wrong (it's 9985 in decimal)..
I discovered that I need to reverse the two last bytes - and I've been trying all sorts of 'unsigned longs' and 0xFFFFFFF things, but I don't really know what i'm doing, and nothing is working (I didn't pay attention in Hex classes at school!)
Can someone give me an easy way (in C or Obj-C) to switch the last two bytes around?
If I see it correctly, you want to write the length as
an 32-bit integer in big-endian byte order. This can simply be done as:
int length = ...
uint32_t lengthBE = OSSwapHostToBigInt32(length);
[contents appendBytes:&lengthBE length:4];
I'm trying to store some game related information on the uint64_t context property of GKScore - to create a better gaming experience with the new Game Center Challenges. However, I'm not getting it right. I built a struct like below:
typedef struct{
unsigned int gameMode;
unsigned int destroyed;
unsigned int duration;
} GameInfo;
I try the following:
uint64_t myContext
GameInfo info;
info.gameMode = 2;
info.destroyed = 50;
info.duration = 100;
NSData *data = [NSData dataWithBytes:&info length:sizeof(info)];
[data getBytes:&myContext length:sizeof(myContext)];
to pack the struct to a NSData and then write the bytes to myContext.
Then, I try to recreate the information using the 64bit integer as follows:
NSData *newData = [NSData dataWithBytes:&myContext length:sizeof(myContext)];
GameInfo *result = (GameInfo*) [newData bytes];
however, when I log out the values, I see that I'm only able to capture the first two values (gameMode and destroyed). If I add more variables to the struct, I still only capture the first 2 variables.
What am I doing wrong? Is there a smarter way to do this?
You are trying to pack 96 bits of data (3 unsigned ints on iOS / ARM) into a 64 bit container. So you see the first two 32-bit values and not the third.
Maybe you could try using shorts or chars, depending on the range of values your struct will hold, and try to get the stuct's size down to < 64 bits. I think 3 char on ARM will get aligned out to 48 bits (might be wrong about that if so please let me know!). So maybe use short anyway.
EDIT: example of possible way to change your struct, assuming you'll only store 16-bit values in each field:
typedef struct{
uint16_t gameMode;
uint16_t destroyed;
uint16_t duration;
} GameInfo;
Ok, I'm a little stumped here, as I've never really dealt with anything this low level. Say I want to add the following bytes to an NSMutableData object:
0x01, 0xF, 0x64, 0x0, 0x6A
How do I even go about doing this? I imagine it's something to do with the appendBytes:length: method, but I honestly don't know how to transform what I have above into an NSMutableData.
Any help would be greatly appreciated!
This should do it:
NSMutableData *data = [NSMutableData data];
char bytesToAppend[5] = {0x01, 0xf0, 0x64, 0x0, 0x6a};
[data appendBytes:bytesToAppend length:sizeof(bytesToAppend)];
I am trying to send the following hex to NSOutputstream 0x0000000e000000010000001000003014
I'm able to send hex that is 8 bit with the following code:
long myhex = 0x0000000e00000001;
NSData *data = [[NSData alloc] initWithBytes:&myhex length: sizeof(myhex)];
[outputStream write:[data bytes] maxLength:[data length]];
The problem is when I try this:
long myhex = 0x0000000e000000010000001000003014;
it says "integer constant is too long for its type"
I cant seem to figure out what type of integer will except this hex value.
Instead of trying to find an integer type long enough, you should probably just create an array of bytes and send that. Not only will you eventually be unable to find a type long enough for the data you wish to send, but there are also differences in the order of bytes in integers on different platforms.
So, to send arbitrarily long data in any order, use an array of bytes (unsigned char, or, preferably, uint8_t from stdint.h), e.g.:
uint8_t dataBytes[] = { 0x00, … , 0x0e, … 0x30, 0x14 };
NSData *data = [[NSData alloc] initWithBytes:dataBytes length:sizeof(dataBytes)];
- (void)pushDigitalJoin: (NSString*)joinNumber
{
char joinByteArray[] = {
0x05, 0x00, 0x06, 0x00, 0x00, 0x03, 0x27
};
int joinIntNumber = ([joinNumber intValue] - 1);
char *upperByte;
char *lowerByte;
NSString *decimalString = [NSString stringWithFormat:#"%i", 0xff];
*upperByte = joinIntNumber & [decimalString intValue];
*lowerByte = joinIntNumber >> 8;
joinByteArray[7]= *upperByte;
joinByteArray[8] = *lowerByte;
int i;
for (i = 0; i < sizeof(joinByteArray); i++) {
NSLog(#"joinByteArray: position-%i | value-%i",i,joinByteArray[i]);
}
}
basically i have the byte array
i need to change the last 2 bytes based on the "joinNumber"
then add those 2 bytes to the array
however i get compile errors on the joinIntNumber >> 8 and the operation above that which uses the and operator doesnt seem to work. (output always shows 39)
so how do i correctly use these bitwise operators and get my 2bytes added to the array?
CHANGES MADE TO REFLECT COMMENTS AND SHOW OUTPUT (ANSWER(:
- (void)pushDigitalJoin: (NSString*)joinNumber
{
char joinByteArray[] = {
0x05, 0x00, 0x06, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00
};
int joinIntNumber = ([joinNumber intValue] - 1);
char upperByte = nil;
char lowerByte = nil;
// NSString *decimalString = [NSString stringWithFormat:#"%i", 0xff];
upperByte = joinIntNumber & 0xff;//[decimalString intValue];
lowerByte = joinIntNumber >> 8;
joinByteArray[7]= upperByte;
joinByteArray[8] = lowerByte;
int i;
for (i = 0; i < sizeof(joinByteArray); i++) {
NSLog(#"joinByteArray: position-%i | value-%x",i,joinByteArray[i]);
}
}
OUTPUT (joinnumber = 5):
2011-08-26 11:06:07.554 Cameleon[2213:40b] joinByteArray: position-0 | value-5
2011-08-26 11:06:07.555 Cameleon[2213:40b] joinByteArray: position-1 | value-0
2011-08-26 11:06:07.557 Cameleon[2213:40b] joinByteArray: position-2 | value-6
2011-08-26 11:06:07.558 Cameleon[2213:40b] joinByteArray: position-3 | value-0
2011-08-26 11:06:07.559 Cameleon[2213:40b] joinByteArray: position-4 | value-0
2011-08-26 11:06:07.561 Cameleon[2213:40b] joinByteArray: position-5 | value-3
2011-08-26 11:06:07.562 Cameleon[2213:40b] joinByteArray: position-6 | value-27
2011-08-26 11:06:07.563 Cameleon[2213:40b] joinByteArray: position-7 | value-4
2011-08-26 11:06:07.564 Cameleon[2213:40b] joinByteArray: position-8 | value-0
so how do i correctly use these bitwise operators and get my 2bytes added to the array?
You don't. The array is declared on the stack and has fixed size (7 bytes). If you try to add values onto the end, you'll wind up stomping on other values on the stack and probably corrupting the stack.
Unrelated, but also problematic is this:
NSString *decimalString = [NSString stringWithFormat:#"%i", 0xff];
*upperByte = joinIntNumber & [decimalString intValue];
That really doesn't make any sense... why are you creating a string from an int only to take it's intValue? It'd be better to write:
*upperByte = joinIntNumber & 0xff;
And another thing... you're declaring upperByte and lowerByte as character pointes (char*), but you don't set them to point at anything in particular. So when you try to set the characters that they point to as in the above line, you're going to end up putting the values into random places.
If you want a C array that you can modify, you should declare one that's large enough to hold any values that you're going to add, in this case:
char joinByteArray[] = {
0x05, 0x00, 0x06, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00
};
You could also create it on the heap with malloc() and friends, but again you'd need to make it large enough at the outset to hold your extra values, or else grow the array as necessary with realloc() before adding your new values. In any case, don't write past the end of your array.
First problem: joinByteArray is only 7-elements long, so you can't assign to indices 7 and 8. Not sure what you're trying to do here. Is this array supposed to grow over time as you receive more numbers? If so, you're better off using a NSMutableArray or NSMutableData and storing that in an instance variable:
char initialBytes[] = {
0x05, 0x00, 0x06, 0x00, 0x00, 0x03, 0x27
};
NSMutableData *joinBytes = [[NSMutableData alloc] initWithBytes:initialBytes length:7];
Second problem: you declare upperByte and lowerByte as pointers, but they should just be stack-allocated variables. Or better yet, use an array for this to make appending the data easier later on:
char newBytes[2];
newBytes[0] = joinIntNumber & 0xff;
newBytes[1] = joinIntNumber >> 8;
Once you've got that, you can append to the data:
[joinBytes appendBytes:newBytes length:2];
I'm not sure what it is you're trying to do, but you may want to consider endianess (see, for example, NSSwapHostIntToBig).
This may be closer to what you are looking for.
- (void)pushDigitalJoin: (NSString*)joinNumber
{
//You are appending 2 more values so you need to specify
//that jointByteArray is 9
unsigned char joinByteArray[9] = {
0x05, 0x00, 0x06, 0x00, 0x00, 0x03, 0x27
};
int joinIntNumber = ([joinNumber intValue] - 1);
//Upper and lower byte do not need to be char*
//unless you want to needlessly malloc memory for them
char upperByte;
char lowerByte;
//0xff is an int (unsigned) so this is useless
//NSString *decimalString = [NSString stringWithFormat:#"%i", 0xff];
//To get upper byte you need to know the size of int
//use int32_t to specify >> 24 so you don't need to use sizeof
upperByte = joinIntNumber >> ((sizeof(joinIntNumber) - 1) * 8);
lowerByte = joinIntNumber & 0xFF;
joinByteArray[7] = upperByte;
joinByteArray[8] = lowerByte;
int i;
for (i = 0; i < sizeof(joinByteArray); i++) {
//Should log hex since you are manipulating bytes
NSLog(#"joinByteArray: position-%X | value-%X",i,joinByteArray[i]);
}
}