tizen 2.3 release
[external/buxton.git] / src / shared / serialize.c
1 /*
2  * This file is part of buxton.
3  *
4  * Copyright (C) 2013 Intel Corporation
5  *
6  * buxton is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1
9  * of the License, or (at your option) any later version.
10  */
11
12 #ifdef HAVE_CONFIG_H
13         #include "config.h"
14 #endif
15
16 #include <errno.h>
17 #include <malloc.h>
18 #include <stdarg.h>
19 #include <stdint.h>
20 #include <stdbool.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "buxton.h"
25 #include "log.h"
26 #include "serialize.h"
27 #include "smack.h"
28 #include "util.h"
29
30
31 size_t buxton_serialize(BuxtonData *source, BuxtonString *label,
32                         uint8_t **target)
33 {
34         size_t length;
35         size_t size;
36         size_t offset = 0;
37         uint8_t *data = NULL;
38         size_t ret = 0;
39
40         assert(source);
41         assert(target);
42
43         /* DataType + length field */
44         size = sizeof(BuxtonDataType) + (sizeof(uint32_t) * 2) + label->length;
45
46         /* Total size will be different for string data */
47         switch (source->type) {
48         case STRING:
49                 length = source->store.d_string.length;
50                 break;
51         default:
52                 length = sizeof(source->store);
53                 break;
54         }
55
56         size += length;
57
58         /* Allocate memory big enough to hold all information */
59         data = malloc0(size);
60         if (!data) {
61                 abort();
62         }
63
64         /* Write the entire BuxtonDataType to the first block */
65         memcpy(data, &(source->type), sizeof(BuxtonDataType));
66         offset += sizeof(BuxtonDataType);
67
68         /* Write out the length of the label field */
69         memcpy(data+offset, &(label->length), sizeof(uint32_t));
70         offset += sizeof(uint32_t);
71
72         /* Write out the length of the data field */
73         memcpy(data+offset, &length, sizeof(uint32_t));
74         offset += sizeof(uint32_t);
75
76         /* Write out the label field */
77         memcpy(data+offset, label->value, label->length);
78         offset += label->length;
79
80         /* Write the data itself */
81         switch (source->type) {
82         case STRING:
83                 memcpy(data+offset, source->store.d_string.value, length);
84                 break;
85         case INT32:
86                 memcpy(data+offset, &(source->store.d_int32), sizeof(int32_t));
87                 break;
88         case UINT32:
89                 memcpy(data+offset, &(source->store.d_uint32), sizeof(uint32_t));
90                 break;
91         case INT64:
92                 memcpy(data+offset, &(source->store.d_int64), sizeof(int64_t));
93                 break;
94         case UINT64:
95                 memcpy(data+offset, &(source->store.d_uint64), sizeof(uint64_t));
96                 break;
97         case FLOAT:
98                 memcpy(data+offset, &(source->store.d_float), sizeof(float));
99                 break;
100         case DOUBLE:
101                 memcpy(data+offset, &(source->store.d_double), sizeof(double));
102                 break;
103         case BOOLEAN:
104                 memcpy(data+offset, &(source->store.d_boolean), sizeof(bool));
105                 break;
106         default:
107                 abort();
108         }
109
110         ret = size;
111         *target = data;
112
113         assert(ret >= BXT_MINIMUM_SIZE);
114
115         return ret;
116 }
117
118 void buxton_deserialize(uint8_t *source, BuxtonData *target,
119                         BuxtonString *label)
120 {
121         size_t offset = 0;
122         size_t length = 0;
123         BuxtonDataType type;
124
125         assert(source);
126         assert(target);
127         assert(label);
128
129         /* Retrieve the BuxtonDataType */
130         type = *(BuxtonDataType*)source;
131         offset += sizeof(BuxtonDataType);
132
133         /* Retrieve the length of the label */
134         label->length = *(uint32_t*)(source+offset);
135         offset += sizeof(uint32_t);
136
137         /* Retrieve the length of the value */
138         length = *(uint32_t*)(source+offset);
139         offset += sizeof(uint32_t);
140
141         /* Retrieve the label */
142         label->value = malloc(label->length);
143         if (label->length > 0 && !label->value) {
144                 abort();
145         }
146         memcpy(label->value, source+offset, label->length);
147         offset += label->length;
148
149         switch (type) {
150         case STRING:
151                 /* User must free the string */
152                 target->store.d_string.value = malloc(length);
153                 if (!target->store.d_string.value) {
154                         abort();
155                 }
156                 memcpy(target->store.d_string.value, source+offset, length);
157                 target->store.d_string.length = (uint32_t)length;
158                 break;
159         case INT32:
160                 target->store.d_int32 = *(int32_t*)(source+offset);
161                 break;
162         case UINT32:
163                 target->store.d_uint32 = *(uint32_t*)(source+offset);
164                 break;
165         case INT64:
166                 target->store.d_int64 = *(int64_t*)(source+offset);
167                 break;
168         case UINT64:
169                 target->store.d_uint64 = *(uint64_t*)(source+offset);
170                 break;
171         case FLOAT:
172                 target->store.d_float = *(float*)(source+offset);
173                 break;
174         case DOUBLE:
175                 memcpy(&target->store.d_double, source + offset, sizeof(double));
176                 break;
177         case BOOLEAN:
178                 target->store.d_boolean = *(bool*)(source+offset);
179                 break;
180         default:
181                 buxton_debug("Invalid BuxtonDataType: %lu\n", type);
182                 abort();
183         }
184
185         /* Successful */
186         target->type = type;
187 }
188
189 size_t buxton_serialize_message(uint8_t **dest, BuxtonControlMessage message,
190                                 uint32_t msgid, BuxtonArray *list)
191 {
192         uint16_t i = 0;
193         uint8_t *data = NULL;
194         size_t ret = 0;
195         size_t offset = 0;
196         size_t size = 0;
197         size_t curSize = 0;
198         uint16_t control, msg;
199
200         assert(dest);
201
202         buxton_debug("Serializing message...\n");
203
204         if (list->len > BUXTON_MESSAGE_MAX_PARAMS) {
205                 errno = EINVAL;
206                 return ret;
207         }
208
209         if (message >= BUXTON_CONTROL_MAX || message < BUXTON_CONTROL_SET) {
210                 errno = EINVAL;
211                 return ret;
212         }
213
214         /*
215          * initial size =
216          * control code + control message (uint16_t * 2) +
217          * message size (uint32_t) +
218          * message id (uint32_t) +
219          * param count (uint32_t)
220          */
221         data = malloc0(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) +
222                        sizeof(uint32_t));
223         if (!data) {
224                 errno = ENOMEM;
225                 goto end;
226         }
227
228         control = BUXTON_CONTROL_CODE;
229         memcpy(data, &control, sizeof(uint16_t));
230         offset += sizeof(uint16_t);
231
232         msg = (uint16_t)message;
233         memcpy(data+offset, &msg, sizeof(uint16_t));
234         offset += sizeof(uint16_t);
235
236         /* Save room for final size */
237         offset += sizeof(uint32_t);
238
239         memcpy(data+offset, &msgid, sizeof(uint32_t));
240         offset += sizeof(uint32_t);
241
242         /* Now write the parameter count */
243         memcpy(data+offset, &(list->len), sizeof(uint32_t));
244         offset += sizeof(uint32_t);
245
246         size = offset;
247
248         /* Deal with parameters */
249         BuxtonData *param;
250         size_t p_length = 0;
251         for (i=0; i < list->len; i++) {
252                 param = buxton_array_get(list, i);
253                 if (!param) {
254                         errno = EINVAL;
255                         goto fail;
256                 }
257
258                 switch (param->type) {
259                 case STRING:
260                         p_length = param->store.d_string.length;
261                         break;
262                 case INT32:
263                         p_length = sizeof(int32_t);
264                         break;
265                 case UINT32:
266                         p_length = sizeof(uint32_t);
267                         break;
268                 case INT64:
269                         p_length = sizeof(int64_t);
270                         break;
271                 case UINT64:
272                         p_length = sizeof(uint64_t);
273                         break;
274                 case FLOAT:
275                         p_length = sizeof(float);
276                         break;
277                 case DOUBLE:
278                         p_length = sizeof(double);
279                         break;
280                 case BOOLEAN:
281                         p_length = sizeof(bool);
282                         break;
283                 default:
284                         errno = EINVAL;
285                         buxton_log("Invalid parameter type %lu\n", param->type);
286                         goto fail;
287                 };
288
289                 buxton_debug("offset: %lu\n", offset);
290                 buxton_debug("value length: %lu\n", p_length);
291
292                 /* Need to allocate enough room to hold this data */
293                 size += sizeof(uint16_t) + sizeof(uint32_t) + p_length;
294
295                 if (curSize < size) {
296                         if (!(data = greedy_realloc((void**)&data, &curSize, size))) {
297                                 errno = ENOMEM;
298                                 goto fail;
299                         }
300                         memzero(data+offset, size - offset);
301                 }
302
303                 /* Copy data type */
304                 memcpy(data+offset, &(param->type), sizeof(uint16_t));
305                 offset += sizeof(uint16_t);
306
307                 /* Write out the length of value */
308                 memcpy(data+offset, &p_length, sizeof(uint32_t));
309                 offset += sizeof(uint32_t);
310
311                 switch (param->type) {
312                 case STRING:
313                         memcpy(data+offset, param->store.d_string.value, p_length);
314                         break;
315                 case INT32:
316                         memcpy(data+offset, &(param->store.d_int32), sizeof(int32_t));
317                         break;
318                 case UINT32:
319                         memcpy(data+offset, &(param->store.d_uint32), sizeof(uint32_t));
320                         break;
321                 case INT64:
322                         memcpy(data+offset, &(param->store.d_int64), sizeof(int64_t));
323                         break;
324                 case UINT64:
325                         memcpy(data+offset, &(param->store.d_uint64), sizeof(uint64_t));
326                         break;
327                 case FLOAT:
328                         memcpy(data+offset, &(param->store.d_float), sizeof(float));
329                         break;
330                 case DOUBLE:
331                         memcpy(data+offset, &(param->store.d_double), sizeof(double));
332                         break;
333                 case BOOLEAN:
334                         memcpy(data+offset, &(param->store.d_boolean), sizeof(bool));
335                         break;
336                 default:
337                         /* already tested this above, can't get here
338                          * normally */
339                         assert(0);
340                 };
341                 offset += p_length;
342                 p_length = 0;
343         }
344
345         memcpy(data+BUXTON_LENGTH_OFFSET, &offset, sizeof(uint32_t));
346
347         ret = offset;
348         *dest = data;
349
350 fail:
351         /* Clean up */
352         if (ret == 0) {
353                 free(data);
354         }
355 end:
356         buxton_debug("Serializing returned:%lu\n", ret);
357         return ret;
358 }
359
360 ssize_t buxton_deserialize_message(uint8_t *data,
361                                   BuxtonControlMessage *r_message,
362                                   size_t size, uint32_t *r_msgid,
363                                   BuxtonData **list)
364 {
365         size_t offset = 0;
366         ssize_t ret = -1;
367         size_t min_length = BUXTON_MESSAGE_HEADER_LENGTH;
368         uint16_t control, message;
369         size_t n_params, c_param, c_length;
370         BuxtonDataType c_type = 0;
371         BuxtonData *k_list = NULL;
372         BuxtonData c_data;
373         uint32_t msgid;
374
375         assert(data);
376         assert(r_message);
377         assert(list);
378
379         buxton_debug("Deserializing message...\n");
380         buxton_debug("size=%lu\n", size);
381
382         if (size < min_length) {
383                 errno = EINVAL;
384                 goto end;
385         }
386
387         /* Copy the control code */
388         control = *(uint16_t*)data;
389         offset += sizeof(uint16_t);
390
391         /* Check this is a valid buxton message */
392         if (control != BUXTON_CONTROL_CODE) {
393                 errno = EINVAL;
394                 goto end;
395         }
396
397         /* Obtain the control message */
398         message = *(BuxtonControlMessage*)(data+offset);
399         offset += sizeof(uint16_t);
400
401         /* Ensure control message is in valid range */
402         if (message <= BUXTON_CONTROL_MIN || message >= BUXTON_CONTROL_MAX) {
403                 errno = EINVAL;
404                 goto end;
405         }
406
407         /* Skip size since our caller got this already */
408         offset += sizeof(uint32_t);
409
410         /* Obtain the message id */
411         msgid = *(uint32_t*)(data+offset);
412         offset += sizeof(uint32_t);
413
414         /* Obtain number of parameters */
415         n_params = *(uint32_t*)(data+offset);
416         offset += sizeof(uint32_t);
417         buxton_debug("total params: %d\n", n_params);
418
419         if (n_params > BUXTON_MESSAGE_MAX_PARAMS) {
420                 errno = EINVAL;
421                 goto end;
422         }
423
424         k_list = malloc0(sizeof(BuxtonData)*n_params);
425         if (n_params && !k_list) {
426                 errno = ENOMEM;
427                 goto end;
428         }
429
430         memzero(&c_data, sizeof(BuxtonData));
431
432         for (c_param = 0; c_param < n_params; c_param++) {
433                 buxton_debug("param: %d\n", c_param + 1);
434                 buxton_debug("offset=%lu\n", offset);
435                 /* Don't read past the end of the buffer */
436                 if (offset + sizeof(uint16_t) + sizeof(uint32_t) > size) {
437                         errno = EINVAL;
438                         goto end;
439                 }
440
441                 /* Now unpack type */
442                 memcpy(&c_type, data+offset, sizeof(uint16_t));
443                 offset += sizeof(uint16_t);
444
445                 if (c_type >= BUXTON_TYPE_MAX || c_type <= BUXTON_TYPE_MIN) {
446                         errno = EINVAL;
447                         goto end;
448                 }
449
450                 /* Retrieve the length of the value */
451                 c_length = *(uint32_t*)(data+offset);
452                 if (c_length == 0 && c_type != STRING) {
453                         errno = EINVAL;
454                         goto end;
455                 }
456                 offset += sizeof(uint32_t);
457                 buxton_debug("value length: %lu\n", c_length);
458
459                 /* Don't try to read past the end of our buffer */
460                 if (offset + c_length > size) {
461                         errno = EINVAL;
462                         goto end;
463                 }
464
465                 switch (c_type) {
466                 case STRING:
467                         if (c_length) {
468                                 c_data.store.d_string.value = malloc(c_length);
469                                 if (!c_data.store.d_string.value) {
470                                         errno = ENOMEM;
471                                         goto end;
472                                 }
473                                 memcpy(c_data.store.d_string.value, data+offset, c_length);
474                                 c_data.store.d_string.length = (uint32_t)c_length;
475                                 if (c_data.store.d_string.value[c_length-1] != 0x00) {
476                                         errno = EINVAL;
477                                         buxton_debug("buxton_deserialize_message(): Garbage message\n");
478                                         free(c_data.store.d_string.value);
479                                         goto end;
480                                 }
481                         } else {
482                                 c_data.store.d_string.value = NULL;
483                                 c_data.store.d_string.length = 0;
484                         }
485                         break;
486                 case INT32:
487                         c_data.store.d_int32 = *(int32_t*)(data+offset);
488                         break;
489                 case UINT32:
490                         c_data.store.d_uint32 = *(uint32_t*)(data+offset);
491                         break;
492                 case INT64:
493                         c_data.store.d_int64 = *(int64_t*)(data+offset);
494                         break;
495                 case UINT64:
496                         c_data.store.d_uint64 = *(uint64_t*)(data+offset);
497                         break;
498                 case FLOAT:
499                         c_data.store.d_float = *(float*)(data+offset);
500                         break;
501                 case DOUBLE:
502                         memcpy(&c_data.store.d_double, data + offset, sizeof(double));
503                         break;
504                 case BOOLEAN:
505                         c_data.store.d_boolean = *(bool*)(data+offset);
506                         break;
507                 default:
508                         errno = EINVAL;
509                         goto end;
510                 }
511                 c_data.type = c_type;
512                 k_list[c_param] = c_data;
513                 memzero(&c_data, sizeof(BuxtonData));
514                 offset += c_length;
515         }
516         *r_message = message;
517         *r_msgid = msgid;
518         if (n_params == 0) {
519                 *list = NULL;
520                 free(k_list);
521                 k_list = NULL;
522         } else {
523                 *list = k_list;
524         }
525         ret = (ssize_t)n_params;
526 end:
527         if (ret <= 0) {
528                 free(k_list);
529         }
530
531         buxton_debug("Deserializing returned:%i\n", ret);
532         return ret;
533 }
534
535 size_t buxton_get_message_size(uint8_t *data, size_t size)
536 {
537         size_t r_size;
538
539         assert(data);
540
541         if (size < BUXTON_MESSAGE_HEADER_LENGTH) {
542                 return 0;
543         }
544
545         r_size = *(uint32_t*)(data + BUXTON_LENGTH_OFFSET);
546
547         if (r_size < BUXTON_MESSAGE_HEADER_LENGTH) {
548                 return 0;
549         }
550
551         return r_size;
552 }
553
554 void include_serialize(void)
555 {
556         ;
557 }
558
559 /*
560  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
561  *
562  * Local variables:
563  * c-basic-offset: 8
564  * tab-width: 8
565  * indent-tabs-mode: t
566  * End:
567  *
568  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
569  * :indentSize=8:tabSize=8:noTabs=false:
570  */