Get float value from NSData bytes - ios

how can I write this
float value = *(float *)[data bytes];
in swift?
Thanks.

The corresponding Swift code is
let value = UnsafePointer<Float>(data.bytes).memory
which – as your Objective-C code – assumes that the NSData
objects has (at least) 4 bytes, representing a floating point value
in host byte order.
UnsafePointer<Float>(..) corresponds to the (float *) cast.
.memory corresponds to the dereferencing operator *.
An alternative is
var value : Float = 0
data.getBytes(&value, length: sizeofValue(value))

Related

Objective-C how to convert a keystroke to ASCII character code?

I need to find a way to convert an arbitrary character typed by a user into an ASCII representation to be sent to a network service. My current approach is to create a lookup dictionary and send the corresponding code. After creating this dictionary, I see that it is hard to maintain and determine if it is complete:
__asciiKeycodes[#"F1"] = #(112);
__asciiKeycodes[#"F2"] = #(113);
__asciiKeycodes[#"F3"] = #(114);
//...
__asciiKeycodes[#"a"] = #(97);
__asciiKeycodes[#"b"] = #(98);
__asciiKeycodes[#"c"] = #(99);
Is there a better way to get ASCII character code from an arbitrary key typed by a user (using standard 104 keyboard)?
Objective C has base C primitive data types. There is a little trick you can do. You want to set the keyStroke to a char, and then cast it as an int. The default conversion in c from a char to an int is that char's ascii value. Here's a quick example.
char character= 'a';
NSLog("a = %ld", (int)test);
console output = a = 97
To go the other way around, cast an int as a char;
int asciiValue= (int)97;
NSLog("97 = %c", (char)asciiValue);
console output = 97 = a
Alternatively, you can do a direct conversion within initialization of your int or char and store it in a variable.
char asciiToCharOf97 = (char)97; //Stores 'a' in asciiToCharOf97
int charToAsciiOfA = (int)'a'; //Stores 97 in charToAsciiOfA
This seems to work for most keyboard keys, not sure about function keys and return key.
NSString* input = #"abcdefghijklkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!##$%^&*()_+[]\{}|;':\"\\,./<>?~ ";
for(int i = 0; i<input.length; i ++)
{
NSLog(#"Found (at %i): %i",i , [input characterAtIndex:i]);
}
Use stringWithFormat call and pass the int values.

Very big ID in JSON, how to obtain it without losing precision

I have IDs in JSON file and some of them are really big but they fit inside bounds of unsigned long long int.
"id":9223372036854775807,
How to get this large number from JSON using objectForKey:idKey of NSDictionary?
Can I use NSDecimalNumber? Some of this IDs fit into regular integer.
Tricky. Apple's JSON code converts integers above 10^18 to NSDecimalNumber, and smaller integers to plain NSNumber containing a 64 bit integer value. Now you might have hoped that unsignedLongLongValue would give you a 64 bit value, but it doesn't for NSDecimalNumber: The NSDecimalNumber first gets converted to double, and the result to unsigned long long, so you lose precision.
Here's something that you can add as an extension to NSNumber. It's a bit tricky, because if you get a value very close to 2^64, converting it to double might get rounded to 2^64, which cannot be converted to 64 bit. So we need to divide by 10 first to make sure the result isn't too big.
- (uint64_t)unsigned64bitValue
{
if ([self isKindOfClass:[NSDecimalNumber class]])
{
NSDecimalNumber* asDecimal = (NSDecimalNumber *) self;
uint64_t tmp = (uint64_t) (asDecimal.doubleValue / 10.0);
NSDecimalNumber* tmp1 = [[NSDecimalNumber alloc] initWithUnsignedLongLong:tmp];
NSDecimalNumber* tmp2 = [tmp1 decimalNumberByMultiplyingByPowerOf10: 1];
NSDecimalNumber* remainder = [asDecimal decimalNumberBySubtracting:tmp2];
return (tmp * 10) + remainder.unsignedLongLongValue;
}
else
{
return self.unsignedLongLongValue;
}
}
Or process the raw JSON string, look for '"id" = number; '. With often included white space, you can find the number, then over write it with the number quoted. You can put the data into a mutable data object and get a char pointer to it, to overwrite.
[entered using iPhone so a bit terse]

Float array to float *

What is the difference between float[] and float*?
Also, how can I convert a float array to float *? I need to get a float * and open it, then apply a filter and send it as a float * into my FFT method, but I don't know how to do it because I don't know the real difference between them.
An array usually is a pointer to the first member of the list. When using Array[Identifier], you are accessing to *(p+Identifier).
Making a new array will define a series of pointer next to another, which will make it's use way easier.
You can set your float array in the following ways:
float array1[100] = { 0 };
float *dataArray = (float*)malloc(sizeof(float) * 100);
float *pointerToFloatArray = array1;
These points all relate to C:
the name of an array can be decomposed — i.e. implicitly converted — to a pointer to its first element;
in an array, elements are stored contiguously;
the syntax a[8] is just shorthand for *(a + 8); and
adding n to a pointer, p, is defined to add n * sizeof(*p).
So an array differs from a pointer by being a semantically different thing. But you can supply the name of an array anywhere a pointer is required as it'll be converted.
Separately, you can also add an offset to any pointer using subscript syntax.
Objective-C is a strict superset of C. So these rules also apply to the use of the primitive types in Objective-C.
To understand the distinction, think in terms of mutability. The following is invalid:
char array[];
char value;
array = &value;
You can't reassign array. It is the name of an array. array itself is not mutable at runtime, only the things within it are. Conversely the following is valid:
char *pointer;
char value;
pointer = &value;
You can reassign pointer as often as you like. There's a mutable pointer and you can use it to point to anything.
You can use C-style arrays, like described in this answer: https://stackoverflow.com/a/26263070/3399208,
but better way - is using Objective-C containers and Objective-C objects, for example NSNumber * :
NSArray *array = [#1, #2, #3];
or
NSMutableArray *array = [NSMutableArray array];
NSNumber *number1 = [NSNumber numberWithFloat:20.f];
NSNumber *number2 = #(20.f);
[array addObject:number1];
[array addObject:number2];

NSData to primitive

I have NSData *data. It's value is 000e.
Hence decimal value is 14.
Now I want to get this value into primitive NSUInteger.
I've tried
NSUInteger *hereIWant14 = (NSUInteger *)data.bytes;
but *hereIWant14 value is 3584 what is e00 in hexa. Now I don't know if there is problem with endians or type size or my thinking is completely wrong and 000e and e00 similarity is just pure accident.
It's related to endianness. Use the conversion macros defined in Endian.h:
EndianU16_BtoN(value)
EndianU16_NtoB(value)
EndianS32_BtoN(value)
EndianS32_NtoB(value)
EndianU32_BtoN(value)
EndianU32_NtoB(value)
EndianS64_BtoN(value)
EndianS64_NtoB(value)
EndianU64_BtoN(value)
EndianU64_NtoB(value)
etc.
Method signatures mean:
Endian + U for unsigned S for signed + number of bits + N is native endianness of the system, L is little endian, B is big endian
So if you have an NSData with the content (0x00, 0xE0), and you'd like to interpret it as the value 14, then it contains the data in big endian order, therefore you'll have to use EndianU32_BtoN (of course, this macro is the identity transform on big-endian systems and swaps the bytes only on little-endian machines).
Important: to be future-proof, I'd recommend you to use something else instead of NSUInteger, since the width of this type can vary between different systems (e.g. Apple defines NSUInteger as 64 bit on arm64 systems). So, to be explicit about the number of bits, use uint32_t or uint64_t etc.
Edit: Usage for Big-Endian short value
NSMutableData * data = [[NSMutableData alloc] initWithLength:2];
((unsigned char *)data.mutableBytes)[0] = 0x00;
((unsigned char *)data.mutableBytes)[1] = 0x0E;
NSUInteger integer = NSSwapBigShortToHost(*(unsigned short *)data.mutableBytes);
NSLog(#"%d", integer); // prints 14
Yes, it's because of the endianess as said.
If you need down here two pieces of code to read from a NSData:
u_int16_t signature;
[data getBytes:&signature range:NSMakeRange(0, 2)];
signature = CFSwapInt16(signature);
Usually I use CFSwapInt16 or CFSwapInt32 (for u_int32_t). Otherwise if you have to read for example a string:
char charArray[length];
[data getBytes:charArray range:NSMakeRange(0, length)];
NSData* data = [NSData dataWithBytes:charArray length:length];
NSString* string = [[NSString alloc]initWithData:data encoding:NSStringEncodingConversionAllowLossy];
Hope it can help!

NSData Packet Interpretation

I have a fairly complex issue regarding the interpretation of packets in an app that I am making. A host app sends a packet to client apps with the following structure:
[Header of 10 bytes][peerID of selected client of variable byte length][empty byte][peerID of a client of variable byte length][empty byte][int of 4 bytes][peerID of client of variable byte length][empty byte][int of 4 bytes]
Here is a sample packet that is produced under this structure:
434e4c50 00000000 006a3134 31303837 34393634 00313233 38313638 35383900 000003e8 31343130 38373439 36340000 0003e8
Converted it looks like this:
CNLP j1410874964 1238168589 Ë1410874964 Ë
"CNLP j" is the packet header of 10 bytes. "1410874964" is the peerID of the selected client. "1238168589" is the peerID of another client. " Ë" has an int value of 1000. "1410874964" is the peerID of the other client (in this case, the selected client). " Ë" also has an int value of 1000. Basically, in this packet I am communicating 2 things - who the selected client is and the int value associated with each client.
My problem exists on the interpretation side (client side). To interpret this particular type of packet, I use the following method:
+ (NSMutableDictionary *)infoFromData:(NSData *)data atOffset:(size_t) offset
{
size_t count;
NSMutableDictionary *info = [NSMutableDictionary dictionaryWithCapacity:8];
while (offset < [data length])
{
NSString *peerID = [data cnl_stringAtOffset:offset bytesRead:&count];
offset += count;
NSNumber *number = [NSNumber numberWithInteger:[data cnl_int32AtOffset:offset]];
offset += 4;
[info setObject:number forKey:peerID];
}
return info;
}
Typically, each of these packets range between 49 and 51 bytes. "offset" is set in a previous method to reflect the byte number after the packet header plus the empty byte after the selected player (in the case of the above packet, 21). "count" is initialized with a value of 1. In the case of this particular example, length is 51. The following method is passed the above arguments:
- (NSString *)cnl_stringAtOffset:(size_t)offset bytesRead:(size_t *)amount
{
const char *charBytes = (const char *)[self bytes];
NSString *string = [NSString stringWithUTF8String:charBytes + offset];
*amount = strlen(charBytes + offset) + 1;
return string;
}
This method is supposed to read through a variable length string in the packet, set the offset to the byte immediately after the empty byte pad behind the peerID string, and return the string that was read. "amount" is then set to the number of bytes the method read through for the string (this is becomes the new value of count after returning to the first method). "offset" and "count" are then added together to become the new "offset" - where interpretation of the int portion of the packet will begin. The above arguments are passed to the following method:
- (int)cnl_int32AtOffset:(size_t)offset
{
const int *intBytes = (const int *)[self bytes];
return ntohl(intBytes[offset / 4]);
}
This method is intended to return the 32 bit (4 byte) int value read at the current offset value of the packet. I believe that the problem exists in this method when the offset is a number that is not divisible by 4. In this case, the first int value of 1000 was correctly interpreted, and 32 was returned as the offset during the first iteration of the while loop. However, during the second iteration, the int value interpreted was 909377536 (obtained from reading bytes 36340000 in the packet instead of bytes 000003E8) This was likely due to the fact that the offset during this iteration was set to 47 (not divisible by 4). After interpreting the 32 bit int in the category above, 4 is added to the offset in the first method to account for a 4 byte (32 bit int). If my intuition about an offset not divisible by zero is correct, any suggestions to get around this problem are greatly appreciated. I have been looking for a way to solve this problem for quite some time and perhaps fresh eyes may help. Thanks for any help!!!
The unportable version (undefined behaviour for many reasons):
return ntohl(*(const int *)([self bytes]+offset));
A semi-portable version is somewhat trickier, but in C99 it appears that you can assume int32_t is "the usual" two's complement representation (no trap representations, no padding bits), thus:
// The cast is necessary to prevent arithmetic on void* which is nonstandard.
const uint8_t * p = (const uint8_t *)[self bytes]+offset;
// The casts ensure the result type is big enough to hold the shifted value.
// We use uint32_t to prevent UB when shifting into the sign bit.
uint32_t n = ((uint32_t)p[0]<<24) | ((uint32_t)p[1]<<16) | ((uint32_t)p[2]<<8) | ((uint32_t)p[3]);
// Jump through some hoops to prevent UB on "negative" numbers.
// An equivalent to the third expression is -(int32_t)~n-1.
// A good compiler should be able to optimize this into nothing.
return (n <= INT32_MAX) ? (int32_t)n : -(int32_t)(UINT32_MAX-n)-1;
This won't work on architectures without 8-bit bytes, but such architectures probably have different conventions for how things are passed over the network.
A good compiler should be able to optimize this into a single (possibly byte-swapped) load on suitable architectures.

Resources