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