JSON file read 3840 error - objective-c

Reading this file city.list.us.json.gz (uncompressed) gets an error (3840) doing:
NSString * path = [mb pathForResource:#"city.list.us" ofType:#"json" inDirectory:#"JSON"];
NSString * string = [NSString stringWithContentsOfUTF8File:path];
NSData * data = [string dataUsingEncoding:NSASCIIStringEncoding];
NSLog(#"isValidJSONObject:%#", [NSJSONSerialization isValidJSONObject:data] ? #"Yes" : #"No");
NSError * bobo = nil;
id blob = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&bobo];
[NSApp presentError:bobo];
which reads ok - length 1873878 bytes, looks ok in vi (set list), but does not yield a non-nil object.
A head -4 of the file shows:
{"_id":4070245,"name":"Jones Crossroads","country":"US","coord":{"lon":-85.484657,"lat":31.21073}}
{"_id":4344544,"name":"Vernon Parish","country":"US","coord":{"lon":-93.183502,"lat":31.11685}}
{"_id":4215307,"name":"Pennick","country":"US","coord":{"lon":-81.55899,"lat":31.313}}
{"_id":5285039,"name":"Black Bear Spring","country":"US","coord":{"lon":-110.288139,"lat":31.386209}}
To my un-expert JSON eyes, it appears this is a file of cites, has an object per line with 4 values (_id,name,country,coord), last an object containing 2 values (lat,lon).
Also tried NSASCIIStringEncoding for the NSData conversion but no joy.
Any ideas?

That's not valid JSON. It's a large number of JSON dictionaries but they are not related to each other.
Most likely the expected JSON (an array of dictionaries) is supposed to look like
[{"_id":4070245,"name":"Jones Crossroads","country":"US","coord":{"lon":-85.484657,"lat":31.21073}},
{"_id":4344544,"name":"Vernon Parish","country":"US","coord":{"lon":-93.183502,"lat":31.11685}},
{"_id":4215307,"name":"Pennick","country":"US","coord":{"lon":-81.55899,"lat":31.313}},
{"_id":5285039,"name":"Black Bear Spring","country":"US","coord":{"lon":-110.288139,"lat":31.386209}}]
I wrapped the whole text in square brackets [] and added commas at the end of each line.

Related

initWithBase64EncodedString return nil

My resultString is 'PHNhbWxwOlJlc3BvbnNlIH...c3BvbnNlPgoK' and when i am decoding it shows me decodedData as nil.
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:resultString options:0];
I also tried this string with https://www.base64decode.org/ ,
it successfully shows results.
What wrong here in decoding ?
Probably you have some invalid characters in your string, like padding new lines. Try to pass NSDataBase64DecodingIgnoreUnknownCharacters option instead of 0.
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:resultString options:NSDataBase64DecodingIgnoreUnknownCharacters];
Almost certainly your string is not valid Base64, but that it is "close enough" that base64decode.org accepts it. The most likely cause is that you've dropped a trailing =. base64decode.org is tolerant of that, and just quietly throws away what it can't decode (the last byte in that case). NSData is not tolerant of that, because it's not valid Base64.
base64decode.org is also tolerant of random non-base64 characters in the string and just throws them away. NSData is not (again, sine it's invalid).
Try this! Simple solution :) Must need Foundation.framework. By default initWithBase64EncodedString method returns nil when the input is not recognized as valid Base-64. Please check your string is a valid Base-64 type or not!
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:#"eyJuYW1lIjoidmlnbmVzaCJ9" options:0];
NSError *dataError;
NSDictionary* responseObject = [NSJSONSerialization JSONObjectWithData:decodedData
options:kNilOptions
error:&dataError];
if(dataError == nil) {
NSLog(#"Result %#",responseObject);
}

JSON data has "bad" characters that causes NSJSONSerialization to die

I am using the ATV version of TVH Client - if you haven't looked at this it's worth looking at TVH to glimpse madness in the face. It has a JSON API that sends back data, including the electronic program guide. Sometimes the channels put accented characters in their data. Here is an example, this is the result from Postman, note the ? char in the description:
{
"eventId": 14277,
"episodeId": 14278,
"channelName": "49.3 CometTV",
"channelUuid": "02fe96403d58d53d71fde60649bf2b9a",
"channelNumber": "49.3",
"start": 1480266000,
"stop": 1480273200,
"title": "The Brain That Wouldn't Die",
"description": "Dr. Bill Cortner and his fianc�e, Jan Compton , are driving to his lab when they get into a horrible car accident. Compton is decapitated. But Cortner is not fazed by this seemingly insurmountable hurdle. His expertise is in transplants, and he is excited to perform the first head transplant. Keeping Compton's head alive in his lab, Cortner plans the groundbreaking yet unorthodox surgery. First, however, he needs a body."
},
If this data is fed into NSJSONSerialization, it returns an error. So to avoid this, the data is first fed into this function:
+ (NSDictionary*)convertFromJsonToObjectFixUtf8:(NSData*)responseData error:(__autoreleasing NSError**)error {
NSMutableData *FileData = [NSMutableData dataWithLength:[responseData length]];
for (int i = 0; i < [responseData length]; ++i) {
char *a = &((char*)[responseData bytes])[i];
if ( (int)*a >0 && (int)*a < 0x20 ) {
((char*)[FileData mutableBytes])[i] = 0x20;
} else {
((char*)[FileData mutableBytes])[i] = ((char*)[responseData bytes])[i];
}
}
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:FileData //1
options:kNilOptions
error:error];
if( *error ) {
NSLog(#"[JSON Error (2nd)] output - %#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
NSDictionary *userInfo = #{ NSLocalizedDescriptionKey:[NSString stringWithFormat:NSLocalizedString(#"Tvheadend returned malformed JSON - check your Tvheadend's Character Set for each mux and choose the correct one!", nil)] };
*error = [[NSError alloc] initWithDomain:#"Not ready" code:NSURLErrorBadServerResponse userInfo:userInfo];
return nil;
}
return json;
}
This cleans up the case when there is a control character in the data, but not an accent like the case above. When I feed in that data I get the "Tvheadend returned malformed JSON" error.
One problem is that the user can change the character set among a limited number of selections, and the server does not tell the client what it is. So one channel might use UTF8 and another ISO-8891-1, and there is no way to know which to use on the client side.
So: can anyone offer a suggestion on how to process this data so we feed clean strings into NSJSONSerialization?
I still do not know the root cause of the problem I am seeing - the server is sending not only high-bit characters like the ones I noted above, but I also found that it contained control characters too! Looking over other threads it appears I am not the only one seeing this problem, so hopefully others will find this useful...
The basic trick is to convert the original data from the server to a string using UTF8. If there are any of these "bad" chars in it, the conversion will fail. So you check if the resulting string is empty, and try another charset. Eventually you'll get data back. Now you take that string and strip out any control chars. Now you take that result, which is now UTF8 "clean", and convert it back to UTF8 NSData. That will pass through the JSON conversion without error. Phew!
Here is the solution I finally used:
// ... the original data from the URL is in responseData
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if ( str == nil ) {
str = [[NSString alloc] initWithData:responseData encoding:NSISOLatin1StringEncoding];
}
if ( str == nil ) {
str = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
}
NSCharacterSet *controls = [NSCharacterSet controlCharacterSet];
NSString *stripped = [[str componentsSeparatedByCharactersInSet:controls] componentsJoinedByString:#""];
NSData *data = [stripped dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
I hope someone finds this useful!

Web Service JSON nsdictionary unicode string [duplicate]

NSData* jsonData is the http response contains JSON data.
NSString* jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
NSLog(#"jsonString: %#", jsonString);
I got the result:
{ "result": "\u8aaa" }
What is the proper way to encoding the data to the correct string, not unicode string like "\uxxxx"?
If you convert the JSON data
{ "result" : "\u8aaa" }
to a NSDictionary (e.g. using NSJSONSerialization) and print the dictionary
NSError *error;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
NSLog(#"%#", jsonDict);
then you will get the output
{
result = "\U8aaa";
}
The reason is that the description method of NSDictionary uses "\Unnnn" escape sequences
for all non-ASCII characters. But that is only for display in the console, the dictionary is correct!
If you print the value of the key
NSLog(#"%#", [jsonDict objectForKey:#"result"]);
then you will get the expected output
說
I don't quite understand what the problem is. AFNetworking has given you a valid JSON packet. If you want the above code to output the character instead of the \u… escape sequence, you should coax the server feeding you the result to change its output. But this shouldn't be necessary. What you most likely want to do next is run it through a JSON deserializer…
NSDictionary * data = [NSJSONSerialization JSONObjectWithData:jsonData …];
…and you should get the following dictionary back: #{#"result":#"說"}. Note that the result key holds a string with a single character, which I'm guessing is what you want.
BTW: In future, I suggest you copy-paste output into your question rather than transcribing it by hand. It'll avoid several needless rounds of corrections and confusion.

carriage return for encoding

Im trying to send ascii encoded message to a server. My problem is coming in when I try to append the carriage return to the string
-(void)button2Pressed
{
NSMutableString *mutableString = [NSMutableString stringWithString:#"h323name get"];
[self sendStringCommand:mutableString];
}
-(void)sendStringCommand:(NSMutableString*)string
{
[string appendString:#"\\r"];
NSLog(#"string %# wtf",[string dataUsingEncoding:NSASCIIStringEncoding]);
NSData * testData = [[NSData alloc]initWithBytes:[string dataUsingEncoding:NSASCIIStringEncoding] length:sizeof([string dataUsingEncoding:NSASCIIStringEncoding])];
[socket writeData:testData withTimeout:20 tag:1];
}
currently this outputs this:
string <68333233 6e616d65 20676574 5c72> wtf
which should be
string <68333233 6e616d65 20676574 0d> wtf
Just plain /r did a new line hence the wtf characters after the data in the nslog
You have too many backslashes. Try this:
[string appendString:#"\r"];
Also, your creation of testData is completely wrong. The way you are creating testData is passing a pointer to an NSData object as the "bytes" parameter, and passing the size of a pointer to an NSData as the "length" parameter. You should just do this:
NSData *testData = [string dataUsingEncoding:NSASCIIStringEncoding];

Why does this NSString created from an NSData object fail to show it has contents?

Why does the following code produce the logging at the bottom ?
Here is the anomaly- my second NSLog should print the chrStr but produces nothing, empty, which is verified by this debug command:
(gdb) po chrStr
object returns empty description
However, the third NSString where I re-convert the NSString back to NSData object DOES display the the data, the same value as in the first NSLog, as it should. This would indicate to me that chrStr must have actual contents. But it seems not to be so from the NSLOG or the po command. Why ?
NSString *login;
NSString *pass;
// Purpose: NSString *loginString = [NSString stringWithFormat:#"\000%#\000%#", login, pass];
login = #"Loginname"; // text string1
pass = #"Password"; // text string2
// convert text strings to data objects
NSData *subData1 = [login dataUsingEncoding:NSUTF8StringEncoding];
NSData *subData2 = [pass dataUsingEncoding:NSUTF8StringEncoding];
// embed a NULL into new NSData object
NSMutableData *data = [NSMutableData data];
unsigned char zeroByte = 0;
[data appendBytes:&zeroByte length:1];
// append string1, NULL, string2 to data object
[data appendData:subData1];
[data appendBytes:&zeroByte length:1];
[data appendData:subData2];
NSLog(#"1.NSData: %#", data); // print data object
// create a character string from data object
NSString *chrStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"2.NSString: %#", chrStr); // print character string
// create data object from string object
NSData *chrData = [chrStr dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"3.NSDATA: %#", chrData); // print data object
Produces:
[1071:207] 1.NSData: 004c6f67 696e6e61 6d650050 61737377 6f7264
[1071:207] 2.NSString:
[1071:207] 3.NSDATA: 004c6f67 696e6e61 6d650050 61737377 6f7264
This is a real mystery to me. If chrStr is empty then 3-NSDATA could not display its info, but it does !
What am I trying to accomplish ? Well, check my very first comment line: // purpose:
That line when uncommented produces a warning, even though it actually works, so I was trying to do it another way that allowed me to have a clean compile. If you see a better way to accomplish that objective, I all eyes and ears. But please don't dwell on why that #"\000%#\000%#" string is necessary, start out accepting that it is. Thanks.
In C (and therefore objective-c), a null byte is used to represent the end of a string. When you create the string object, it takes all of the data you have given it without parsing, which is why you can convert it back to data successfully. However, when you display the string, the system reads the string up to the first null byte, which is the first byte. Therefore, the string contains data, but any system functions which read byte by byte instead of using the strings returned length will think it is empty. When you work with non-displayable characters, you should try to use data objects over string objects as often as possible.