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