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