2012-11-21 10 views
5

Con riferimento alla seguente domanda: Convert NSData into HEX NSSStringConversione NSData in Hex NSString

Ho risolto il problema utilizzando la soluzione fornita da Erik Aigner che è:

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

Tuttavia, c'è un piccolo problema che se ci sono degli zeri in più sul retro, il valore della stringa sarebbe diverso. Per es. se i dati hexa è una stringa @ "3.700.000 miliardi", quando convertiti usando uno scanner a intero:

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

Il risultato sarebbe 4294967295, che non è corretto. Non dovrebbe essere 55 come viene preso solo l'hexa 37?

Quindi, come faccio a sbarazzarmi degli zeri?

EDIT: (In risposta alla CRD)

Ciao, grazie per chiarire i miei dubbi. Quindi quello che stai facendo è in realtà leggere il numero intero a 64 bit direttamente da un puntatore a byte giusto? Comunque ho un'altra domanda. Come si esegue effettivamente il cast di NSData su un puntatore a byte?

Per semplificare la comprensione, spiegherò cosa ho fatto in origine.

In primo luogo, quello che ho fatto è stato per visualizzare i dati del file che ho (i dati sono in formato esadecimale)

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

uscita:

enter image description here

successivo, quello che ho fatto è stato leggere e compensare i primi 8 byte del file e convertirli in una stringa.

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

Come si può vedere, 0x3700000000000000 è il successivo 8 byte. Le uniche modifiche che avrei dovuto fare per accedere ai successivi 8 byte sarebbe quello di cambiare il valore di SeekFileToOffset a 8, in modo da accedere ai successivi 8 byte di dati.

Tutto sommato, la soluzione che mi hai dato è utile, tuttavia non sarebbe pratico inserire manualmente i valori esadecimali. Se la formattazione dei byte come una stringa e quindi l'analisi non è il modo per farlo, allora come posso accedere direttamente ai primi 8 byte dei dati e convertirli in un puntatore a byte?

+0

Questa è un'implementazione estremamente lenta. Formattare prima in un buffer e poi convertire in 'NSString'. – trojanfoe

risposta

3

in cui sembra essere cercare di convertire 8 byte memorizzati in un NSData in un numero intero a 64 bit (ci sono 8 byte in 0x3700000000000000).

Se questo è il tuo obiettivo, fallo formattando i byte come stringa e quindi analizzandoli è non il modo per farlo. È necessario scoprire quale sia il formato endian (vale a dire prima o il byte più significativo) in cui si trovano i dati e quindi utilizzare le funzioni di conversione endian appropriate.

BTW il motivo che stai ricevendo 4294967295 (0xFFFFFFFF) è perché si sta ponendo la NSScanner di leggere un intero a 32 bit e il numero (0x3700000000000000) overflow.

risposta al commento

Mentre il 86 è little-endian è possibile leggere un integer a 64 bit little-endian diretta da un puntatore di byte semplicemente fusione:

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

Se avete bisogno per leggere i dati big-endian, puoi utilizzare una funzione di conversione endian come Endian64_Swap, che capovolge ciò che hai, quindi leggi quindi capovolgi.

Si noti che l'x86 non richiede l'accesso ai dati da allineare, ma funzionerà meglio se lo è.

+0

Questo è quello che sto cercando di ottenere. In precedenza ho provato a inizializzare la stringa usando NSData con NSUTF16LittleEndianStringEncoding, ma mi ha dato 7. Tuttavia, dopo aver letto la tua risposta e aver cercato un consiglio esternamente, mi sono reso conto che questo modo di procedere è errato e completamente sbagliato. Qualche idea su come scoprire in che formato Endian sono i miei dati prima di convertirli? – Dawson

+0

@Dawson - C'è un modo per determinare realmente il formato di endian, è possibile indovinare in base ai valori ma non si dovrebbe * sapere *. Quindi, a meno che non si conosca l'intervallo di valori atteso, è necessario trovare la risposta da chiunque stia producendo i dati. – CRD

+0

Supponendo che i dati siano di formato little endian. Quali sono le funzioni di conversione appropriate che posso utilizzare per convertire (0x3700000000000000) in un numero intero a 64 bit, che in questo caso è 55? Da quello che so, NSScanner non sembra avere una funzione appropriata per questo. – Dawson

3

4,294,967,295 è ULONG_MAX, quindi sembra che lo scanner trabocchi semplicemente. (Il metodo scanHexInt mangia tutte le cifre hexa che trova, e dal momento che lo zero è una cifra hexa, anche, il metodo recupera l'intero numero, ottenere passato ULONG_MAX.)

+0

il problema sembra essere il più significativo e il meno significativo. Se utilizzo la codifica little endian, la stringa molto probabilmente prenderà solo 37 e ignorerà gli zeri. Ma come faccio a raggiungere questo? – Dawson

+0

Cosa stai cercando di fare, dalla visualizzazione di alto livello? – zoul

+0

Sto provando a convertire 8 byte in un numero intero a 64 bit, ma non sono sicuro di quale sia il modo appropriato per farlo. Sembra che il mio metodo per ottenere questo risultato sia sbagliato. Quindi, sto cercando un consiglio. – Dawson