Converting HEX NSString To NSData

27,311

Solution 1

NSString *command = @"72ff63cea198b3edba8f7e0c23acc345050187a0cde5a9872cbab091ab73e553";

command = [command stringByReplacingOccurrencesOfString:@" " withString:@""];
NSMutableData *commandToSend= [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < [command length]/2; i++) {
    byte_chars[0] = [command characterAtIndex:i*2];
    byte_chars[1] = [command characterAtIndex:i*2+1];
    whole_byte = strtol(byte_chars, NULL, 16);
    [commandToSend appendBytes:&whole_byte length:1]; 
}
NSLog(@"%@", commandToSend);

Solution 2

Here is another method that also handles leading <, trailing > and embedded spaces such as

<9dc69faf a7434ba9 aef57f5c 365d571f 4c3753c4 ae13db42 57d184ca e00246c5>

Code:

+ (NSData *)dataFromHexString:(NSString *)string
{
    string = [string lowercaseString];
    NSMutableData *data= [NSMutableData new];
    unsigned char whole_byte;
    char byte_chars[3] = {'\0','\0','\0'};
    int i = 0;
    int length = string.length;
    while (i < length-1) {
        char c = [string characterAtIndex:i++];
        if (c < '0' || (c > '9' && c < 'a') || c > 'f')
            continue;
        byte_chars[0] = c;
        byte_chars[1] = [string characterAtIndex:i++];
        whole_byte = strtol(byte_chars, NULL, 16);
        [data appendBytes:&whole_byte length:1];
    }
    return data;
}

This is based on the answer by @Nikunj R. Jadav

Solution 3

This might be more useful, Apple has shared a NSData category.

NSData+HexString.m

The code is:

@implementation NSData (HexString)

// Not efficent
+(id)dataWithHexString:(NSString *)hex
{
    char buf[3];
    buf[2] = '\0';
    NSAssert(0 == [hex length] % 2, @"Hex strings should have an even number of digits (%@)", hex);
    unsigned char *bytes = malloc([hex length]/2);
    unsigned char *bp = bytes;
    for (CFIndex i = 0; i < [hex length]; i += 2) {
        buf[0] = [hex characterAtIndex:i];
        buf[1] = [hex characterAtIndex:i+1];
        char *b2 = NULL;
        *bp++ = strtol(buf, &b2, 16);
        NSAssert(b2 == buf + 2, @"String should be all hex digits: %@ (bad digit around %d)", hex, i);
    }

    return [NSData dataWithBytesNoCopy:bytes length:[hex length]/2 freeWhenDone:YES];
}

@end

Solution 4

I see several solution have been post only able to convert string with even length.

So here is my solution which also able return correct data if the string is odd length like this "DBA" became data like this this "\x0D\xBA"

+ (NSData *)dataFromHexString:(NSString *) string {
    if([string length] % 2 == 1){
        string = [@"0"stringByAppendingString:string];
    }

    const char *chars = [string UTF8String];
    int i = 0, len = (int)[string length];

    NSMutableData *data = [NSMutableData dataWithCapacity:len / 2];
    char byteChars[3] = {'\0','\0','\0'};
    unsigned long wholeByte;

    while (i < len) {
        byteChars[0] = chars[i++];
        byteChars[1] = chars[i++];
        wholeByte = strtoul(byteChars, NULL, 16);
        [data appendBytes:&wholeByte length:1];
    }
    return data;

}
Share:
27,311
Pranav Jaiswal
Author by

Pranav Jaiswal

Senior software engineer specialized in app development for iOS. Writing, debugging, optimizing, and architecting the code that powers the apps we love to use is what I do all day. My ability to communicate complex concepts, to come up with best-of-breed solutions, and execute these solutions in time to strategic problems are someone things that can bring immediate value and impact in the shortest period of time to a project. I have proven ability to drive a project from ground-up to completion and get software shipped. #SOreadytohelp

Updated on July 09, 2022

Comments

  • Pranav Jaiswal
    Pranav Jaiswal almost 2 years

    I'm trying to convert a Hex NSString to NSData (I'm using the below attached code). The following is the output:

    <00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000>
    

    which looks totally irrelevant to me. Any idea/ suggestions on where its going wrong?

    NSString *strData = @"72ff63cea198b3edba8f7e0c23acc345050187a0cde5a9872cbab091ab73e553";
    
    NSLog(@"string Data length is %d",[strData length]);
    
    NSMutableData *commandToSend= [[NSMutableData alloc] init];
    unsigned char whole_byte;
    char byte_chars[2];
    int i;
    for (i=0; i < [strData length]/2; i++) {
    
        byte_chars[0] = [strData characterAtIndex:i*2];
        byte_chars[1] = [strData characterAtIndex:i*2+1];
        whole_byte = strtol(byte_chars, NULL, [strData length]);
        [commandToSend appendBytes:&whole_byte length:1]; 
    }
    NSLog(@"%@", commandToSend);    
    
    • Praveen S
      Praveen S over 12 years
      Should you not pass 16 to strtol?
  • Pranav Jaiswal
    Pranav Jaiswal over 12 years
    what's the output that you are getting?
  • Nikunj Jadav
    Nikunj Jadav over 12 years
    its returns <72ff63ce a198b3ed ba8f7e0c 23acc345 050187a0 cde5a987 2cbab091 ab73e553>
  • Pranav Jaiswal
    Pranav Jaiswal over 12 years
    one more ques whole_byte = strtol(byte_chars, NULL, 16); why the third param is passed as 16 Constant?
  • MikeS
    MikeS over 10 years
    Nice answer. Useful for converting NSData deviceToken descriptions back into NSData.
  • Moxarth
    Moxarth over 6 years
    it looks like in answer we are getting the same answer as what we have given string to convert . ? but how to convert that string data into informative one ? i mean after scanning for BLE device , i got the advertisement data like ` kCBAdvDataManufacturerData = <ffff0215 e84a40af 7b8de88d 4a7b40af afe84a40 40af7b8d c3>; ` this . so now from this , how to convert ,in order to access its data . i supposed to find out Major Minor TxPower from this given data ,. how can we do this ? @NikunjJadav
  • Moxarth
    Moxarth over 6 years
    @NikunjJadav even i have raised the question for this [stackoverflow.com/questions/45854508/… . please look into it and guide me through it . thanks .
  • Benny Davidovitz
    Benny Davidovitz over 5 years
    memory dynamically allocated by call to malloc() at ... is not reachable after line .... > return [NSData dataWithBytesNoCopy:bytes length:[hex length]/2 freeWhenDone:YES];