4

I have an NSString that has hex information such as

<00000020 66747970 4d344120 00000000 4d344120 6d703432 69736f6d 00000000 00031203

which came from NSData. What I need to do is convert that NSString of Hex data to Ascii which would be:

[0][0][0] ftypM4A [0][0][0][0]M4A mp42isom[0][0][0][0][0][3][18][3] 

As you might be able to tell this is a M4A file. I loaded the first part of the file in to NSData using NSFileHandle. I then stored it into NSString:

NSData *data = [filehandle readDataOfLength:1000];
NSString *str = [[NSString alloc]initWithString:[NSString stringWithFormat:@"%@",data]];

Anyone know how to convert NSData directly or convert the NSString to ascii? Thanks!

broccolifarmer
  • 465
  • 7
  • 15
  • why don't you try to write an algorithm to achieve it...? – holex Mar 07 '13 at 16:38
  • You are doing it wrong. Don't convert data to string and then attempt to extract string fragments from it. Extract the fragments directly from the data. – trojanfoe Mar 07 '13 at 16:38
  • Yeah - I have looked at the above but could not get it to work correctly and I guess I kind of wanted an Objective-C way of doing it, not including C. I guess I don't have the know how to write the algorithm to accomplish it. – broccolifarmer Mar 07 '13 at 16:45
  • Oh - and I would like to do it directly from the date - but again, not sure how to do it. Basically - what I am looking for is similar to doing a cat -v on a non text file. Thanks again for your comments so far! – broccolifarmer Mar 07 '13 at 16:46
  • What about `[[NSString alloc] initWithBytes:data.bytes length:data.length encoding:NSASCIIStringEncoding]`? – zneak Mar 07 '13 at 16:47
  • If you want to replace non-printable characters with printed characters, you should probably use a `NSMutableString` and iterate over the bytes in `data`, adding them as characters if they're `>= 0x20` or adding them with the format string `[%hhu]` otherwise. – zneak Mar 07 '13 at 16:51

1 Answers1

8

you should have done something like this:

NSData *_data = // ... whatever
NSMutableString *_string = [NSMutableString stringWithString:@""];
for (int i = 0; i < _data.length; i++) {
    unsigned char _byte;
    [_data getBytes:&_byte range:NSMakeRange(i, 1)];
    if (_byte >= 32 && _byte < 127) {
        [_string appendFormat:@"%c", _byte];
    } else {
        [_string appendFormat:@"[%d]", _byte];
    }
}
NSLog(@"%@", _string);
holex
  • 23,961
  • 7
  • 62
  • 76
  • 1
    Worked perfect! Exactly what I wanted it to do! Thanks – broccolifarmer Mar 07 '13 at 17:04
  • Yeah - I guess I just have very limited understanding of bytes and how they are stored. Meaning - I don't understand how %c is converting 32-127 ascii codes. And I didn't understand how to read data bit by bit. I am going to try to read up on this. I googled my life away for a couple hours - and you completed in two minutes. Always makes me feel stupid! – broccolifarmer Mar 07 '13 at 17:54
  • I'm sorry, I didn't want you to feel this. You just looked very keen, and I was like "it was not too hard question, but I was happy to help". :) – holex Mar 07 '13 at 19:35
  • 2
    here are some explanation. the `%c` formatter means only one `ASCII` character as it is, the `%d` formatter is just a normal integer value, and the `_byte` is the current byte in the data. so, the logic is if I found a presentable `ASCII` char (the range is `32` to `126`), I put the character in the output string, otherwise I put the decimal code in brackets... and I do the same procedure for all byte in the data. – holex Mar 07 '13 at 19:44
  • Thanks for that! My last question is, How did you know the byte would return an ascii code such as 32-127 and not hex, binary or some other equivalent? Also - how did you know to use unsigned char for _byte instead of int. Sorry - just trying to learn! – broccolifarmer Mar 08 '13 at 14:03
  • 1
    it strongly depends on the output you wanted, because you wanted to manage the data byte-by-byte, the `char` is perfect here because it stores 8 bits (no more!), which is a byte exactly. we don't here any negative numbers, so I'm using the `unsigned` modifier. what the `char` stores is just a number, I'll decide how I want to use it. if it is between the valid `ASCII` range, I'm using it as character (`%c`), otherwise I'm using the same `char` value like a simple number (`%d`). – holex Mar 08 '13 at 15:56
  • 1
    we read one byte in the loop in each iteration step, which is 8 bits only, the `int` is 32 bits (currently). we could store 8 bits in 32 bits, just we have to init the variable like `int _byte = 0;`, otherwise the rest 24 bit will contain what the memory segment has, and it probably mess our value up. (note: the `-getBytes:range:` fill up only 8 bits!) so, choosing `char` was just my decision, to avoid the possible mistakes here. instead of the `char`, I could have used `BOOL` as well which is highly illogical, but technically works because the `BOOL` values are also stored on 8 bits. tricky. – holex Mar 08 '13 at 16:05
  • Awesome - Thanks for your help. Makes perfect sense! – broccolifarmer Mar 08 '13 at 16:08