Objective-C Equivalent to string.unpack('N') in Ruby - objective-c

I am trying to convert a string to a 32-bit unsigned, network (big-endian) byte order. I can't seem to figure out how to do this. In Ruby I accomplish this by string.unpack('N') - but can't seem how to manage this in Objective-C. Any suggestions? Thanks!

In Objective-C you would convert NSString to NSData. Then you can access the bytes from the NSData object.
NSString *str = #"😄 H€llö Wòrld";
NSData *data = [str dataUsingEncoding:NSUTF32BigEndianStringEncoding];
NSLog(#"%#", data);
// Output:
// <0001f604 00000020 00000048 000020ac 0000006c 0000006c 000000f6 00000020 00000057 000000f2 00000072 0000006c 00000064>
const uint8_t *bytes = [data bytes]; // pointer to converted bytes
NSUInteger length = [data length]; // number of converted bytes

Related

Reading ASCII file byte by byte in Objective C

I have a ASCII file which I want to read byte by byte into a Byte buffer. I am clueless and confused between many aspects. Can anyone guide me with the correct way to do it?
Any help is appreciated.
I finaly got the answer here. So what I did is,
NSMutableString *bundlePath = [NSMutableString stringWithString:
[[NSBundle mainBundle]pathForResource:#"excercise1" ofType:nil]];
NSData *myData = [NSData dataWithContentsOfFile:bundlePath];
uint8_t * bytePtr = (uint8_t * )[myData bytes];
NSInteger totalData = [myData length] / sizeof(uint8_t);
NSLog(#"Data byte chunk: ");
for (int i = 0 ; i < totalData; i ++)
{
NSLog(#" %x", bytePtr[i]);
}
and it worked as I wanted it to be. I got the bytes in an array.

objective c hmac sha 256 gives wrong nsdata output

So finally figured out how to do an hmac sha 256 hashing. I will be using this for a wcf service api i made. My problem is that the NSData output that my method is sending out have spaces.
eg. This is how it looks like what my API sends out
"2efb00aba01a3f5b674fba3063b43fee7a9356947118......"
And this is how my iphone app shows it
<2efb00ab a01a3f5b 674fba30.....>
This is how my code in objective c looks like:
NSData *hmacSHA256(NSString *key, NSString *data)
{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
return [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
}
This came from this answer:
https://stackoverflow.com/a/8459123/639713
Anyway, my issue is, how do I deal with this. How do I convert the NSdata output to string? And if does get converted to string I'm guessing the output will be different from what the WCF Service API sends out. Do I change how the API processes it's hmacsha256 output?
Thanks!
You could modify your method slightly so that instead of creating an NSData containing the digest bytes, you could create a string formatting the bytes as hexadecimal.
NSString *hmacSHA256(NSString *key, NSString *data)
{
const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
NSMutableString *result = [NSMutableString string];
for (int i = 0; i < sizeof cHMAC, i++)
{
[result appendFormat:#"%02hhx", cHMAC[i]];
}
return result;
}
<2efb00ab a01a3f5b 674fba30.....> looks like the result of calling -[NSData description], like NSLog would do for any %# format strings. The NSData itself represents a sequence of bytes. The output you're after appears to be the byte sequence as a hexidecimal string. See Best way to serialize an NSData into a hexadeximal string for how to serialize the NSData to that format.

Null result on Converting NSData to NSString

I am facing a problem when converting NSData to NSString. I'm using UTF8Enconding but the result is null!!
Here is the data I receive <100226ab c0a8010b 00000000 00000000> it must be either 192.168.1.11 or 192.168.1.17.
This is the method I use to convert :
NSString *ipAddress = [[NSString alloc] initWithData:address encoding:NSUTF8StringEncoding];
Is there anything wrong?!
By the way, This the did receive data delegate of GCDAsyncUdpSocket library.
From the documentation of GCDAsyncUdpSocket:
The localAddress method returns a sockaddr structure wrapped in a
NSData object.
The following code unwraps the data to a sockaddr structure and converts the IP address to a NSString. It works with IPv4 and IPv6 addresses.
#include <sys/socket.h>
#include <netdb.h>
NSData *data = ...; // your data
NSLog(#"data = %#", data);
// Copy data to a "sockaddr_storage" structure.
struct sockaddr_storage sa;
socklen_t salen = sizeof(sa);
[data getBytes:&sa length:salen];
// Get host from socket address as C string:
char host[NI_MAXHOST];
getnameinfo((struct sockaddr *)&sa, salen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
// Convert C string to NSString:
NSString *ipAddress = [[NSString alloc] initWithBytes:host length:strlen(host) encoding:NSUTF8StringEncoding];
NSLog(#"strAddr = %#", ipAddress);
Output:
data = <100226ab c0a8010b 00000000 00000000>
strAddr = 192.168.1.11
This is not a string response. This is binary data. If you consider <100226ab c0a8010b 00000000 00000000>, look at the coa8010b: c0 in hex is equal to 192 in decimal, a8 = 168, 01 = 1, and 0b = 11. In short, this is a binary representation, not a string representation, of 192.168.1.11.
You may want to more carefully examine the GCDAsyncUdpSocket documentation for the nature of response you should get, as it's apparently binary data, not a string.
I guess there is problem with the encoding . I have also faced similar issue and solved by:
NSString *responseString =[[NSString alloc] initWithBytes:[data bytes] length:[data length] encoding:NSUnicodeStringEncoding];
Found a much quicker way to do it, using inet_ntoa():
//Get the bytes from the data and cast it to the correct struct
struct sockaddr_in *addr = (struct sockaddr_in *)[address bytes];
//inet_ntoa converts from the binary format to a C string
NSString *IP = [NSString stringWithCString:inet_ntoa(addr->sin_addr) encoding:NSASCIIStringEncoding];
First try with other encoding formats available
1. NSASCIIStringEncoding
2. NSMacOSRomanStringEncoding
3. NSShiftJISStringEncoding.
even if it not works,try like the following ways
1. NSData *data = [NSData dataWithContentsOfURL:URL];
// Assuming data is in UTF8.
NSString *string = [NSString stringWithUTF8String:[data bytes]];
2. This is like as you done.
// if data is in another encoding, for example ISO-8859-1
NSString *string = [[NSString alloc]
initWithData:data encoding: NSISOLatin1StringEncoding];

Obj-C How to convert NSData to an array of ints?

I have a NSData item that is holding a bunch of ints. How do I go about getting them out and into an NSArray?
The memory structure in the NSData is 32-bit int in little-endian order, one right after the other.
Sorry for the basic question, but still learning the obj-c way of doing things :)
You can use the functions defined in OSByteOrder.h to deal with endianness. Aside from that quirk, this is really just a matter of grabbing the byte buffer and iterating over it.
// returns an NSArray containing NSNumbers from an NSData
// the NSData contains a series of 32-bit little-endian ints
NSArray *arrayFromData(NSData *data) {
void *bytes = [data bytes];
NSMutableArray *ary = [NSMutableArray array];
for (NSUInteger i = 0; i < [data length]; i += sizeof(int32_t)) {
int32_t elem = OSReadLittleInt32(bytes, i);
[ary addObject:[NSNumber numberWithInt:elem]];
}
return ary;
}
Sounds like there are cleaner ways to do what you're trying to do, but this should work:
NSData *data = ...; // Initialized earlier
int *values = [data bytes], cnt = [data length]/sizeof(int);
for (int i = 0; i < cnt; ++i)
NSLog(#"%d\n", values[i]);
This answer is very similar to other answers above, but I found it instructive to play with casting the NSData bytes back to an int32_t[] array. This code works correctly on a little-endian processor (x64 in my case) but would be silently wrong on big-endian (PPC) because the byte representation would be big-endian.
int32_t raw_data[] = {0,1,2,3,4,5,6,7,8,9,10};
printf("raw_data has %d elements\n", sizeof(raw_data)/sizeof(*raw_data));
NSData *data = [NSData dataWithBytes:(void*)raw_data length:sizeof(raw_data)];
printf("data has %d bytes\n", [data length]);
int32_t *int_data_out = (int32_t*) [data bytes];
for (int i=0; i<[data length]/4; ++i)
printf("int %d = %d\n", i, int_data_out[i]);
[data release];
One possible solution below.
To take endianness into account, look up Core Endian Reference in the XCode doc set (you probably would use EndianS32_LtoN (32 bit litte endian to native endianness)).
int mem[]= {0x01, 0x02, 0x03, 0x04, 0xff};
NSData * data = [NSData dataWithBytes:mem length:sizeof(mem)*sizeof(int)];
NSMutableArray * ar = [NSMutableArray arrayWithCapacity:10];
/* read ints out of the data and add them to the array, one at a time */
int idx=0;
for(;idx<[data length]/sizeof(int);idx+=sizeof(int))
[ar addObject:[NSNumber numberWithInt:*(int *)([data bytes] + idx)]];
NSLog(#"Array:%#", ar);

how convert [NSData length] to a NSData

ex:
NSData *data = [NSData dataWithContentsOfFile:filePath];
int len = [data length];
if len = 10000,
i hope i can convert 1000 to a NSData look like
char hoperesult[] = {0x10, 0x27, 0x00, 0x00}
and hoperesult[] must always 4 Bytes
So you want the length in 4 little-endian bytes, correct? I think this will do it:
unsigned int len = [data length];
uint32_t little = (uint32_t)NSSwapHostIntToLittle(len);
NSData *byteData = [NSData dataWithBytes:&little length:4];
(Note that most network protocols use big-endian, but you showed little-endian so that's what this does.)
I'm not 100% sure what you mean here, but I think you are attempting to fill hoperesult with the values found in the file at 'filePath'.
struct _hoperesult {
char data[4];
} *hoperesult;
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSUInteger len = [data length];
NSRange offset;
offset.location = 0;
offset.length = sizeof(_hoperesult);
NSData *hoperesultData;
while( (offset.location + offset.length) < len ) {
hoperesultData = [data subdataWithRange:offset];
// the equivalent of your char hoperesult[] content...
hoperesult = [hoperesultData bytes]
}
An instance of NSData can return a pointer to the actual bytes of data using the "bytes" method. It returns a (const void *). You could in theory simply cast [data bytes] to a char * and use the offset directly; or you can do like in the above code and return smaller chucks of NSData.
Hope that helps!