Fix crash when discovering devices & platforms.
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocpayloadparse.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 // Defining _POSIX_C_SOURCE macro with 200112L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1-2001 base
24 // specification (excluding the XSI extension).
25 // For POSIX.1-2001 base specification,
26 // Refer http://pubs.opengroup.org/onlinepubs/009695399/
27 // Required for strok_r
28 #define _POSIX_C_SOURCE 200112L
29 #include <string.h>
30 #include "ocpayloadcbor.h"
31 #include <stdlib.h>
32 #include "logger.h"
33 #include "oic_malloc.h"
34 #include "ocstackinternal.h"
35 #include "ocpayload.h"
36 #include "cbor.h"
37 #include "oic_string.h"
38
39 #define TAG "OCPayloadParse"
40
41 static OCStackResult OCParseDiscoveryPayload(OCPayload** outPayload, CborValue* arrayVal);
42 static OCStackResult OCParseDevicePayload(OCPayload** outPayload, CborValue* arrayVal);
43 static OCStackResult OCParsePlatformPayload(OCPayload** outPayload, CborValue* arrayVal);
44 static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue* repParent);
45 static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* arrayVal);
46 static OCStackResult OCParsePresencePayload(OCPayload** outPayload, CborValue* arrayVal);
47 static OCStackResult OCParseSecurityPayload(OCPayload** outPayload, CborValue* arrayVal);
48
49 OCStackResult OCParsePayload(OCPayload** outPayload, OCPayloadType payloadType,
50         const uint8_t* payload, size_t payloadSize)
51 {
52     CborParser parser;
53     CborValue rootValue;
54     bool err = false;
55
56     OC_LOG_V(INFO, TAG, "CBOR Parsing size: %d", payloadSize, payload);
57     if((err = cbor_parser_init(payload, payloadSize, 0, &parser, &rootValue)) != false)
58     {
59         OC_LOG_V(ERROR, TAG, "CBOR Parser init failed: %d", err);
60         return OC_STACK_ERROR;
61     }
62
63     if(!cbor_value_is_array(&rootValue))
64     {
65         OC_LOG_V(ERROR, TAG, "CBOR payload root object is not an array :%x", rootValue.type);
66         return OC_STACK_MALFORMED_RESPONSE;
67     }
68
69     CborValue arrayValue;
70     // enter the array
71     err = err || cbor_value_enter_container(&rootValue, &arrayValue);
72
73     if(err || arrayValue.type != CborMapType)
74     {
75         OC_LOG_V(ERROR, TAG, "CBOR payload parse failed :%d", err);
76         return OC_STACK_MALFORMED_RESPONSE;
77     }
78
79     OCStackResult result = OC_STACK_ERROR;
80     switch(payloadType)
81     {
82         case PAYLOAD_TYPE_DISCOVERY:
83             result = OCParseDiscoveryPayload(outPayload, &arrayValue);
84             break;
85         case PAYLOAD_TYPE_DEVICE:
86             result = OCParseDevicePayload(outPayload, &arrayValue);
87             break;
88         case PAYLOAD_TYPE_PLATFORM:
89             result = OCParsePlatformPayload(outPayload, &arrayValue);
90             break;
91         case PAYLOAD_TYPE_REPRESENTATION:
92             result = OCParseRepPayload(outPayload, &arrayValue);
93             break;
94         case PAYLOAD_TYPE_PRESENCE:
95             result = OCParsePresencePayload(outPayload, &arrayValue);
96             break;
97         case PAYLOAD_TYPE_SECURITY:
98             result = OCParseSecurityPayload(outPayload, &arrayValue);
99             break;
100         default:
101             OC_LOG_V(ERROR, TAG, "ParsePayload Type default: %d", payloadType);
102             result = OC_STACK_ERROR;
103             break;
104     }
105
106     if(result == OC_STACK_OK)
107     {
108         err = err || cbor_value_leave_container(&rootValue, &arrayValue);
109         if(err != CborNoError)
110         {
111             return OC_STACK_MALFORMED_RESPONSE;
112         }
113     }
114     else
115     {
116         OC_LOG_V(INFO, TAG, "Finished parse payload, result is %d", result);
117     }
118
119     return result;
120 }
121
122 void OCFreeOCStringLL(OCStringLL* ll);
123
124 static OCStackResult OCParseSecurityPayload(OCPayload** outPayload, CborValue* arrayVal)
125 {
126     if (!outPayload)
127     {
128         return OC_STACK_INVALID_PARAM;
129     }
130
131     bool err = false;
132     char * securityData = NULL;
133
134     if(cbor_value_is_map(arrayVal))
135     {
136         CborValue curVal;
137         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_REPRESENTATION, &curVal);
138
139         if(cbor_value_is_valid(&curVal))
140         {
141             size_t len;
142             err = err || cbor_value_dup_text_string(&curVal, &securityData, &len, NULL);
143         }
144     }
145     else
146     {
147         OC_LOG(ERROR, TAG, "Cbor main value not a map");
148         return OC_STACK_MALFORMED_RESPONSE;
149     }
150
151     err = err || cbor_value_advance(arrayVal);
152
153     if(err)
154     {
155         OC_LOG(ERROR, TAG, "Cbor in error condition");
156         OICFree(securityData);
157         return OC_STACK_MALFORMED_RESPONSE;
158     }
159
160     *outPayload = (OCPayload*)OCSecurityPayloadCreate(securityData);
161     OICFree(securityData);
162
163     return OC_STACK_OK;
164
165 }
166
167 static char* InPlaceStringTrim(char* str)
168 {
169     while (str[0] == ' ')
170     {
171         ++str;
172     }
173
174     size_t lastchar = strlen(str);
175
176     while (str[lastchar] == ' ')
177     {
178         str[lastchar] = '\0';
179         --lastchar;
180     }
181
182     return str;
183 }
184
185 static OCStackResult OCParseDiscoveryPayload(OCPayload** outPayload, CborValue* arrayVal)
186 {
187     if (!outPayload)
188     {
189         return OC_STACK_INVALID_PARAM;
190     }
191
192     bool err = false;
193
194     OCDiscoveryPayload* out = OCDiscoveryPayloadCreate();
195
196     if(!out)
197     {
198         return OC_STACK_NO_MEMORY;
199     }
200
201     size_t resourceCount = 0;
202     while(!err &&
203             cbor_value_is_map(arrayVal))
204     {
205         OCResourcePayload* resource = (OCResourcePayload*)OICCalloc(1, sizeof(OCResourcePayload));
206         if(!resource)
207         {
208             OC_LOG(ERROR, TAG, "Memory allocation failed");
209             OCDiscoveryPayloadDestroy(out);
210             return OC_STACK_NO_MEMORY;
211         }
212         CborValue curVal;
213
214         // Uri
215         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_HREF, &curVal);
216         size_t len;
217         err = err || cbor_value_dup_text_string(&curVal, &(resource->uri), &len, NULL);
218
219         // SID
220         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_SERVER_INSTANCE_ID, &curVal);
221         err = err || cbor_value_dup_byte_string(&curVal, &(resource->sid), &len, NULL);
222
223         // Prop Tag
224         {
225             err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_PROPERTY, &curVal);
226             // ResourceTypes
227             CborValue rtVal;
228             err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_RESOURCE_TYPE, &rtVal);
229
230             if (!err && cbor_value_is_text_string(&rtVal))
231             {
232                 char* input = NULL;
233                 char* savePtr;
234                 err = err || cbor_value_dup_text_string(&rtVal, &input, &len, NULL);
235
236                 if (input)
237                 {
238                     char* curPtr = strtok_r(input, " ", &savePtr);
239
240                     while (curPtr)
241                     {
242                         char* trimmed = InPlaceStringTrim(curPtr);
243                         if (trimmed[0] !='\0')
244                         {
245                             if (!OCResourcePayloadAddResourceType(resource, trimmed))
246                             {
247                                 OICFree(resource->uri);
248                                 OICFree(resource->sid);
249                                 OCFreeOCStringLL(resource->types);
250                                 OICFree(resource);
251                                 OCDiscoveryPayloadDestroy(out);
252                                 return OC_STACK_NO_MEMORY;
253                             }
254                         }
255                         curPtr = strtok_r(NULL, " ", &savePtr);
256                     }
257                     OICFree(input);
258                 }
259             }
260
261             // Interface Types
262             CborValue ifVal;
263             err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_INTERFACE, &ifVal);
264
265             if (!err && cbor_value_is_text_string(&ifVal))
266             {
267                 char* input = NULL;
268                 char* savePtr;
269                 err = err || cbor_value_dup_text_string(&ifVal, &input, &len, NULL);
270
271                 if (input)
272                 {
273                     char* curPtr = strtok_r(input, " ", &savePtr);
274
275                     while (curPtr)
276                     {
277                         char* trimmed = InPlaceStringTrim(curPtr);
278                         if (trimmed[0] !='\0')
279                         {
280                             if (!OCResourcePayloadAddInterface(resource, trimmed))
281                             {
282                                 OICFree(resource->uri);
283                                 OICFree(resource->sid);
284                                 OCFreeOCStringLL(resource->types);
285                                 OICFree(resource);
286                                 OCDiscoveryPayloadDestroy(out);
287                                 return OC_STACK_NO_MEMORY;
288                             }
289                         }
290                         curPtr = strtok_r(NULL, " ", &savePtr);
291                     }
292                     OICFree(input);
293                 }
294             }
295
296             // Policy
297             {
298                 CborValue policyMap;
299                 err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_POLICY, &policyMap);
300
301                 // Bitmap
302                 CborValue val;
303                 err = err || cbor_value_map_find_value(&policyMap, OC_RSRVD_BITMAP, &val);
304                 uint64_t temp = 0;
305                 err = err || cbor_value_get_uint64(&val, &temp);
306                 resource->bitmap = (uint8_t)temp;
307                 // Secure Flag
308                 err = err || cbor_value_map_find_value(&policyMap, OC_RSRVD_SECURE, &val);
309                 if(cbor_value_is_valid(&val))
310                 {
311                     err = err || cbor_value_get_boolean(&val, &(resource->secure));
312                     // Port
313                     CborValue port;
314                     err = err || cbor_value_map_find_value(&policyMap, OC_RSRVD_HOSTING_PORT,
315                                     &port);
316                     if(cbor_value_is_valid(&port))
317                     {
318                         err = err || cbor_value_get_uint64(&port, &temp);
319                         resource->port = (uint16_t)temp;
320                     }
321                 }
322             }
323         }
324
325         err = err || cbor_value_advance(arrayVal);
326         if(err)
327         {
328             OICFree(resource->uri);
329             OICFree(resource->sid);
330             OCFreeOCStringLL(resource->types);
331             OCFreeOCStringLL(resource->interfaces);
332             OICFree(resource);
333             OCDiscoveryPayloadDestroy(out);
334             OC_LOG_V(ERROR, TAG, "CBOR in error condition", err);
335             return OC_STACK_MALFORMED_RESPONSE;
336         }
337         ++resourceCount;
338         OCDiscoveryPayloadAddNewResource(out, resource);
339     }
340
341     if(err)
342     {
343         OCDiscoveryPayloadDestroy(out);
344         return OC_STACK_MALFORMED_RESPONSE;
345     }
346     else
347     {
348         *outPayload = (OCPayload*)out;
349         return OC_STACK_OK;
350     }
351 }
352
353 static OCStackResult OCParseDevicePayload(OCPayload** outPayload, CborValue* arrayVal)
354 {
355     if (!outPayload)
356     {
357         return OC_STACK_INVALID_PARAM;
358     }
359
360     bool err = false;
361
362     if(cbor_value_is_map(arrayVal))
363     {
364         char* uri = NULL;
365         uint8_t* sid = NULL;
366         char* dname = NULL;
367         char* specVer = NULL;
368         char* dmVer = NULL;
369         CborValue curVal;
370          err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_HREF, &curVal);
371         size_t len;
372          err = err || cbor_value_dup_text_string(&curVal, &uri, &len, NULL);
373
374         // Representation
375         {
376              err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_REPRESENTATION, &curVal);
377
378             CborValue repVal;
379             // Device ID
380             err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_DEVICE_ID, &repVal);
381             if(cbor_value_is_valid(&repVal))
382             {
383                 err = err || cbor_value_dup_byte_string(&repVal, &sid, &len, NULL);
384             }
385             // Device Name
386             err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_DEVICE_NAME, &repVal);
387             if(cbor_value_is_valid(&repVal))
388             {
389                 err = err || cbor_value_dup_text_string(&repVal, &dname, &len, NULL);
390             }
391             // Device Spec Version
392             err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_SPEC_VERSION, &repVal);
393             if(cbor_value_is_valid(&repVal))
394             {
395                 err = err || cbor_value_dup_text_string(&repVal, &specVer, &len, NULL);
396             }
397
398             // Data Model Version
399             err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_DATA_MODEL_VERSION, &repVal);
400             if (cbor_value_is_valid(&repVal))
401             {
402                 err = err || cbor_value_dup_text_string(&repVal, &dmVer, &len, NULL);
403             }
404         }
405
406          err = err || cbor_value_advance(arrayVal);
407
408         if(err)
409         {
410             OICFree(uri);
411             OICFree(sid);
412             OICFree(dname);
413             OICFree(specVer);
414             OICFree(dmVer);
415             OC_LOG_V(ERROR, TAG, "CBOR in error condition %d", err);
416             return OC_STACK_MALFORMED_RESPONSE;
417         }
418
419         *outPayload = (OCPayload*)OCDevicePayloadCreate(uri, sid, dname, specVer, dmVer);
420
421         OICFree(uri);
422         OICFree(sid);
423         OICFree(dname);
424         OICFree(specVer);
425         OICFree(dmVer);
426         if(!*outPayload)
427         {
428             return OC_STACK_NO_MEMORY;
429         }
430
431         return OC_STACK_OK;
432     }
433     else
434     {
435         OC_LOG(ERROR, TAG, "Root device node was not a map");
436         return OC_STACK_MALFORMED_RESPONSE;
437     }
438
439 }
440
441 static OCStackResult OCParsePlatformPayload(OCPayload** outPayload, CborValue* arrayVal)
442 {
443     if (!outPayload)
444     {
445         return OC_STACK_INVALID_PARAM;
446     }
447
448     bool err = false;
449
450     if(cbor_value_is_map(arrayVal))
451     {
452         char* uri = NULL;
453         OCPlatformInfo info = {0};
454         CborValue curVal;
455          err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_HREF, &curVal);
456         size_t len;
457          err = err || cbor_value_dup_text_string(&curVal, &uri, &len, NULL);
458
459         // Representation
460         {
461              err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_REPRESENTATION, &curVal);
462
463             CborValue repVal;
464             // Platform ID
465              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_PLATFORM_ID, &repVal);
466              if(cbor_value_is_valid(&repVal))
467              {
468                  err = err || cbor_value_dup_text_string(&repVal, &(info.platformID), &len, NULL);
469              }
470
471             // MFG Name
472              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_MFG_NAME, &repVal);
473              if(cbor_value_is_valid(&repVal))
474              {
475                  err = err || cbor_value_dup_text_string(&repVal, &(info.manufacturerName), &len, NULL);
476              }
477
478             // MFG URL
479              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_MFG_URL, &repVal);
480             if(cbor_value_is_valid(&repVal))
481             {
482                  err = err || cbor_value_dup_text_string(&repVal, &(info.manufacturerUrl), &len, NULL);
483             }
484
485             // Model Num
486              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_MODEL_NUM, &repVal);
487             if(cbor_value_is_valid(&repVal))
488             {
489                  err = err || cbor_value_dup_text_string(&repVal, &(info.modelNumber), &len, NULL);
490             }
491
492             // Date of Mfg
493              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_MFG_DATE, &repVal);
494             if(cbor_value_is_valid(&repVal))
495             {
496                  err = err || cbor_value_dup_text_string(&repVal, &(info.dateOfManufacture), &len,
497                         NULL);
498             }
499
500             // Platform Version
501              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_PLATFORM_VERSION, &repVal);
502             if(cbor_value_is_valid(&repVal))
503             {
504                  err = err || cbor_value_dup_text_string(&repVal, &(info.platformVersion), &len,
505                         NULL);
506             }
507
508             // OS Version
509              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_OS_VERSION, &repVal);
510             if(cbor_value_is_valid(&repVal))
511             {
512                  err = err || cbor_value_dup_text_string(&repVal, &(info.operatingSystemVersion),
513                         &len, NULL);
514             }
515
516             // Hardware Version
517              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_HARDWARE_VERSION, &repVal);
518             if(cbor_value_is_valid(&repVal))
519             {
520                  err = err || cbor_value_dup_text_string(&repVal, &(info.hardwareVersion), &len,
521                         NULL);
522             }
523
524             // Firmware Version
525              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_FIRMWARE_VERSION, &repVal);
526             if(cbor_value_is_valid(&repVal))
527             {
528                  err = err || cbor_value_dup_text_string(&repVal, &(info.firmwareVersion), &len,
529                         NULL);
530             }
531
532             // Support URL
533              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_SUPPORT_URL, &repVal);
534             if(cbor_value_is_valid(&repVal))
535             {
536                  err = err || cbor_value_dup_text_string(&repVal, &(info.supportUrl), &len, NULL);
537             }
538
539             // System Time
540              err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_SYSTEM_TIME, &repVal);
541             if(cbor_value_is_valid(&repVal))
542             {
543                  err = err || cbor_value_dup_text_string(&repVal, &(info.systemTime), &len, NULL);
544             }
545         }
546
547          err = err || cbor_value_advance(arrayVal);
548
549         if(err)
550         {
551             OICFree(info.dateOfManufacture);
552             OICFree(info.firmwareVersion);
553             OICFree(info.hardwareVersion);
554             OICFree(info.manufacturerName);
555             OICFree(info.manufacturerUrl);
556             OICFree(info.modelNumber);
557             OICFree(info.operatingSystemVersion);
558             OICFree(info.platformID);
559             OICFree(info.platformVersion);
560             OICFree(info.supportUrl);
561             OICFree(info.systemTime);
562             OC_LOG(ERROR, TAG, "CBOR error In ParsePlatformPayload");
563             return OC_STACK_MALFORMED_RESPONSE;
564         }
565
566         *outPayload = (OCPayload*)OCPlatformPayloadCreateAsOwner(uri, &info);
567
568         if(!*outPayload)
569         {
570             return OC_STACK_NO_MEMORY;
571         }
572
573         return OC_STACK_OK;
574     }
575     else
576     {
577         OC_LOG(ERROR, TAG, "Root device node was not a map");
578         return OC_STACK_MALFORMED_RESPONSE;
579     }
580 }
581
582 static OCRepPayloadPropType DecodeCborType(CborType type)
583 {
584     switch (type)
585     {
586             case CborNullType:
587                 return OCREP_PROP_NULL;
588             case CborIntegerType:
589                 return OCREP_PROP_INT;
590             case CborDoubleType:
591                 return OCREP_PROP_DOUBLE;
592             case CborBooleanType:
593                 return OCREP_PROP_BOOL;
594             case CborTextStringType:
595                 return OCREP_PROP_STRING;
596             case CborMapType:
597                 return OCREP_PROP_OBJECT;
598             case CborArrayType:
599                 return OCREP_PROP_ARRAY;
600             default:
601                 return OCREP_PROP_NULL;
602     }
603 }
604 static bool OCParseArrayFindDimensionsAndType(const CborValue* parent, size_t dimensions[MAX_REP_ARRAY_DEPTH],
605         OCRepPayloadPropType* type)
606 {
607     bool err = false;
608     CborValue insideArray;
609     *type = OCREP_PROP_NULL;
610     dimensions[0] = dimensions[1] = dimensions[2] = 0;
611
612     err = err || cbor_value_enter_container(parent, &insideArray);
613
614     while (cbor_value_is_valid(&insideArray))
615     {
616         OCRepPayloadPropType tempType = DecodeCborType(cbor_value_get_type(&insideArray));
617
618         if (tempType == OCREP_PROP_ARRAY)
619         {
620             size_t subdim[MAX_REP_ARRAY_DEPTH];
621             tempType = OCREP_PROP_NULL;
622             err = err || OCParseArrayFindDimensionsAndType(&insideArray, subdim, &tempType);
623
624             if (subdim[2] != 0)
625             {
626                 OC_LOG(ERROR, TAG, "Parse array helper, sub-array too deep");
627             }
628
629             dimensions[1] = dimensions[1] >= subdim[0] ? dimensions[1] : subdim[0];
630             dimensions[2] = dimensions[2] >= subdim[1] ? dimensions[2] : subdim[1];
631
632             if (*type != OCREP_PROP_NULL && tempType != OCREP_PROP_NULL
633                     && *type != tempType)
634             {
635                 OC_LOG(ERROR, TAG, "Array parse failed, mixed arrays not allowed (subtype)");
636                 return true;
637             }
638             else if (*type == OCREP_PROP_NULL)
639             {
640                 // We don't know the type of this array yet, so the assignment is OK
641                 *type = tempType;
642             }
643         }
644         else if (*type == OCREP_PROP_NULL)
645         {
646             // We don't know the type of this array yet, so the assignment is OK
647             *type = tempType;
648         }
649         // tempType is allowed to be NULL, since it might now know the answer yet
650         else if (tempType != OCREP_PROP_NULL && *type != tempType)
651         {
652             // this is an invalid situation!
653             OC_LOG(ERROR, TAG, "Array parse failed, mixed arrays not allowed");
654             return true;
655         }
656
657         ++dimensions[0];
658         cbor_value_advance(&insideArray);
659     }
660
661     return err;
662 }
663
664 static size_t getAllocSize(OCRepPayloadPropType type)
665 {
666     switch (type)
667     {
668         case OCREP_PROP_INT:
669             return sizeof (int64_t);
670         case OCREP_PROP_DOUBLE:
671             return sizeof (double);
672         case OCREP_PROP_BOOL:
673             return sizeof (bool);
674         case OCREP_PROP_STRING:
675             return sizeof (char*);
676         case OCREP_PROP_OBJECT:
677             return sizeof (OCRepPayload*);
678         default:
679             return 0;
680     }
681 }
682
683 static size_t arrayStep(size_t dimensions[MAX_REP_ARRAY_DEPTH], size_t elementNum)
684 {
685     return
686         (dimensions[1] == 0 ? 1 : dimensions[1]) *
687         (dimensions[2] == 0 ? 1 : dimensions[2]) *
688         elementNum;
689 }
690
691 static bool OCParseArrayFillArray(const CborValue* parent, size_t dimensions[MAX_REP_ARRAY_DEPTH],
692         OCRepPayloadPropType type, void* targetArray)
693 {
694     bool err = false;
695     CborValue insideArray;
696
697     err = err || cbor_value_enter_container(parent, &insideArray);
698
699     size_t i = 0;
700     char* tempStr = NULL;
701     size_t tempLen = 0;
702     OCRepPayload* tempPl = NULL;
703
704     size_t newdim[MAX_REP_ARRAY_DEPTH];
705     newdim[0] = dimensions[1];
706     newdim[1] = dimensions[2];
707     newdim[2] = 0;
708
709     while (!err && i < dimensions[0] && cbor_value_is_valid(&insideArray))
710     {
711         if (cbor_value_get_type(&insideArray) != CborNullType)
712         {
713             switch (type)
714             {
715                 case OCREP_PROP_INT:
716                     if (dimensions[1] == 0)
717                     {
718                         err = err || cbor_value_get_int64(&insideArray,
719                                 &(((int64_t*)targetArray)[i]));
720                     }
721                     else
722                     {
723                         err = err || OCParseArrayFillArray(&insideArray, newdim,
724                             type,
725                             &(((int64_t*)targetArray)[arrayStep(dimensions, i)])
726                             );
727                     }
728                     break;
729                 case OCREP_PROP_DOUBLE:
730                     if (dimensions[1] == 0)
731                     {
732                         err = err || cbor_value_get_double(&insideArray,
733                                 &(((double*)targetArray)[i]));
734                     }
735                     else
736                     {
737                         err = err || OCParseArrayFillArray(&insideArray, newdim,
738                             type,
739                             &(((double*)targetArray)[arrayStep(dimensions, i)])
740                             );
741                     }
742                     break;
743                 case OCREP_PROP_BOOL:
744                     if (dimensions[1] == 0)
745                     {
746                         err = err || cbor_value_get_boolean(&insideArray,
747                                 &(((bool*)targetArray)[i]));
748                     }
749                     else
750                     {
751                         err = err || OCParseArrayFillArray(&insideArray, newdim,
752                             type,
753                             &(((bool*)targetArray)[arrayStep(dimensions, i)])
754                             );
755                     }
756                     break;
757                 case OCREP_PROP_STRING:
758                     if (dimensions[1] == 0)
759                     {
760                         err = err || cbor_value_dup_text_string(&insideArray,
761                                 &tempStr, &tempLen, NULL);
762                         ((char**)targetArray)[i] = tempStr;
763                         tempStr = NULL;
764                     }
765                     else
766                     {
767                         err = err || OCParseArrayFillArray(&insideArray, newdim,
768                             type,
769                             &(((char**)targetArray)[arrayStep(dimensions, i)])
770                             );
771                     }
772                     break;
773                 case OCREP_PROP_OBJECT:
774                     if (dimensions[1] == 0)
775                     {
776                         err = err || OCParseSingleRepPayload(&tempPl, &insideArray);
777                         ((OCRepPayload**)targetArray)[i] = tempPl;
778                         tempPl = NULL;
779                     }
780                     else
781                     {
782                         err = err || OCParseArrayFillArray(&insideArray, newdim,
783                             type,
784                             &(((OCRepPayload**)targetArray)[arrayStep(dimensions, i)])
785                             );
786                     }
787                     break;
788                 default:
789                     OC_LOG(ERROR, TAG, "Invalid Array type in Parse Array");
790                     err = true;
791                     break;
792             }
793         }
794         ++i;
795         err = err || cbor_value_advance(&insideArray);
796     }
797
798     return err;
799 }
800
801 static bool OCParseArray(OCRepPayload* out, const char* name, CborValue* container)
802 {
803     OCRepPayloadPropType type;
804     size_t dimensions[MAX_REP_ARRAY_DEPTH];
805     bool err = OCParseArrayFindDimensionsAndType(container, dimensions, &type);
806
807     if (err)
808     {
809         OC_LOG(ERROR, TAG, "Array details weren't clear");
810         return err;
811     }
812
813     if (type == OCREP_PROP_NULL)
814     {
815         err = err || OCRepPayloadSetNull(out, name);
816         err = err || cbor_value_advance(container);
817         return err;
818     }
819
820     size_t dimTotal = calcDimTotal(dimensions);
821     size_t allocSize = getAllocSize(type);
822     void* arr = OICCalloc(dimTotal, allocSize);
823
824     if (!arr)
825     {
826         OC_LOG(ERROR, TAG, "Array Parse allocation failed");
827         return true;
828     }
829
830     err = err || OCParseArrayFillArray(container, dimensions, type, arr);
831
832     switch (type)
833     {
834         case OCREP_PROP_INT:
835             if (err || !OCRepPayloadSetIntArrayAsOwner(out, name, (int64_t*)arr, dimensions))
836             {
837                 OICFree(arr);
838                 err = true;
839             }
840             break;
841         case OCREP_PROP_DOUBLE:
842             if (err || !OCRepPayloadSetDoubleArrayAsOwner(out, name, (double*)arr, dimensions))
843             {
844                 OICFree(arr);
845                 err = true;
846             }
847             break;
848         case OCREP_PROP_BOOL:
849             if (err || !OCRepPayloadSetBoolArrayAsOwner(out, name, (bool*)arr, dimensions))
850             {
851                 OICFree(arr);
852                 err = true;
853             }
854             break;
855         case OCREP_PROP_STRING:
856             if (err || !OCRepPayloadSetStringArrayAsOwner(out, name, (char**)arr, dimensions))
857             {
858                 for(size_t i = 0; i < dimTotal; ++i)
859                 {
860                     OICFree(((char**)arr)[i]);
861                 }
862                 OICFree(arr);
863                 err = true;
864             }
865             break;
866         case OCREP_PROP_OBJECT:
867             if (err || !OCRepPayloadSetPropObjectArrayAsOwner(out, name, (OCRepPayload**)arr, dimensions))
868             {
869                 for(size_t i = 0; i < dimTotal; ++i)
870                 {
871                     OCRepPayloadDestroy(((OCRepPayload**)arr)[i]);
872                 }
873                 OICFree(arr);
874                 err = true;
875             }
876             break;
877         default:
878             OC_LOG(ERROR, TAG, "Invalid Array type in Parse Array");
879             err = true;
880             break;
881     }
882
883     return err;
884 }
885
886 static bool OCParseSingleRepPayload(OCRepPayload** outPayload, CborValue* repParent)
887 {
888     if (!outPayload)
889     {
890         return false;
891     }
892
893     *outPayload = OCRepPayloadCreate();
894     OCRepPayload* curPayload = *outPayload;
895     bool err = false;
896     if(!*outPayload)
897     {
898         return CborErrorOutOfMemory;
899     }
900
901     size_t len;
902     CborValue curVal;
903     err = err || cbor_value_map_find_value(repParent, OC_RSRVD_HREF, &curVal);
904     if(cbor_value_is_valid(&curVal))
905     {
906         err = err || cbor_value_dup_text_string(&curVal, &curPayload->uri, &len,
907             NULL);
908     }
909
910     err = err || cbor_value_map_find_value(repParent, OC_RSRVD_PROPERTY, &curVal);
911     if(cbor_value_is_valid(&curVal))
912     {
913         CborValue insidePropValue = {0};
914         err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_RESOURCE_TYPE,
915                 &insidePropValue);
916
917         if(cbor_value_is_text_string(&insidePropValue))
918         {
919             char* allRt = NULL;
920             err = err || cbor_value_dup_text_string(&insidePropValue, &allRt, &len, NULL);
921
922             char* savePtr;
923
924             if (allRt)
925             {
926                 char* curPtr = strtok_r(allRt, " ", &savePtr);
927
928                 while (curPtr)
929                 {
930                     char* trimmed = InPlaceStringTrim(curPtr);
931                     if (trimmed[0] != '\0')
932                     {
933                         OCRepPayloadAddResourceType(curPayload, curPtr);
934                     }
935                     curPtr = strtok_r(NULL, " ", &savePtr);
936                 }
937             }
938             OICFree(allRt);
939         }
940
941         err = err || cbor_value_map_find_value(&curVal, OC_RSRVD_INTERFACE, &insidePropValue);
942
943         if(cbor_value_is_text_string(&insidePropValue))
944         {
945             char* allIf = NULL;
946             err = err || cbor_value_dup_text_string(&insidePropValue, &allIf, &len, NULL);
947
948             char* savePtr;
949
950             if (allIf)
951             {
952                 char* curPtr = strtok_r(allIf, " ", &savePtr);
953
954                 while (curPtr)
955                 {
956                     char* trimmed = InPlaceStringTrim(curPtr);
957                     if (trimmed[0] != '\0')
958                     {
959                         OCRepPayloadAddInterface(curPayload, curPtr);
960                     }
961                     curPtr = strtok_r(NULL, " ", &savePtr);
962                 }
963             }
964             OICFree(allIf);
965         }
966     }
967
968     err = err || cbor_value_map_find_value(repParent, OC_RSRVD_REPRESENTATION, &curVal);
969     if(cbor_value_is_map(&curVal))
970     {
971         CborValue repMap;
972         err = err || cbor_value_enter_container(&curVal, &repMap);
973
974         while(!err && cbor_value_is_valid(&repMap))
975         {
976             char* name;
977             err = err || cbor_value_dup_text_string(&repMap, &name, &len, NULL);
978
979             err = err || cbor_value_advance(&repMap);
980
981             int64_t intval = 0;
982             bool boolval = false;
983             char* strval = NULL;
984             double doubleval = 0;
985             OCRepPayload* pl;
986
987             switch(cbor_value_get_type(&repMap))
988             {
989                 case CborNullType:
990                     err = !OCRepPayloadSetNull(curPayload, name);
991                     break;
992                 case CborIntegerType:
993                     err = err || cbor_value_get_int64(&repMap, &intval);
994                     if (!err)
995                     {
996                         err = !OCRepPayloadSetPropInt(curPayload, name, intval);
997                     }
998                     break;
999                 case CborDoubleType:
1000                     err = err || cbor_value_get_double(&repMap, &doubleval);
1001                     if (!err)
1002                     {
1003                         err = !OCRepPayloadSetPropDouble(curPayload, name, doubleval);
1004                     }
1005                     break;
1006                 case CborBooleanType:
1007                     err = err || cbor_value_get_boolean(&repMap, &boolval);
1008                     if (!err)
1009                     {
1010                         err = !OCRepPayloadSetPropBool(curPayload, name, boolval);
1011                     }
1012                     break;
1013                 case CborTextStringType:
1014                     err = err || cbor_value_dup_text_string(&repMap, &strval, &len, NULL);
1015                     if (!err)
1016                     {
1017                         err = !OCRepPayloadSetPropStringAsOwner(curPayload, name, strval);
1018                     }
1019                     break;
1020                 case CborMapType:
1021                     err = err || OCParseSingleRepPayload(&pl, &repMap);
1022                     if (!err)
1023                     {
1024                         err = !OCRepPayloadSetPropObjectAsOwner(curPayload, name, pl);
1025                     }
1026                     break;
1027                 case CborArrayType:
1028                     err = err || OCParseArray(curPayload, name, &repMap);
1029                     break;
1030                 default:
1031                     OC_LOG_V(ERROR, TAG, "Parsing rep property, unknown type %d", repMap.type);
1032                     err = true;
1033             }
1034
1035              err = err || cbor_value_advance(&repMap);
1036             OICFree(name);
1037         }
1038         err = err || cbor_value_leave_container(&curVal, &repMap);
1039     }
1040
1041     if(err)
1042     {
1043         OCRepPayloadDestroy(*outPayload);
1044         *outPayload = NULL;
1045     }
1046
1047     return err;
1048 }
1049 static OCStackResult OCParseRepPayload(OCPayload** outPayload, CborValue* arrayVal)
1050 {
1051     if (!outPayload)
1052     {
1053         return OC_STACK_INVALID_PARAM;
1054     }
1055
1056     bool err = false;
1057
1058     OCRepPayload* rootPayload = NULL;
1059     OCRepPayload* curPayload = NULL;
1060     OCRepPayload* temp = NULL;
1061     while(!err && cbor_value_is_map(arrayVal))
1062     {
1063          err = err || OCParseSingleRepPayload(&temp, arrayVal);
1064
1065         if(rootPayload == NULL)
1066         {
1067             rootPayload = temp;
1068             curPayload = temp;
1069         }
1070         else
1071         {
1072             curPayload->next = temp;
1073             curPayload = curPayload->next;
1074         }
1075
1076
1077          err = err || cbor_value_advance(arrayVal);
1078         if(err)
1079         {
1080             OCRepPayloadDestroy(rootPayload);
1081             OC_LOG(ERROR, TAG, "CBOR error in ParseRepPayload");
1082             return OC_STACK_MALFORMED_RESPONSE;
1083         }
1084     }
1085
1086     *outPayload = (OCPayload*)rootPayload;
1087
1088     return OC_STACK_OK;
1089 }
1090
1091 static OCStackResult OCParsePresencePayload(OCPayload** outPayload, CborValue* arrayVal)
1092 {
1093     if (!outPayload)
1094     {
1095         return OC_STACK_INVALID_PARAM;
1096     }
1097
1098     bool err = false;
1099     if(cbor_value_is_map(arrayVal))
1100     {
1101         uint64_t seqNum = 0;
1102         uint64_t maxAge = 0;
1103         OCPresenceTrigger trigger = OC_PRESENCE_TRIGGER_CREATE;
1104         char* tempStr = NULL;
1105         size_t len = 0;
1106
1107         CborValue curVal;
1108         // Sequence Number
1109         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_NONCE, &curVal);
1110         err = err || cbor_value_get_uint64(&curVal, &seqNum);
1111
1112         // Max Age
1113         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_TTL, &curVal);
1114         err = err || cbor_value_get_uint64(&curVal, &maxAge);
1115
1116         // Trigger
1117         err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_TRIGGER, &curVal);
1118         err = err || cbor_value_dup_text_string(&curVal, &tempStr, &len, NULL);
1119         trigger = convertTriggerStringToEnum(tempStr);
1120         OICFree(tempStr);
1121         tempStr = NULL;
1122
1123         // Resource type name
1124          err = err || cbor_value_map_find_value(arrayVal, OC_RSRVD_RESOURCE_TYPE, &curVal);
1125         if(cbor_value_is_valid(&curVal))
1126         {
1127              err = err || cbor_value_dup_text_string(&curVal, &tempStr, &len, NULL);
1128         }
1129
1130         err = err || cbor_value_advance(arrayVal);
1131
1132         if(!err)
1133         {
1134             *outPayload = (OCPayload*)OCPresencePayloadCreate(seqNum, maxAge, trigger, tempStr);
1135         }
1136         OICFree(tempStr);
1137
1138         if(err)
1139         {
1140             OCPayloadDestroy(*outPayload);
1141             OC_LOG(ERROR, TAG, "CBOR error Parse Presence Payload");
1142             return OC_STACK_MALFORMED_RESPONSE;
1143         }
1144
1145         if(!*outPayload)
1146         {
1147             return OC_STACK_NO_MEMORY;
1148         }
1149
1150         return OC_STACK_OK;
1151     }
1152     else
1153     {
1154         OC_LOG(ERROR, TAG, "Root presence node was not a map");
1155         return OC_STACK_MALFORMED_RESPONSE;
1156     }
1157 }