e6738f58e9094b2cc6c87b2ee3b4bd58f9c18ab2
[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
30 #include <string.h>
31 #include <stdlib.h>
32 #include "ocpayload.h"
33 #include "oic_string.h"
34 #include "oic_malloc.h"
35 #include "ocpayloadcbor.h"
36 #include "ocstackinternal.h"
37 #include "payload_logging.h"
38 #include "platform_features.h"
39 #include "ocendpoint.h"
40
41 #define TAG "OIC_RI_PAYLOADPARSE"
42
43 /*
44  * The length of UINT64_MAX as a decimal string.
45  */
46 #define UINT64_MAX_STRLEN 20
47
48 static OCStackResult OCParseDiscoveryPayload(OCPayload **outPayload, CborValue *arrayVal);
49 static CborError OCParseSingleRepPayload(OCRepPayload **outPayload, CborValue *repParent, bool isRoot);
50 static OCStackResult OCParseRepPayload(OCPayload **outPayload, CborValue *arrayVal);
51 static OCStackResult OCParsePresencePayload(OCPayload **outPayload, CborValue *arrayVal);
52 static OCStackResult OCParseSecurityPayload(OCPayload **outPayload, const uint8_t *payload, size_t size);
53
54 OCStackResult OCParsePayload(OCPayload **outPayload, OCPayloadType payloadType,
55         const uint8_t *payload, size_t payloadSize)
56 {
57     OCStackResult result = OC_STACK_MALFORMED_RESPONSE;
58     CborError err;
59
60     VERIFY_PARAM_NON_NULL(TAG, outPayload, "Conversion of outPayload failed");
61     VERIFY_PARAM_NON_NULL(TAG, payload, "Invalid cbor payload value");
62
63     OIC_LOG_V(INFO, TAG, "CBOR Parsing size: %zu of Payload Type: %d, Payload:",
64             payloadSize, payloadType);
65     OIC_LOG_BUFFER(DEBUG, TAG, payload, payloadSize);
66
67     CborParser parser;
68     CborValue rootValue;
69
70     err = cbor_parser_init(payload, payloadSize, 0, &parser, &rootValue);
71     VERIFY_CBOR_SUCCESS(TAG, err, "Failed initializing init value")
72
73     switch(payloadType)
74     {
75         case PAYLOAD_TYPE_DISCOVERY:
76             result = OCParseDiscoveryPayload(outPayload, &rootValue);
77             break;
78         case PAYLOAD_TYPE_REPRESENTATION:
79             result = OCParseRepPayload(outPayload, &rootValue);
80             break;
81         case PAYLOAD_TYPE_PRESENCE:
82             result = OCParsePresencePayload(outPayload, &rootValue);
83             break;
84         case PAYLOAD_TYPE_SECURITY:
85             result = OCParseSecurityPayload(outPayload, payload, payloadSize);
86             break;
87         default:
88             OIC_LOG_V(ERROR, TAG, "ParsePayload Type default: %d", payloadType);
89             result = OC_STACK_INVALID_PARAM;
90             break;
91     }
92
93     OIC_LOG_V(INFO, TAG, "Finished parse payload, result is %d", result);
94
95 exit:
96     return result;
97 }
98
99 static OCStackResult OCParseSecurityPayload(OCPayload** outPayload, const uint8_t *payload,
100         size_t size)
101 {
102     if (size > 0)
103     {
104         *outPayload = (OCPayload *)OCSecurityPayloadCreate(payload, size);
105     }
106     else
107     {
108         *outPayload = NULL;
109     }
110     return OC_STACK_OK;
111 }
112
113 static char* InPlaceStringTrim(char* str)
114 {
115     while (str[0] == ' ')
116     {
117         ++str;
118     }
119
120     size_t lastchar = strlen(str);
121
122     while (str[lastchar] == ' ')
123     {
124         str[lastchar] = '\0';
125         --lastchar;
126     }
127
128     return str;
129 }
130
131 static CborError OCParseStringLL(CborValue *map, char *type, OCStringLL **resource)
132 {
133     CborValue val;
134     CborError err = cbor_value_map_find_value(map, type, &val);
135     VERIFY_CBOR_SUCCESS(TAG, err, "to find StringLL TAG");
136
137     if (cbor_value_is_array(&val))
138     {
139         CborValue txtStr;
140         err = cbor_value_enter_container(&val, &txtStr);
141         VERIFY_CBOR_SUCCESS(TAG, err, "to enter container");
142         while (cbor_value_is_text_string(&txtStr))
143         {
144             size_t len = 0;
145             char *input = NULL;
146             err = cbor_value_dup_text_string(&txtStr, &input, &len, NULL);
147             VERIFY_CBOR_SUCCESS(TAG, err, "to find StringLL value.");
148             if (input)
149             {
150                 char *savePtr = NULL;
151                 char *curPtr = strtok_r(input, " ", &savePtr);
152                 while (curPtr)
153                 {
154                     char *trimmed = InPlaceStringTrim(curPtr);
155                     if (trimmed && strlen(trimmed) > 0)
156                     {
157                         if (!OCResourcePayloadAddStringLL(resource, trimmed))
158                         {
159                             return CborErrorOutOfMemory;
160                         }
161                     }
162                     curPtr = strtok_r(NULL, " ", &savePtr);
163                 }
164                 free(input);  // Free *TinyCBOR allocated* string.
165             }
166             if (cbor_value_is_text_string(&txtStr))
167             {
168                 err = cbor_value_advance(&txtStr);
169                 VERIFY_CBOR_SUCCESS(TAG, err, "to advance string value");
170             }
171         }
172     }
173 exit:
174     return err;
175 }
176
177 static OCStackResult OCParseDiscoveryPayload(OCPayload **outPayload, CborValue *rootValue)
178 {
179     OCStackResult ret = OC_STACK_INVALID_PARAM;
180     OCResourcePayload *resource = NULL;
181     OCDiscoveryPayload *temp = NULL;
182     OCDiscoveryPayload *rootPayload = NULL;
183     OCDiscoveryPayload *curPayload = NULL;
184     OCEndpointPayload *endpoint = NULL;
185     size_t len = 0;
186     CborError err = CborNoError;
187     *outPayload = NULL;
188
189     VERIFY_PARAM_NON_NULL(TAG, outPayload, "Invalid Parameter outPayload");
190     VERIFY_PARAM_NON_NULL(TAG, rootValue, "Invalid Parameter rootValue");
191     if (cbor_value_is_array(rootValue))
192     {
193         // Root value is already inside the main root array
194         CborValue rootMap;
195
196         // Enter the main root map
197         ret = OC_STACK_MALFORMED_RESPONSE;
198         err = cbor_value_enter_container(rootValue, &rootMap);
199         VERIFY_CBOR_SUCCESS(TAG, err, "to enter root map container");
200         while (cbor_value_is_map(&rootMap))
201         {
202             ret = OC_STACK_NO_MEMORY;
203             temp = OCDiscoveryPayloadCreate();
204             VERIFY_PARAM_NON_NULL(TAG, temp, "Failed error initializing discovery payload");
205
206             // Look for DI
207             CborValue curVal;
208             err = cbor_value_map_find_value(&rootMap, OC_RSRVD_DEVICE_ID, &curVal);
209             VERIFY_CBOR_SUCCESS(TAG, err, "to find device id tag");
210             if (cbor_value_is_valid(&curVal))
211             {
212                 if (cbor_value_is_byte_string(&curVal))
213                 {
214                     err = cbor_value_dup_byte_string(&curVal, (uint8_t **)&(temp->sid), &len, NULL);
215                     VERIFY_CBOR_SUCCESS(TAG, err, "to copy device id value");
216                 }
217                 else if (cbor_value_is_text_string(&curVal))
218                 {
219                     err = cbor_value_dup_text_string(&curVal, &(temp->sid), &len, NULL);
220                     VERIFY_CBOR_SUCCESS(TAG, err, "to copy device id value");
221                 }
222             }
223
224             // BaseURI - Not a mandatory field
225             err = cbor_value_map_find_value(&rootMap, OC_RSRVD_BASE_URI, &curVal);
226             VERIFY_CBOR_SUCCESS(TAG, err, "to find uri tag");
227             if (cbor_value_is_text_string(&curVal))
228             {
229                 err = cbor_value_dup_text_string(&curVal, &(temp->baseURI), &len, NULL);
230                 VERIFY_CBOR_SUCCESS(TAG, err, "to find base uri value");
231             }
232
233             // RT - Not a mandatory field
234             err = cbor_value_map_find_value(&rootMap, OC_RSRVD_RESOURCE_TYPE, &curVal);
235             if (cbor_value_is_valid(&curVal))
236             {
237                 err = OCParseStringLL(&rootMap, OC_RSRVD_RESOURCE_TYPE, &temp->type);
238                 VERIFY_CBOR_SUCCESS(TAG, err, "to find resource type");
239             }
240
241             // IF - Not a mandatory field
242             err = cbor_value_map_find_value(&rootMap, OC_RSRVD_INTERFACE, &curVal);
243             if (cbor_value_is_valid(&curVal))
244             {
245                 err =  OCParseStringLL(&rootMap, OC_RSRVD_INTERFACE, &temp->iface);
246                 VERIFY_CBOR_SUCCESS(TAG, err, "to find interface");
247             }
248
249             // Name - Not a mandatory field
250             err = cbor_value_map_find_value(&rootMap, OC_RSRVD_DEVICE_NAME, &curVal);
251             if (cbor_value_is_text_string(&curVal))
252             {
253                 err = cbor_value_dup_text_string(&curVal, &temp->name, &len, NULL);
254                 VERIFY_CBOR_SUCCESS(TAG, err, "to find device name");
255             }
256
257             // Look for Links which will have an array as the value
258             CborValue linkMap;
259             err = cbor_value_map_find_value(&rootMap, OC_RSRVD_LINKS, &linkMap);
260             VERIFY_CBOR_SUCCESS(TAG, err, "to find links tag");
261
262             // Enter the links array and start iterating through the array processing
263             // each resource which shows up as a map.
264             CborValue resourceMap;
265             err = cbor_value_enter_container(&linkMap, &resourceMap);
266             VERIFY_CBOR_SUCCESS(TAG, err, "to enter link map");
267
268             while (cbor_value_is_map(&resourceMap))
269             {
270                 int bitmap;
271
272                 resource = (OCResourcePayload *)OICCalloc(1, sizeof(OCResourcePayload));
273                 VERIFY_PARAM_NON_NULL(TAG, resource, "Failed allocating resource payload");
274
275                 // Uri
276                 err = cbor_value_map_find_value(&resourceMap, OC_RSRVD_HREF, &curVal);
277                 VERIFY_CBOR_SUCCESS(TAG, err, "to find href tag");
278                 err = cbor_value_dup_text_string(&curVal, &(resource->uri), &len, NULL);
279                 VERIFY_CBOR_SUCCESS(TAG, err, "to find href value");
280
281                 // Rel - Not a mandatory field
282                 err = cbor_value_map_find_value(&resourceMap, OC_RSRVD_REL, &curVal);
283                 VERIFY_CBOR_SUCCESS(TAG, err, "to find rel tag");
284                 if (cbor_value_is_valid(&curVal))
285                 {
286                     err = cbor_value_dup_text_string(&curVal, &(resource->rel), &len, NULL);
287                     VERIFY_CBOR_SUCCESS(TAG, err, "to find rel value");
288                 }
289
290                 // ResourceTypes
291                 err =  OCParseStringLL(&resourceMap, OC_RSRVD_RESOURCE_TYPE, &resource->types);
292                 VERIFY_CBOR_SUCCESS(TAG, err, "to find resource type tag/value");
293
294                 // Interface Types
295                 err =  OCParseStringLL(&resourceMap, OC_RSRVD_INTERFACE, &resource->interfaces);
296                 if (CborNoError != err)
297                 {
298                     if (!OCResourcePayloadAddStringLL(&resource->interfaces, OC_RSRVD_INTERFACE_LL))
299                     {
300                         OIC_LOG(ERROR, TAG, "Failed to add string to StringLL");
301                         goto exit;
302                     }
303                 }
304
305                 // Policy
306                 CborValue policyMap;
307                 err = cbor_value_map_find_value(&resourceMap, OC_RSRVD_POLICY, &policyMap);
308                 VERIFY_CBOR_SUCCESS(TAG, err, "to find policy tag");
309
310                 // Bitmap
311                 err = cbor_value_map_find_value(&policyMap, OC_RSRVD_BITMAP, &curVal);
312                 VERIFY_CBOR_SUCCESS(TAG, err, "to find bitmap tag");
313                 err = cbor_value_get_int(&curVal, &bitmap);
314                 VERIFY_CBOR_SUCCESS(TAG, err, "to find bitmap value");
315                 resource->bitmap = (uint8_t)bitmap;
316
317                 // Secure Flag
318                 err = cbor_value_map_find_value(&policyMap, OC_RSRVD_SECURE, &curVal);
319                 VERIFY_CBOR_SUCCESS(TAG, err, "to find secure tag");
320                 if (cbor_value_is_boolean(&curVal))
321                 {
322                     err = cbor_value_get_boolean(&curVal, &(resource->secure));
323                     VERIFY_CBOR_SUCCESS(TAG, err, "to find secure value");
324                 }
325
326                 // Port
327                 err = cbor_value_map_find_value(&policyMap, OC_RSRVD_HOSTING_PORT, &curVal);
328                 VERIFY_CBOR_SUCCESS(TAG, err, "to find port tag");
329                 if (cbor_value_is_integer(&curVal))
330                 {
331                     int port;
332
333                     err = cbor_value_get_int(&curVal, &port);
334                     VERIFY_CBOR_SUCCESS(TAG, err, "to find port value");
335                     resource->port = (uint16_t)port;
336                 }
337
338 #ifdef TCP_ADAPTER
339                 // TCP Port
340                 err = cbor_value_map_find_value(&policyMap, OC_RSRVD_TCP_PORT, &curVal);
341                 if (cbor_value_is_integer(&curVal))
342                 {
343                     int tcpPort;
344
345                     err = cbor_value_get_int(&curVal, &tcpPort);
346                     VERIFY_CBOR_SUCCESS(TAG, err, "to find tcp port value");
347                     resource->tcpPort = (uint16_t)tcpPort;
348                 }
349
350 #ifdef __WITH_TLS__
351                 // TLS Port
352                 err = cbor_value_map_find_value(&policyMap, OC_RSRVD_TLS_PORT, &curVal);
353                 if (cbor_value_is_integer(&curVal))
354                 {
355                     int tlsPort;
356
357                     err = cbor_value_get_int(&curVal, &tlsPort);
358                     VERIFY_CBOR_SUCCESS(TAG, err, "to find tcp tls port value");
359                     resource->tcpPort = (uint16_t)tlsPort;
360                 }
361 #endif
362 #endif
363                 // Endpoints
364                 CborValue epsMap;
365                 err = cbor_value_map_find_value(&resourceMap, OC_RSRVD_ENDPOINTS, &epsMap);
366                 VERIFY_CBOR_SUCCESS(TAG, err, "to find eps tag");
367
368                 if (cbor_value_is_array(&epsMap))
369                 {
370                     CborValue epMap;
371                     err = cbor_value_enter_container(&epsMap, &epMap);
372                     VERIFY_CBOR_SUCCESS(TAG, err, "to enter endpoint map");
373
374                     while (cbor_value_is_map(&epMap))
375                     {
376                         endpoint = NULL;
377                         int pri = 0;
378                         char *endpointStr = NULL;
379                         OCStackResult ret = OC_STACK_ERROR;
380                         endpoint = (OCEndpointPayload *)OICCalloc(1, sizeof(OCEndpointPayload));
381                         VERIFY_PARAM_NON_NULL(TAG, endpoint, "Failed allocating endpoint payload");
382
383                         // ep
384                         err = cbor_value_map_find_value(&epMap, OC_RSRVD_ENDPOINT, &curVal);
385                         VERIFY_CBOR_SUCCESS(TAG, err, "to find endpoint tag");
386                         err = cbor_value_dup_text_string(&curVal, &endpointStr, &len, NULL);
387                         VERIFY_CBOR_SUCCESS(TAG, err, "to find endpoint value");
388
389                         ret = OCParseEndpointString(endpointStr, endpoint);
390                         OICFree(endpointStr);
391
392                         if (OC_STACK_OK == ret)
393                         {
394                             // pri
395                             err = cbor_value_map_find_value(&epMap, OC_RSRVD_PRIORITY, &curVal);
396                             VERIFY_CBOR_SUCCESS(TAG, err, "to find priority tag");
397                             err = cbor_value_get_int(&curVal, &pri);
398                             VERIFY_CBOR_SUCCESS(TAG, err, "to find priority value");
399                             endpoint->pri = (uint16_t)pri;
400                             OCResourcePayloadAddNewEndpoint(resource, endpoint);
401                             endpoint = NULL;
402                         }
403                         else
404                         {
405                             if (OC_STACK_ADAPTER_NOT_ENABLED == ret)
406                             {
407                                 OIC_LOG(ERROR, TAG, "Ignore unrecognized endpoint info");
408                             }
409                             // destroy endpoint
410                             OCDiscoveryEndpointDestroy(endpoint);
411                             endpoint = NULL;
412                         }
413
414                         err = cbor_value_advance(&epMap);
415                         VERIFY_CBOR_SUCCESS(TAG, err, "to advance endpoint map");
416                     }
417
418                     err = cbor_value_leave_container(&epsMap, &epMap);
419                     VERIFY_CBOR_SUCCESS(TAG, err, "to leave eps map");
420                 }
421
422                 err = cbor_value_advance(&resourceMap);
423                 VERIFY_CBOR_SUCCESS(TAG, err, "to advance resource map");
424
425                 OCDiscoveryPayloadAddNewResource(temp, resource);
426             }
427
428             err = cbor_value_leave_container(&linkMap, &resourceMap);
429             VERIFY_CBOR_SUCCESS(TAG, err, "to leave resource map");
430
431             err = cbor_value_advance(&rootMap);
432             VERIFY_CBOR_SUCCESS(TAG, err, "to advance root map");
433
434             if(rootPayload == NULL)
435             {
436                 rootPayload = temp;
437                 curPayload = temp;
438             }
439             else
440             {
441                 curPayload->next = temp;
442                 curPayload = curPayload->next;
443             }
444         }
445
446         err = cbor_value_leave_container(rootValue, &rootMap);
447         VERIFY_CBOR_SUCCESS(TAG, err, "to leave root map");
448
449     }
450     else
451     {
452         OIC_LOG(ERROR, TAG, "Malformed packet ");
453         goto exit;
454     }
455
456     *outPayload = (OCPayload *)rootPayload;
457     OIC_LOG_PAYLOAD(DEBUG, *outPayload);
458
459     return OC_STACK_OK;
460
461 exit:
462     OCDiscoveryEndpointDestroy(endpoint);
463     OCDiscoveryResourceDestroy(resource);
464     OCDiscoveryPayloadDestroy(rootPayload);
465     return ret;
466 }
467
468 static OCRepPayloadPropType DecodeCborType(CborType type)
469 {
470     switch (type)
471     {
472         case CborNullType:
473             return OCREP_PROP_NULL;
474         case CborIntegerType:
475             return OCREP_PROP_INT;
476         case CborDoubleType:
477         case CborFloatType:
478             return OCREP_PROP_DOUBLE;
479         case CborBooleanType:
480             return OCREP_PROP_BOOL;
481         case CborTextStringType:
482             return OCREP_PROP_STRING;
483         case CborByteStringType:
484             return OCREP_PROP_BYTE_STRING;
485         case CborMapType:
486             return OCREP_PROP_OBJECT;
487         case CborArrayType:
488             return OCREP_PROP_ARRAY;
489         default:
490             return OCREP_PROP_NULL;
491     }
492 }
493
494 static CborError OCParseArrayFindDimensionsAndType(const CborValue *parent,
495         size_t dimensions[MAX_REP_ARRAY_DEPTH], OCRepPayloadPropType *type)
496 {
497     CborValue insideArray;
498     *type = OCREP_PROP_NULL;
499     dimensions[0] = dimensions[1] = dimensions[2] = 0;
500
501     CborError err = cbor_value_enter_container(parent, &insideArray);
502     VERIFY_CBOR_SUCCESS(TAG, err, "Failed to enter container");
503
504     while (cbor_value_is_valid(&insideArray))
505     {
506         OCRepPayloadPropType tempType = DecodeCborType(cbor_value_get_type(&insideArray));
507
508         if (tempType == OCREP_PROP_ARRAY)
509         {
510             size_t subdim[MAX_REP_ARRAY_DEPTH];
511             tempType = OCREP_PROP_NULL;
512             err = OCParseArrayFindDimensionsAndType(&insideArray, subdim, &tempType);
513             VERIFY_CBOR_SUCCESS(TAG, err, "Failed to parse array");
514
515             if (subdim[2] != 0)
516             {
517                 OIC_LOG(ERROR, TAG, "Parse array helper, sub-array too deep");
518             }
519
520             dimensions[1] = dimensions[1] >= subdim[0] ? dimensions[1] : subdim[0];
521             dimensions[2] = dimensions[2] >= subdim[1] ? dimensions[2] : subdim[1];
522
523             if (*type != OCREP_PROP_NULL && tempType != OCREP_PROP_NULL && *type != tempType)
524             {
525                 OIC_LOG(ERROR, TAG, "Array parse failed, mixed arrays not allowed (subtype)");
526                 return CborUnknownError;
527             }
528             else if (*type == OCREP_PROP_NULL)
529             {
530                 // We don't know the type of this array yet, so the assignment is OK
531                 *type = tempType;
532             }
533         }
534         else if (*type == OCREP_PROP_NULL)
535         {
536             // We don't know the type of this array yet, so the assignment is OK
537             *type = tempType;
538         }
539         // tempType is allowed to be NULL, since it might now know the answer yet
540         else if (tempType != OCREP_PROP_NULL && *type != tempType)
541         {
542             // this is an invalid situation!
543             OIC_LOG(ERROR, TAG, "Array parse failed, mixed arrays not allowed");
544             return CborUnknownError;
545         }
546
547         ++dimensions[0];
548         err = cbor_value_advance(&insideArray);
549         VERIFY_CBOR_SUCCESS(TAG, err, "Failed to advance array");
550     }
551
552 exit:
553     return err;
554 }
555
556 static size_t getAllocSize(OCRepPayloadPropType type)
557 {
558     switch (type)
559     {
560         case OCREP_PROP_INT:
561             return sizeof (int64_t);
562         case OCREP_PROP_DOUBLE:
563             return sizeof (double);
564         case OCREP_PROP_BOOL:
565             return sizeof (bool);
566         case OCREP_PROP_STRING:
567             return sizeof (char*);
568         case OCREP_PROP_BYTE_STRING:
569             return sizeof (OCByteString);
570         case OCREP_PROP_OBJECT:
571             return sizeof (OCRepPayload*);
572         default:
573             return 0;
574     }
575 }
576
577 static size_t arrayStep(size_t dimensions[MAX_REP_ARRAY_DEPTH], size_t elementNum)
578 {
579     return
580         (dimensions[1] == 0 ? 1 : dimensions[1]) *
581         (dimensions[2] == 0 ? 1 : dimensions[2]) *
582         elementNum;
583 }
584
585 static CborError OCParseArrayFillArray(const CborValue *parent,
586         size_t dimensions[MAX_REP_ARRAY_DEPTH], OCRepPayloadPropType type, void *targetArray)
587 {
588     CborValue insideArray;
589
590     size_t i = 0;
591     char *tempStr = NULL;
592     OCByteString ocByteStr = { .bytes = NULL, .len = 0};
593     size_t tempLen = 0;
594     OCRepPayload *tempPl = NULL;
595
596     size_t newdim[MAX_REP_ARRAY_DEPTH];
597     newdim[0] = dimensions[1];
598     newdim[1] = dimensions[2];
599     newdim[2] = 0;
600
601     CborError err = cbor_value_enter_container(parent, &insideArray);
602     VERIFY_CBOR_SUCCESS(TAG, err, "Failed to enter container");
603
604     while (!err && i < dimensions[0] && cbor_value_is_valid(&insideArray))
605     {
606         bool noAdvance = false;
607         if (cbor_value_get_type(&insideArray) != CborNullType)
608         {
609             switch (type)
610             {
611                 case OCREP_PROP_INT:
612                     if (dimensions[1] == 0)
613                     {
614                         err = cbor_value_get_int64(&insideArray, &(((int64_t*)targetArray)[i]));
615                     }
616                     else
617                     {
618                         err = OCParseArrayFillArray(&insideArray, newdim, type,
619                             &(((int64_t*)targetArray)[arrayStep(dimensions, i)]));
620                     }
621                     break;
622                 case OCREP_PROP_DOUBLE:
623                     if (dimensions[1] == 0)
624                     {
625                         double *d = &(((double*)targetArray)[i]);
626                         if (cbor_value_get_type(&insideArray) == CborDoubleType)
627                         {
628                             err = cbor_value_get_double(&insideArray, d);
629                         }
630                         else
631                         {
632                             /* must be float */
633                             float f;
634                             err = cbor_value_get_float(&insideArray, &f);
635                             if (!err)
636                                 *d = f;
637                         }
638                     }
639                     else
640                     {
641                         err = OCParseArrayFillArray(&insideArray, newdim, type,
642                             &(((double*)targetArray)[arrayStep(dimensions, i)]));
643                     }
644                     break;
645                 case OCREP_PROP_BOOL:
646                     if (dimensions[1] == 0)
647                     {
648                         err = cbor_value_get_boolean(&insideArray, &(((bool*)targetArray)[i]));
649                     }
650                     else
651                     {
652                         err = OCParseArrayFillArray(&insideArray, newdim, type,
653                             &(((bool*)targetArray)[arrayStep(dimensions, i)]));
654                     }
655                     break;
656                 case OCREP_PROP_STRING:
657                     if (dimensions[1] == 0)
658                     {
659                         err = cbor_value_dup_text_string(&insideArray, &tempStr, &tempLen, NULL);
660                         ((char**)targetArray)[i] = tempStr;
661                         tempStr = NULL;
662                     }
663                     else
664                     {
665                         err = OCParseArrayFillArray(&insideArray, newdim, type,
666                             &(((char**)targetArray)[arrayStep(dimensions, i)]));
667                     }
668                     break;
669                 case OCREP_PROP_BYTE_STRING:
670                     if (dimensions[1] == 0)
671                     {
672                         err = cbor_value_dup_byte_string(&insideArray, &(ocByteStr.bytes),
673                                 &(ocByteStr.len), NULL);
674                         ((OCByteString*)targetArray)[i] = ocByteStr;
675                     }
676                     else
677                     {
678                         err = OCParseArrayFillArray(&insideArray, newdim, type,
679                                 &(((OCByteString*)targetArray)[arrayStep(dimensions, i)]));
680                     }
681                     break;
682                 case OCREP_PROP_OBJECT:
683                     if (dimensions[1] == 0)
684                     {
685                         err = OCParseSingleRepPayload(&tempPl, &insideArray, false);
686                         ((OCRepPayload**)targetArray)[i] = tempPl;
687                         tempPl = NULL;
688                         noAdvance = true;
689                     }
690                     else
691                     {
692                         err = OCParseArrayFillArray(&insideArray, newdim, type,
693                             &(((OCRepPayload**)targetArray)[arrayStep(dimensions, i)]));
694                     }
695                     break;
696                 default:
697                     OIC_LOG(ERROR, TAG, "Invalid Array type in Parse Array");
698                     err = CborErrorUnknownType;
699                     break;
700             }
701             VERIFY_CBOR_SUCCESS(TAG, err, "Failed setting repPayload");
702         }
703         ++i;
704         if (!noAdvance && cbor_value_is_valid(&insideArray))
705         {
706             err = cbor_value_advance(&insideArray);
707             VERIFY_CBOR_SUCCESS(TAG, err, "Failed advnce insideArray");
708         }
709     }
710
711 exit:
712     return err;
713 }
714
715 static CborError OCParseArray(OCRepPayload *out, const char *name, CborValue *container)
716 {
717     void *arr = NULL;
718
719     OCRepPayloadPropType type = OCREP_PROP_NULL;
720     size_t dimensions[MAX_REP_ARRAY_DEPTH] = { 0 };
721
722     size_t dimTotal = 0;
723     size_t allocSize = 0;
724     bool res = true;
725     CborError err = OCParseArrayFindDimensionsAndType(container, dimensions, &type);
726     VERIFY_CBOR_SUCCESS(TAG, err, "Array details weren't clear");
727
728     if (type == OCREP_PROP_NULL)
729     {
730         res = OCRepPayloadSetNull(out, name);
731         err = (CborError) !res;
732         VERIFY_CBOR_SUCCESS(TAG, err, "Failed setting value");
733         return err;
734     }
735
736     dimTotal = calcDimTotal(dimensions);
737     allocSize = getAllocSize(type);
738     arr = OICCalloc(dimTotal, allocSize);
739     VERIFY_PARAM_NON_NULL(TAG, arr, "Array Parse allocation failed");
740
741     res = OCParseArrayFillArray(container, dimensions, type, arr);
742     VERIFY_CBOR_SUCCESS(TAG, err, "Failed parse array");
743
744     switch (type)
745     {
746         case OCREP_PROP_INT:
747             res = OCRepPayloadSetIntArrayAsOwner(out, name, (int64_t *)arr, dimensions);
748             break;
749         case OCREP_PROP_DOUBLE:
750             res = OCRepPayloadSetDoubleArrayAsOwner(out, name, (double *)arr, dimensions);
751             break;
752         case OCREP_PROP_BOOL:
753             res = OCRepPayloadSetBoolArrayAsOwner(out, name, (bool *)arr, dimensions);
754             break;
755         case OCREP_PROP_STRING:
756             res = OCRepPayloadSetStringArrayAsOwner(out, name, (char **)arr, dimensions);
757             break;
758         case OCREP_PROP_BYTE_STRING:
759             res = OCRepPayloadSetByteStringArrayAsOwner(out, name, (OCByteString *)arr, dimensions);
760             break;
761         case OCREP_PROP_OBJECT:
762             res = OCRepPayloadSetPropObjectArrayAsOwner(out, name, (OCRepPayload**)arr, dimensions);
763             break;
764         default:
765             OIC_LOG(ERROR, TAG, "Invalid Array type in Parse Array");
766             break;
767     }
768     err = (CborError) !res;
769     VERIFY_CBOR_SUCCESS(TAG, err, "Failed setting array parameter");
770     return CborNoError;
771 exit:
772     if (type == OCREP_PROP_STRING)
773     {
774         for(size_t i = 0; i < dimTotal; ++i)
775         {
776             OICFree(((char**)arr)[i]);
777         }
778     }
779     if (type == OCREP_PROP_BYTE_STRING)
780     {
781         for(size_t i = 0; i < dimTotal; ++i)
782         {
783             OICFree(((OCByteString*)arr)[i].bytes);
784         }
785     }
786     if (type == OCREP_PROP_OBJECT)
787     {
788         for(size_t i = 0; i < dimTotal; ++i)
789         {
790             OCRepPayloadDestroy(((OCRepPayload**)arr)[i]);
791         }
792     }
793     OICFree(arr);
794     return err;
795 }
796
797 static CborError OCParseSingleRepPayload(OCRepPayload **outPayload, CborValue *objMap, bool isRoot)
798 {
799     CborError err = CborUnknownError;
800     char *name = NULL;
801     bool res = false;
802     VERIFY_PARAM_NON_NULL(TAG, outPayload, "Invalid Parameter outPayload");
803     VERIFY_PARAM_NON_NULL(TAG, objMap, "Invalid Parameter objMap");
804
805     if (cbor_value_is_map(objMap) || cbor_value_is_array(objMap))
806     {
807         if (!*outPayload)
808         {
809             *outPayload = OCRepPayloadCreate();
810             if (!*outPayload)
811             {
812                 return CborErrorOutOfMemory;
813             }
814         }
815
816         OCRepPayload *curPayload = *outPayload;
817
818         uint64_t arrayIndex = 0;
819         size_t len = 0;
820         CborValue repMap;
821         err = cbor_value_enter_container(objMap, &repMap);
822         VERIFY_CBOR_SUCCESS(TAG, err, "Failed entering repMap");
823
824         while (!err && cbor_value_is_valid(&repMap))
825         {
826             if (cbor_value_is_map(objMap) && cbor_value_is_text_string(&repMap))
827             {
828                 err = cbor_value_dup_text_string(&repMap, &name, &len, NULL);
829                 VERIFY_CBOR_SUCCESS(TAG, err, "Failed finding tag name in the map");
830                 err = cbor_value_advance(&repMap);
831                 VERIFY_CBOR_SUCCESS(TAG, err, "Failed advancing rootMap");
832                 if (name &&
833                     isRoot &&
834                     ((0 == strcmp(OC_RSRVD_HREF, name)) ||
835                      (0 == strcmp(OC_RSRVD_RESOURCE_TYPE, name)) ||
836                     (0 == strcmp(OC_RSRVD_INTERFACE, name))))
837                 {
838                     err = cbor_value_advance(&repMap);
839                     free(name);  // Free *TinyCBOR allocated* string.
840                     continue;
841                 }
842             }
843             else if (cbor_value_is_array(objMap))
844             {
845                 name = (char*)OICCalloc(UINT64_MAX_STRLEN + 1, sizeof(char));
846                 VERIFY_PARAM_NON_NULL(TAG, name, "Failed allocating tag name in the map");
847 #ifdef PRIu64
848                 snprintf(name, UINT64_MAX_STRLEN + 1, "%" PRIu64, arrayIndex);
849 #else
850                 /*
851                  * Some libc implementations do not support the PRIu64 format
852                  * specifier.  Since we don't expect huge heterogeneous arrays,
853                  * we should never hit the error path below in practice.
854                  */
855                 if (arrayIndex <= UINT32_MAX)
856                 {
857                     snprintf(name, UINT64_MAX_STRLEN + 1, "%" PRIu32, (uint32_t)arrayIndex);
858                 }
859                 else
860                 {
861                     err = CborErrorDataTooLarge;
862                     OICFree(name);
863                     continue;
864                 }
865 #endif
866             }
867             CborType type = cbor_value_get_type(&repMap);
868             switch (type)
869             {
870                 case CborNullType:
871                     res = OCRepPayloadSetNull(curPayload, name);
872                     break;
873                 case CborIntegerType:
874                     {
875                         int64_t intval = 0;
876                         err = cbor_value_get_int64(&repMap, &intval);
877                         VERIFY_CBOR_SUCCESS(TAG, err, "Failed getting int value");
878                         res = OCRepPayloadSetPropInt(curPayload, name, intval);
879                     }
880                     break;
881                 case CborDoubleType:
882                     {
883                         double doubleval = 0;
884                         err = cbor_value_get_double(&repMap, &doubleval);
885                         VERIFY_CBOR_SUCCESS(TAG, err, "Failed getting double value");
886                         res = OCRepPayloadSetPropDouble(curPayload, name, doubleval);
887                     }
888                     break;
889                 case CborBooleanType:
890                     {
891                         bool boolval = false;
892                         err = cbor_value_get_boolean(&repMap, &boolval);
893                         VERIFY_CBOR_SUCCESS(TAG, err, "Failed getting boolean value");
894                         res = OCRepPayloadSetPropBool(curPayload, name, boolval);
895                     }
896                     break;
897                 case CborTextStringType:
898                     {
899                         char *strval = NULL;
900                         err = cbor_value_dup_text_string(&repMap, &strval, &len, NULL);
901                         VERIFY_CBOR_SUCCESS(TAG, err, "Failed getting string value");
902                         res = OCRepPayloadSetPropStringAsOwner(curPayload, name, strval);
903                     }
904                     break;
905                 case CborByteStringType:
906                     {
907                         uint8_t* bytestrval = NULL;
908                         err = cbor_value_dup_byte_string(&repMap, &bytestrval, &len, NULL);
909                         VERIFY_CBOR_SUCCESS(TAG, err, "Failed getting byte string value");
910                         OCByteString tmp = {.bytes = bytestrval, .len = len};
911                         res = OCRepPayloadSetPropByteStringAsOwner(curPayload, name, &tmp);
912                     }
913                     break;
914                 case CborMapType:
915                     {
916                         OCRepPayload *pl = NULL;
917                         err = OCParseSingleRepPayload(&pl, &repMap, false);
918                         VERIFY_CBOR_SUCCESS(TAG, err, "Failed setting parse single rep");
919                         res = OCRepPayloadSetPropObjectAsOwner(curPayload, name, pl);
920                     }
921                     break;
922                 case CborArrayType:
923                     err = OCParseArray(curPayload, name, &repMap);
924                     if (err != CborNoError)
925                     {
926                         // OCParseArray will fail if the array contains mixed types, try
927                         // to parse as payload with non-negative integer value names
928                         OCRepPayload *pl = NULL;
929                         err = OCParseSingleRepPayload(&pl, &repMap, false);
930                         VERIFY_CBOR_SUCCESS(TAG, err, "Failed setting parse single rep");
931                         res = OCRepPayloadSetPropObjectAsOwner(curPayload, name, pl);
932                     }
933                     break;
934                 default:
935                     OIC_LOG_V(ERROR, TAG, "Parsing rep property, unknown type %d", repMap.type);
936                     res = false;
937             }
938             if (type != CborArrayType)
939             {
940                 err = (CborError) !res;
941             }
942             VERIFY_CBOR_SUCCESS(TAG, err, "Failed setting value");
943
944             if (type != CborMapType && cbor_value_is_valid(&repMap))
945             {
946                 err = cbor_value_advance(&repMap);
947                 VERIFY_CBOR_SUCCESS(TAG, err, "Failed advance repMap");
948             }
949             OICFree(name);
950             name = NULL;
951             ++arrayIndex;
952         }
953         if (cbor_value_is_container(objMap))
954         {
955             err = cbor_value_leave_container(objMap, &repMap);
956             VERIFY_CBOR_SUCCESS(TAG, err, "Failed to leave container");
957         }
958         return err;
959     }
960
961 exit:
962     OICFree(name);
963     OCRepPayloadDestroy(*outPayload);
964     *outPayload = NULL;
965     return err;
966 }
967
968 static OCStackResult OCParseRepPayload(OCPayload **outPayload, CborValue *root)
969 {
970     OCStackResult ret = OC_STACK_INVALID_PARAM;
971     CborError err;
972     OCRepPayload *temp = NULL;
973     OCRepPayload *rootPayload = NULL;
974     OCRepPayload *curPayload = NULL;
975     CborValue rootMap = *root;
976     VERIFY_PARAM_NON_NULL(TAG, outPayload, "Invalid Parameter outPayload");
977     VERIFY_PARAM_NON_NULL(TAG, root, "Invalid Parameter root");
978
979     *outPayload = NULL;
980     if (cbor_value_is_array(root))
981     {
982         err = cbor_value_enter_container(root, &rootMap);
983         VERIFY_CBOR_SUCCESS(TAG, err, "Failed entering repMap");
984     }
985     while (cbor_value_is_valid(&rootMap))
986     {
987         temp = OCRepPayloadCreate();
988         ret = OC_STACK_NO_MEMORY;
989         VERIFY_PARAM_NON_NULL(TAG, temp, "Failed allocating memory");
990
991         CborValue curVal;
992         ret = OC_STACK_MALFORMED_RESPONSE;
993
994         // temporary fix to check for malformed cbor payload
995         if (!cbor_value_is_map(&rootMap) && !cbor_value_is_array(&rootMap)){
996             goto exit;
997         }
998
999         if (cbor_value_is_map(&rootMap))
1000         {
1001             err = cbor_value_map_find_value(&rootMap, OC_RSRVD_HREF, &curVal);
1002             VERIFY_CBOR_SUCCESS(TAG, err, "to find href tag");
1003             if (cbor_value_is_text_string(&curVal))
1004             {
1005                 size_t len = 0;
1006                 err = cbor_value_dup_text_string(&curVal, &temp->uri, &len, NULL);
1007                 VERIFY_CBOR_SUCCESS(TAG, err, "Failed to find uri");
1008             }
1009         }
1010
1011         // Resource types
1012         if (cbor_value_is_map(&rootMap))
1013         {
1014             if (CborNoError == cbor_value_map_find_value(&rootMap, OC_RSRVD_RESOURCE_TYPE, &curVal))
1015             {
1016                 err =  OCParseStringLL(&rootMap, OC_RSRVD_RESOURCE_TYPE, &temp->types);
1017                 VERIFY_CBOR_SUCCESS(TAG, err, "Failed to find rt type tag/value");
1018             }
1019         }
1020
1021         // Interface Types
1022         if (cbor_value_is_map(&rootMap))
1023         {
1024             if (CborNoError == cbor_value_map_find_value(&rootMap, OC_RSRVD_INTERFACE, &curVal))
1025             {
1026                 err =  OCParseStringLL(&rootMap, OC_RSRVD_INTERFACE, &temp->interfaces);
1027                 VERIFY_CBOR_SUCCESS(TAG, err, "Failed to find interfaces tag/value");
1028             }
1029         }
1030
1031         if (cbor_value_is_map(&rootMap))
1032         {
1033             err = OCParseSingleRepPayload(&temp, &rootMap, true);
1034             VERIFY_CBOR_SUCCESS(TAG, err, "Failed to parse single rep payload");
1035         }
1036
1037         if(rootPayload == NULL)
1038         {
1039             rootPayload = temp;
1040             curPayload = temp;
1041         }
1042         else
1043         {
1044             curPayload->next = temp;
1045             curPayload = curPayload->next;
1046         }
1047
1048         if (cbor_value_is_array(&rootMap))
1049         {
1050             err = cbor_value_advance(&rootMap);
1051             VERIFY_CBOR_SUCCESS(TAG, err, "Failed to advance single rep payload");
1052         }
1053     }
1054     *outPayload = (OCPayload *)rootPayload;
1055     return OC_STACK_OK;
1056
1057 exit:
1058     OCRepPayloadDestroy(temp);
1059     OCRepPayloadDestroy(rootPayload);
1060     OIC_LOG(ERROR, TAG, "CBOR error in ParseRepPayload");
1061     return ret;
1062 }
1063
1064 static OCStackResult OCParsePresencePayload(OCPayload **outPayload, CborValue *rootValue)
1065 {
1066     OCStackResult ret = OC_STACK_INVALID_PARAM;
1067     OCPresencePayload *payload = NULL;
1068     VERIFY_PARAM_NON_NULL(TAG, outPayload, "Invalid Parameter outPayload");
1069
1070     *outPayload = NULL;
1071
1072     payload = (OCPresencePayload *)OICCalloc(1, sizeof(OCPresencePayload));
1073     ret = OC_STACK_NO_MEMORY;
1074     VERIFY_PARAM_NON_NULL(TAG, payload, "Failed allocating presence payload");
1075     payload->base.type = PAYLOAD_TYPE_PRESENCE;
1076     ret = OC_STACK_MALFORMED_RESPONSE;
1077
1078     if (cbor_value_is_map(rootValue))
1079     {
1080         CborValue curVal;
1081         uint64_t temp = 0;
1082         uint8_t trigger;
1083
1084         // Sequence Number
1085         CborError err = cbor_value_map_find_value(rootValue, OC_RSRVD_NONCE, &curVal);
1086         VERIFY_CBOR_SUCCESS(TAG, err, "Failed finding nonce tag");
1087         err = cbor_value_get_uint64(&curVal, &temp);
1088         payload->sequenceNumber = (uint32_t)temp;
1089         VERIFY_CBOR_SUCCESS(TAG, err, "Failed finding nonce value");
1090
1091         // Max Age
1092         err = cbor_value_map_find_value(rootValue, OC_RSRVD_TTL, &curVal);
1093         VERIFY_CBOR_SUCCESS(TAG, err, "Failed finding ttl tag");
1094         temp = 0;
1095         err = cbor_value_get_uint64(&curVal, &temp);
1096         payload->maxAge = (uint32_t)temp;
1097         VERIFY_CBOR_SUCCESS(TAG, err, "Failed finding ttl value");
1098
1099         // Trigger
1100         err = cbor_value_map_find_value(rootValue, OC_RSRVD_TRIGGER, &curVal);
1101         VERIFY_CBOR_SUCCESS(TAG, err, "Failed finding trigger tag");
1102         err = cbor_value_get_simple_type(&curVal, &trigger);
1103         VERIFY_CBOR_SUCCESS(TAG, err, "Failed finding trigger value");
1104         payload->trigger = (OCPresenceTrigger)trigger;
1105
1106         // Resource type name
1107         err = cbor_value_map_find_value(rootValue, OC_RSRVD_RESOURCE_TYPE, &curVal);
1108         VERIFY_CBOR_SUCCESS(TAG, err, "to find res type tag");
1109         if (cbor_value_is_text_string(&curVal))
1110         {
1111             size_t len = 0;
1112             err = cbor_value_dup_text_string(&curVal, &payload->resourceType, &len, NULL);
1113             VERIFY_CBOR_SUCCESS(TAG, err, "Failed finding resource type value");
1114         }
1115
1116         err = cbor_value_advance(rootValue);
1117         VERIFY_CBOR_SUCCESS(TAG, err, "Failed advancing root value");
1118
1119         *outPayload = (OCPayload *)payload;
1120         return OC_STACK_OK;
1121     }
1122 exit:
1123     OIC_LOG(ERROR, TAG, "CBOR error Parse Presence Payload");
1124     OCPresencePayloadDestroy(payload);
1125     return ret;
1126 }