1 // Copyright Maciej Sobczak 2008-2019.
2 // This file is part of YAMI4.
3 //
4 // YAMI4 is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // YAMI4 is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with YAMI4. If not, see <http://www.gnu.org/licenses/>.
16
17 #include "parameters-details.h"
18 #include "allocator.h"
19 #include "fatal_errors.h"
20 #include "parameters.h"
21 #include "serialization.h"
22 #include <cstring>
23 #include <new>
24
25 using namespace yami;
26 using namespace yami::details;
27
type_code(core::parameter_type t)28 int details::type_code(core::parameter_type t)
29 {
30 int res = 0; // dummy initialization to please the compiler
31 switch (t)
32 {
33 case core::boolean: res = 1; break;
34 case core::integer: res = 2; break;
35 case core::long_long: res = 3; break;
36 case core::double_float: res = 4; break;
37 case core::string: res = 5; break;
38 case core::binary: res = 6; break;
39 case core::boolean_array: res = 7; break;
40 case core::integer_array: res = 8; break;
41 case core::long_long_array: res = 9; break;
42 case core::double_float_array: res = 10; break;
43 case core::string_array: res = 11; break;
44 case core::binary_array: res = 12; break;
45 case core::nested_parameters: res = 13; break;
46 case core::nested_parameters_array: res = 14; break;
47 default:
48 fatal_failure(__FILE__, __LINE__);
49 }
50
51 return res;
52 }
53
get_type_from_code(int code,core::parameter_type & type)54 core::result details::get_type_from_code(
55 int code, core::parameter_type & type)
56 {
57 core::result res = core::ok;
58 switch (code)
59 {
60 case 1: type = core::boolean; break;
61 case 2: type = core::integer; break;
62 case 3: type = core::long_long; break;
63 case 4: type = core::double_float; break;
64 case 5: type = core::string; break;
65 case 6: type = core::binary; break;
66 case 7: type = core::boolean_array; break;
67 case 8: type = core::integer_array; break;
68 case 9: type = core::long_long_array; break;
69 case 10: type = core::double_float_array; break;
70 case 11: type = core::string_array; break;
71 case 12: type = core::binary_array; break;
72 case 13: type = core::nested_parameters; break;
73 case 14: type = core::nested_parameters_array; break;
74 default:
75 res = core::unexpected_value;
76 }
77
78 return res;
79 }
80
set(const char * name,std::size_t length,allocator & alloc)81 core::result entry_name::set(const char * name, std::size_t length,
82 allocator & alloc)
83 {
84 core::result res;
85 name_length = length;
86 if (length <= short_name_optimization_threshold)
87 {
88 std::memcpy(buffer.short_value, name, length);
89 res = core::ok;
90 }
91 else
92 {
93 char * allocated =
94 static_cast<char *>(alloc.allocate(length));
95 if (allocated != NULL)
96 {
97 std::memcpy(allocated, name, length);
98 buffer.long_value = allocated;
99 res = core::ok;
100 }
101 else
102 {
103 res = core::no_memory;
104 }
105 }
106
107 return res;
108 }
109
value() const110 const char * entry_name::value() const
111 {
112 const char * res;
113 if (name_length <= short_name_optimization_threshold)
114 {
115 res = buffer.short_value;
116 }
117 else
118 {
119 res = buffer.long_value;
120 }
121
122 return res;
123 }
124
clear(allocator & alloc)125 void entry_name::clear(allocator & alloc)
126 {
127 if (name_length > short_name_optimization_threshold)
128 {
129 alloc.deallocate(buffer.long_value);
130 }
131
132 name_length = 0;
133 }
134
equals(const char * str,std::size_t length) const135 bool entry_name::equals(const char * str, std::size_t length) const
136 {
137 bool res = false;
138
139 if (length == name_length)
140 {
141 if (name_length <= short_name_optimization_threshold)
142 {
143 res = std::memcmp(buffer.short_value, str, length) == 0;
144 }
145 else
146 {
147 res = std::memcmp(buffer.long_value, str, length) == 0;
148 }
149 }
150
151 return res;
152 }
153
dump(dump_sink & sink) const154 void entry_name::dump(dump_sink & sink) const
155 {
156 if (name_length <= short_name_optimization_threshold)
157 {
158 sink.dump(buffer.short_value, name_length);
159 }
160 else
161 {
162 sink.dump(buffer.long_value, name_length);
163 }
164 }
165
clear(allocator & alloc)166 void string_array_element::clear(allocator & alloc)
167 {
168 if (value != NULL)
169 {
170 alloc.deallocate(value);
171 value = NULL;
172 length = 0;
173 }
174 }
175
clear(allocator & alloc)176 void binary_array_element::clear(allocator & alloc)
177 {
178 if (value != NULL)
179 {
180 alloc.deallocate(value);
181 value = NULL;
182 length = 0;
183 }
184 }
185
clear_item(allocator & alloc)186 void entry::clear_item(allocator & alloc)
187 {
188 if (type == core::string && item.str.own)
189 {
190 alloc.deallocate(item.str.value);
191 }
192 else if (type == core::binary && item.bin.own)
193 {
194 alloc.deallocate(item.bin.value);
195 }
196 else if (type == core::boolean_array && item.ba.own)
197 {
198 alloc.deallocate(item.ba.values);
199 }
200 else if (type == core::integer_array && item.ia.own)
201 {
202 alloc.deallocate(item.ia.values);
203 }
204 else if (type == core::long_long_array && item.La.own)
205 {
206 alloc.deallocate(item.La.values);
207 }
208 else if (type == core::double_float_array && item.da.own)
209 {
210 alloc.deallocate(item.da.values);
211 }
212 else if (type == core::string_array && item.sa.own)
213 {
214 for (std::size_t i = 0; i != item.sa.length; ++i)
215 {
216 item.sa.values[i].clear(alloc);
217 }
218
219 alloc.deallocate(item.sa.values);
220 }
221 else if (type == core::binary_array && item.bina.own)
222 {
223 for (std::size_t i = 0; i != item.bina.length; ++i)
224 {
225 item.bina.values[i].clear(alloc);
226 }
227
228 alloc.deallocate(item.bina.values);
229 }
230 else if (type == core::nested_parameters)
231 {
232 // deep clear
233
234 item.nested->clear();
235
236 alloc.deallocate(item.nested);
237 }
238 else if (type == core::nested_parameters_array)
239 {
240 for (std::size_t i = 0; i != item.nesteda.length; ++i)
241 {
242 // deep clear
243 item.nesteda.values[i].clear();
244 }
245
246 alloc.deallocate(item.nesteda.values);
247 }
248
249 type = core::unused;
250 }
251
get_serialize_buffer_size(const core::parameters & params,std::size_t & size)252 void details::get_serialize_buffer_size(
253 const core::parameters & params,
254 std::size_t & size) // starts with 0 (for root) and gets updated
255 {
256 // number of entries
257 size += 4;
258
259 for (size_t i = 0; i != params.num_of_entries_; ++i)
260 {
261 const entry & e = params.data_[i];
262
263 if (e.type != core::unused)
264 {
265 // name length and the name itself:
266 size += 4;
267 size += round_up_4(e.name.name_length);
268
269 // type
270 size += 4;
271
272 // value
273 switch (e.type)
274 {
275 case core::boolean:
276 case core::integer:
277 size += 4;
278 break;
279 case core::long_long:
280 size += 8;
281 break;
282 case core::double_float:
283 size += 8;
284 break;
285 case core::string:
286 // length and value
287 size += 4;
288 size += round_up_4(e.item.str.length);
289 break;
290 case core::binary:
291 // length and value
292 size += 4;
293 size += round_up_4(e.item.bin.length);
294 break;
295 case core::boolean_array:
296 // length and packed values
297 size += 4;
298 size += round_up_4((e.item.ba.length + 7) / 8);
299 break;
300 case core::integer_array:
301 // length and values (each value 4 bytes)
302 size += 4;
303 size += round_up_4(e.item.ia.length * 4);
304 break;
305 case core::long_long_array:
306 // length and values (each value 8 bytes)
307 size += 4;
308 size += round_up_4(e.item.La.length * 8);
309 break;
310 case core::double_float_array:
311 // length and values (each value 8 bytes)
312 size += 4;
313 size += round_up_4(e.item.da.length * 8);
314 break;
315 case core::string_array:
316 // length and then each entry as a string
317 size += 4;
318 for (std::size_t j = 0; j != e.item.sa.length; ++j)
319 {
320 // length of array entry and its value
321 size += 4;
322 size += round_up_4(e.item.sa.values[j].length);
323 }
324 break;
325 case core::binary_array:
326 // length and then each entry separately
327 size += 4;
328 for (std::size_t j = 0; j != e.item.bina.length; ++j)
329 {
330 // length of array entry and its value
331 size += 4;
332 size += round_up_4(e.item.bina.values[j].length);
333 }
334 break;
335 case core::nested_parameters:
336 get_serialize_buffer_size(*e.item.nested, size);
337 break;
338 case core::nested_parameters_array:
339 // length and then each nested object separately
340 size += 4;
341 for (std::size_t j = 0; j != e.item.nesteda.length; ++j)
342 {
343 get_serialize_buffer_size(e.item.nesteda.values[j], size);
344 }
345 break;
346 default:
347 fatal_failure(__FILE__, __LINE__);
348 }
349 }
350 }
351 }
352
353 // helper for serializing individual entries
serialize_entry(const details::entry & e,char ** buffers,const std::size_t * buffer_sizes,std::size_t num_of_buffers,std::size_t & current_buffer,char * & buffer_position)354 core::result details::serialize_entry(
355 const details::entry & e,
356 char * * buffers,
357 const std::size_t * buffer_sizes,
358 std::size_t num_of_buffers,
359 std::size_t & current_buffer, char * & buffer_position)
360 {
361 // name length and the name itself:
362 core::result res = put_string(buffers, buffer_sizes, num_of_buffers,
363 current_buffer, buffer_position,
364 e.name.value(), e.name.name_length);
365 if (res == core::ok)
366 {
367 // type
368 res = put_integer(buffers, buffer_sizes, num_of_buffers,
369 current_buffer, buffer_position,
370 type_code(e.type));
371 if (res == core::ok)
372 {
373 // value
374 switch (e.type)
375 {
376 case core::boolean:
377 res = put_integer(
378 buffers, buffer_sizes, num_of_buffers,
379 current_buffer, buffer_position,
380 static_cast<int>(e.item.b));
381 break;
382 case core::integer:
383 res = put_integer(
384 buffers, buffer_sizes, num_of_buffers,
385 current_buffer, buffer_position,
386 e.item.i);
387 break;
388 case core::long_long:
389 res = put_long_long(
390 buffers, buffer_sizes, num_of_buffers,
391 current_buffer, buffer_position,
392 e.item.L);
393 break;
394 case core::double_float:
395 res = put_double_float(
396 buffers, buffer_sizes, num_of_buffers,
397 current_buffer, buffer_position,
398 e.item.d);
399 break;
400 case core::string:
401 res = put_string(
402 buffers, buffer_sizes, num_of_buffers,
403 current_buffer, buffer_position,
404 e.item.str.value, e.item.str.length);
405 break;
406 case core::binary:
407 res = put_string(
408 buffers, buffer_sizes, num_of_buffers,
409 current_buffer, buffer_position,
410 reinterpret_cast<const char *>(e.item.bin.value),
411 e.item.bin.length);
412 break;
413 case core::boolean_array:
414 res = put_boolean_array(
415 buffers, buffer_sizes, num_of_buffers,
416 current_buffer, buffer_position,
417 e.item.ba.values, e.item.ba.length);
418 break;
419 case core::integer_array:
420 res = put_integer_array(
421 buffers, buffer_sizes, num_of_buffers,
422 current_buffer, buffer_position,
423 e.item.ia.values, e.item.ia.length);
424 break;
425 case core::long_long_array:
426 res = put_long_long_array(
427 buffers, buffer_sizes, num_of_buffers,
428 current_buffer, buffer_position,
429 e.item.La.values, e.item.La.length);
430 break;
431 case core::double_float_array:
432 res = put_double_float_array(
433 buffers, buffer_sizes, num_of_buffers,
434 current_buffer, buffer_position,
435 e.item.da.values, e.item.da.length);
436 break;
437 case core::string_array:
438 {
439 const std::size_t array_length = e.item.sa.length;
440 const string_array_element * values =
441 e.item.sa.values;
442 res = put_integer(
443 buffers, buffer_sizes, num_of_buffers,
444 current_buffer, buffer_position,
445 static_cast<int>(array_length));
446 for (std::size_t i = 0;
447 res == core::ok && i != array_length; ++i)
448 {
449 res = put_string(
450 buffers, buffer_sizes, num_of_buffers,
451 current_buffer, buffer_position,
452 values[i].value, values[i].length);
453 }
454 }
455 break;
456 case core::binary_array:
457 {
458 const std::size_t array_length = e.item.bina.length;
459 const binary_array_element * values =
460 e.item.bina.values;
461 res = put_integer(
462 buffers, buffer_sizes, num_of_buffers,
463 current_buffer, buffer_position,
464 static_cast<int>(array_length));
465 for (std::size_t i = 0;
466 res == core::ok && i != array_length; ++i)
467 {
468 res = put_string(
469 buffers, buffer_sizes, num_of_buffers,
470 current_buffer, buffer_position,
471 reinterpret_cast<const char *>(
472 values[i].value),
473 values[i].length);
474 }
475 }
476 break;
477 case core::nested_parameters:
478 // recursively:
479 res = serialize(*e.item.nested,
480 buffers, buffer_sizes, num_of_buffers,
481 current_buffer, buffer_position);
482 break;
483 case core::nested_parameters_array:
484 {
485 const std::size_t array_length = e.item.nesteda.length;
486 res = put_integer(
487 buffers, buffer_sizes, num_of_buffers,
488 current_buffer, buffer_position,
489 static_cast<int>(array_length));
490 for (std::size_t i = 0;
491 res == core::ok && i != array_length; ++i)
492 {
493 const core::parameters & nested =
494 e.item.nesteda.values[i];
495 res = serialize(nested,
496 buffers, buffer_sizes, num_of_buffers,
497 current_buffer, buffer_position);
498 }
499 }
500 break;
501 default:
502 fatal_failure(__FILE__, __LINE__);
503 }
504 }
505 }
506
507 return res;
508 }
509
serialize(const core::parameters & params,char ** buffers,const std::size_t * buffer_sizes,std::size_t num_of_buffers,std::size_t & current_buffer,char * & buffer_position)510 core::result details::serialize(
511 const core::parameters & params,
512 char * * buffers,
513 const std::size_t * buffer_sizes,
514 std::size_t num_of_buffers,
515 std::size_t & current_buffer, char * & buffer_position)
516 {
517 // number of non-empty entries:
518 core::result res = put_integer(
519 buffers, buffer_sizes, num_of_buffers,
520 current_buffer, buffer_position,
521 (int)params.size());
522
523 for (std::size_t i = 0; i != params.num_of_entries_ &&
524 res == core::ok; ++i)
525 {
526 const details::entry & e = params.data_[i];
527
528 if (e.type != core::unused)
529 {
530 res = serialize_entry(e,
531 buffers, buffer_sizes, num_of_buffers, current_buffer, buffer_position);
532 }
533 }
534
535 return res;
536 }
537
538 // helper for deserializing individual entries
deserialize_entry(core::parameters & params,const char ** buffers,const std::size_t * buffer_sizes,std::size_t num_of_buffers,std::size_t & current_buffer,const char * & buffer_position)539 core::result details::deserialize_entry(
540 core::parameters & params,
541 const char * * buffers,
542 const std::size_t * buffer_sizes,
543 std::size_t num_of_buffers,
544 std::size_t & current_buffer, const char * & buffer_position)
545 {
546 // name length and the name itself:
547 const char * name;
548 std::size_t name_length;
549 core::result res = get_string(
550 buffers, buffer_sizes, num_of_buffers,
551 current_buffer, buffer_position,
552 name, name_length, params.allocator_);
553 if (res == core::ok)
554 {
555 // type
556 int type_code;
557 res = get_integer(
558 buffers, buffer_sizes, num_of_buffers,
559 current_buffer, buffer_position,
560 type_code);
561 if (res == core::ok)
562 {
563 core::parameter_type type;
564 res = get_type_from_code(type_code, type);
565 if (res == core::ok)
566 {
567 // value
568 switch (type)
569 {
570 case core::boolean:
571 {
572 int raw_value;
573 res = get_integer(
574 buffers, buffer_sizes, num_of_buffers,
575 current_buffer, buffer_position,
576 raw_value);
577 if (res == core::ok)
578 {
579 bool value = raw_value != 0;
580 res = params.set_boolean(
581 name, name_length, value);
582 }
583 }
584 break;
585 case core::integer:
586 {
587 int value;
588 res = get_integer(
589 buffers, buffer_sizes, num_of_buffers,
590 current_buffer, buffer_position,
591 value);
592 if (res == core::ok)
593 {
594 res = params.set_integer(
595 name, name_length, value);
596 }
597 }
598 break;
599 case core::long_long:
600 {
601 long long value;
602 res = get_long_long(
603 buffers, buffer_sizes, num_of_buffers,
604 current_buffer, buffer_position,
605 value);
606 if (res == core::ok)
607 {
608 res = params.set_long_long(
609 name, name_length, value);
610 }
611 }
612 break;
613 case core::double_float:
614 {
615 double value;
616 res = get_double_float(
617 buffers, buffer_sizes, num_of_buffers,
618 current_buffer, buffer_position,
619 value);
620 if (res == core::ok)
621 {
622 res = params.set_double_float(
623 name, name_length, value);
624 }
625 }
626 break;
627 case core::string:
628 {
629 const char * value;
630 std::size_t value_length;
631 res = get_string(
632 buffers, buffer_sizes, num_of_buffers,
633 current_buffer, buffer_position,
634 value, value_length, params.allocator_);
635 if (res == core::ok)
636 {
637 res = do_set_string(
638 name, name_length,
639 value, value_length,
640 params.data_,
641 params.num_of_entries_,
642 params.allocator_, true);
643 }
644 }
645 break;
646 case core::binary:
647 {
648 const char * value;
649 std::size_t value_length;
650 res = get_string(
651 buffers, buffer_sizes, num_of_buffers,
652 current_buffer, buffer_position,
653 value, value_length, params.allocator_);
654 if (res == core::ok)
655 {
656 res = do_set_binary(
657 name, name_length,
658 value, value_length,
659 params.data_,
660 params.num_of_entries_,
661 params.allocator_, true);
662 }
663 }
664 break;
665 case core::boolean_array:
666 {
667 bool * values;
668 std::size_t values_length;
669 res = get_boolean_array(
670 buffers, buffer_sizes, num_of_buffers,
671 current_buffer, buffer_position,
672 values, values_length, params.allocator_);
673 if (res == core::ok)
674 {
675 res = do_set_boolean_array(
676 name, name_length,
677 values, values_length,
678 params.data_,
679 params.num_of_entries_,
680 params.allocator_, true);
681 }
682 }
683 break;
684 case core::integer_array:
685 {
686 int * values;
687 std::size_t values_length;
688 res = get_integer_array(
689 buffers, buffer_sizes, num_of_buffers,
690 current_buffer, buffer_position,
691 values, values_length, params.allocator_);
692 if (res == core::ok)
693 {
694 res = do_set_integer_array(
695 name, name_length,
696 values, values_length,
697 params.data_,
698 params.num_of_entries_,
699 params.allocator_, true);
700 }
701 }
702 break;
703 case core::long_long_array:
704 {
705 long long * values;
706 std::size_t values_length;
707 res = get_long_long_array(
708 buffers, buffer_sizes, num_of_buffers,
709 current_buffer, buffer_position,
710 values, values_length, params.allocator_);
711 if (res == core::ok)
712 {
713 res = do_set_long_long_array(
714 name, name_length,
715 values, values_length,
716 params.data_,
717 params.num_of_entries_,
718 params.allocator_, true);
719 }
720 }
721 break;
722 case core::double_float_array:
723 {
724 double * values;
725 std::size_t values_length;
726 res = get_double_float_array(
727 buffers, buffer_sizes, num_of_buffers,
728 current_buffer, buffer_position,
729 values, values_length, params.allocator_);
730 if (res == core::ok)
731 {
732 res = do_set_double_float_array(
733 name, name_length,
734 values, values_length,
735 params.data_,
736 params.num_of_entries_,
737 params.allocator_, true);
738 }
739 }
740 break;
741 case core::string_array:
742 {
743 int tmp;
744 res = get_integer(
745 buffers, buffer_sizes, num_of_buffers,
746 current_buffer, buffer_position,
747 tmp);
748 if (res == core::ok)
749 {
750 const std::size_t array_length =
751 static_cast<std::size_t>(tmp);
752 std::size_t item_index;
753 res = do_create_string_array(
754 name, name_length,
755 array_length, item_index,
756 params.data_,
757 params.num_of_entries_,
758 params.allocator_);
759 for (std::size_t i = 0;
760 res == core::ok && i != array_length;
761 ++i)
762 {
763 const char * value;
764 std::size_t value_length;
765 res = get_string(
766 buffers, buffer_sizes,
767 num_of_buffers,
768 current_buffer, buffer_position,
769 value, value_length,
770 params.allocator_);
771 if (res == core::ok)
772 {
773 res = do_place_string_in_array(
774 item_index, i,
775 value, value_length,
776 params.data_,
777 params.allocator_);
778 if (res != core::ok)
779 {
780 params.allocator_.deallocate(value);
781 }
782 }
783 }
784 }
785 }
786 break;
787 case core::binary_array:
788 {
789 int tmp;
790 res = get_integer(
791 buffers, buffer_sizes, num_of_buffers,
792 current_buffer, buffer_position,
793 tmp);
794 if (res == core::ok)
795 {
796 const std::size_t array_length =
797 static_cast<std::size_t>(tmp);
798 std::size_t item_index;
799 res = do_create_binary_array(
800 name, name_length,
801 array_length, item_index,
802 params.data_,
803 params.num_of_entries_,
804 params.allocator_);
805 for (std::size_t i = 0;
806 res == core::ok && i != array_length;
807 ++i)
808 {
809 const char * value;
810 std::size_t value_length;
811 res = get_string(
812 buffers, buffer_sizes,
813 num_of_buffers,
814 current_buffer, buffer_position,
815 value, value_length,
816 params.allocator_);
817 if (res == core::ok)
818 {
819 res = do_place_binary_in_array(
820 item_index, i,
821 value, value_length,
822 params.data_,
823 params.allocator_);
824 if (res != core::ok)
825 {
826 params.allocator_.deallocate(value);
827 }
828 }
829 }
830 }
831 }
832 break;
833 case core::nested_parameters:
834 {
835 core::parameters * nested;
836 res = params.create_nested_parameters(
837 name, name_length, nested);
838 if (res == core::ok)
839 {
840 res = deserialize(*nested,
841 buffers, buffer_sizes, num_of_buffers,
842 current_buffer, buffer_position);
843 }
844 }
845 break;
846 case core::nested_parameters_array:
847 {
848 int tmp;
849 res = get_integer(
850 buffers, buffer_sizes, num_of_buffers,
851 current_buffer, buffer_position,
852 tmp);
853 if (res == core::ok)
854 {
855 const std::size_t array_length =
856 static_cast<std::size_t>(tmp);
857 std::size_t item_index;
858 res = do_create_nested_array(
859 name, name_length,
860 array_length, item_index,
861 params.data_,
862 params.num_of_entries_,
863 params.allocator_);
864 for (std::size_t i = 0;
865 res == core::ok && i != array_length;
866 ++i)
867 {
868 core::parameters * nested;
869 res = do_access_nested_in_array(
870 item_index, i,
871 nested,
872 params.data_);
873 if (res == core::ok)
874 {
875 res = deserialize(*nested,
876 buffers, buffer_sizes, num_of_buffers,
877 current_buffer, buffer_position);
878 }
879 }
880 }
881 }
882 break;
883 default:
884 fatal_failure(__FILE__, __LINE__);
885 }
886 }
887 }
888
889 // optimization opportunity:
890 // reuse the name buffer between iterations
891 // or even fuse it directly into the entry
892 params.allocator_.deallocate(name);
893 }
894
895 return res;
896 }
897
deserialize(core::parameters & params,const char ** buffers,const std::size_t * buffer_sizes,std::size_t num_of_buffers,std::size_t & current_buffer,const char * & buffer_position)898 core::result details::deserialize(
899 core::parameters & params,
900 const char * * buffers,
901 const std::size_t * buffer_sizes,
902 std::size_t num_of_buffers,
903 std::size_t & current_buffer, const char * & buffer_position)
904 {
905 // read number of entries for current object
906 int raw_size;
907 core::result res = get_integer(
908 buffers, buffer_sizes, num_of_buffers,
909 current_buffer, buffer_position,
910 raw_size);
911
912 if (res == core::ok)
913 {
914 for (int i = 0; i != raw_size && res == core::ok; ++i)
915 {
916 res = deserialize_entry(params,
917 buffers, buffer_sizes, num_of_buffers,
918 current_buffer, buffer_position);
919 }
920 }
921
922 return res;
923 }
924
find_entry(const entry * data,std::size_t num_of_entries,const char * name,std::size_t name_length)925 std::size_t details::find_entry(
926 const entry * data, std::size_t num_of_entries,
927 const char * name, std::size_t name_length)
928 {
929 std::size_t index = num_of_entries;
930
931 if (data != NULL)
932 {
933 for (std::size_t i = 0; i != num_of_entries; ++i)
934 {
935 if (data[i].type != core::unused &&
936 data[i].name_equals(name, name_length))
937 {
938 index = i;
939 break;
940 }
941 }
942 }
943
944 return index;
945 }
946
find_empty_entry(entry * & data,std::size_t & num_of_entries,std::size_t & index,allocator & alloc)947 core::result details::find_empty_entry(
948 entry * & data, std::size_t & num_of_entries,
949 std::size_t & index, allocator & alloc)
950 {
951 // note: initialization here is not needed
952 // (the logic later on guarantees that it will be always set)
953 // but exists to please less smart compilers
954
955 core::result res = core::ok;
956
957 if (data == NULL)
958 {
959 // no data entries, this will be the first one
960
961 data = static_cast<entry*>(
962 alloc.allocate(sizeof(entry) * initial_number_of_entries));
963 if (data != NULL)
964 {
965 num_of_entries = initial_number_of_entries;
966 for (std::size_t i = 0; i != num_of_entries; ++i)
967 {
968 data[i].type = core::unused;
969 }
970 index = 0;
971 res = core::ok;
972 }
973 else
974 {
975 res = core::no_memory;
976 }
977 }
978 else
979 {
980 // some entries already exist,
981 // try to find an empty one
982
983 for (std::size_t i = 0; i != num_of_entries; ++i)
984 {
985 if (data[i].type == core::unused)
986 {
987 index = i;
988 res = core::ok;
989 break;
990 }
991 }
992
993 if (index == num_of_entries)
994 {
995 // no empty entry found, expand the set
996
997 const std::size_t new_capacity = 2 * num_of_entries;
998 entry * new_data = static_cast<entry *>(
999 alloc.allocate(sizeof(entry) * new_capacity));
1000 if (new_data != NULL)
1001 {
1002 std::memcpy(new_data, data, sizeof(entry) * num_of_entries);
1003 alloc.deallocate(data);
1004 data = new_data;
1005
1006 for (std::size_t i = num_of_entries; i != new_capacity; ++i)
1007 {
1008 data[i].type = core::unused;
1009 }
1010 index = num_of_entries;
1011 num_of_entries = new_capacity;
1012
1013 res = core::ok;
1014 }
1015 else
1016 {
1017 res = core::no_memory;
1018 }
1019 }
1020 }
1021
1022 return res;
1023 }
1024
prepare_for_set(entry * & data,std::size_t & num_of_entries,const char * name,std::size_t name_length,std::size_t & index,allocator & alloc)1025 core::result details::prepare_for_set(
1026 entry * & data, std::size_t & num_of_entries,
1027 const char * name, std::size_t name_length,
1028 std::size_t & index, allocator & alloc)
1029 {
1030 core::result res;
1031
1032 index = find_entry(data, num_of_entries, name, name_length);
1033 if (index != num_of_entries)
1034 {
1035 // existing entry found
1036
1037 entry & e = data[index];
1038
1039 if (e.type != core::nested_parameters)
1040 {
1041 // simple entries and arrays
1042
1043 e.clear_item(alloc);
1044 }
1045 else
1046 {
1047 // nested entry needs to be deeply destroyed
1048
1049 e.item.nested->clear();
1050 alloc.deallocate(e.item.nested);
1051 }
1052
1053 res = core::ok;
1054 }
1055 else
1056 {
1057 res = find_empty_entry(data, num_of_entries, index, alloc);
1058 if (res == core::ok)
1059 {
1060 res = data[index].set_name(name, name_length, alloc);
1061 }
1062 }
1063
1064 return res;
1065 }
1066
find_next_used(const entry * data,std::size_t num_of_entries,std::size_t current_index)1067 std::size_t details::find_next_used(
1068 const entry * data, std::size_t num_of_entries,
1069 std::size_t current_index)
1070 {
1071 std::size_t res = num_of_entries;
1072 for (std::size_t i = current_index + 1; i != num_of_entries; ++i)
1073 {
1074 if (data[i].type != core::unused)
1075 {
1076 res = i;
1077 break;
1078 }
1079 }
1080
1081 return res;
1082 }
1083
do_set_string(const char * name,std::size_t name_length,const char * value,std::size_t value_length,entry * & data,std::size_t & num_of_entries,allocator & alloc,bool own)1084 core::result details::do_set_string(
1085 const char * name, std::size_t name_length,
1086 const char * value, std::size_t value_length,
1087 entry * & data, std::size_t & num_of_entries,
1088 allocator & alloc, bool own)
1089 {
1090 std::size_t index;
1091 const core::result res = prepare_for_set(data, num_of_entries,
1092 name, name_length, index, alloc);
1093
1094 if (res == core::ok)
1095 {
1096 entry * e = data + index;
1097
1098 e->type = core::string;
1099 e->item.str.value = value;
1100 e->item.str.length = value_length;
1101 e->item.str.own = own;
1102 }
1103
1104 return res;
1105 }
1106
do_set_binary(const char * name,std::size_t name_length,const void * value,std::size_t value_length,entry * & data,std::size_t & num_of_entries,allocator & alloc,bool own)1107 core::result details::do_set_binary(
1108 const char * name, std::size_t name_length,
1109 const void * value, std::size_t value_length,
1110 entry * & data, std::size_t & num_of_entries,
1111 allocator & alloc, bool own)
1112 {
1113 std::size_t index;
1114 const core::result res = prepare_for_set(data, num_of_entries,
1115 name, name_length, index, alloc);
1116
1117 if (res == core::ok)
1118 {
1119 entry * e = data + index;
1120
1121 e->type = core::binary;
1122 e->item.bin.value = value;
1123 e->item.bin.length = value_length;
1124 e->item.bin.own = own;
1125 }
1126
1127 return res;
1128 }
1129
do_set_boolean_array(const char * name,std::size_t name_length,const bool * values,std::size_t array_length,entry * & data,std::size_t & num_of_entries,allocator & alloc,bool own)1130 core::result details::do_set_boolean_array(
1131 const char * name, std::size_t name_length,
1132 const bool * values, std::size_t array_length,
1133 entry * & data, std::size_t & num_of_entries,
1134 allocator & alloc, bool own)
1135 {
1136 std::size_t index;
1137 const core::result res = prepare_for_set(data, num_of_entries,
1138 name, name_length, index, alloc);
1139
1140 if (res == core::ok)
1141 {
1142 entry * e = data + index;
1143
1144 e->type = core::boolean_array;
1145 e->item.ba.values = const_cast<bool *>(values);
1146 e->item.ba.length = array_length;
1147 e->item.ba.own = own;
1148 }
1149
1150 return res;
1151 }
1152
do_set_integer_array(const char * name,std::size_t name_length,const int * values,std::size_t array_length,entry * & data,std::size_t & num_of_entries,allocator & alloc,bool own)1153 core::result details::do_set_integer_array(
1154 const char * name, std::size_t name_length,
1155 const int * values, std::size_t array_length,
1156 entry * & data, std::size_t & num_of_entries,
1157 allocator & alloc, bool own)
1158 {
1159 std::size_t index;
1160 const core::result res = prepare_for_set(data, num_of_entries,
1161 name, name_length, index, alloc);
1162
1163 if (res == core::ok)
1164 {
1165 entry * e = data + index;
1166
1167 e->type = core::integer_array;
1168 e->item.ia.values = const_cast<int *>(values);
1169 e->item.ia.length = array_length;
1170 e->item.ia.own = own;
1171 }
1172
1173 return res;
1174 }
1175
do_set_long_long_array(const char * name,std::size_t name_length,const long long * values,std::size_t array_length,entry * & data,std::size_t & num_of_entries,allocator & alloc,bool own)1176 core::result details::do_set_long_long_array(
1177 const char * name, std::size_t name_length,
1178 const long long * values, std::size_t array_length,
1179 entry * & data, std::size_t & num_of_entries,
1180 allocator & alloc, bool own)
1181 {
1182 std::size_t index;
1183 const core::result res = prepare_for_set(data, num_of_entries,
1184 name, name_length, index, alloc);
1185
1186 if (res == core::ok)
1187 {
1188 entry * e = data + index;
1189
1190 e->type = core::long_long_array;
1191 e->item.La.values = const_cast<long long *>(values);
1192 e->item.La.length = array_length;
1193 e->item.La.own = own;
1194 }
1195
1196 return res;
1197 }
1198
do_set_double_float_array(const char * name,std::size_t name_length,const double * values,std::size_t array_length,entry * & data,std::size_t & num_of_entries,allocator & alloc,bool own)1199 core::result details::do_set_double_float_array(
1200 const char * name, std::size_t name_length,
1201 const double * values, std::size_t array_length,
1202 entry * & data, std::size_t & num_of_entries,
1203 allocator & alloc, bool own)
1204 {
1205 std::size_t index;
1206 const core::result res = prepare_for_set(data, num_of_entries,
1207 name, name_length, index, alloc);
1208
1209 if (res == core::ok)
1210 {
1211 entry * e = data + index;
1212
1213 e->type = core::double_float_array;
1214 e->item.da.values = const_cast<double *>(values);
1215 e->item.da.length = array_length;
1216 e->item.da.own = own;
1217 }
1218
1219 return res;
1220 }
1221
do_create_string_array(const char * name,std::size_t name_length,std::size_t array_length,std::size_t & index,entry * & data,std::size_t & num_of_entries,allocator & alloc)1222 core::result details::do_create_string_array(
1223 const char * name, std::size_t name_length,
1224 std::size_t array_length, std::size_t & index,
1225 entry * & data, std::size_t & num_of_entries,
1226 allocator & alloc)
1227 {
1228 core::result res;
1229
1230 const std::size_t raw_length =
1231 array_length * sizeof(string_array_element);
1232 string_array_element * new_array =
1233 static_cast<string_array_element *>(
1234 alloc.allocate(raw_length));
1235 if (new_array != NULL)
1236 {
1237 for (std::size_t i = 0; i != array_length; ++i)
1238 {
1239 new_array[i].value = NULL;
1240 new_array[i].length = 0;
1241 }
1242
1243 res = prepare_for_set(data, num_of_entries,
1244 name, name_length, index, alloc);
1245
1246 if (res == core::ok)
1247 {
1248 entry * e = data + index;
1249
1250 e->type = core::string_array;
1251 e->item.sa.values = new_array;
1252 e->item.sa.length = array_length;
1253 e->item.sa.own = true;
1254 }
1255 else
1256 {
1257 alloc.deallocate(new_array);
1258 }
1259 }
1260 else
1261 {
1262 res = core::no_memory;
1263 }
1264
1265 return res;
1266 }
1267
do_create_binary_array(const char * name,std::size_t name_length,std::size_t array_length,std::size_t & index,entry * & data,std::size_t & num_of_entries,allocator & alloc)1268 core::result details::do_create_binary_array(
1269 const char * name, std::size_t name_length,
1270 std::size_t array_length, std::size_t & index,
1271 entry * & data, std::size_t & num_of_entries,
1272 allocator & alloc)
1273 {
1274 core::result res;
1275
1276 const std::size_t raw_length =
1277 array_length * sizeof(binary_array_element);
1278 binary_array_element * new_array =
1279 static_cast<binary_array_element *>(
1280 alloc.allocate(raw_length));
1281 if (new_array != NULL)
1282 {
1283 for (std::size_t i = 0; i != array_length; ++i)
1284 {
1285 new_array[i].value = NULL;
1286 new_array[i].length = 0;
1287 }
1288
1289 res = prepare_for_set(data, num_of_entries,
1290 name, name_length, index, alloc);
1291
1292 if (res == core::ok)
1293 {
1294 entry * e = data + index;
1295
1296 e->type = core::binary_array;
1297 e->item.bina.values = new_array;
1298 e->item.bina.length = array_length;
1299 e->item.bina.own = true;
1300 }
1301 else
1302 {
1303 alloc.deallocate(new_array);
1304 }
1305 }
1306 else
1307 {
1308 res = core::no_memory;
1309 }
1310
1311 return res;
1312 }
1313
do_create_nested_array(const char * name,std::size_t name_length,std::size_t array_length,std::size_t & index,entry * & data,std::size_t & num_of_entries,allocator & alloc)1314 core::result details::do_create_nested_array(
1315 const char * name, std::size_t name_length,
1316 std::size_t array_length, std::size_t & index,
1317 entry * & data, std::size_t & num_of_entries,
1318 allocator & alloc)
1319 {
1320 core::result res;
1321
1322 const std::size_t raw_length =
1323 array_length * sizeof(core::parameters);
1324 core::parameters * new_array =
1325 static_cast<core::parameters *>(
1326 alloc.allocate(raw_length));
1327 if (new_array != NULL)
1328 {
1329 for (std::size_t i = 0; i != array_length; ++i)
1330 {
1331 new (&new_array[i]) core::parameters(alloc, true);
1332 }
1333
1334 res = prepare_for_set(data, num_of_entries,
1335 name, name_length, index, alloc);
1336
1337 if (res == core::ok)
1338 {
1339 entry * e = data + index;
1340
1341 e->type = core::nested_parameters_array;
1342 e->item.nesteda.values = new_array;
1343 e->item.nesteda.length = array_length;
1344 e->item.nesteda.own = true;
1345 }
1346 else
1347 {
1348 for (std::size_t i = 0; i != array_length; ++i)
1349 {
1350 new_array[i].clear();
1351 }
1352
1353 alloc.deallocate(new_array);
1354 }
1355 }
1356 else
1357 {
1358 res = core::no_memory;
1359 }
1360
1361 return res;
1362 }
1363
do_set_string_in_array(std::size_t item_index,std::size_t array_index,const char * value,std::size_t value_length,entry * data,allocator & alloc)1364 core::result details::do_set_string_in_array(
1365 std::size_t item_index, std::size_t array_index,
1366 const char * value, std::size_t value_length,
1367 entry * data, allocator & alloc)
1368 {
1369 core::result res;
1370
1371 char * new_buffer =
1372 static_cast<char *>(alloc.allocate(value_length));
1373 if (new_buffer != NULL)
1374 {
1375 std::memcpy(new_buffer, value, value_length);
1376
1377 res = do_place_string_in_array(
1378 item_index, array_index,
1379 new_buffer, value_length,
1380 data, alloc);
1381
1382 if (res != core::ok)
1383 {
1384 alloc.deallocate(new_buffer);
1385 }
1386 }
1387 else
1388 {
1389 res = core::no_memory;
1390 }
1391
1392 return res;
1393 }
1394
do_set_binary_in_array(std::size_t item_index,std::size_t array_index,const void * value,std::size_t value_length,entry * data,allocator & alloc)1395 core::result details::do_set_binary_in_array(
1396 std::size_t item_index, std::size_t array_index,
1397 const void * value, std::size_t value_length,
1398 entry * data, allocator & alloc)
1399 {
1400 core::result res;
1401
1402 void * new_buffer = alloc.allocate(value_length);
1403 if (new_buffer != NULL)
1404 {
1405 std::memcpy(new_buffer, value, value_length);
1406
1407 res = do_place_binary_in_array(
1408 item_index, array_index,
1409 new_buffer, value_length,
1410 data, alloc);
1411
1412 if (res != core::ok)
1413 {
1414 alloc.deallocate(new_buffer);
1415 }
1416 }
1417 else
1418 {
1419 res = core::no_memory;
1420 }
1421
1422 return res;
1423 }
1424
do_place_string_in_array(std::size_t item_index,std::size_t array_index,const char * value,std::size_t value_length,entry * data,allocator & alloc)1425 core::result details::do_place_string_in_array(
1426 std::size_t item_index, std::size_t array_index,
1427 const char * value, std::size_t value_length,
1428 entry * data, allocator & alloc)
1429 {
1430 core::result res;
1431
1432 const entry * e = data + item_index;
1433 if (e->type == core::string_array)
1434 {
1435 if (array_index < e->item.sa.length)
1436 {
1437 e->item.sa.values[array_index].clear(alloc);
1438 e->item.sa.values[array_index].value = value;
1439 e->item.sa.values[array_index].length = value_length;
1440 res = core::ok;
1441 }
1442 else
1443 {
1444 res = core::no_such_index;
1445 }
1446 }
1447 else
1448 {
1449 res = core::bad_type;
1450 }
1451
1452 return res;
1453 }
1454
do_place_binary_in_array(std::size_t item_index,std::size_t array_index,const void * value,std::size_t value_length,entry * data,allocator & alloc)1455 core::result details::do_place_binary_in_array(
1456 std::size_t item_index, std::size_t array_index,
1457 const void * value, std::size_t value_length,
1458 entry * data, allocator & alloc)
1459 {
1460 core::result res;
1461
1462 const entry * e = data + item_index;
1463 if (e->type == core::binary_array)
1464 {
1465 if (array_index < e->item.bina.length)
1466 {
1467 e->item.bina.values[array_index].clear(alloc);
1468 e->item.bina.values[array_index].value = value;
1469 e->item.bina.values[array_index].length = value_length;
1470 res = core::ok;
1471 }
1472 else
1473 {
1474 res = core::no_such_index;
1475 }
1476 }
1477 else
1478 {
1479 res = core::bad_type;
1480 }
1481
1482 return res;
1483 }
1484
do_access_nested_in_array(std::size_t item_index,std::size_t array_index,core::parameters * & nested,entry * data)1485 core::result details::do_access_nested_in_array(
1486 std::size_t item_index, std::size_t array_index,
1487 core::parameters * & nested,
1488 entry * data)
1489 {
1490 core::result res;
1491
1492 const entry * e = data + item_index;
1493 if (e->type == core::nested_parameters_array)
1494 {
1495 if (array_index < e->item.nesteda.length)
1496 {
1497 nested = &e->item.nesteda.values[array_index];
1498 res = core::ok;
1499 }
1500 else
1501 {
1502 res = core::no_such_index;
1503 }
1504 }
1505 else
1506 {
1507 res = core::bad_type;
1508 }
1509
1510 return res;
1511 }
1512