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