2012-11-21 1 views
5

Со ссылкой на следующий вопрос: Convert NSData into HEX NSSStringПреобразования NSData в Hex NSString

Я решил проблему с помощью раствора, представленного Эрик Айгнер, который:

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]]; 
} 

Тем не менее, есть одна маленькая проблема что, если на задней стороне есть дополнительные нули, значение строки будет отличаться. Напр. если данные гекса имеет строку @ «3700000000000000», когда преобразуется с помощью сканера в целое:

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

Результат будет 4294967295, что неправильно. Разве это не должно быть 55, поскольку принимается только гекса 37?

Итак, как мне избавиться от нулей?

EDIT: (В ответ на CRD)

Привет, спасибо за разъяснения моих сомнений. Итак, что вы делаете, это действительно прочитать 64-битное целое прямо из указателя байтов? Однако у меня есть другой вопрос. Как вы на самом деле бросаете NSData в указатель байтов?

Чтобы вам было легче понять, я объясню, что я сделал изначально.

Во-первых, то, что я сделал, чтобы отобразить данные файла, которые у меня есть (данные в шестнадцатеричном формате)

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

Выход:

enter image description here

Далее, что я сделал читать и смещать первые 8 байтов файла и преобразовывать их в строку.

// 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); 

Как видите, 0x3700000000000000 является следующим 8 байтами. Единственные изменения, которые я должен был бы сделать для доступа к следующим 8 байтам, - это изменить значение SeekFileToOffset на 8, чтобы получить доступ к следующим 8 байтам данных.

В общем, решение, которое вы мне дали, полезно, однако было бы нецелесообразно вводить шестнадцатеричные значения вручную. Если форматирование байтов как строки и затем их разбор не является способом сделать это, то как мне получить доступ к первым 8 байтам данных напрямую и передать их в указатель байтов?

+0

Это чрезвычайно медленная реализация. Сначала форматируйте в буфер, а затем конвертируйте в 'NSString'. – trojanfoe

ответ

3

Кажется, вы пытаетесь преобразовать 8 байтов, хранящихся в NSData в 64-битовое целое число (8 байт в 0x3700000000000000).

Если это ваша цель, то сделайте это, отформатировав байты в виде строки, а затем разобрав их, это не способ сделать это. Вам нужно выяснить, какой формат (то есть самый младший или самый старший байт), в котором находятся ваши данные, а затем использовать соответствующие функции преобразования endian.

Кстати, причина, по которой вы получаете 4294967295 (0xFFFFFFFF), - это то, что вы просите NSScanner прочитать 32-разрядное целое число и ваш номер (0x3700000000000000).

Ответ на комментарий

Поскольку х86 прямой порядок байтов вы можете прочитать немного-Endian 64-разрядное целое число прямо из указателя байта, только литье:

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

Если вам нужно для чтения данных в формате big-endian, вы можете использовать функцию преобразования endian, такую ​​как Endian64_Swap, - которая просто переворачивает то, что у вас есть, поэтому читайте, затем переводите.

Обратите внимание на то, что для x86 не требуется , для доступа к данным требуется, но он будет работать лучше, если это так.

+0

Это то, чего я пытаюсь достичь. Я уже пробовал инициализировать строку, используя NSData с NSUTF16LittleEndianStringEncoding, но это дало мне 7. Однако, прочитав ваш ответ и обратившись за советом извне, я понял, что этот способ сделать это ошибочен и совершенно ошибочен. Любая идея о том, как узнать, какой формат в формате endian используется перед преобразованием? – Dawson

+0

@ Dawson - Существует способ действительно определить формат endian, вы можете догадаться, основываясь на значениях, но вы бы не знали *. Поэтому, если вы не знаете диапазон ожидаемых значений, вам нужно найти ответ от того, кто производит данные. – CRD

+0

Предполагая, что данные имеют малоформатный формат. Какие подходящие функции преобразования я мог бы использовать для преобразования (0x3700000000000000) в 64-разрядное целое число, которое в этом случае равно 55? Из того, что я знаю, NSScanner, похоже, не имеет соответствующей функции для этого. – Dawson

3

4,294,967,295 - ULONG_MAX, поэтому кажется, что сканер просто переполняется. (Метод scanHexInt ест все шестнадцатеричные цифры, которые он находит, а так как нуль также является шестнадцатеричной цифрой, метод перекрывает все число, пройдя ULONG_MAX.)

+0

проблема связана с самым значительным и наименее значимым битом. Если я использую маленькую кодировку endian, строка, скорее всего, займет всего 37 и игнорирует нули позади. Но как мне это достичь? – Dawson

+0

Что вы действительно пытаетесь сделать, с точки зрения высокого уровня? – zoul

+0

Я пытаюсь преобразовать 8 байтов в 64-битное целое число, но я не уверен, что это подходящий способ сделать это. Похоже, мой метод достижения этого неверен. Поэтому я ищу совета. – Dawson