Hex string to NSString - objective-c

I have an hex string coming from server, I have to convert that hex string to NSString. I used some of the methods found in this post How to convert an NSString to hex values
I almost got the same text except that Ú appear randomly in some place.
I've change Ú into bold text to be easy to find in the following example.
Can you guys help me what's wrong with the algorithm.
My algorithm
- (NSString *) stringFromHex:(NSString *)str
{
NSMutableData *stringData = [[NSMutableData alloc] init];
unsigned char whole_byte;
char byte_chars[3] = {'\0','\0','\0'};
int i;
for (i=0; i < [str length] / 2; i++) {
byte_chars[0] = [str characterAtIndex:i*2];
byte_chars[1] = [str characterAtIndex:i*2+1];
whole_byte = strtol(byte_chars, NULL, 16);
[stringData appendBytes:&whole_byte length:1];
}
return [[NSString alloc] initWithData:stringData encoding:NSASCIIStringEncoding];
}
Hex string from server
7539686132564968635943666c6348532f564a656261736b526a47585a75734a625a61316c5753475a645575625a5253386f473574347678694c4930695648704c52473170547a4f6b356552da554675394e58672b6943743857524637557748755961634435306936437a7a535a726d6e53664e6e523862433232594a4f593638655464314c6747324763544f56357a736f544c49734e734ada672f77472f6b6b4b48446c644659426d51334d3dda
Normal string from server which is RSA encoded string
u9ha2VIhcYCflcHS/VJebaskRjGXZusJbZa1lWSGZdUubZRS8oG5t4vxiLI0iVHpLRG1pTzOk5eR
UFu9NXg+iCt8WRF7UwHuYacD50i6CzzSZrmnSfNnR8bC22YJOY68eTd1LgG2GcTOV5zsoTLIsNsJ
g/wG/kkKHDldFYBmQ3M=
Normal string converted using my above algorithm
u9ha2VIhcYCflcHS/VJebaskRjGXZusJbZa1lWSGZdUubZRS8oG5t4vxiLI0iVHpLRG1pTzOk5eRÚUFu9NXg+iCt8WRF7UwHuYacD50i6CzzSZrmnSfNnR8bC22YJOY68eTd1LgG2GcTOV5zsoTLIsNsJÚg/wG/kkKHDldFYBmQ3M=Ú

The server seems to convert DA to a space, probably because DA lies outside the ASCII range, which only runs up to 7A due to it using only 7 bits.
The algorithm converts DA to Ú, which seems to be ok when using Latin-1 encoding. Using a different encoding from the list here, such as NSUTF8StringEncoding, might help.

Related

ObjC / iOS: How to retrieve unicode hex code for character?

So, I know how to convert a unicode hex code into an NSString consisting of the unicode character referenced by that code:
NSString *ucStr = #"\\u004A"; // hex code for capital J
NSString *theLetter = [ucStr mutableCopy];
CFStringRef transform = CFSTR("Any-Hex/Java");
CFStringTransform((__bridge CFMutableStringRef)theLetter, NULL, transform, YES);
// theLetter is now #"J"
...However, I don't seem to understand how to go in the other direction, i.e. starting with an NSString #"J", output the NSString #"004A".
Simply extract each character and format it using the format string #"%04x", as below:
NSString *input = #"How now brown cow";
for (NSUInteger i = 0; i < [input length]; i++) {
unichar c = [input characterAtIndex:i];
NSLog(#"%04x", (unsigned)c);
// or NSString *s = [NSString stringWithFormat:#"%04x", (unsigned)c];
}
BTW I don't understand the code you have posted, but as that wasn't the question, it doesn't matter.

Creating iOS SHA1 Hash with UTF-8 characters

I'm using this code to create hash from giving string to devolving IOS App.
-(NSString*) sha1:(NSString*)input
{
const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:input.length];
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, data.length, digest);
NSMutableString* output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++)
[output appendFormat:#"%02x", digest[i]];
return output;
}
my PHP code is
sha1(json_encode($array));
I have string that contain Arabic languages.
when I create hash from English string and compare it with hash created from php code under Ubuntu*strong text* the result will be the same.
but when I create the hash with Arabic character it will and compare it with hash created from php code does't mach the result.
so what is the man problem with this code.
Thanks
input.length is the number of characters, not the number of bytes, the difference is that many bytes under UTF8 encoding are multiple bytes in length.
Replace:
const char *cstr = [input cStringUsingEncoding:NSUTF8StringEncoding];
NSData *data = [NSData dataWithBytes:cstr length:input.length];
with the NSString method:
NSData *data = [input dataUsingEncoding: NSUTF8StringEncoding];
There is no need for the intermediate const char *cstr.
I found my problem that come from my PHP json_encode($array) function.
so I found this function in http://php.net/manual/en/function.json-encode.php that encode my json with UTF-8 character
function my_json_encode($arr)
{
//convmap since 0x80 char codes so it takes all multibyte codes (above ASCII 127). So such characters are being "hidden" from normal json_encoding
array_walk_recursive($arr, function (&$item, $key) { if (is_string($item)) $item = mb_encode_numericentity($item, array (0x80, 0xffff, 0, 0xffff), 'UTF-8'); });
return mb_decode_numericentity(json_encode($arr), array (0x80, 0xffff, 0, 0xffff), 'UTF-8');
}
EX:
sha1(my_json_encode($newArray)

How to "concat" bytes from NSString and its length together?

I have a NSString [WORD] that has some length [LEN]. What i need to do is to get bytes from this string and put them together with length in short (2 bytes), so i would have [WORD] [LEN].
E.g.
String "AB" in utf8 HEX is 4142. Length of this string is 2==> 0002 in HEX.
So everything together is 41420002. How to get this bytes together?
I think this code does what you want.
NSString *myString = #"AB";
const char *chars = [myString UTF8String];
NSMutableString * result = [NSMutableString string];
for (int i=0; i < [myString length]; i++) {
[result appendFormat:#"%X", chars[i]];
}
[result appendFormat:#"%04X", [myString length]];
NSLog(#"%#", result);
Hope it helps!

How to create UIIMage from Hex Data?

I am using XMPP and XMPP will give me a photo data like the following:
a3f549fa9705e7ead2905de0b6a804227ecdd404
So I assume the above data is the photo data and I assume that it's Hex data. (maybe I am wrong)
So I use the following to create the UIImage, but it doesn't work
anyone know how to do it?
What I am trying to do is to change command from Hex String into NSData.
NSString* command = #"a3f549fa9705e7ead2905de0b6a804227ecdd404";
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];
}
UIImage *image = [UIImage imageWithData: commandToSend];
The string is 40 characters long and surely looks hex-encoded. This makes 160 bits of information. And this 160 reminds me of SHA-1, in accordance with this document:
http://xmpp.org/extensions/xep-0153.html
So what you have here is the checksum of an image, not the image itself. You need to read the document to find out how to get the whole image.

Using Objective C/Cocoa to unescape unicode characters, ie \u1234

Some sites that I am fetching data from are returning UTF-8 strings, with the UTF-8 characters escaped, ie: \u5404\u500b\u90fd
Is there a built in cocoa function that might assist with this or will I have to write my own decoding algorithm.
It's correct that Cocoa does not offer a solution, yet Core Foundation does: CFStringTransform.
CFStringTransform lives in a dusty, remote corner of Mac OS (and iOS) and so it's a little know gem. It is the front end to Apple's ICU compatible string transformation engine. It can perform real magic like transliterations between greek and latin (or about any known scripts), but it can also be used to do mundane tasks like unescaping strings from a crappy server:
NSString *input = #"\\u5404\\u500b\\u90fd";
NSString *convertedString = [input mutableCopy];
CFStringRef transform = CFSTR("Any-Hex/Java");
CFStringTransform((__bridge CFMutableStringRef)convertedString, NULL, transform, YES);
NSLog(#"convertedString: %#", convertedString);
// prints: 各個都, tada!
As I said, CFStringTransform is really powerful. It supports a number of predefined transforms, like case mappings, normalizations or unicode character name conversion. You can even design your own transformations.
I have no idea why Apple does not make it available from Cocoa.
Edit 2015:
OS X 10.11 and iOS 9 add the following method to Foundation:
- (nullable NSString *)stringByApplyingTransform:(NSString *)transform reverse:(BOOL)reverse;
So the example from above becomes...
NSString *input = #"\\u5404\\u500b\\u90fd";
NSString *convertedString = [input stringByApplyingTransform:#"Any-Hex/Java"
reverse:YES];
NSLog(#"convertedString: %#", convertedString);
Thanks #nschmidt for the heads up.
There is no built-in function to do C unescaping.
You can cheat a little with NSPropertyListSerialization since an "old text style" plist supports C escaping via \Uxxxx:
NSString* input = #"ab\"cA\"BC\\u2345\\u0123";
// will cause trouble if you have "abc\\\\uvw"
NSString* esc1 = [input stringByReplacingOccurrencesOfString:#"\\u" withString:#"\\U"];
NSString* esc2 = [esc1 stringByReplacingOccurrencesOfString:#"\"" withString:#"\\\""];
NSString* quoted = [[#"\"" stringByAppendingString:esc2] stringByAppendingString:#"\""];
NSData* data = [quoted dataUsingEncoding:NSUTF8StringEncoding];
NSString* unesc = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable format:NULL
errorDescription:NULL];
assert([unesc isKindOfClass:[NSString class]]);
NSLog(#"Output = %#", unesc);
but mind that this isn't very efficient. It's far better if you write up your own parser. (BTW are you decoding JSON strings? If yes you could use the existing JSON parsers.)
Here's what I ended up writing. Hopefully this will help some people along.
+ (NSString*) unescapeUnicodeString:(NSString*)string
{
// unescape quotes and backwards slash
NSString* unescapedString = [string stringByReplacingOccurrencesOfString:#"\\\"" withString:#"\""];
unescapedString = [unescapedString stringByReplacingOccurrencesOfString:#"\\\\" withString:#"\\"];
// tokenize based on unicode escape char
NSMutableString* tokenizedString = [NSMutableString string];
NSScanner* scanner = [NSScanner scannerWithString:unescapedString];
while ([scanner isAtEnd] == NO)
{
// read up to the first unicode marker
// if a string has been scanned, it's a token
// and should be appended to the tokenized string
NSString* token = #"";
[scanner scanUpToString:#"\\u" intoString:&token];
if (token != nil && token.length > 0)
{
[tokenizedString appendString:token];
continue;
}
// skip two characters to get past the marker
// check if the range of unicode characters is
// beyond the end of the string (could be malformed)
// and if it is, move the scanner to the end
// and skip this token
NSUInteger location = [scanner scanLocation];
NSInteger extra = scanner.string.length - location - 4 - 2;
if (extra < 0)
{
NSRange range = {location, -extra};
[tokenizedString appendString:[scanner.string substringWithRange:range]];
[scanner setScanLocation:location - extra];
continue;
}
// move the location pas the unicode marker
// then read in the next 4 characters
location += 2;
NSRange range = {location, 4};
token = [scanner.string substringWithRange:range];
unichar codeValue = (unichar) strtol([token UTF8String], NULL, 16);
[tokenizedString appendString:[NSString stringWithFormat:#"%C", codeValue]];
// move the scanner past the 4 characters
// then keep scanning
location += 4;
[scanner setScanLocation:location];
}
// done
return tokenizedString;
}
+ (NSString*) escapeUnicodeString:(NSString*)string
{
// lastly escaped quotes and back slash
// note that the backslash has to be escaped before the quote
// otherwise it will end up with an extra backslash
NSString* escapedString = [string stringByReplacingOccurrencesOfString:#"\\" withString:#"\\\\"];
escapedString = [escapedString stringByReplacingOccurrencesOfString:#"\"" withString:#"\\\""];
// convert to encoded unicode
// do this by getting the data for the string
// in UTF16 little endian (for network byte order)
NSData* data = [escapedString dataUsingEncoding:NSUTF16LittleEndianStringEncoding allowLossyConversion:YES];
size_t bytesRead = 0;
const char* bytes = data.bytes;
NSMutableString* encodedString = [NSMutableString string];
// loop through the byte array
// read two bytes at a time, if the bytes
// are above a certain value they are unicode
// otherwise the bytes are ASCII characters
// the %C format will write the character value of bytes
while (bytesRead < data.length)
{
uint16_t code = *((uint16_t*) &bytes[bytesRead]);
if (code > 0x007E)
{
[encodedString appendFormat:#"\\u%04X", code];
}
else
{
[encodedString appendFormat:#"%C", code];
}
bytesRead += sizeof(uint16_t);
}
// done
return encodedString;
}
simple code:
const char *cString = [unicodeStr cStringUsingEncoding:NSUTF8StringEncoding];
NSString *resultStr = [NSString stringWithCString:cString encoding:NSNonLossyASCIIStringEncoding];
from: https://stackoverflow.com/a/7861345