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