Search code examples
iosobjective-csocketsdecoding

Unable To Decode Data Objective-C


I'm connected to a socket that send me data. But i'm trying to convert the data to a string, but it is not working. Before the conversation:

<6d020000 7b225265 73756c74 223a302c 22547970 65223a22 4664732e 49464150 492e4150 
49416972 63726166 74496e66 6f222c22 456e6769 6e65436f 756e7422 3a342c22 466c6170 
73436f6e 66696775 72617469 6f6e223a 5b7b2246 6c617073 416e676c 65223a30 2c224e61 
6d65223a 2230c2b0 222c2253 686f7274 4e616d65 223a2230 c2b0222c 22536c61 7473416e 
676c6522 3a307d2c 7b22466c 61707341 6e676c65 223a312c 224e616d 65223a22 31c2b022 
2c225368 6f72744e 616d6522 3a2231c2 b0222c22 536c6174 73416e67 6c65223a 317d2c7b 
22466c61 7073416e 676c6522 3a352c22 4e616d65 223a2235 c2b0222c 2253686f 72744e61 
6d65223a 2235c2b0 222c2253 6c617473 416e676c 65223a35 7d2c7b22 466c6170 73416e67 
6c65223a 31302c22 4e616d65 223a2231 30c2b022 2c225368 6f72744e 616d6522 3a223130 
c2b0222c 22536c61 7473416e 676c6522 3a31307d 2c7b2246 6c617073 416e676c 65223a32 
302c224e 616d6522 3a223230 c2b0222c 2253686f 72744e61 6d65223a 223230c2 b0222c22 
536c6174 73416e67 6c65223a 32307d2c 7b22466c 61707341 6e676c65 223a3235 2c224e61 
6d65223a 223235c2 b0222c22 53686f72 744e616d 65223a22 3235c2b0 222c2253 6c617473 
416e676c 65223a32 357d2c7b 22466c61 7073416e 676c6522 3a33302c 224e616d 65223a22 
3330c2b0 222c2253 686f7274 4e616d65 223a2233 30c2b022 2c22536c 61747341 6e676c65 
223a3330 7d5d2c22 4675656c 54616e6b 436f756e 74223a32 2c224861 73417574 6f70696c 
6f74223a 74727565 2c224e61 6d65223a 22426f65 696e6720 3734372d 34303022 2c225370 
6f696c65 72547970 65223a36 7d>

After the conversation, i get this: "m\^B".

This is my code:

case NSStreamEventHasBytesAvailable: {
        if(stream == inputStream) {
            NSLog(@"inputStream is ready.");

            uint8_t buf[1024];
            NSInteger len = 0;

            len = [inputStream read:buf maxLength:1024];


            if(len > 0) {
                NSMutableData* data=[[NSMutableData alloc] initWithLength:0];

                [data appendBytes: (const void *)buf length:len];

                NSLog(@"%@", data);

                NSString *s = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

                [self readIn:s];
                NSLog(@"%@", s);

            }
        }
        break;
    }

Solution

  • The first four bytes are a little endian representation of 0x0000026D, and would appear to represent the number of bytes in the string payload. You can theoretically just skip the first four bytes and you'll get your string.

    NSData *payload = [data subdataWithRange:NSMakeRange(4, data.length - 4)];
    

    And if you convert that, you get:

    {
        "Result": 0,
        "Type": "Fds.IFAPI.APIAircraftInfo",
        "EngineCount": 4,
        "FlapsConfiguration": [{
            "FlapsAngle": 0,
            "Name": "0°",
            "ShortName": "0°",
            "SlatsAngle": 0
        }, {
            "FlapsAngle": 1,
            "Name": "1°",
            "ShortName": "1°",
            "SlatsAngle": 1
        }, {
            "FlapsAngle": 5,
            "Name": "5°",
            "ShortName": "5°",
            "SlatsAngle": 5
        }, {
            "FlapsAngle": 10,
            "Name": "10°",
            "ShortName": "10°",
            "SlatsAngle": 10
        }, {
            "FlapsAngle": 20,
            "Name": "20°",
            "ShortName": "20°",
            "SlatsAngle": 20
        }, {
            "FlapsAngle": 25,
            "Name": "25°",
            "ShortName": "25°",
            "SlatsAngle": 25
        }, {
            "FlapsAngle": 30,
            "Name": "30°",
            "ShortName": "30°",
            "SlatsAngle": 30
        }],
        "FuelTankCount": 2,
        "HasAutopilot": true,
        "Name": "Boeing 747-400",
        "SpoilerType": 6
    }
    

    (I prettified that, but, that's basically what the payload contained.)


    Please note your code assumes to be assuming that it will be able to read all of the data in one call to read. But your payload was bigger than this example (621 bytes), it could easily exceed your buffer size (of 1024 bytes). Or you could have troubles if another message came in before you finished reading the prior message. I'd suggest you actually read those four bytes to figure out how much data is expected.

    To get the number of bytes, you can read in the first four bytes only, and then convert that to a uint32_t:

    uint32_t length;
    [data getBytes:&length length:4];
    length = CFSwapInt32LittleToHost(length);  // not technically required on little endian devices, but prudent in case this code is ever run on a big endian environment
    

    I would then suggest reading in precisely that number of bytes from your stream and convert that to a string.