carriage return for encoding - objective-c

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

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!

Comparing strings to keyboard input in Objective C

I'm having some trouble comparing NSStrings in Objective C. I looked at apples documentation, and it appears that there is a function that returns a boolean called isEqualToString. However, the statement never executes.
NSString* randomCombo = #"rypo";
NSFileHandle* kbd = [NSFileHandle fileHandleWithStandardInput];
NSData* inputData = [kbd availableData];
NSString* line = [[NSString alloc]initWithData : inputData encoding : NSUTF8StringEncoding];
NSLog(#"You entered: %#", line);
NSLog(#"The string to match is: %#", randomCombo);
if([line isEqualToString : randomCombo]){
NSLog(#"you win.");
}
Do I need to encode the NSString, randomCombo? Can anybody help me figure out what the problem is here?
When you use return to end your input, there's a newline character appended to the string which the other string doesn't have.
You need to either terminate input using control-D, which just closes the pipe without starting a new line, or trim the '\n' off of the string afterwards.

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.

NSString to char[]?

struct DATA
{
unsigned char USERNAME[32];
};
i want copy a NSString to struct DATA.USERNAME , how to do it ?
You can use the -[NSString UTF8String] method to get a C string of your NSString. Then, you can use strncpy(DATA.USERNAME, [mystring UTF8String], 32); to copy that string into the structure.
You first need to know what encoding is expected. NSString can generate bytes in a wide range of encodings. Then you pass a pointer to the USERNAME array to getCString:maxLength:encoding:. So, for example, if you want to copy the contents of the NSString myCocoaString as UTF-8 into USERNAME field of a DATA struct called myData, you'd do:
BOOL success = [myCocoaString getCString:myData.USERNAME maxLength:32 encoding:NSUTF8StringEncoding];
NSLog(#"Was %# to store string contents in USERNAME!", success ? #"able" : #"not able");