Merge branch 'master' into simulator.
[platform/upstream/iotivity.git] / resource / csdk / stack / src / ocpayloadconvert.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 #include "ocpayloadcbor.h"
22 #include "platform_features.h"
23 #include <stdlib.h>
24 #include "oic_malloc.h"
25 #include "oic_string.h"
26 #include "logger.h"
27 #include "ocpayload.h"
28 #include "ocrandom.h"
29 #include "ocresourcehandler.h"
30 #include "cbor.h"
31 #include "rdpayload.h"
32
33 #define TAG "OCPayloadConvert"
34 // Arbitrarily chosen size that seems to contain the majority of packages
35 #define INIT_SIZE (255)
36
37 // CBOR Links Map Length
38 #define DISCOVERY_CBOR_LINKS_MAP_LEN 4
39
40 // Functions all return either a CborError, or a negative version of the OC_STACK return values
41 static int64_t OCConvertPayloadHelper(OCPayload* payload, uint8_t* outPayload, size_t* size);
42 static int64_t OCConvertDiscoveryPayload(OCDiscoveryPayload* payload, uint8_t* outPayload,
43         size_t* size);
44 static int64_t OCConvertDevicePayload(OCDevicePayload* payload, uint8_t* outPayload,
45         size_t* size);
46 static int64_t OCConvertPlatformPayload(OCPlatformPayload* payload, uint8_t* outPayload,
47         size_t* size);
48 static int64_t OCConvertRepPayload(OCRepPayload* payload, uint8_t* outPayload, size_t* size);
49 static int64_t OCConvertRepMap(CborEncoder *map, const OCRepPayload* payload);
50 static int64_t OCConvertPresencePayload(OCPresencePayload* payload, uint8_t* outPayload,
51         size_t* size);
52 static int64_t OCConvertSecurityPayload(OCSecurityPayload* payload, uint8_t* outPayload,
53         size_t* size);
54 static int64_t OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload* payload);
55 static int64_t OCConvertArray(CborEncoder* parent, const OCRepPayloadValueArray* valArray);
56
57 static int64_t AddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
58         const char* value);
59
60 static int64_t ConditionalAddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
61         const char* value);
62
63 OCStackResult OCConvertPayload(OCPayload* payload, uint8_t** outPayload, size_t* size)
64 {
65     // TinyCbor Version 47a78569c0 or better on master is required for the re-allocation
66     // strategy to work.  If you receive the following assertion error, please do a git-pull
67     // from the extlibs/tinycbor/tinycbor directory
68     #define CborNeedsUpdating  (CborErrorOutOfMemory < CborErrorDataTooLarge)
69     OC_STATIC_ASSERT(!CborNeedsUpdating, "tinycbor needs to be updated to at least 47a78569c0");
70     #undef CborNeedsUpdating
71     if (!payload)
72     {
73         OC_LOG(ERROR, TAG, "Payload parameter NULL");
74         return OC_STACK_INVALID_PARAM;
75     }
76
77     if (!outPayload || !size)
78     {
79         OC_LOG(ERROR, TAG, "Out parameter/s parameter NULL");
80         return OC_STACK_INVALID_PARAM;
81     }
82
83     OC_LOG_V(INFO, TAG, "Converting payload of type %d", payload->type);
84
85     size_t curSize = INIT_SIZE;
86     uint8_t* out = (uint8_t*)OICCalloc(1, curSize);
87     int64_t err = OCConvertPayloadHelper(payload, out, &curSize);
88
89     if (err == CborErrorOutOfMemory)
90     {
91         // reallocate "out" and try again!
92         uint8_t* out2 = (uint8_t*)OICRealloc(out, curSize);
93
94         if (!out2)
95         {
96             OICFree(out);
97             return OC_STACK_NO_MEMORY;
98         }
99
100         out = out2;
101         err = OCConvertPayloadHelper(payload, out, &curSize);
102     }
103
104     if (err == 0)
105     {
106         if (curSize < INIT_SIZE)
107         {
108             uint8_t* out2 = (uint8_t*)OICRealloc(out, curSize);
109
110             if (!out2)
111             {
112                 OICFree(out);
113                 return OC_STACK_NO_MEMORY;
114             }
115
116             out = out2;
117         }
118
119         *size = curSize;
120         *outPayload = out;
121         return OC_STACK_OK;
122     }
123     else if (err < 0)
124     {
125         return (OCStackResult)-err;
126     }
127     else
128     {
129         return OC_STACK_ERROR;
130     }
131 }
132
133 static int64_t OCConvertPayloadHelper(OCPayload* payload, uint8_t* outPayload, size_t* size)
134 {
135     switch(payload->type)
136     {
137         case PAYLOAD_TYPE_DISCOVERY:
138             return OCConvertDiscoveryPayload((OCDiscoveryPayload*)payload, outPayload, size);
139         case PAYLOAD_TYPE_DEVICE:
140             return OCConvertDevicePayload((OCDevicePayload*)payload, outPayload, size);
141         case PAYLOAD_TYPE_PLATFORM:
142             return OCConvertPlatformPayload((OCPlatformPayload*)payload, outPayload, size);
143         case PAYLOAD_TYPE_REPRESENTATION:
144             return OCConvertRepPayload((OCRepPayload*)payload, outPayload, size);
145         case PAYLOAD_TYPE_PRESENCE:
146             return OCConvertPresencePayload((OCPresencePayload*)payload, outPayload, size);
147         case PAYLOAD_TYPE_SECURITY:
148             return OCConvertSecurityPayload((OCSecurityPayload*)payload, outPayload, size);
149         case PAYLOAD_TYPE_RD:
150             return OCRDPayloadToCbor((OCRDPayload*)payload, outPayload, size);
151         default:
152             OC_LOG_V(INFO,TAG, "ConvertPayload default %d", payload->type);
153             return OC_STACK_NOTIMPL;
154     }
155 }
156
157 static int64_t checkError(int64_t err, CborEncoder* encoder, uint8_t* outPayload, size_t* size)
158 {
159     if (err == CborErrorOutOfMemory)
160     {
161         *size += encoder->ptr - encoder->end;
162         return err;
163     }
164     else if (err != 0)
165     {
166         OC_LOG_V(ERROR, TAG, "Convert Payload failed : %zd", err);
167         return err;
168     }
169     else
170     {
171         *size = encoder->ptr - outPayload;
172         return 0;
173     }
174 }
175
176 static int64_t OCConvertSecurityPayload(OCSecurityPayload* payload, uint8_t* outPayload,
177         size_t* size)
178 {
179     CborEncoder encoder;
180     int64_t err = 0;
181
182     cbor_encoder_init(&encoder, outPayload, *size, 0);
183
184     CborEncoder map;
185
186     err = err | cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
187
188     if(payload->securityData)
189     {
190         err = err | cbor_encode_text_string(&map, payload->securityData,
191                                             strlen(payload->securityData));
192     }
193
194     err = err | cbor_encoder_close_container(&encoder, &map);
195     return checkError(err, &encoder, outPayload, size);
196 }
197
198 static char* OCStringLLJoin(OCStringLL* val)
199 {
200     OCStringLL* temp = val;
201     size_t size = strlen(temp->value);
202
203     while (temp->next)
204     {
205         ++size;
206         temp = temp->next;
207         size += strlen(temp->value);
208     }
209
210     char* joinedStr = (char*)OICCalloc(sizeof(char), size + 1);
211
212     if (!joinedStr)
213     {
214         return NULL;
215     }
216
217     OICStrcat(joinedStr, size + 1, val->value);
218     while (val->next)
219     {
220         val = val->next;
221         OICStrcat(joinedStr, size + 1, " ");
222         OICStrcat(joinedStr, size + 1, val->value);
223     }
224     return joinedStr;
225 }
226
227 static int64_t OCConvertDiscoveryPayload(OCDiscoveryPayload* payload, uint8_t* outPayload,
228         size_t* size)
229 {
230     CborEncoder encoder = {0};
231     CborEncoder rootArray = {0};
232     int64_t err = 0;
233
234     cbor_encoder_init(&encoder, outPayload, *size, 0);
235
236     if (payload->resources)
237     {
238         /*
239         The format for the payload is "modelled" as JSON.
240
241         [                                                       // rootArray
242             {                                                   // rootMap
243                 "di" : UUID,                                    // device ID
244                 links :[                                        // linksArray contains maps of resources
245                             {
246                                 href, rt, if, policy            // Resource 1
247                             },
248                             {
249                                 href, rt, if, policy            // Resource 2
250                             },
251                             .
252                             .
253                             .
254                         ]
255             }
256         ]
257         */
258         CborEncoder rootMap = {0};
259         size_t resourceCount =  OCDiscoveryPayloadGetResourceCount(payload);
260
261         // Open the main root array
262         err = err | cbor_encoder_create_array(&encoder, &rootArray, 1);
263
264         // Open the root map in the root array
265         err = err | cbor_encoder_create_map(&rootArray, &rootMap, CborIndefiniteLength);
266
267         // Insert Device ID into the root map
268         err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_DEVICE_ID,
269                 sizeof(OC_RSRVD_DEVICE_ID) - 1);
270         err = err | cbor_encode_byte_string(&rootMap, payload->sid, UUID_SIZE);
271
272         // Insert baseURI if present
273         err = err | ConditionalAddTextStringToMap(&rootMap, OC_RSRVD_BASE_URI,
274                                                   sizeof(OC_RSRVD_BASE_URI) - 1,
275                                                   payload->baseURI);
276
277         // Insert Links into the root map.
278         CborEncoder linkArray = {0};
279         err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_LINKS,
280                     sizeof(OC_RSRVD_LINKS) - 1);
281         err = err | cbor_encoder_create_array(&rootMap, &linkArray, resourceCount);
282
283         for(size_t i = 0; i < resourceCount; ++i)
284         {
285             CborEncoder resourceMapElement = {0};
286             OCResourcePayload* resource = OCDiscoveryPayloadGetResource(payload, i);
287             if(!resource)
288             {
289                 OICFree(outPayload);
290                 return OC_STACK_INVALID_PARAM;
291             }
292
293             // resource map inside the links array.
294             err = err | cbor_encoder_create_map(&linkArray, &resourceMapElement,
295                 DISCOVERY_CBOR_LINKS_MAP_LEN);
296
297             // Below are insertions of the resource properties into the map.
298             // Uri
299             err = err | AddTextStringToMap(&resourceMapElement, OC_RSRVD_HREF,
300                         sizeof(OC_RSRVD_HREF) - 1,
301                         resource->uri);
302             // Resource Type
303             if (resource->types)
304             {
305                 char* joinedTypes = OCStringLLJoin(resource->types);
306                 if (joinedTypes)
307                 {
308                     err = err | cbor_encode_text_string(&resourceMapElement, OC_RSRVD_RESOURCE_TYPE,
309                             sizeof(OC_RSRVD_RESOURCE_TYPE) - 1);
310                     err = err | cbor_encode_text_string(&resourceMapElement, joinedTypes,
311                             strlen(joinedTypes));
312                     OICFree(joinedTypes);
313                 }
314                 else
315                 {
316                     return OC_STACK_NO_MEMORY;
317                 }
318             }
319             // Interface Types
320             if (resource->interfaces)
321             {
322                 char* joinedInterfaces = OCStringLLJoin(resource->interfaces);
323                 if (joinedInterfaces)
324                 {
325                     err = err | cbor_encode_text_string(&resourceMapElement, OC_RSRVD_INTERFACE,
326                             sizeof(OC_RSRVD_INTERFACE) - 1);
327                     err = err | cbor_encode_text_string(&resourceMapElement, joinedInterfaces,
328                             strlen(joinedInterfaces));
329                     OICFree(joinedInterfaces);
330                 }
331                 else
332                 {
333                     return OC_STACK_NO_MEMORY;
334                 }
335             }
336
337             // Policy
338             CborEncoder policyMap = {0};
339             err = err | cbor_encode_text_string(&resourceMapElement, OC_RSRVD_POLICY,
340                     sizeof(OC_RSRVD_POLICY) - 1);
341             err = err | cbor_encoder_create_map(&resourceMapElement, &policyMap, CborIndefiniteLength);
342
343             // Bitmap
344             err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_BITMAP,
345                     sizeof(OC_RSRVD_BITMAP) - 1);
346             err = err | cbor_encode_uint(&policyMap, resource->bitmap);
347
348             if(resource->secure)
349             {
350                 err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_SECURE,
351                         sizeof(OC_RSRVD_SECURE) - 1);
352                 err = err | cbor_encode_boolean(&policyMap, OC_RESOURCE_SECURE);
353
354                 if(resource->port != 0)
355                 {
356                     err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_HOSTING_PORT,
357                             sizeof(OC_RSRVD_HOSTING_PORT) - 1);
358                     err = err | cbor_encode_uint(&policyMap, resource->port);
359                 }
360             }
361             if (payload->baseURI)
362             {
363                 err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_HOSTING_PORT,
364                                                     sizeof(OC_RSRVD_HOSTING_PORT) - 1);
365                 err = err | cbor_encode_uint(&policyMap, resource->port);
366             }
367
368             err = err | cbor_encoder_close_container(&resourceMapElement, &policyMap);
369
370             // Finsihed encoding a resource, close the map.
371             err = err | cbor_encoder_close_container(&linkArray, &resourceMapElement);
372         }
373         // Close links array inside the root map.
374         err = err | cbor_encoder_close_container(&rootMap, &linkArray);
375         // close root map inside the root array.
376         err = err | cbor_encoder_close_container(&rootArray, &rootMap);
377         // Close the final root array.
378         err = err | cbor_encoder_close_container(&encoder, &rootArray);
379     }
380
381     return checkError(err, &encoder, outPayload, size);
382 }
383
384 static int64_t OCConvertDevicePayload(OCDevicePayload* payload, uint8_t* outPayload,
385         size_t* size)
386 {
387     CborEncoder encoder = {0};
388     int64_t err = 0;
389
390     cbor_encoder_init(&encoder, outPayload, *size, 0);
391     CborEncoder repMap;
392     err = err | cbor_encoder_create_map(&encoder, &repMap, CborIndefiniteLength);
393
394     // Device ID
395     err = err | cbor_encode_text_string(&repMap, OC_RSRVD_DEVICE_ID,
396             sizeof(OC_RSRVD_DEVICE_ID) - 1);
397     err = err | cbor_encode_byte_string(&repMap, payload->sid, UUID_SIZE);
398
399     // Device Name
400     err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_DEVICE_NAME,
401             sizeof(OC_RSRVD_DEVICE_NAME) - 1,
402             payload->deviceName);
403
404     // Device Spec Version
405     err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SPEC_VERSION,
406             sizeof(OC_RSRVD_SPEC_VERSION) - 1,
407             payload->specVersion);
408
409     // Device data Model Version
410     err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_DATA_MODEL_VERSION,
411             sizeof(OC_RSRVD_DATA_MODEL_VERSION) - 1,
412             payload->dataModelVersion);
413
414     err = err | cbor_encoder_close_container(&encoder, &repMap);
415
416     return checkError(err, &encoder, outPayload, size);
417 }
418
419 static int64_t OCConvertPlatformPayload(OCPlatformPayload* payload, uint8_t* outPayload,
420         size_t* size)
421 {
422     CborEncoder encoder = {0};
423     int64_t err = 0;
424
425     cbor_encoder_init(&encoder, outPayload, *size, 0);
426     {
427         CborEncoder repMap;
428         err = err | cbor_encoder_create_map(&encoder, &repMap, CborIndefiniteLength);
429
430         // Platform ID
431         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_PLATFORM_ID,
432                 sizeof(OC_RSRVD_PLATFORM_ID) - 1,
433                 payload->info.platformID);
434
435         // MFG Name
436         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_NAME,
437                 sizeof(OC_RSRVD_MFG_NAME) - 1,
438                 payload->info.manufacturerName);
439
440         // MFG Url
441         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_URL,
442                 sizeof(OC_RSRVD_MFG_URL) - 1,
443                 payload->info.manufacturerUrl);
444
445         // Model Num
446         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MODEL_NUM,
447                 sizeof(OC_RSRVD_MODEL_NUM) - 1,
448                 payload->info.modelNumber);
449
450         // Date of Mfg
451         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_DATE,
452                 sizeof(OC_RSRVD_MFG_DATE) - 1,
453                 payload->info.dateOfManufacture);
454
455         // Platform Version
456         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_PLATFORM_VERSION,
457                 sizeof(OC_RSRVD_PLATFORM_VERSION) - 1,
458                 payload->info.platformVersion);
459
460         // OS Version
461         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_OS_VERSION,
462                 sizeof(OC_RSRVD_OS_VERSION) - 1,
463                 payload->info.operatingSystemVersion);
464
465         // Hardware Version
466         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_HARDWARE_VERSION,
467                 sizeof(OC_RSRVD_HARDWARE_VERSION) - 1,
468                 payload->info.hardwareVersion);
469
470         // Firmware Version
471         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_FIRMWARE_VERSION,
472                 sizeof(OC_RSRVD_FIRMWARE_VERSION) - 1,
473                 payload->info.firmwareVersion);
474
475         // Support URL
476         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SUPPORT_URL,
477                 sizeof(OC_RSRVD_SUPPORT_URL) - 1,
478                 payload->info.supportUrl);
479
480         // System Time
481         err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SYSTEM_TIME,
482                 sizeof(OC_RSRVD_SYSTEM_TIME) - 1,
483                 payload->info.systemTime);
484
485         // Close Map
486         err = err | cbor_encoder_close_container(&encoder, &repMap);
487     }
488
489     return checkError(err, &encoder, outPayload, size);
490 }
491
492 static int64_t OCConvertArrayItem(CborEncoder* array, const OCRepPayloadValueArray* valArray,
493         size_t index)
494 {
495     int64_t err = 0;
496     switch (valArray->type)
497     {
498         case OCREP_PROP_NULL:
499             OC_LOG(ERROR, TAG, "ConvertArray Invalid NULL");
500             err = CborUnknownError;
501             break;
502         case OCREP_PROP_INT:
503             err = err | cbor_encode_int(array, valArray->iArray[index]);
504             break;
505         case OCREP_PROP_DOUBLE:
506             err = err | cbor_encode_double(array, valArray->dArray[index]);
507             break;
508         case OCREP_PROP_BOOL:
509             err = err | cbor_encode_boolean(array, valArray->bArray[index]);
510             break;
511         case OCREP_PROP_STRING:
512             if (!valArray->strArray[index])
513             {
514                 err = err | cbor_encode_null(array);
515             }
516             else
517             {
518                 err = err | cbor_encode_text_string(array, valArray->strArray[index],
519                         strlen(valArray->strArray[index]));
520             }
521             break;
522         case OCREP_PROP_BYTE_STRING:
523             if (!valArray->strArray[index])
524             {
525                 err = err | cbor_encode_null(array);
526             }
527             else
528             {
529                 err = err | cbor_encode_byte_string(array, valArray->ocByteStrArray[index].bytes,
530                         valArray->ocByteStrArray[index].len);
531             }
532             break;
533         case OCREP_PROP_OBJECT:
534             if (!valArray->objArray[index])
535             {
536                 err = err | cbor_encode_null(array);
537             }
538             else
539             {
540                 err = OCConvertRepMap(array, valArray->objArray[index]);
541             }
542             break;
543         case OCREP_PROP_ARRAY:
544             OC_LOG(ERROR, TAG, "ConvertArray Invalid child array");
545             err = CborUnknownError;
546             break;
547     }
548
549     return err;
550 }
551 static int64_t OCConvertArray(CborEncoder* parent, const OCRepPayloadValueArray* valArray)
552 {
553     CborEncoder array;
554     int64_t err = 0;
555
556     err = err | cbor_encoder_create_array(parent, &array, valArray->dimensions[0]);
557
558     for (size_t i = 0; i < valArray->dimensions[0];++i)
559     {
560         if (valArray->dimensions[1] != 0)
561         {
562             CborEncoder array2;
563             err = err | cbor_encoder_create_array(&array, &array2, valArray->dimensions[1]);
564
565             for (size_t j = 0; j < valArray->dimensions[1]; ++j)
566             {
567                 if (valArray->dimensions[2] != 0)
568                 {
569                     CborEncoder array3;
570                     err = err | cbor_encoder_create_array(&array2, &array3,
571                             valArray->dimensions[2]);
572
573                     for(size_t k = 0; k < valArray->dimensions[2]; ++k)
574                     {
575                         OCConvertArrayItem(&array3, valArray,
576                             j * valArray->dimensions[2] +
577                             i * valArray->dimensions[2] * valArray->dimensions[1] +
578                             k);
579                     }
580                     err = err | cbor_encoder_close_container(&array2, &array3);
581                 }
582                 else
583                 {
584                     OCConvertArrayItem(&array2, valArray,
585                             i * valArray->dimensions[1] + j);
586                 }
587             }
588             err = err | cbor_encoder_close_container(&array, &array2);
589         }
590         else
591         {
592             OCConvertArrayItem(&array, valArray, i);
593         }
594     }
595     err = err | cbor_encoder_close_container(parent, &array);
596     return err;
597 }
598
599 static int64_t OCConvertRepMap(CborEncoder *map, const OCRepPayload* payload)
600 {
601     int64_t err = 0;
602     CborEncoder repMap;
603     err = err | cbor_encoder_create_map(map, &repMap, CborIndefiniteLength);
604     err = err | OCConvertSingleRepPayload(&repMap, payload);
605     err = err | cbor_encoder_close_container(map, &repMap);
606     return err;
607 }
608
609 static int64_t OCConvertSingleRepPayload(CborEncoder* repMap, const OCRepPayload* payload)
610 {
611     int64_t err = 0;
612     OCRepPayloadValue* value = payload->values;
613     while(value)
614     {
615         err = err | cbor_encode_text_string(repMap,
616                 value->name,
617                 strlen(value->name));
618         switch(value->type)
619         {
620             case OCREP_PROP_NULL:
621                 err = err | cbor_encode_null(repMap);
622                 break;
623             case OCREP_PROP_INT:
624                 err = err | cbor_encode_int(repMap,
625                         value->i);
626                 break;
627             case OCREP_PROP_DOUBLE:
628                 err = err | cbor_encode_double(repMap,
629                         value->d);
630                 break;
631             case OCREP_PROP_BOOL:
632                 err = err | cbor_encode_boolean(repMap,
633                         value->b);
634                 break;
635             case OCREP_PROP_STRING:
636                 err = err | cbor_encode_text_string(repMap,
637                         value->str, strlen(value->str));
638                 break;
639             case OCREP_PROP_BYTE_STRING:
640                 err = err | cbor_encode_byte_string(repMap,
641                         value->ocByteStr.bytes, value->ocByteStr.len);
642                 break;
643             case OCREP_PROP_OBJECT:
644                 err = err | OCConvertRepMap(repMap, value->obj);
645                 break;
646             case OCREP_PROP_ARRAY:
647                 err = err | OCConvertArray(repMap, &value->arr);
648                 break;
649             default:
650                 OC_LOG_V(ERROR, TAG, "Invalid Prop type: %d",
651                         value->type);
652                 break;
653         }
654         value = value->next;
655     }
656
657     return err;
658 }
659
660 static int64_t OCConvertRepPayload(OCRepPayload* payload, uint8_t* outPayload, size_t* size)
661 {
662     CborEncoder encoder = {0};
663     int64_t err = 0;
664
665     cbor_encoder_init(&encoder, outPayload, *size, 0);
666     CborEncoder rootMap;
667     err = err | cbor_encoder_create_map(&encoder, &rootMap, CborIndefiniteLength);
668
669     if (payload->types)
670     {
671         OC_LOG(INFO, TAG, "Payload has types or interfaces");
672         char* joinedTypes = OCStringLLJoin(payload->types);
673         if (joinedTypes)
674         {
675             err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_RESOURCE_TYPE,
676                     sizeof(OC_RSRVD_RESOURCE_TYPE) - 1);
677             err = err | cbor_encode_text_string(&rootMap, joinedTypes,
678                     strlen(joinedTypes));
679             OICFree(joinedTypes);
680         }
681         else
682         {
683             return OC_STACK_NO_MEMORY;
684         }
685     }
686     if (payload->interfaces)
687     {
688         char* joinedInterfaces = OCStringLLJoin(payload->interfaces);
689         if (joinedInterfaces)
690         {
691             err = err | cbor_encode_text_string(&rootMap, OC_RSRVD_INTERFACE,
692                     sizeof(OC_RSRVD_INTERFACE) - 1);
693             err = err | cbor_encode_text_string(&rootMap, joinedInterfaces,
694                     strlen(joinedInterfaces));
695             OICFree(joinedInterfaces);
696         }
697         else
698         {
699             return OC_STACK_NO_MEMORY;
700         }
701     }
702
703     while(payload != NULL && (err == 0 || err == CborErrorOutOfMemory))
704     {
705         err = err | OCConvertSingleRepPayload(&rootMap, payload);
706         payload = payload->next;
707     }
708
709     // Close main array
710     err = err | cbor_encoder_close_container(&encoder, &rootMap);
711
712     return checkError(err, &encoder, outPayload, size);
713 }
714
715 static int64_t OCConvertPresencePayload(OCPresencePayload* payload,
716         uint8_t* outPayload, size_t* size)
717 {
718     CborEncoder encoder = {0};
719     int64_t err = 0;
720
721     cbor_encoder_init(&encoder, outPayload, *size, 0);
722     CborEncoder map;
723     err = err | cbor_encoder_create_map(&encoder, &map, CborIndefiniteLength);
724
725     // Sequence Number
726     err = err | cbor_encode_text_string(&map,
727             OC_RSRVD_NONCE,
728             sizeof(OC_RSRVD_NONCE) - 1);
729     err = err | cbor_encode_uint(&map, payload->sequenceNumber);
730
731     // Max Age
732     err = err | cbor_encode_text_string(&map,
733             OC_RSRVD_TTL,
734             sizeof(OC_RSRVD_TTL) - 1);
735     err = err | cbor_encode_uint(&map, payload->maxAge);
736
737     // Trigger
738     const char* triggerStr = convertTriggerEnumToString(payload->trigger);
739     err = err | AddTextStringToMap(&map, OC_RSRVD_TRIGGER, sizeof(OC_RSRVD_TRIGGER) - 1,
740             triggerStr);
741
742     // Resource type name
743     if(payload->trigger != OC_PRESENCE_TRIGGER_DELETE)
744     {
745         err = err | ConditionalAddTextStringToMap(&map, OC_RSRVD_RESOURCE_TYPE,
746                 sizeof(OC_RSRVD_RESOURCE_TYPE) - 1, payload->resourceType);
747     }
748
749     // Close Map
750     err = err | cbor_encoder_close_container(&encoder, &map);
751
752     return checkError(err, &encoder, outPayload, size);
753 }
754
755 static int64_t AddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
756         const char* value)
757 {
758     return cbor_encode_text_string(map, key, keylen) |
759            cbor_encode_text_string(map, value, strlen(value));
760 }
761
762 static int64_t ConditionalAddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
763         const char* value)
764 {
765     return value ? AddTextStringToMap(map, key, keylen, value) : 0;
766 }