NSJSONSerialization does not produce valid UTF8 string - objective-c

I have an NSDictionary that I try to convert to JSON using the following code
NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:kNilOptions error:nil];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
The resulting data object looks good, but the final NSString remains NULL. If I create the NSString with NSASCIIStringEncoding I get a proper string object, but any multibyte UTF8 characters are of course maimed.
Shouldn't dataWithJSONObject always yield valid UTF8 data whenever the function is succesful?
Details: I'm pretty sure the culprit is somewhere in my input data (strings parsed from custom binary format), but there is quite a lot of data and I'm not sure how to efficiently detect where the problem is.

Related

Unable to decode gzipped Base64 NSString

So I'm trying to decode a base64 encoded string but I'm not having any luck.. decodedString is always null! I've tried for hours and totally out of ideas. Even tried third party libraries.
Code:
NSString *input = #"H4sIAAAAAAAEALWSTW/TQBCG/0q15wTN7Je9voU2RFFUFCnuASGE9mMcTB0n9QcSQvx3xm6QWsSFAzev53l3Zp9dcb8+HFab9fZOFGJ/3Ny+bbvdrt+MX56ePp9OeDyKhSi3TJWr+z0zEtAtQS1RligLowowbxSAzqWdyA/7NUMP+7tVueb12FPXi5vi5uOP+XubuJoHkpjQOghBW5c5Dzpo0sZj8FYaztVtP6MSeHG+XIMKpJQEQQcgnSobrHVRxco6qY2WcgoOdHq4NkKzENV7fyKOrnx3brneXNeHoavjY+PbxD+jb6hNfg7BQlCqh7Kesb+eNkfjZM65R/o+zxUpwxAzTyoinyL5hLnPJBkbK6h8YPTSnb9SHGbcGcgQfJDBWY0qhop5ixoJdRYUMZ6oedf44zzO5G1ftxxEqbSx4uenufVvr/9vile3MJndPbeaxPaD715YskswS4WlxAKhgCnASv+wKPMSTYHuuf7NN3XyA92ex3bgTdU/mB8vU/Iw+GHsOfpa2MvrFEGBTSEjrPiRVImCT8T7qJSMs5VJbPMX5JgDcAQDAAA=";
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:input options:0];
NSString *decodedString = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
NSLog(#"Decode String Value: %#", decodedString);
The Base64 decoded output is not a string, it is binary data.
You are getting nil returned because it is not a UTF-8 string and arbitrary data is generally not valid UTF-8.
Decode using NSDataBase64DecodingIgnoreUnknownCharacters to avoid the decoder discarding non-Base-64 bytes.
NSData *decodedData = [[NSData alloc]initWithBase64EncodedString:input
options:NSDataBase64DecodingIgnoreUnknownCharacters];
Once you have decodedData, you can decompress the buffer with whatever function or library you decide on, then you can read the string. You may want to look at the answer here for an idea of how to decompress your data.
decodedData is not nil.
It's value is: <1f8b0800 ...
1f8b let me think it's a GZip.
Any hex data is not convertible as such into a String using UTF8 Encoding. UTF8 doesn't have value for each possible hex. There are non-valid combination, and so your final string is nil.
For instance, transform an UIImage into PNG HexData (using UIImagePNGRepresentation()) and try it to convert it into a NSString using NSUTF8StringEncoding. You'll see.
Using the code of https://github.com/nicklockwood/GZIP/ (first one I found):
NSData *unzippedData = [decodedData gunzippedData];
NSString *decodedString = [[NSString alloc] initWithData:unzippedData encoding:NSUTF8StringEncoding];
Output:
"MESSAGEID":"PgGCBnrKKsGuhqq_mm1gg","TIMESTAMP":"2019-03-12T12:53:05.3004826","TYPE":"UPDATE","users" : [{"userId":"8be21d1690bb46979a04b4e45a1ba625","insId":"20","operId":"30222e0b4b0e4df6b669c3cf69245422","itemUserId":15,"fName":"Aaron","lName":"Strickland","calendarId":0,"editTime":"2019-03-12T12:53:05.3815928","keyId":"ce71bc7ae3c145adad18a72e56cf0fab","projectId":"950710ab2b96413cbfd186141e147b3e","delFlag":0,"userPin":"123456"}],"keys" : [{"keyId":"ce71bc7ae3c145adad18a72e56cf0fab","projectId":"950710ab2b96413cbfd186141e147b3e","insId":"20","itemKeyId":15,"startTime":"2016-05-31T21:10:00","endTime":"2019-03-28T15:19:00","validateCount":13,"editTime":"2019-03-12T12:53:05.3815928","updateStatus":1,"delFlag":0,"calendarId":"b306db7e1f924fdebade3813dd596f5d"}]
Seems almost like JSON. I would have add "{" and "}" around it.
With a little of workaround:
NSMutableData *finalData = [[NSMutableData alloc] initWithData:[#"{" dataUsingEncoding:NSUTF8StringEncoding]];
[finalData appendData:unzippedData];
[finalData appendData:[#"}" dataUsingEncoding:NSUTF8StringEncoding]];
NSData *dictionary = [NSJSONSerialization JSONObjectWithData:finalData options:0 error:nil];
NSLog(#"dictionary: %#", dictionary);
It's up to you to know why the syntax is strange, but with that you a "usable" NSDictionary.

How to convert NSData to NSString and revert the NSString to NSData?

My task is to encrypt a file(.png, .txt, any..)
In order to achieve it what I doing is
Encryption:
Read a file and store it into NSData.
Convert NSData to NSString.
Encrypt the NSString with help of AESCrypt
Store the NSString in a file
Decryption
Read the encrypted string
Decrypt it with the help of AESCrypt
Convert it back to NSData
Save it back to some location
Below is the code that I am doing in order convert a file to NSString:
NSString* sourceFile = #"/Users/Vikas/Desktop/theHulk.png";
NSData *data = [[NSFileManager defaultManager] contentsAtPat
h:sourceFile];
NSString *dataAsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
Problem:
The above code is able to read and store the file to NSData however when I am converting the NSData to NSString, the value I am getting is nil
Research
StackOver Flow 1
StackOver Flow 2
S.P: If you have better suggestion for file encryption then please let me know as I am newbie.
According to this blog the string to data conversion forces a trailing \0 byte, which you might have to remove. This can be done as follows:
data = [data subdataWithRange:NSMakeRange(0, [data length] - 1)];
Try see if that works for you.

NSString returning NULL while doing NSUTF8StringEncoding

Following is my code
NSString *res = [valueArray valueForKey:#"key"];
NSData *newdata=[res dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
res=[[NSString alloc] initWithData:newdata encoding:NSNonLossyASCIIStringEncoding];
nameTxt.text = [NSString stringWithFormat:#"%#",res]; // Assigning to textfield
this works properly.
But sometimes it returns NULL data, mostly it happens when string contents large data.
Anyone have idea why this is happening?
NSString *res = [valueArray valueForKey:#"key"];
That's funny: using a valueForKey: on a variable named ...Array. Rather seems to be a dictionary?
NSData *newdata = [res dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
creating a raw UTF8 encoded data from a string always works: No need for allowLossyConversion.
res = [[NSString alloc] initWithData:newdata encoding:NSNonLossyASCIIStringEncoding];
Converting the UTF8 encoded raw data to ASCII does only work if the UTF8 did not contain any characters out of the very restricted ASCII range. Otherwise nil is returned.
This seems to be the only reason for this obfuscated bit of code: filter out non-ASCII strings. Otherwise the conversion does not make the slightest sense.

How to encode NSData raw bytes directly to UTF-16 (Unicode)?

Environment: iOS Xcode Objective-C Garbled Unicode UTF-16
My Question:
I got the file content from a remote file and then stored it into NSData object, then I want to convert the NSData to Unicode encoding (note: not UTF-8,UTF-16 will okay), the problem is that I do not know the original file content encoding, what can I do to convert the unknown raw bytes into Unicode (UTF-16)?
I have tried so many method, but no one successfully touch my target, the code:
NSData *chunk = [NSData dataWithContentsOfURL:url];
NSString* newStr = [[[NSString alloc] initWithData:chunk encoding:NSUTF16LittleEndianStringEncoding] autorelease];
NSData* d = [newStr dataUsingEncoding:NSUnicodeStringEncoding];
[d writeToFile:newFilePath atomically:YES];
got the file into NSData, encode it into Unicode and write to file.
NSString* converted_str = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding];
NSData * d = [(id)CFStringCreateExternalRepresentation(NULL, (CFStringRef)converted_str, kCFStringEncodingUnicode, 0) autorelease];
[d writeToFile:newFilePath atomically:YES];
convert the NSData to NSString, then restore it into NSData for write to file, not work.
[converted_str writeToFile:newFilePath atomically:YES encoding:NSUnicodeStringEncoding error:&error];
write to file directly using NSString object, garbled.
CFStringRef converted_str = CFStringCreateWithBytes(NULL, [chunk bytes],[chunk length], kCFStringEncodingUTF8,false);
CFStringRef newStr = [chunk dataUsingEncoding:NSUTF8StringEncoding];
NSData * d = [(id)CFStringCreateExternalRepresentation(NULL, (CFStringRef)big5Str, NSUnicodeStringEncoding, 0) autorelease];
[d writeToFile:newFilePath atomically:YES];
Using cString to do the encoding work, but also failure.
char converted[([chunk length] + 1)];
[chunk getCString:converted maxLength:([chunk length] + 1) encoding: NSWindowsCP1251StringEncoding];
NSLog(#"converted:%s", converted);
NSString *converted_str = [NSString stringWithCString:converted encoding:NSUnicodeStringEncoding];
NSLog(#"converted_str:%#", converted_str);
I also using usedEncoding:&xxx to get the original file encoding, then try to decode it into string object using the returned encoding, ..., failure again.
NSStringEncoding encoding;
NSString *chunk = [[NSString alloc] initWithContentsOfURL:[rb fileURL] usedEncoding:&encoding error:&error];
...
I then try to using kCFStringEncodingUTF16 to get the Unicode encoded buffer, but failure.
NSStringEncoding encode = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingUTF16);
NSString *chunk = [NSString stringWithContentsOfURL:url encoding:encode error:&error];
In the end, I want to try libiconv for iOS( iPhone,iPad), but the trouble is the encoding of source content is unknown, the usedEncoding:&xxx function can not always work.
I have no idea of this trouble ... :(
Is there someone meet the similar question, please give me some direction, any answer will be most appreciated , thank you.
Sincerely wishing you and your family happiness and health.

Convert NSArray of bytes to NSData

I'm trying to download a file in Objective-C from a REST service but having some issues. Right now, the service returns a byte[] in JSON. I was able to get the array by using the json-framework.
NSURL *url = [NSURL URLWithString:#"http://192.168.10.215:8888/Service/RO/GetAllTheBytes/test.txt"];
NSString *str = [[NSString alloc] initWithContentsOfURL:url];
NSDictionary *jsonDic = [str JSONValue];
NSArray *fileContents = [jsonDic objectForKey:#"fileContents"];
Now I want to use this array of bytes to create a file, but I'm having trouble creating the file. Should I convert the NSArray to NSData, and how?
Change your service to return a Base64 string. There are a bunch of Objective-C Base64 decoders out there, some of which are half-decent.
A NSArray of NSNumbers is really really really stupid, with a minimum space overhead of about 300% (although not quite as bad as JRA-11693).