Merge branch 'master' into resource-container
[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 : %zd", err);
170         return err;
171     }
172     else
173     {
174         *size = encoder->ptr - outPayload;
175         return 0;
176     }
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 rootArray;
188     err = err | cbor_encoder_create_array(&encoder, &rootArray, 1);
189     CborEncoder map;
190
191     err = err | cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
192
193     if(payload->securityData)
194     {
195         err = err | AddTextStringToMap(&map, OC_RSRVD_REPRESENTATION,
196                 sizeof(OC_RSRVD_REPRESENTATION) - 1,
197                 payload->securityData);
198     }
199
200     err = err | cbor_encoder_close_container(&rootArray, &map);
201
202     err = err | cbor_encoder_close_container(&encoder, &rootArray);
203     return checkError(err, &encoder, outPayload, size);
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         OCResourceCollectionPayload *colResources = payload->collectionResources;
262         while (colResources)
263         {
264             if (OC_STACK_OK != OCTagsPayloadToCbor(colResources->tags, &colArray))
265             {
266                 goto cbor_error;
267             }
268             if (OC_STACK_OK != OCLinksPayloadToCbor(colResources->setLinks, &colArray))
269             {
270                 goto cbor_error;
271             }
272             colResources = colResources->next;
273         }
274         cborEncoderResult = cbor_encoder_close_container(&rootArray, &colArray);
275         if (CborNoError != cborEncoderResult)
276         {
277             OC_LOG(ERROR, TAG, "Failed closing collection array.");
278             goto cbor_error;
279         }
280         cborEncoderResult = cbor_encoder_close_container(&encoder, &rootArray);
281         if (CborNoError != cborEncoderResult)
282         {
283             OC_LOG(ERROR, TAG, "Failed closing root array.");
284             goto cbor_error;
285         }
286     }
287     else if (payload->resources)
288     {
289         size_t resourceCount =  OCDiscoveryPayloadGetResourceCount(payload);
290         err = err | cbor_encoder_create_array(&encoder, &rootArray, resourceCount);
291
292         for(size_t i = 0; i < resourceCount; ++i)
293         {
294             CborEncoder map;
295             OCResourcePayload* resource = OCDiscoveryPayloadGetResource(payload, i);
296             if(!resource)
297             {
298                 OICFree(outPayload);
299                 return OC_STACK_INVALID_PARAM;
300             }
301
302             err = err | cbor_encoder_create_map(&rootArray, &map, DISCOVERY_CBOR_RES_MAP_LEN);
303
304             // Device ID
305             err = err | cbor_encode_text_string(&map, OC_RSRVD_DEVICE_ID,
306                     sizeof(OC_RSRVD_DEVICE_ID) - 1);
307             err = err | cbor_encode_byte_string(&map, resource->sid, UUID_SIZE);
308
309             {
310                 CborEncoder linkArray;
311                 err = err | cbor_encode_text_string(&map, OC_RSRVD_LINKS, sizeof(OC_RSRVD_LINKS) -1);
312                 err = err | cbor_encoder_create_array(&map, &linkArray, CborIndefiniteLength);
313
314                 // Link Map
315                 {
316                     CborEncoder linkMap;
317                     err = err | cbor_encoder_create_map(&linkArray, &linkMap, DISCOVERY_CBOR_LINKS_MAP_LEN);
318
319                     // Uri
320                     err = err | AddTextStringToMap(&linkMap, OC_RSRVD_HREF,
321                             sizeof(OC_RSRVD_HREF) - 1,
322                             resource->uri);
323                     // Resource Type
324                     if (resource->types)
325                     {
326                         char* joinedTypes = OCStringLLJoin(resource->types);
327                         if (joinedTypes)
328                         {
329                             err = err | cbor_encode_text_string(&linkMap, OC_RSRVD_RESOURCE_TYPE,
330                                     sizeof(OC_RSRVD_RESOURCE_TYPE) - 1);
331                             err = err | cbor_encode_text_string(&linkMap, joinedTypes,
332                                     strlen(joinedTypes));
333                             OICFree(joinedTypes);
334                         }
335                         else
336                         {
337                             return OC_STACK_NO_MEMORY;
338                         }
339                     }
340                     // Interface Types
341                     if (resource->interfaces)
342                     {
343                         char* joinedInterfaces = OCStringLLJoin(resource->interfaces);
344                         if (joinedInterfaces)
345                         {
346                             err = err | cbor_encode_text_string(&linkMap, OC_RSRVD_INTERFACE,
347                                     sizeof(OC_RSRVD_INTERFACE) - 1);
348                             err = err | cbor_encode_text_string(&linkMap, joinedInterfaces,
349                                     strlen(joinedInterfaces));
350                             OICFree(joinedInterfaces);
351                         }
352                         else
353                         {
354                             return OC_STACK_NO_MEMORY;
355                         }
356                     }
357                     // Policy
358                     {
359                         CborEncoder policyMap;
360                         err = err | cbor_encode_text_string(&linkMap, OC_RSRVD_POLICY,
361                                 sizeof(OC_RSRVD_POLICY) - 1);
362                         err = err | cbor_encoder_create_map(&linkMap, &policyMap, CborIndefiniteLength);
363
364                         // Bitmap
365                         err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_BITMAP,
366                                 sizeof(OC_RSRVD_BITMAP) - 1);
367                         err = err | cbor_encode_uint(&policyMap, resource->bitmap);
368
369                         if(resource->secure)
370                         {
371                             err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_SECURE,
372                                     sizeof(OC_RSRVD_SECURE) - 1);
373                             err = err | cbor_encode_boolean(&policyMap, OC_RESOURCE_SECURE);
374
375                             if(resource->port != 0)
376                             {
377                                 err = err | cbor_encode_text_string(&policyMap, OC_RSRVD_HOSTING_PORT,
378                                         sizeof(OC_RSRVD_HOSTING_PORT) - 1);
379                                 err = err | cbor_encode_uint(&policyMap, resource->port);
380                             }
381                         }
382
383                         err = err | cbor_encoder_close_container(&linkMap, &policyMap);
384                     }
385                     // Close
386                     err = err | cbor_encoder_close_container(&linkArray, &linkMap);
387                 }
388                 err = err | cbor_encoder_close_container(&map, &linkArray);
389             }
390             err = err | cbor_encoder_close_container(&rootArray, &map);
391         }
392         // Close main array
393         err = err | cbor_encoder_close_container(&encoder, &rootArray);
394     }
395
396     return checkError(err, &encoder, outPayload, size);
397 cbor_error:
398     OICFree(outPayload);
399     return OC_STACK_ERROR;
400 }
401
402 static int64_t OCConvertDevicePayload(OCDevicePayload* payload, uint8_t* outPayload,
403         size_t* size)
404 {
405     CborEncoder encoder = {0};
406     int64_t err = 0;
407
408     cbor_encoder_init(&encoder, outPayload, *size, 0);
409     CborEncoder rootArray;
410     err = err | cbor_encoder_create_array(&encoder, &rootArray, 1);
411
412     {
413         CborEncoder map;
414         err = err | cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
415
416         // uri
417         err = err | ConditionalAddTextStringToMap(&map, OC_RSRVD_HREF, sizeof(OC_RSRVD_HREF) - 1,
418                 payload->uri);
419
420         // Rep Map
421         {
422             CborEncoder repMap;
423             err = err | cbor_encode_text_string(&map, OC_RSRVD_REPRESENTATION,
424                     sizeof(OC_RSRVD_REPRESENTATION) - 1);
425             err = err | cbor_encoder_create_map(&map, &repMap, CborIndefiniteLength);
426
427             // Device ID
428             err = err | cbor_encode_text_string(&repMap, OC_RSRVD_DEVICE_ID,
429                     sizeof(OC_RSRVD_DEVICE_ID) - 1);
430             err = err | cbor_encode_byte_string(&repMap, payload->sid, UUID_SIZE);
431
432             // Device Name
433             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_DEVICE_NAME,
434                     sizeof(OC_RSRVD_DEVICE_NAME) - 1,
435                     payload->deviceName);
436
437             // Device Spec Version
438             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SPEC_VERSION,
439                     sizeof(OC_RSRVD_SPEC_VERSION) - 1,
440                     payload->specVersion);
441
442             // Device data Model Version
443             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_DATA_MODEL_VERSION,
444                     sizeof(OC_RSRVD_DATA_MODEL_VERSION) - 1,
445                     payload->dataModelVersion);
446
447             err = err | cbor_encoder_close_container(&map, &repMap);
448         }
449
450         // Close Map
451         err = err | cbor_encoder_close_container(&rootArray, &map);
452     }
453
454     // Close main array
455     err = err | cbor_encoder_close_container(&encoder, &rootArray);
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     CborEncoder rootArray;
468     err = err | cbor_encoder_create_array(&encoder, &rootArray, 1);
469     {
470         CborEncoder map;
471         err = err | cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
472
473         // uri
474         err = err | ConditionalAddTextStringToMap(&map, OC_RSRVD_HREF, sizeof(OC_RSRVD_HREF) - 1,
475                 payload->uri);
476
477         // Rep Map
478         {
479             CborEncoder repMap;
480             err = err | cbor_encode_text_string(&map, OC_RSRVD_REPRESENTATION,
481                     sizeof(OC_RSRVD_REPRESENTATION) - 1);
482             err = err | cbor_encoder_create_map(&map, &repMap, CborIndefiniteLength);
483
484             // Platform ID
485             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_PLATFORM_ID,
486                     sizeof(OC_RSRVD_PLATFORM_ID) - 1,
487                     payload->info.platformID);
488
489             // MFG Name
490             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_NAME,
491                     sizeof(OC_RSRVD_MFG_NAME) - 1,
492                     payload->info.manufacturerName);
493
494             // MFG Url
495             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_URL,
496                     sizeof(OC_RSRVD_MFG_URL) - 1,
497                     payload->info.manufacturerUrl);
498
499             // Model Num
500             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MODEL_NUM,
501                     sizeof(OC_RSRVD_MODEL_NUM) - 1,
502                     payload->info.modelNumber);
503
504             // Date of Mfg
505             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_MFG_DATE,
506                     sizeof(OC_RSRVD_MFG_DATE) - 1,
507                     payload->info.dateOfManufacture);
508
509             // Platform Version
510             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_PLATFORM_VERSION,
511                     sizeof(OC_RSRVD_PLATFORM_VERSION) - 1,
512                     payload->info.platformVersion);
513
514             // OS Version
515             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_OS_VERSION,
516                     sizeof(OC_RSRVD_OS_VERSION) - 1,
517                     payload->info.operatingSystemVersion);
518
519             // Hardware Version
520             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_HARDWARE_VERSION,
521                     sizeof(OC_RSRVD_HARDWARE_VERSION) - 1,
522                     payload->info.hardwareVersion);
523
524             // Firmware Version
525             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_FIRMWARE_VERSION,
526                     sizeof(OC_RSRVD_FIRMWARE_VERSION) - 1,
527                     payload->info.firmwareVersion);
528
529             // Support URL
530             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SUPPORT_URL,
531                     sizeof(OC_RSRVD_SUPPORT_URL) - 1,
532                     payload->info.supportUrl);
533
534             // System Time
535             err = err | ConditionalAddTextStringToMap(&repMap, OC_RSRVD_SYSTEM_TIME,
536                     sizeof(OC_RSRVD_SYSTEM_TIME) - 1,
537                     payload->info.systemTime);
538             err = err | cbor_encoder_close_container(&map, &repMap);
539         }
540
541         // Close Map
542         err = err | cbor_encoder_close_container(&rootArray, &map);
543     }
544
545     // Close main array
546     err = err | cbor_encoder_close_container(&encoder, &rootArray);
547
548     return checkError(err, &encoder, outPayload, size);
549 }
550
551 static int64_t OCConvertArrayItem(CborEncoder* array, const OCRepPayloadValueArray* valArray,
552         size_t index)
553 {
554     int64_t err = 0;
555     switch (valArray->type)
556     {
557         case OCREP_PROP_NULL:
558             OC_LOG(ERROR, TAG, "ConvertArray Invalid NULL");
559             err = CborUnknownError;
560             break;
561         case OCREP_PROP_INT:
562             err = err | cbor_encode_int(array, valArray->iArray[index]);
563             break;
564         case OCREP_PROP_DOUBLE:
565             err = err | cbor_encode_double(array, valArray->dArray[index]);
566             break;
567         case OCREP_PROP_BOOL:
568             err = err | cbor_encode_boolean(array, valArray->bArray[index]);
569             break;
570         case OCREP_PROP_STRING:
571             if (!valArray->strArray[index])
572             {
573                 err = err | cbor_encode_null(array);
574             }
575             else
576             {
577                 err = err | cbor_encode_text_string(array, valArray->strArray[index],
578                         strlen(valArray->strArray[index]));
579             }
580             break;
581         case OCREP_PROP_BYTE_STRING:
582             if (!valArray->strArray[index])
583             {
584                 err = err | cbor_encode_null(array);
585             }
586             else
587             {
588                 err = err | cbor_encode_byte_string(array, valArray->ocByteStrArray[index].bytes,
589                         valArray->ocByteStrArray[index].len);
590             }
591             break;
592         case OCREP_PROP_OBJECT:
593             if (!valArray->objArray[index])
594             {
595                 err = err | cbor_encode_null(array);
596             }
597             else
598             {
599                 err = OCConvertSingleRepPayload(array, valArray->objArray[index]);
600             }
601             break;
602         case OCREP_PROP_ARRAY:
603             OC_LOG(ERROR, TAG, "ConvertArray Invalid child array");
604             err = CborUnknownError;
605             break;
606     }
607
608     return err;
609 }
610 static int64_t OCConvertArray(CborEncoder* parent, const OCRepPayloadValueArray* valArray)
611 {
612     CborEncoder array;
613     int64_t err = 0;
614
615     err = err | cbor_encoder_create_array(parent, &array, valArray->dimensions[0]);
616
617     for (size_t i = 0; i < valArray->dimensions[0];++i)
618     {
619         if (valArray->dimensions[1] != 0)
620         {
621             CborEncoder array2;
622             err = err | cbor_encoder_create_array(&array, &array2, valArray->dimensions[1]);
623
624             for (size_t j = 0; j < valArray->dimensions[1]; ++j)
625             {
626                 if (valArray->dimensions[2] != 0)
627                 {
628                     CborEncoder array3;
629                     err = err | cbor_encoder_create_array(&array2, &array3,
630                             valArray->dimensions[2]);
631
632                     for(size_t k = 0; k < valArray->dimensions[2]; ++k)
633                     {
634                         OCConvertArrayItem(&array3, valArray,
635                             j * valArray->dimensions[2] +
636                             i * valArray->dimensions[2] * valArray->dimensions[1] +
637                             k);
638                     }
639                     err = err | cbor_encoder_close_container(&array2, &array3);
640                 }
641                 else
642                 {
643                     OCConvertArrayItem(&array2, valArray,
644                             i * valArray->dimensions[1] + j);
645                 }
646             }
647             err = err | cbor_encoder_close_container(&array, &array2);
648         }
649         else
650         {
651             OCConvertArrayItem(&array, valArray, i);
652         }
653     }
654     err = err | cbor_encoder_close_container(parent, &array);
655     return err;
656 }
657
658 static int64_t OCConvertSingleRepPayload(CborEncoder* parent, const OCRepPayload* payload)
659 {
660     int64_t err = 0;
661     CborEncoder map;
662     err = err | cbor_encoder_create_map(parent, &map, CborIndefiniteLength);
663
664     // Uri
665     err = err | ConditionalAddTextStringToMap(&map, OC_RSRVD_HREF,
666             sizeof(OC_RSRVD_HREF) - 1,
667             payload->uri);
668
669     // Prop Map
670     // resource types, interfaces
671     if(payload->types || payload->interfaces)
672     {
673         OC_LOG(INFO, TAG, "Payload has types or interfaces");
674         err = err | cbor_encode_text_string(&map,
675                 OC_RSRVD_PROPERTY,
676                 sizeof(OC_RSRVD_PROPERTY) - 1);
677         CborEncoder propMap;
678         err = err | cbor_encoder_create_map(&map, &propMap, 2);
679
680         if (payload->types)
681         {
682             char* joinedTypes = OCStringLLJoin(payload->types);
683             if (joinedTypes)
684             {
685                 err = err | cbor_encode_text_string(&propMap, OC_RSRVD_RESOURCE_TYPE,
686                         sizeof(OC_RSRVD_RESOURCE_TYPE) - 1);
687                 err = err | cbor_encode_text_string(&propMap, joinedTypes,
688                         strlen(joinedTypes));
689                 OICFree(joinedTypes);
690             }
691             else
692             {
693                 return OC_STACK_NO_MEMORY;
694             }
695         }
696         if (payload->interfaces)
697         {
698             char* joinedInterfaces = OCStringLLJoin(payload->interfaces);
699             if (joinedInterfaces)
700             {
701                 err = err | cbor_encode_text_string(&propMap, OC_RSRVD_INTERFACE,
702                         sizeof(OC_RSRVD_INTERFACE) - 1);
703                 err = err | cbor_encode_text_string(&propMap, joinedInterfaces,
704                         strlen(joinedInterfaces));
705                 OICFree(joinedInterfaces);
706             }
707             else
708             {
709                 return OC_STACK_NO_MEMORY;
710             }
711         }
712         err = err | cbor_encoder_close_container(&map, &propMap);
713     }
714
715     // Rep Map
716     {
717         CborEncoder repMap;
718         err = err | cbor_encode_text_string(&map,
719                 OC_RSRVD_REPRESENTATION,
720                 sizeof(OC_RSRVD_REPRESENTATION) - 1);
721         err = err | cbor_encoder_create_map(&map, &repMap, CborIndefiniteLength);
722         OCRepPayloadValue* value = payload->values;
723         while(value)
724         {
725             err = err | cbor_encode_text_string(&repMap,
726                     value->name,
727                     strlen(value->name));
728             switch(value->type)
729             {
730                 case OCREP_PROP_NULL:
731                     err = err | cbor_encode_null(&repMap);
732                     break;
733                 case OCREP_PROP_INT:
734                     err = err | cbor_encode_int(&repMap,
735                             value->i);
736                     break;
737                 case OCREP_PROP_DOUBLE:
738                     err = err | cbor_encode_double(&repMap,
739                             value->d);
740                     break;
741                 case OCREP_PROP_BOOL:
742                     err = err | cbor_encode_boolean(&repMap,
743                             value->b);
744                     break;
745                 case OCREP_PROP_STRING:
746                     err = err | cbor_encode_text_string(&repMap,
747                             value->str, strlen(value->str));
748                     break;
749                 case OCREP_PROP_BYTE_STRING:
750                     err = err | cbor_encode_byte_string(&repMap,
751                             value->ocByteStr.bytes, value->ocByteStr.len);
752                     break;
753                 case OCREP_PROP_OBJECT:
754                     err = err | OCConvertSingleRepPayload(&repMap, value->obj);
755                     break;
756                 case OCREP_PROP_ARRAY:
757                     err = err | OCConvertArray(&repMap, &value->arr);
758                     break;
759                 default:
760                     OC_LOG_V(ERROR, TAG, "Invalid Prop type: %d",
761                             value->type);
762                     break;
763             }
764             value = value->next;
765         }
766
767         err = err | cbor_encoder_close_container(&map, &repMap);
768     }
769
770     // Close Map
771     err = err | cbor_encoder_close_container(parent, &map);
772
773     return err;
774 }
775
776 static int64_t OCConvertRepPayload(OCRepPayload* payload, uint8_t* outPayload, size_t* size)
777 {
778     CborEncoder encoder = {0};
779     int64_t err = 0;
780
781     cbor_encoder_init(&encoder, outPayload, *size, 0);
782     CborEncoder rootArray;
783     err = err | cbor_encoder_create_array(&encoder, &rootArray, CborIndefiniteLength);
784
785     while(payload != NULL && (err == 0 || err == CborErrorOutOfMemory))
786     {
787         err = err | OCConvertSingleRepPayload(&rootArray, payload);
788         payload = payload->next;
789     }
790
791     // Close main array
792     err = err | cbor_encoder_close_container(&encoder, &rootArray);
793
794     return checkError(err, &encoder, outPayload, size);
795 }
796
797 static int64_t OCConvertPresencePayload(OCPresencePayload* payload,
798         uint8_t* outPayload, size_t* size)
799 {
800     CborEncoder encoder = {0};
801     int64_t err = 0;
802
803     cbor_encoder_init(&encoder, outPayload, *size, 0);
804     CborEncoder rootArray;
805
806     err = err | cbor_encoder_create_array(&encoder, &rootArray, 1);
807
808     CborEncoder map;
809     err = err | cbor_encoder_create_map(&rootArray, &map, CborIndefiniteLength);
810
811     // Sequence Number
812     err = err | cbor_encode_text_string(&map,
813             OC_RSRVD_NONCE,
814             sizeof(OC_RSRVD_NONCE) - 1);
815     err = err | cbor_encode_uint(&map, payload->sequenceNumber);
816
817     // Max Age
818     err = err | cbor_encode_text_string(&map,
819             OC_RSRVD_TTL,
820             sizeof(OC_RSRVD_TTL) - 1);
821     err = err | cbor_encode_uint(&map, payload->maxAge);
822
823     // Trigger
824     const char* triggerStr = convertTriggerEnumToString(payload->trigger);
825     err = err | AddTextStringToMap(&map, OC_RSRVD_TRIGGER, sizeof(OC_RSRVD_TRIGGER) - 1,
826             triggerStr);
827
828     // Resource type name
829     if(payload->trigger != OC_PRESENCE_TRIGGER_DELETE)
830     {
831         err = err | ConditionalAddTextStringToMap(&map, OC_RSRVD_RESOURCE_TYPE,
832                 sizeof(OC_RSRVD_RESOURCE_TYPE) - 1, payload->resourceType);
833     }
834
835     // Close Map
836     err = err | cbor_encoder_close_container(&rootArray, &map);
837     err = err | cbor_encoder_close_container(&encoder, &rootArray);
838
839     return checkError(err, &encoder, outPayload, size);
840 }
841
842 static int64_t AddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
843         const char* value)
844 {
845     return cbor_encode_text_string(map, key, keylen) |
846            cbor_encode_text_string(map, value, strlen(value));
847 }
848
849 static int64_t ConditionalAddTextStringToMap(CborEncoder* map, const char* key, size_t keylen,
850         const char* value)
851 {
852     return value ? AddTextStringToMap(map, key, keylen, value) : 0;
853 }