Convert NSArray of bytes to NSData - objective-c

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).

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.

NSJSONSerialization does not produce valid UTF8 string

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.

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.

Reading from plist to NSArray

I am trying to read and I also need to write to a plist.
So far I am trying to simply read the contents in.
Here is my appSettings.plist:
NSBundle* bundle = [NSBundle mainBundle];
NSString* plistPath = [bundle pathForResource:#"appSettings" ofType:#"plist"];
NSDictionary *tmp = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
I tried to do this:
NSArray *mruItems = [[NSArray alloc] initWithArray:[tmp objectForKey:#"lastSearches"]];
But it throws an error. A check I did on the [tmp objectForKey:#"lastSearches"] type revealed this is not an NSArray...
How can I read the contents into my NSArray?
Thanks!
(I would love to have some info on writing too)
If you look at the screenshot above you see that it's pretty clear that "lastSearches" is a Dictionary, not a list. You can try to switch the type there to a Array type instead and it should work for you.
Another solution would be to iterate over the keys in that dictionary:
NSDictionary *lastSearches = [tmp objectForKey:#"lastSearches"];
for (NSString *key in lastSearches.allKeys)
{
NSString *value = [lastSearches objectForKey:key];
}
Note that this would not be in order, and you probably would have to sort before iterating over it.
Indeed it's not an array but a dictionary (look at your image).