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