How to store struct information on a uint64_t for Game Center challenges - objective-c

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;

Related

NSMutableData increment the underneath pointer and pass it to other APIs

I have been given a task to replace all uint_8 * to NSMutableData.
In the existing code, a lot of pointer arithmetic is done on uint8_t and then passed onto other APIs which also accept uint8_t *.
However, when replacing uint_8 * with NSMutableData, how do I pointer arithmetic on NSMutableData?
One approach is
convert NSMutableData to uint8_t *.
do pointer arithmetic on uint8_t *.
convert uint8_t * back to NSMutableData and pass it to other APIs.
however, when converting uint8_t * to NSMutableData, I do not have length.
How to solve this?
Old code
func(uint8_t *p);
func2() {
uint8_t *p; //points to some piece of memory
func(p+10); //pass base address+ 10 bytes
}
New Code
func(NSMutableData *p);
func2() {
NSMutableData *data = [[NSMutableData alloc]
initWithLength:size];
// now, how to pass data + 10 bytes to func
func(???)
}

Convert 1 byte to int Objective-C

I have an NSData packet with data in it. I need to convert the byte at range 8, 1 to an int. To get the data at that location I do the following.
NSData *byte = [packet subdataWithRange:NSMakeRange(8, 1)];
If I NSLog byte
<01>
How do I think convert this to an int? This is probably the most basic of questions but I am just not getting it right.
Any help would be appreciated.
Update
With that data the int should be equal to 1. I am not sure if this has anything todo with Endian.
use -[NSData bytes] to get raw buffer and read from it
int i = *((char *)[byte bytes])
or use -[NSData getBytes:length:]
char buff;
[bytes getBytes:&buff length:1];
int i = buff;
make sure you are reading from char * not int *, otherwise you are accessing invalid memory location, which may or may not crash or provide correct result.

get float value from nsdata objective-c iOS

I am trying to get a float value from a NSData object which contains several hex values. e.g. EC 51 38 41
From this 4 Byte values i want to get the float value 11.52. How do i have to do this in xcode?
I have tried it with NSScanner (scanFloat, scanHexFloat), NSNumberformatter and NSNumber, i created an Byte Array and tried float myFloat = *(float*)&myByteArray. All these Options i found here at stackoverflow.
I tested it in Windows with C# and there it was no problem:
byte[] bytes = new byte[4] { 0xEC, 0x51, 0x38, 0x41 };
float myFloat = System.BitConverter.ToSingle(bytes, 0);
Does anybody know how i have to do this in xcode???
Thanks, Benjamin
When converting binary data from a foreign protocol always make sure to include proper swapping for endianness:
uint32_t hostData = CFSwapInt32BigToHost(*(const uint32_t *)[data bytes]);
float value = *(float *)(&hostData);
You have to know the endianness of the encoded data. You might need to use CFSwapInt32LittleToHost instead.
NSData * data = ...; // loaded from bluetooth
float z;
[data getBytes:&z length:sizeof(float)];
Try this.
I have tries it with NSScanner (scanFloat, scanHexFloat), NSNumberformatter and NSNumber
You're barking up the wrong tree here. NSScanner is for scanning strings. NSNumber is not the same as NSData, and NSNumberFormatter won't work with NSData either.
NSData is a container for plain old binary data. You've apparently got a float stored in an NSData instance; if you want to access it, you'll need to get the data's bytes and then interpret those bytes however you like, e.g. by casting to float:
float *p = (float*)[myData bytes]; // -bytes returns a void* that points to the data
float f = *p;

Arbitrary precision bit manipulation (Objective C)

I need to do bit operations on representations of arbitrary precision numbers in Objective C. So far I have been using NSData objects to hold the numbers - is there a way to bit shift the content of those? If not, is there a different way to achieve this?
Using NSMutableData you can fetch the byte in a char, shift your bits and replace it with -replaceBytesInRange:withBytes:.
I don't see any other solution except for writing your own date holder class using a char * buffer to hold the raw data.
As you'll have spotted, Apple doesn't provide arbitrary precision support. Nothing is provided larger than the 1024-bit integers in vecLib.
I also don't think NSData provides shifts and rolls. So you're going to have to roll your own. E.g. a very naive version, which may have some small errors as I'm typing it directly here:
#interface NSData (Shifts)
- (NSData *)dataByShiftingLeft:(NSUInteger)bitCount
{
// we'll work byte by byte
int wholeBytes = bitCount >> 3;
int extraBits = bitCount&7;
NSMutableData *newData = [NSMutableData dataWithLength:self.length + wholeBytes + (extraBits ? 1 : 0)];
if(extraBits)
{
uint8_t *sourceBytes = [self bytes];
uint8_t *destinationBytes = [newData mutableBytes];
for(int index = 0; index < self.length-1; index++)
{
destinationBytes[index] =
(sourceBytes[index] >> (8-extraBits)) |
(sourceBytes[index+1] << extraBits);
}
destinationBytes[index] = roll >> (8-extraBits);
}
else
/* just copy all of self into the beginning of newData */
return newData;
}
#end
Of course, that assumes the number of bits you want to shift by is itself expressible as an NSUInteger, amongst other sins.

Problem while converting NSData to int

Using foundation and cocoa frameworks on Mac, I am trying to convert an NSData object in humanly understandable number.
Let say the NSData object is an image of NPIXEL. I know the binary data are coded in big endian and represent 32 bit integer (to be more precise 32 bit two complements integer). I write the piece of code bellow to convert the NSData into an int array. But the value I got are completely wrong (this does not means the measurement are bad, I used a special software to read the data and the value given by the software are different from the one I got with my code).
-(int *) GetArrayOfLongInt
{
//Get the total number of element into the Array
int Nelements=[self NPIXEL];
//CREATE THE ARRAY
int array[Nelements];
//FILL THE ARRAY
int32_t intValue;
int32_t swappedValue;
double Value;
int Nbit = abs(BITPIX)*GCOUNT*(PCOUNT + Nelements); Nbit/=sizeof(int32_t);
int i=0;
int step=sizeof(int32_t);
for(int bit=0; bit < Nbit; bit+=step)
{
[Img getBytes:&swappedValue range:NSMakeRange(bit,step)];
intValue= NSSwapBigIntToHost(swappedValue);
array[i]=intValue;
i++;
}
return array;
}
This piece of code (with minor change) work perfectly when the binary data represent float or double, but I dont when it is 16,32 or 64 bit integer. I also tried changingNSSapBigIntToHostintoNSSwapLittleInttoHost`. I even tried with long, but the results is still the same, I got bad values. What wrong I am doing ?
PS: Some of the variable in my code are already set elsewhere in my program. BITPIX is the bit size of each pixel. In this case 32. GCOUNT is equal to 1, PCOUNT 0 and Nelements is the total number of pixel I should have in my image.
Returning a pointer to a local variable is a very bad idea. array could get overwritten at any time (or if you were to write through the pointer, you could corrupt the stack). You probably want something like:
// CREATE THE ARRAY
int *array = malloc(Nelements * sizeof(int));
Your algorithm seems a bit overkill, too. Why not just copy out the whole array from the NSData object, and then byteswap the entries in place? Something like:
int32_t length = [Img length];
int32_t *array = malloc(length);
[Img getBytes:array length:length];
for (i = 0; i < length/sizeof(int32_t); i++)
{
array[i] = NSSwapBigIntToHost(array[i]);
}