Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert NSData into Hex NSString

With reference to the following question: Convert NSData into HEX NSString

I have solved the problem using the solution provided by Erik Aigner which is:

NSData *data = ...;
NSUInteger capacity = [data length] * 2;
NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:capacity];
const unsigned char *dataBuffer = [data bytes];
NSInteger i;
for (i=0; i<[data length]; ++i) {
  [stringBuffer appendFormat:@"%02X", (NSUInteger)dataBuffer[i]];
}

However, there is one small problem in that if there are extra zeros at the back, the string value would be different. For eg. if the hexa data is of a string @"3700000000000000", when converted using a scanner to integer:

unsigned result = 0;
NSScanner *scanner = [NSScanner scannerWithString:stringBuffer];
[scanner scanHexInt:&result];
NSLog(@"INTEGER: %u",result);

The result would be 4294967295, which is incorrect. Shouldn't it be 55 as only the hexa 37 is taken?

So how do I get rid of the zeros?

EDIT: (In response to CRD)

Hi, thanks for clarifying my doubts. So what you're doing is to actually read the 64-bit integer directly from a byte pointer right? However I have another question. How do you actually cast NSData to a byte pointer?

To make it easier for you to understand, I'll explain what I did originally.

First, I displayed the data of the file I have (data is in hexadecimal)

NSData *file = [NSData dataWithContentsOfFile:@"file path here"];
NSLog(@"Patch File: %@",file);

Output:

enter image description here

Next, I read and offset the first 8 bytes of the file and converted them into a string.

// 0-8 bytes
[file seekToFileOffset:0];
NSData *b = [file readDataOfLength:8];
NSUInteger capacity = [b length] * 2;
NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:capacity];
const unsigned char *dataBuffer = [b bytes];
NSInteger i;
for (i=0; i<[b length]; ++i) {
    [stringBuffer appendFormat:@"%02X", (NSUInteger)dataBuffer[i]];
}
NSLog(@"0-8 bytes HEXADECIMAL: %@",stringBuffer);

As you can see, 0x3700000000000000 is the next 8 bytes. The only changes I would have to make to access the next 8 bytes would be to change the value of SeekFileToOffset to 8, so as to access the next 8 bytes of data.

All in all, the solution you gave me is useful, however it would not be practical to enter the hexadecimal values manually. If formatting the bytes as a string and then parsing them is not the way to do it, then how do I access the first 8 bytes of the data directly and cast them into a byte pointer?

like image 576
Dawson Avatar asked Nov 21 '12 08:11

Dawson


2 Answers

You appear to be trying to convert 8 bytes stored in an NSData into an 64-bit integer (there are 8 bytes in 0x3700000000000000).

If this is your goal then doing it by formatting the bytes as a string and then parsing them is not the way to do it. You need to find out what endian format (i.e. least or most significant byte first) your data is in and then use the appropriate endian conversion functions.

BTW the reason why you're getting 4294967295 (0xFFFFFFFF) is because you are asking the NSScanner to read a 32-bit integer and your number (0x3700000000000000) overflows.

Response to comment

As the x86 is little-endian you can read a little-endian 64-bit integer direct from a byte pointer by just casting:

Byte bytes[] = { 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
NSLog(@"%lld", *(int64_t *)bytes);

If you need to read big-endian data then you can use an endian conversion function such as Endian64_Swap - which just flips what you have, so read then flip.

Note that the x86 does not require data access to be aligned, but will perform better if it is.

like image 139
CRD Avatar answered Sep 22 '22 04:09

CRD


4,294,967,295 is ULONG_MAX, so it appears that the scanner simply overflows. (The scanHexInt method eats all the hexa digits it finds, and since zero is a hexa digit, too, the method slurps the whole number, getting past ULONG_MAX.)

like image 37
zoul Avatar answered Sep 18 '22 04:09

zoul