summaryrefslogtreecommitdiff
path: root/SmartDeviceLink/SDLRPCPayload.m
blob: 90c09175b75539c021a4616c4b793997e5c49d49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//  SDLRPCPayload.h
//


#import "SDLRPCPayload.h"

#import "SDLDebugTool.h"

const NSUInteger RPC_HEADER_SIZE = 12;

@implementation SDLRPCPayload

- (instancetype)initWithData:(NSData *)data {
    unsigned long dataLength = data.length;

    if (data == nil || dataLength == 0) {
        [SDLDebugTool logInfo:@"Error: data is nil."];
        return nil;
    }

    if (dataLength < RPC_HEADER_SIZE) {
        [SDLDebugTool logInfo:@"Error: insfficient data to form RPC header."];
        return nil;
    }

    if (self = [self init]) {
        @try {
            // Setup our pointers for data access
            UInt8 *bytePointer = (UInt8 *)data.bytes;
            UInt32 *ui32Pointer = (UInt32 *)data.bytes;

            // Extract the parts
            UInt8 rpcType = (bytePointer[0] & 0xF0) >> 4;

            self.rpcType = rpcType;

            UInt32 functionID = ui32Pointer[0];
            functionID = CFSwapInt32BigToHost(functionID) & 0x0FFFFFFF;
            self.functionID = functionID;

            UInt32 correlationID = ui32Pointer[1];
            correlationID = CFSwapInt32BigToHost(correlationID);
            self.correlationID = correlationID;

            UInt32 jsonDataSize = ui32Pointer[2];
            jsonDataSize = CFSwapInt32BigToHost(jsonDataSize);

            NSData *jsonData = nil;
            NSUInteger offsetOfJSONData = RPC_HEADER_SIZE;
            if (jsonDataSize > 0 && jsonDataSize <= dataLength - RPC_HEADER_SIZE) {
                jsonData = [data subdataWithRange:NSMakeRange(offsetOfJSONData, jsonDataSize)];
            }
            self.jsonData = jsonData;

            NSData *binaryData = nil;
            NSUInteger offsetOfBinaryData = RPC_HEADER_SIZE + jsonDataSize;
            NSInteger binaryDataSize = data.length - jsonDataSize - RPC_HEADER_SIZE;
            if (binaryDataSize > 0) {
                binaryData = [data subdataWithRange:NSMakeRange(offsetOfBinaryData, binaryDataSize)];
            }
            self.binaryData = binaryData;

        } @catch (NSException *e) {
            // Print exception information
            [SDLDebugTool logFormat:@"NSException caught in SDLRPCPayload::initWithData\nName: %@\nReason: %@\nData: %@", e.name, e.reason, data.debugDescription];
            return nil;
        }
    }

    return self;
}

- (NSData *)data {
    // Header is:
    // RPC Type - first 4 bits
    // RPC Function ID - next 28 bits
    // Correlation ID - next 32 bits
    // JSON size - next 32 bits
    UInt8 headerBuffer[RPC_HEADER_SIZE];
    *(UInt32 *)&headerBuffer[0] = CFSwapInt32HostToBig(self.functionID);
    *(UInt32 *)&headerBuffer[4] = CFSwapInt32HostToBig(self.correlationID);
    *(UInt32 *)&headerBuffer[8] = CFSwapInt32HostToBig((UInt32)self.jsonData.length);
    UInt8 rpcType = (self.rpcType & 0x0F) << 4;
    headerBuffer[0] &= 0x0F;
    headerBuffer[0] |= rpcType;

    // Serialize the header, the json data then the binary data
    NSMutableData *dataOut = [NSMutableData dataWithCapacity:[self size]];
    [dataOut appendBytes:&headerBuffer length:12];
    [dataOut appendData:self.jsonData];
    [dataOut appendData:self.binaryData];

    return dataOut;
}

- (NSUInteger)size {
    NSUInteger headerSize = RPC_HEADER_SIZE;
    NSUInteger jsonDataSize = self.jsonData.length;
    NSUInteger binaryDataSize = self.binaryData.length;

    return (headerSize + jsonDataSize + binaryDataSize);
}

- (NSString *)description {
    NSMutableString *description = [[NSMutableString alloc] init];
    [description appendFormat:@" rpcType:%i, functionID:%i, correlationID:%i, json:%lu bytes, binary:%lu bytes", self.rpcType, (unsigned int)self.functionID, (unsigned int)self.correlationID, (unsigned long)self.jsonData.length, (unsigned long)self.binaryData.length];

    return description;
}

+ (id)rpcPayloadWithData:(NSData *)data {
    return [[SDLRPCPayload alloc] initWithData:data];
}
@end