Line data Source code
1 : // Copyright (c) 2019 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snapdatabase
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 :
21 : /** \file
22 : * \brief Database file implementation.
23 : *
24 : * Each table uses one or more files. Each file is handled by a dbfile
25 : * object and a corresponding set of blocks.
26 : */
27 :
28 : // self
29 : //
30 : #include "snapdatabase/data/structure.h"
31 :
32 : #include "snapdatabase/data/convert.h"
33 :
34 :
35 : // snaplogger lib
36 : //
37 : #include <snaplogger/message.h>
38 :
39 :
40 : // boost lib
41 : //
42 : #include <boost/algorithm/string.hpp>
43 :
44 :
45 : // C++ lib
46 : //
47 : #include <iostream>
48 :
49 :
50 : // last include
51 : //
52 : #include <snapdev/poison.h>
53 :
54 :
55 :
56 : namespace snapdatabase
57 : {
58 :
59 :
60 :
61 : namespace
62 : {
63 :
64 :
65 : struct name_to_struct_type_t
66 : {
67 : char const * f_name = nullptr;
68 : struct_type_t f_type = struct_type_t::STRUCT_TYPE_END;
69 : };
70 :
71 : #define NAME_TO_STRUCT_TYPE(name) { #name, struct_type_t::STRUCT_TYPE_##name }
72 :
73 : name_to_struct_type_t g_name_to_struct_type[] =
74 : {
75 : // WARNING: Keep in alphabetical order
76 : //
77 : NAME_TO_STRUCT_TYPE(ARRAY16),
78 : NAME_TO_STRUCT_TYPE(ARRAY32),
79 : NAME_TO_STRUCT_TYPE(ARRAY8),
80 : NAME_TO_STRUCT_TYPE(BITS128),
81 : NAME_TO_STRUCT_TYPE(BITS16),
82 : NAME_TO_STRUCT_TYPE(BITS256),
83 : NAME_TO_STRUCT_TYPE(BITS32),
84 : NAME_TO_STRUCT_TYPE(BITS512),
85 : NAME_TO_STRUCT_TYPE(BITS64),
86 : NAME_TO_STRUCT_TYPE(BITS8),
87 : NAME_TO_STRUCT_TYPE(BUFFER16),
88 : NAME_TO_STRUCT_TYPE(BUFFER32),
89 : NAME_TO_STRUCT_TYPE(BUFFER8),
90 : NAME_TO_STRUCT_TYPE(END), // to end a list
91 : NAME_TO_STRUCT_TYPE(FLOAT32),
92 : NAME_TO_STRUCT_TYPE(FLOAT64),
93 : NAME_TO_STRUCT_TYPE(INT128),
94 : NAME_TO_STRUCT_TYPE(INT16),
95 : NAME_TO_STRUCT_TYPE(INT256),
96 : NAME_TO_STRUCT_TYPE(INT32),
97 : NAME_TO_STRUCT_TYPE(INT512),
98 : NAME_TO_STRUCT_TYPE(INT64),
99 : NAME_TO_STRUCT_TYPE(INT8),
100 : NAME_TO_STRUCT_TYPE(MSTIME),
101 : NAME_TO_STRUCT_TYPE(OID),
102 : NAME_TO_STRUCT_TYPE(P16STRING),
103 : NAME_TO_STRUCT_TYPE(P32STRING),
104 : NAME_TO_STRUCT_TYPE(P8STRING),
105 : NAME_TO_STRUCT_TYPE(REFERENCE),
106 : NAME_TO_STRUCT_TYPE(RENAMED),
107 : NAME_TO_STRUCT_TYPE(STRUCTURE),
108 : NAME_TO_STRUCT_TYPE(TIME),
109 : NAME_TO_STRUCT_TYPE(UINT128),
110 : NAME_TO_STRUCT_TYPE(UINT16),
111 : NAME_TO_STRUCT_TYPE(UINT256),
112 : NAME_TO_STRUCT_TYPE(UINT32),
113 : NAME_TO_STRUCT_TYPE(UINT512),
114 : NAME_TO_STRUCT_TYPE(UINT64),
115 : NAME_TO_STRUCT_TYPE(UINT8),
116 : NAME_TO_STRUCT_TYPE(USTIME),
117 : NAME_TO_STRUCT_TYPE(VERSION),
118 : NAME_TO_STRUCT_TYPE(VOID)
119 : };
120 :
121 :
122 :
123 :
124 :
125 :
126 : struct field_sizes_t
127 : {
128 : ssize_t f_size = 0;
129 : ssize_t f_field_size = 0;
130 : };
131 :
132 :
133 : #pragma GCC diagnostic push
134 : //#pragma GCC diagnostic ignored "-Wpedantic"
135 : constexpr field_sizes_t const g_struct_type_sizes[] =
136 : {
137 : [static_cast<int>(struct_type_t::STRUCT_TYPE_END)] = { INVALID_SIZE, 0 },
138 : [static_cast<int>(struct_type_t::STRUCT_TYPE_VOID)] = { 0, 0 },
139 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BITS8)] = { sizeof(uint8_t), 0 },
140 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BITS16)] = { sizeof(uint16_t), 0 },
141 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BITS32)] = { sizeof(uint32_t), 0 },
142 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BITS64)] = { sizeof(uint64_t), 0 },
143 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BITS128)] = { sizeof(uint64_t) * 2, 0 },
144 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BITS256)] = { sizeof(uint64_t) * 4, 0 },
145 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BITS512)] = { sizeof(uint64_t) * 8, 0 },
146 : [static_cast<int>(struct_type_t::STRUCT_TYPE_INT8)] = { sizeof(int8_t), 0 },
147 : [static_cast<int>(struct_type_t::STRUCT_TYPE_UINT8)] = { sizeof(uint8_t), 0 },
148 : [static_cast<int>(struct_type_t::STRUCT_TYPE_INT16)] = { sizeof(int16_t), 0 },
149 : [static_cast<int>(struct_type_t::STRUCT_TYPE_UINT16)] = { sizeof(uint16_t), 0 },
150 : [static_cast<int>(struct_type_t::STRUCT_TYPE_INT32)] = { sizeof(int32_t), 0 },
151 : [static_cast<int>(struct_type_t::STRUCT_TYPE_UINT32)] = { sizeof(uint32_t), 0 },
152 : [static_cast<int>(struct_type_t::STRUCT_TYPE_INT64)] = { sizeof(int64_t), 0 },
153 : [static_cast<int>(struct_type_t::STRUCT_TYPE_UINT64)] = { sizeof(uint64_t), 0 },
154 : [static_cast<int>(struct_type_t::STRUCT_TYPE_INT128)] = { sizeof(int64_t) * 2, 0 },
155 : [static_cast<int>(struct_type_t::STRUCT_TYPE_UINT128)] = { sizeof(uint64_t) * 2, 0 },
156 : [static_cast<int>(struct_type_t::STRUCT_TYPE_INT256)] = { sizeof(int64_t) * 4, 0 },
157 : [static_cast<int>(struct_type_t::STRUCT_TYPE_UINT256)] = { sizeof(uint64_t) * 4, 0 },
158 : [static_cast<int>(struct_type_t::STRUCT_TYPE_INT512)] = { sizeof(int64_t) * 8, 0 },
159 : [static_cast<int>(struct_type_t::STRUCT_TYPE_UINT512)] = { sizeof(uint64_t) * 8, 0 },
160 : [static_cast<int>(struct_type_t::STRUCT_TYPE_FLOAT32)] = { sizeof(float), 0 },
161 : [static_cast<int>(struct_type_t::STRUCT_TYPE_FLOAT64)] = { sizeof(double), 0 },
162 : [static_cast<int>(struct_type_t::STRUCT_TYPE_FLOAT128)] = { sizeof(long double), 0 },
163 : [static_cast<int>(struct_type_t::STRUCT_TYPE_VERSION)] = { sizeof(uint32_t), 0 },
164 : [static_cast<int>(struct_type_t::STRUCT_TYPE_TIME)] = { sizeof(time_t), 0 },
165 : [static_cast<int>(struct_type_t::STRUCT_TYPE_MSTIME)] = { sizeof(uint64_t), 0 },
166 : [static_cast<int>(struct_type_t::STRUCT_TYPE_USTIME)] = { sizeof(uint64_t), 0 },
167 : [static_cast<int>(struct_type_t::STRUCT_TYPE_P8STRING)] = { VARIABLE_SIZE, 1 },
168 : [static_cast<int>(struct_type_t::STRUCT_TYPE_P16STRING)] = { VARIABLE_SIZE, 2 },
169 : [static_cast<int>(struct_type_t::STRUCT_TYPE_P32STRING)] = { VARIABLE_SIZE, 4 },
170 : [static_cast<int>(struct_type_t::STRUCT_TYPE_STRUCTURE)] = { VARIABLE_SIZE, 0 },
171 : [static_cast<int>(struct_type_t::STRUCT_TYPE_ARRAY8)] = { VARIABLE_SIZE, 1 },
172 : [static_cast<int>(struct_type_t::STRUCT_TYPE_ARRAY16)] = { VARIABLE_SIZE, 2 },
173 : [static_cast<int>(struct_type_t::STRUCT_TYPE_ARRAY32)] = { VARIABLE_SIZE, 4 },
174 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BUFFER8)] = { VARIABLE_SIZE, 1 },
175 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BUFFER16)] = { VARIABLE_SIZE, 2 },
176 : [static_cast<int>(struct_type_t::STRUCT_TYPE_BUFFER32)] = { VARIABLE_SIZE, 4 },
177 : [static_cast<int>(struct_type_t::STRUCT_TYPE_REFERENCE)] = { sizeof(uint64_t), 0 },
178 : [static_cast<int>(struct_type_t::STRUCT_TYPE_OID)] = { sizeof(uint64_t), 0 },
179 : [static_cast<int>(struct_type_t::STRUCT_TYPE_RENAMED)] = { INVALID_SIZE, 0 }
180 : };
181 : #pragma GCC diagnostic pop
182 :
183 :
184 99 : void verify_size(struct_type_t type, size_t size)
185 : {
186 99 : if(static_cast<size_t>(type) >= std::size(g_struct_type_sizes))
187 : {
188 : throw snapdatabase_out_of_range(
189 : "type out of range for converting it to a size ("
190 0 : + to_string(type)
191 0 : + ", max: "
192 0 : + std::to_string(std::size(g_struct_type_sizes))
193 0 : + ").");
194 : }
195 :
196 99 : if(g_struct_type_sizes[static_cast<int>(type)].f_size != static_cast<ssize_t>(size))
197 : {
198 : throw snapdatabase_out_of_range(
199 : "value ("
200 0 : + std::to_string(size)
201 0 : + ") and type ("
202 0 : + to_string(type)
203 0 : + ") sizes do not correspond (expected size: "
204 0 : + std::to_string(g_struct_type_sizes[static_cast<int>(type)].f_size)
205 0 : + ").");
206 : }
207 99 : }
208 :
209 :
210 :
211 : }
212 : // no name namespace
213 :
214 :
215 :
216 :
217 :
218 :
219 0 : std::string to_string(struct_type_t const & type)
220 : {
221 0 : for(size_t idx(0);
222 0 : idx < std::size(g_name_to_struct_type);
223 : ++idx)
224 : {
225 0 : if(g_name_to_struct_type[idx].f_type == type)
226 : {
227 0 : return g_name_to_struct_type[idx].f_name;
228 : }
229 : }
230 :
231 0 : return std::string("*unknown struct type (" + std::to_string(static_cast<int>(type)) + ")*");
232 : }
233 :
234 :
235 2 : struct_type_t name_to_struct_type(std::string const & type_name)
236 : {
237 : #ifdef _DEBUG
238 : // verify in debug because if not in order we can't do a binary search
239 84 : for(size_t idx(1);
240 84 : idx < std::size(g_name_to_struct_type);
241 : ++idx)
242 : {
243 82 : if(strcmp(g_name_to_struct_type[idx - 1].f_name
244 : , g_name_to_struct_type[idx].f_name) >= 0)
245 : {
246 : throw snapdatabase_logic_error(
247 : "names in g_name_to_struct_type area not in alphabetical order: "
248 0 : + std::string(g_name_to_struct_type[idx - 1].f_name)
249 0 : + " >= "
250 0 : + g_name_to_struct_type[idx].f_name
251 0 : + " (position: "
252 0 : + std::to_string(idx)
253 0 : + ").");
254 : }
255 : }
256 : #endif
257 :
258 4 : std::string const uc(boost::algorithm::to_upper_copy(type_name));
259 :
260 2 : int j(std::size(g_name_to_struct_type));
261 2 : int i(0);
262 22 : while(i < j)
263 : {
264 12 : int const p((j - i) / 2 + i);
265 12 : int const r(uc.compare(g_name_to_struct_type[p].f_name));
266 12 : if(r > 0)
267 : {
268 4 : i = p + 1;
269 : }
270 8 : else if(r < 0)
271 : {
272 6 : j = p;
273 : }
274 : else
275 : {
276 2 : return g_name_to_struct_type[p].f_type;
277 : }
278 : }
279 :
280 0 : return INVALID_STRUCT_TYPE;
281 : }
282 :
283 :
284 :
285 0 : flag_definition::flag_definition()
286 : {
287 0 : }
288 :
289 :
290 54 : flag_definition::flag_definition(
291 : std::string const & field_name
292 : , std::string const & flag_name
293 : , size_t pos
294 54 : , size_t size)
295 : : f_field_name(field_name)
296 : , f_flag_name(flag_name)
297 : , f_pos(pos)
298 : , f_size(size)
299 54 : , f_mask(((1 << size) - 1) << pos) // fails if size == 64...
300 : {
301 54 : if(size == 0)
302 : {
303 : throw invalid_parameter(
304 : "Bit field named \""
305 0 : + field_name
306 0 : + "."
307 0 : + flag_name
308 0 : + "\" can't have a size of 0.");
309 : }
310 54 : if(size >= 64)
311 : {
312 : throw invalid_parameter(
313 : "Bit field named \""
314 0 : + field_name
315 0 : + "."
316 0 : + flag_name
317 0 : + "\" is too large ("
318 0 : + std::to_string(size)
319 0 : + " >= 64).");
320 : }
321 54 : if(pos + size > 64)
322 : {
323 : throw invalid_parameter(
324 : "The mask of the bit field named \""
325 0 : + field_name
326 0 : + "."
327 0 : + flag_name
328 0 : + "\" does not fit in a uint64_t.");
329 : }
330 54 : }
331 :
332 :
333 0 : std::string flag_definition::full_name() const
334 : {
335 0 : return f_field_name + "." + f_flag_name;
336 : }
337 :
338 :
339 0 : std::string flag_definition::field_name() const
340 : {
341 0 : return f_field_name;
342 : }
343 :
344 :
345 0 : std::string flag_definition::flag_name() const
346 : {
347 0 : return f_flag_name;
348 : }
349 :
350 :
351 0 : size_t flag_definition::pos() const
352 : {
353 0 : return f_pos;
354 : }
355 :
356 :
357 0 : size_t flag_definition::size() const
358 : {
359 0 : return f_size;
360 : }
361 :
362 :
363 0 : flags_t flag_definition::mask() const
364 : {
365 0 : return f_mask;
366 : }
367 :
368 :
369 :
370 :
371 :
372 170 : field_t::field_t(struct_description_t const * description)
373 170 : : f_description(description)
374 : {
375 170 : }
376 :
377 :
378 288 : field_t::~field_t()
379 : {
380 288 : pointer_t n(next());
381 288 : pointer_t p(previous());
382 144 : if(n != nullptr)
383 : {
384 91 : n->set_previous(p);
385 : }
386 144 : if(p != nullptr)
387 : {
388 113 : p->set_next(n);
389 : }
390 144 : }
391 :
392 :
393 15 : struct_description_t const * field_t::description() const
394 : {
395 15 : return f_description;
396 : }
397 :
398 :
399 3127 : field_t::pointer_t field_t::next() const
400 : {
401 3127 : return f_next.lock();
402 : }
403 :
404 :
405 261 : void field_t::set_next(pointer_t next)
406 : {
407 261 : f_next = next;
408 261 : }
409 :
410 :
411 144 : field_t::pointer_t field_t::previous() const
412 : {
413 144 : return f_previous.lock();
414 : }
415 :
416 :
417 239 : void field_t::set_previous(pointer_t previous)
418 : {
419 239 : f_previous = previous;
420 239 : }
421 :
422 :
423 262 : field_t::pointer_t field_t::first() const
424 : {
425 524 : pointer_t p(f_previous.lock());
426 262 : if(p == nullptr)
427 : {
428 0 : return const_cast<field_t *>(this)->shared_from_this();
429 : }
430 : for(;;)
431 : {
432 866 : pointer_t q(p->f_previous.lock());
433 564 : if(q == nullptr)
434 : {
435 262 : return p;
436 : }
437 302 : p = q;
438 302 : }
439 : }
440 :
441 :
442 0 : field_t::pointer_t field_t::last() const
443 : {
444 0 : pointer_t n(f_next.lock());
445 0 : if(n == nullptr)
446 : {
447 0 : return const_cast<field_t *>(this)->shared_from_this();
448 : }
449 : for(;;)
450 : {
451 0 : pointer_t m(n->f_next.lock());
452 0 : if(m == nullptr)
453 : {
454 0 : return n;
455 : }
456 0 : n = m;
457 0 : }
458 : }
459 :
460 :
461 6442 : struct_type_t field_t::type() const
462 : {
463 6442 : return f_description->f_type;
464 : }
465 :
466 :
467 63 : ssize_t field_t::type_field_size() const
468 : {
469 63 : if(static_cast<size_t>(f_description->f_type) >= std::size(g_struct_type_sizes))
470 : {
471 : throw snapdatabase_out_of_range(
472 : "type out of range for converting it to a field size ("
473 0 : + to_string(f_description->f_type)
474 0 : + ", max: "
475 0 : + std::to_string(std::size(g_struct_type_sizes))
476 0 : + ").");
477 : }
478 :
479 63 : return g_struct_type_sizes[static_cast<int>(f_description->f_type)].f_field_size;
480 : }
481 :
482 :
483 0 : std::string field_t::field_name() const
484 : {
485 0 : return f_description->f_field_name;
486 : }
487 :
488 :
489 0 : std::string field_t::new_name() const
490 : {
491 0 : if(f_description->f_sub_description == nullptr)
492 : {
493 : throw snapdatabase_logic_error(
494 : "Field \""
495 0 : + field_name()
496 0 : + "\" is marked as having a new name (RENAMED) but it has no f_sub_description to define the new name.");
497 : }
498 0 : if(f_description->f_sub_description->f_field_name == nullptr)
499 : {
500 : throw snapdatabase_logic_error(
501 : "Field \""
502 0 : + field_name()
503 0 : + "\" is marked as having a new name (RENAMED) but it has no entries in its f_sub_description defining the new name.");
504 : }
505 :
506 0 : return f_description->f_sub_description->f_field_name;
507 : }
508 :
509 :
510 3121 : std::uint32_t field_t::size() const
511 : {
512 3121 : return f_size;
513 : }
514 :
515 :
516 134 : void field_t::set_size(std::uint32_t size)
517 : {
518 134 : f_size = size;
519 134 : }
520 :
521 :
522 17 : bool field_t::has_flags(std::uint32_t flags) const
523 : {
524 17 : return (f_flags & flags) != 0;
525 : }
526 :
527 :
528 0 : std::uint32_t field_t::flags() const
529 : {
530 0 : return f_flags;
531 : }
532 :
533 :
534 0 : void field_t::set_flags(std::uint32_t flags)
535 : {
536 0 : f_flags = flags;
537 0 : }
538 :
539 :
540 65 : void field_t::add_flags(std::uint32_t flags)
541 : {
542 65 : f_flags |= flags;
543 65 : }
544 :
545 :
546 0 : void field_t::clear_flags(std::uint32_t flags)
547 : {
548 0 : f_flags &= ~flags;
549 0 : }
550 :
551 :
552 0 : flag_definition::pointer_t field_t::find_flag_definition(std::string const & name) const
553 : {
554 0 : auto const & flag(f_flag_definitions.find(name));
555 0 : if(flag == f_flag_definitions.end())
556 : {
557 : throw field_not_found(
558 : "Flag named \""
559 0 : + name
560 0 : + "\", not found.");
561 : }
562 :
563 0 : return flag->second;
564 : }
565 :
566 :
567 54 : void field_t::add_flag_definition(std::string const & name, flag_definition::pointer_t bits)
568 : {
569 54 : f_flag_definitions[name] = bits;
570 54 : }
571 :
572 :
573 1638 : std::uint64_t field_t::offset() const
574 : {
575 1638 : return f_offset;
576 : }
577 :
578 :
579 170 : void field_t::set_offset(std::uint64_t offset)
580 : {
581 170 : f_offset = offset;
582 170 : }
583 :
584 :
585 108 : void field_t::adjust_offset(std::int64_t adjust)
586 : {
587 108 : f_offset += adjust;
588 108 : }
589 :
590 :
591 0 : structure::vector_t const & field_t::sub_structures() const
592 : {
593 0 : return f_sub_structures;
594 : }
595 :
596 :
597 4387 : structure::vector_t & field_t::sub_structures()
598 : {
599 4387 : return f_sub_structures;
600 : }
601 :
602 :
603 5 : structure::pointer_t field_t::operator [] (int idx) const
604 : {
605 5 : if(static_cast<uint32_t>(idx) >= f_sub_structures.size())
606 : {
607 : throw out_of_bounds(
608 : "index ("
609 0 : + std::to_string(idx)
610 0 : + ") is out of bounds (0.."
611 0 : + std::to_string(f_size - 1)
612 0 : + ")");
613 : }
614 5 : return f_sub_structures[idx];
615 : }
616 :
617 :
618 2 : void field_t::set_sub_structures(structure_vector_t const & v)
619 : {
620 2 : f_sub_structures = v;
621 2 : }
622 :
623 :
624 :
625 :
626 :
627 :
628 :
629 :
630 22 : structure::structure(struct_description_t const * descriptions, pointer_t parent)
631 : : f_descriptions(descriptions)
632 22 : , f_parent(parent)
633 : {
634 22 : }
635 :
636 :
637 3 : void structure::set_block(block::pointer_t b, std::uint64_t offset, std::uint64_t size)
638 : {
639 3 : f_buffer = std::make_shared<virtual_buffer>(b, offset, size);
640 3 : }
641 :
642 :
643 3 : void structure::init_buffer()
644 : {
645 3 : f_buffer = std::make_shared<virtual_buffer>();
646 3 : f_start_offset = 0;
647 :
648 3 : size_t const size(parse());
649 :
650 6 : buffer_t d(size);
651 3 : f_buffer->pwrite(d.data(), size, 0, true);
652 :
653 : // TODO: if we add support for defaults, we'll need to initalize the
654 : // buffer with those defaults
655 3 : }
656 :
657 :
658 16 : void structure::set_virtual_buffer(virtual_buffer::pointer_t buffer, reference_t start_offset)
659 : {
660 16 : f_buffer = buffer;
661 16 : f_start_offset = start_offset;
662 16 : }
663 :
664 :
665 1 : virtual_buffer::pointer_t structure::get_virtual_buffer(reference_t & start_offset) const
666 : {
667 1 : start_offset = f_start_offset;
668 1 : return f_buffer;
669 : }
670 :
671 :
672 :
673 :
674 : /** \brief Get the static size or get 0.
675 : *
676 : * This function returns the size of the structure if the size is static.
677 : *
678 : * Most structures are no static, though, they will have variable fields
679 : * such as a string or a buffer. This function returns 0 for those
680 : * structures. You can still get a size using the get_current_size()
681 : * function, just keep in mind that the size may change as the data
682 : * varies in the structure.
683 : *
684 : * \note
685 : * A sub-structure is considered static as long as all of its fields are
686 : * static fields.
687 : *
688 : * \return The size of the structure or 0 if the structure size is variable.
689 : */
690 8 : size_t structure::get_size() const
691 : {
692 8 : size_t result(0);
693 :
694 8 : parse();
695 :
696 25 : for(auto const & f : f_fields_by_name)
697 : {
698 17 : if(f.second->has_flags(field_t::FIELD_FLAG_VARIABLE_SIZE))
699 : {
700 0 : return 0;
701 : }
702 :
703 17 : if(f.second->type() == struct_type_t::STRUCT_TYPE_RENAMED)
704 : {
705 0 : continue;
706 : }
707 :
708 : // the size of the structure field is ignored, it's always 1
709 : // and it has nothing to do with the sze of the resulting
710 : // binary
711 : //
712 17 : if(f.second->type() != struct_type_t::STRUCT_TYPE_STRUCTURE)
713 : {
714 16 : result += f.second->size();
715 : }
716 :
717 18 : for(auto const & s : f.second->sub_structures())
718 : {
719 1 : size_t const size(s->get_size());
720 1 : if(size == 0)
721 : {
722 0 : return 0;
723 : }
724 1 : result += size;
725 : }
726 : }
727 :
728 8 : return result;
729 : }
730 :
731 :
732 262 : size_t structure::get_current_size() const
733 : {
734 262 : size_t result(0);
735 :
736 262 : if(!f_fields_by_name.empty())
737 : {
738 3235 : for(field_t::pointer_t f(f_fields_by_name.begin()->second->first()); f != nullptr; f = f->next())
739 : {
740 2973 : if(f->type() == struct_type_t::STRUCT_TYPE_RENAMED)
741 : {
742 0 : continue;
743 : }
744 :
745 : // the size of the structure field is ignored, it's always 1
746 : // and it has nothing to do with the sze of the resulting
747 : // binary
748 : //
749 2973 : switch(f->type())
750 : {
751 0 : case struct_type_t::STRUCT_TYPE_STRUCTURE:
752 0 : break;
753 :
754 : // for those fields, we need to add a few bytes for the size
755 : //
756 262 : case struct_type_t::STRUCT_TYPE_P8STRING:
757 : case struct_type_t::STRUCT_TYPE_BUFFER8:
758 262 : result += 1 + f->size();
759 262 : break;
760 :
761 220 : case struct_type_t::STRUCT_TYPE_P16STRING:
762 : case struct_type_t::STRUCT_TYPE_BUFFER16:
763 220 : result += 2 + f->size();
764 220 : break;
765 :
766 880 : case struct_type_t::STRUCT_TYPE_P32STRING:
767 : case struct_type_t::STRUCT_TYPE_BUFFER32:
768 880 : result += 4 + f->size();
769 880 : break;
770 :
771 : // the size of arrays is the number of items, not the byte size...
772 : // so instead we'll call the get_current_size() recursively
773 : //
774 0 : case struct_type_t::STRUCT_TYPE_ARRAY8:
775 0 : result += 1;
776 0 : break;
777 :
778 123 : case struct_type_t::STRUCT_TYPE_ARRAY16:
779 123 : result += 2;
780 123 : break;
781 :
782 0 : case struct_type_t::STRUCT_TYPE_ARRAY32:
783 0 : result += 4;
784 0 : break;
785 :
786 1488 : default:
787 1488 : result += f->size();
788 1488 : break;
789 :
790 : }
791 :
792 3183 : for(auto const & s : f->sub_structures())
793 : {
794 210 : result += s->get_current_size();
795 : }
796 : }
797 : }
798 :
799 262 : return result;
800 : }
801 :
802 :
803 72 : structure::pointer_t structure::parent() const
804 : {
805 72 : return f_parent.lock();
806 : }
807 :
808 :
809 174 : field_t::pointer_t structure::get_field(std::string const & field_name, struct_type_t type) const
810 : {
811 174 : if(f_buffer == nullptr)
812 : {
813 : throw field_not_found(
814 : "Trying to access a structure field when the f_buffer"
815 0 : " pointer is still null.");
816 : }
817 :
818 174 : if(field_name.empty())
819 : {
820 : throw snapdatabase_logic_error(
821 0 : "Called get_field() with an empty field name.");
822 : }
823 :
824 : // make sure we've parsed the descriptions
825 : //
826 174 : parse();
827 :
828 348 : structure::pointer_t s(const_cast<structure *>(this)->shared_from_this());
829 174 : field_t::pointer_t f(nullptr);
830 174 : char const * n(field_name.c_str());
831 : for(;;)
832 : {
833 : // Note: at this time we do not support accessing arrays (i.e. having
834 : // '[<index>]') because I don't see the point since indexes need to
835 : // be dynamic pretty much 100% of the time
836 : //
837 179 : char const * e(n);
838 3423 : while(*e != '.' && *e != '\0')
839 : {
840 1622 : ++e;
841 : }
842 184 : std::string const sub_field_name(n, e - n);
843 179 : f = s->find_field(sub_field_name);
844 179 : if(f == nullptr)
845 : {
846 : throw field_not_found(
847 : "This description does not include field named \""
848 0 : + field_name
849 0 : + "\".");
850 : }
851 179 : if(*e == '\0')
852 : {
853 348 : if(type != struct_type_t::STRUCT_TYPE_END
854 174 : && f->type() != type)
855 : {
856 : throw type_mismatch(
857 : "This field type is \""
858 0 : + to_string(f->type())
859 0 : + "\" but we expected \""
860 0 : + to_string(type)
861 0 : + "\".");
862 : }
863 :
864 348 : return f;
865 : }
866 :
867 5 : if(f->description()->f_type != struct_type_t::STRUCT_TYPE_STRUCTURE)
868 : {
869 : throw type_mismatch(
870 : "Field \""
871 0 : + sub_field_name
872 0 : + "\" is not of type structure so you can't get a"
873 0 : " sub-field (i.e. have a perio in the name).");
874 : }
875 :
876 5 : if(f->sub_structures().size() != 1)
877 : {
878 : throw invalid_size(
879 : "A structure requires a sub_structure vector of size 1 (got "
880 0 : + std::to_string(f->sub_structures().size())
881 0 : + " instead).");
882 : }
883 :
884 5 : s = (*f)[0];
885 5 : n = e + 1; // +1 to skip the '.'
886 5 : }
887 : }
888 :
889 :
890 0 : flag_definition::pointer_t structure::get_flag(std::string const & flag_name, field_t::pointer_t & f) const
891 : {
892 0 : char const * s(flag_name.c_str());
893 0 : char const * e(s + flag_name.length());
894 0 : while(e > s && e[-1] != '.')
895 : {
896 0 : --e;
897 : }
898 0 : if(e == s)
899 : {
900 : throw field_not_found(
901 : "Flag named \""
902 0 : + flag_name
903 0 : + "\" must at least include a field name and a flag name.");
904 : }
905 :
906 0 : std::string const field_name(s, e - s);
907 0 : f = get_field(field_name);
908 :
909 : // bit fields have sub-names we can check for `field_name`
910 : //
911 0 : switch(f->type())
912 : {
913 0 : case struct_type_t::STRUCT_TYPE_BITS8:
914 : case struct_type_t::STRUCT_TYPE_BITS16:
915 : case struct_type_t::STRUCT_TYPE_BITS32:
916 : case struct_type_t::STRUCT_TYPE_BITS64:
917 : case struct_type_t::STRUCT_TYPE_BITS128:
918 : case struct_type_t::STRUCT_TYPE_BITS256:
919 : case struct_type_t::STRUCT_TYPE_BITS512:
920 0 : return f->find_flag_definition(e);
921 :
922 0 : default:
923 : // incorrect type
924 : //
925 : throw field_not_found(
926 : "Expected a field of type BITS<size> for flag named \""
927 0 : + flag_name
928 0 : + "\". Got a "
929 0 : + to_string(f->type())
930 0 : + " instead.");
931 :
932 : }
933 : }
934 :
935 :
936 179 : field_t::pointer_t structure::find_field(std::string const & field_name)
937 : {
938 179 : auto field(f_fields_by_name.find(field_name));
939 179 : if(field == f_fields_by_name.end())
940 : {
941 :
942 : // we can't return a field and yet it is mandatory, throw an error
943 : // (if we change a description to still include old fields, we need
944 : // to have a way to point to the new field--see the RENAMED flag).
945 : //
946 : throw field_not_found(
947 : "This description does not include field named \""
948 0 : + field_name
949 0 : + "\".");
950 : }
951 :
952 179 : field_t::pointer_t f(field->second);
953 179 : if(f->type() == struct_type_t::STRUCT_TYPE_RENAMED)
954 : {
955 0 : std::string const new_name(f->new_name());
956 0 : field = f_fields_by_name.find(new_name);
957 0 : if(field == f_fields_by_name.end())
958 : {
959 : throw field_not_found(
960 : "This description renames field \""
961 0 : + field_name
962 0 : + "\" to \""
963 0 : + new_name
964 0 : + "\" but we could not find the latter field.");
965 : }
966 0 : f = field->second;
967 :
968 : // let programmers know that the old name is deprecated
969 : //
970 0 : SNAP_LOG_DEBUG
971 0 : << "Deprecated field name \""
972 : << field_name
973 : << "\" was changed to \""
974 : << new_name
975 : << "\". Please change your code to use the new name."
976 : << SNAP_LOG_SEND;
977 : }
978 :
979 179 : return f;
980 : }
981 :
982 :
983 0 : int64_t structure::get_integer(std::string const & field_name) const
984 : {
985 0 : auto f(get_field(field_name));
986 :
987 0 : verify_size(f->type(), f->size());
988 :
989 0 : switch(f->type())
990 : {
991 0 : case struct_type_t::STRUCT_TYPE_INT8:
992 : {
993 0 : int8_t value(0);
994 0 : f_buffer->pread(&value, sizeof(value), f->offset());
995 0 : return value;
996 : }
997 :
998 0 : case struct_type_t::STRUCT_TYPE_INT16:
999 : {
1000 0 : int16_t value(0);
1001 0 : f_buffer->pread(&value, sizeof(value), f->offset());
1002 0 : return value;
1003 : }
1004 :
1005 0 : case struct_type_t::STRUCT_TYPE_INT32:
1006 : {
1007 0 : int32_t value(0);
1008 0 : f_buffer->pread(&value, sizeof(value), f->offset());
1009 0 : return value;
1010 : }
1011 :
1012 0 : case struct_type_t::STRUCT_TYPE_INT64:
1013 : {
1014 0 : int64_t value(0);
1015 0 : f_buffer->pread(&value, sizeof(value), f->offset());
1016 0 : return value;
1017 : }
1018 :
1019 0 : default:
1020 : throw type_mismatch(
1021 : "This description type is \""
1022 0 : + to_string(f->type())
1023 0 : + "\" but we expected one of \""
1024 0 : + to_string(struct_type_t::STRUCT_TYPE_INT8)
1025 0 : + ", "
1026 0 : + to_string(struct_type_t::STRUCT_TYPE_INT16)
1027 0 : + ", "
1028 0 : + to_string(struct_type_t::STRUCT_TYPE_INT32)
1029 0 : + ", "
1030 0 : + to_string(struct_type_t::STRUCT_TYPE_INT64)
1031 0 : + "\".");
1032 :
1033 : }
1034 : }
1035 :
1036 :
1037 0 : void structure::set_integer(std::string const & field_name, int64_t value)
1038 : {
1039 0 : auto f(get_field(field_name));
1040 :
1041 0 : verify_size(f->type(), f->size());
1042 :
1043 0 : switch(f->type())
1044 : {
1045 0 : case struct_type_t::STRUCT_TYPE_INT8:
1046 : {
1047 0 : int8_t const v(value);
1048 0 : f_buffer->pwrite(&v, sizeof(v), f->offset());
1049 : }
1050 0 : return;
1051 :
1052 0 : case struct_type_t::STRUCT_TYPE_INT16:
1053 : {
1054 0 : int16_t const v(value);
1055 0 : f_buffer->pwrite(&v, sizeof(v), f->offset());
1056 : }
1057 0 : return;
1058 :
1059 0 : case struct_type_t::STRUCT_TYPE_INT32:
1060 : {
1061 0 : int32_t const v(value);
1062 0 : f_buffer->pwrite(&v, sizeof(v), f->offset());
1063 : }
1064 0 : return;
1065 :
1066 0 : case struct_type_t::STRUCT_TYPE_INT64:
1067 0 : f_buffer->pwrite(&value, sizeof(value), f->offset());
1068 0 : return;
1069 :
1070 0 : default:
1071 : throw type_mismatch(
1072 : "This description type is \""
1073 0 : + to_string(f->type())
1074 0 : + "\" but we expected one of \""
1075 0 : + to_string(struct_type_t::STRUCT_TYPE_INT8)
1076 0 : + ", "
1077 0 : + to_string(struct_type_t::STRUCT_TYPE_INT16)
1078 0 : + ", "
1079 0 : + to_string(struct_type_t::STRUCT_TYPE_INT32)
1080 0 : + ", "
1081 0 : + to_string(struct_type_t::STRUCT_TYPE_INT64)
1082 0 : + "\".");
1083 :
1084 : }
1085 : }
1086 :
1087 :
1088 21 : uint64_t structure::get_uinteger(std::string const & field_name) const
1089 : {
1090 42 : auto f(get_field(field_name));
1091 :
1092 21 : verify_size(f->type(), f->size());
1093 :
1094 21 : switch(f->type())
1095 : {
1096 0 : case struct_type_t::STRUCT_TYPE_BITS8:
1097 : case struct_type_t::STRUCT_TYPE_UINT8:
1098 : {
1099 0 : uint8_t value(0);
1100 0 : f_buffer->pread(&value, sizeof(value), f->offset());
1101 0 : return value;
1102 : }
1103 :
1104 1 : case struct_type_t::STRUCT_TYPE_BITS16:
1105 : case struct_type_t::STRUCT_TYPE_UINT16:
1106 : {
1107 1 : uint16_t value(0);
1108 1 : f_buffer->pread(&value, sizeof(value), f->offset());
1109 1 : return value;
1110 : }
1111 :
1112 13 : case struct_type_t::STRUCT_TYPE_BITS32:
1113 : case struct_type_t::STRUCT_TYPE_UINT32:
1114 : case struct_type_t::STRUCT_TYPE_VERSION:
1115 : {
1116 13 : uint32_t value(0);
1117 13 : f_buffer->pread(&value, sizeof(value), f->offset());
1118 13 : return value;
1119 : }
1120 :
1121 7 : case struct_type_t::STRUCT_TYPE_BITS64:
1122 : case struct_type_t::STRUCT_TYPE_UINT64:
1123 : case struct_type_t::STRUCT_TYPE_REFERENCE:
1124 : case struct_type_t::STRUCT_TYPE_OID:
1125 : case struct_type_t::STRUCT_TYPE_TIME:
1126 : case struct_type_t::STRUCT_TYPE_MSTIME:
1127 : case struct_type_t::STRUCT_TYPE_USTIME:
1128 : {
1129 7 : uint64_t value(0);
1130 7 : f_buffer->pread(&value, sizeof(value), f->offset());
1131 7 : return value;
1132 : }
1133 :
1134 0 : default:
1135 : throw type_mismatch(
1136 : "This description type is \""
1137 0 : + to_string(f->type())
1138 0 : + "\" but we expected one of \""
1139 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS8)
1140 0 : + ", "
1141 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS16)
1142 0 : + ", "
1143 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS32)
1144 0 : + ", "
1145 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS64)
1146 0 : + ", "
1147 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT8)
1148 0 : + ", "
1149 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT16)
1150 0 : + ", "
1151 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT32)
1152 0 : + ", "
1153 0 : + to_string(struct_type_t::STRUCT_TYPE_VERSION)
1154 0 : + ", "
1155 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT64)
1156 0 : + ", "
1157 0 : + to_string(struct_type_t::STRUCT_TYPE_REFERENCE)
1158 0 : + ", "
1159 0 : + to_string(struct_type_t::STRUCT_TYPE_OID)
1160 0 : + ", "
1161 0 : + to_string(struct_type_t::STRUCT_TYPE_TIME)
1162 0 : + ", "
1163 0 : + to_string(struct_type_t::STRUCT_TYPE_MSTIME)
1164 0 : + ", "
1165 0 : + to_string(struct_type_t::STRUCT_TYPE_USTIME)
1166 0 : + "\".");
1167 :
1168 : }
1169 : }
1170 :
1171 :
1172 68 : void structure::set_uinteger(std::string const & field_name, uint64_t value)
1173 : {
1174 136 : auto f(get_field(field_name));
1175 :
1176 68 : verify_size(f->type(), f->size());
1177 :
1178 68 : switch(f->type())
1179 : {
1180 1 : case struct_type_t::STRUCT_TYPE_BITS8:
1181 : case struct_type_t::STRUCT_TYPE_UINT8:
1182 : {
1183 1 : uint8_t const v(value);
1184 1 : f_buffer->pwrite(&v, sizeof(v), f->offset());
1185 : }
1186 1 : return;
1187 :
1188 21 : case struct_type_t::STRUCT_TYPE_BITS16:
1189 : case struct_type_t::STRUCT_TYPE_UINT16:
1190 : {
1191 21 : uint16_t const v(value);
1192 21 : f_buffer->pwrite(&v, sizeof(v), f->offset());
1193 : }
1194 21 : return;
1195 :
1196 39 : case struct_type_t::STRUCT_TYPE_BITS32:
1197 : case struct_type_t::STRUCT_TYPE_UINT32:
1198 : case struct_type_t::STRUCT_TYPE_VERSION:
1199 : {
1200 39 : uint32_t const v(value);
1201 39 : f_buffer->pwrite(&v, sizeof(v), f->offset());
1202 : }
1203 39 : return;
1204 :
1205 7 : case struct_type_t::STRUCT_TYPE_BITS64:
1206 : case struct_type_t::STRUCT_TYPE_UINT64:
1207 : case struct_type_t::STRUCT_TYPE_REFERENCE:
1208 : case struct_type_t::STRUCT_TYPE_OID:
1209 : case struct_type_t::STRUCT_TYPE_TIME:
1210 : case struct_type_t::STRUCT_TYPE_MSTIME:
1211 : case struct_type_t::STRUCT_TYPE_USTIME:
1212 7 : f_buffer->pwrite(&value, sizeof(value), f->offset());
1213 7 : return;
1214 :
1215 0 : default:
1216 : throw type_mismatch(
1217 : "This description type is \""
1218 0 : + to_string(f->type())
1219 0 : + "\" but we expected one of \""
1220 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS8)
1221 0 : + ", "
1222 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS16)
1223 0 : + ", "
1224 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS32)
1225 0 : + ", "
1226 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS64)
1227 0 : + ", "
1228 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT8)
1229 0 : + ", "
1230 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT16)
1231 0 : + ", "
1232 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT32)
1233 0 : + ", "
1234 0 : + to_string(struct_type_t::STRUCT_TYPE_VERSION)
1235 0 : + ", "
1236 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT64)
1237 0 : + ", "
1238 0 : + to_string(struct_type_t::STRUCT_TYPE_REFERENCE)
1239 0 : + ", "
1240 0 : + to_string(struct_type_t::STRUCT_TYPE_OID)
1241 0 : + ", "
1242 0 : + to_string(struct_type_t::STRUCT_TYPE_TIME)
1243 0 : + ", "
1244 0 : + to_string(struct_type_t::STRUCT_TYPE_MSTIME)
1245 0 : + ", "
1246 0 : + to_string(struct_type_t::STRUCT_TYPE_USTIME)
1247 0 : + "\".");
1248 :
1249 : }
1250 : }
1251 :
1252 :
1253 0 : uint64_t structure::get_bits(std::string const & flag_name) const
1254 : {
1255 0 : field_t::pointer_t f;
1256 0 : flag_definition::pointer_t flag(get_flag(flag_name, f));
1257 :
1258 0 : verify_size(f->type(), f->size());
1259 :
1260 0 : switch(f->type())
1261 : {
1262 0 : case struct_type_t::STRUCT_TYPE_BITS8:
1263 : {
1264 0 : uint8_t value(0);
1265 0 : f_buffer->pread(&value, sizeof(value), f->offset());
1266 0 : return (value & flag->mask()) >> flag->pos();
1267 : }
1268 :
1269 0 : case struct_type_t::STRUCT_TYPE_BITS16:
1270 : {
1271 0 : uint16_t value(0);
1272 0 : f_buffer->pread(&value, sizeof(value), f->offset());
1273 0 : return (value & flag->mask()) >> flag->pos();
1274 : }
1275 :
1276 0 : case struct_type_t::STRUCT_TYPE_BITS32:
1277 : {
1278 0 : uint32_t value(0);
1279 0 : f_buffer->pread(&value, sizeof(value), f->offset());
1280 0 : return (value & flag->mask()) >> flag->pos();
1281 : }
1282 :
1283 0 : case struct_type_t::STRUCT_TYPE_BITS64:
1284 : {
1285 0 : uint64_t value(0);
1286 0 : f_buffer->pread(&value, sizeof(value), f->offset());
1287 0 : return (value & flag->mask()) >> flag->pos();
1288 : }
1289 :
1290 0 : default:
1291 : throw type_mismatch(
1292 : "This description type is \""
1293 0 : + to_string(f->type())
1294 0 : + "\" but we expected one of \""
1295 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS8)
1296 0 : + ", "
1297 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS16)
1298 0 : + ", "
1299 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS32)
1300 0 : + ", "
1301 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS64)
1302 0 : + "\".");
1303 :
1304 : }
1305 : }
1306 :
1307 :
1308 0 : void structure::set_bits(std::string const & flag_name, uint64_t value)
1309 : {
1310 0 : field_t::pointer_t f;
1311 0 : flag_definition::pointer_t flag(get_flag(flag_name, f));
1312 :
1313 0 : verify_size(f->type(), f->size());
1314 :
1315 0 : switch(f->type())
1316 : {
1317 0 : case struct_type_t::STRUCT_TYPE_BITS8:
1318 : case struct_type_t::STRUCT_TYPE_BITS16:
1319 : case struct_type_t::STRUCT_TYPE_BITS32:
1320 : case struct_type_t::STRUCT_TYPE_BITS64:
1321 0 : break;
1322 :
1323 0 : default:
1324 : throw type_mismatch(
1325 : "This description type is \""
1326 0 : + to_string(f->type())
1327 0 : + "\" but we expected one of \""
1328 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS8)
1329 0 : + ", "
1330 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS16)
1331 0 : + ", "
1332 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS32)
1333 0 : + ", "
1334 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS64)
1335 0 : + "\".");
1336 :
1337 : }
1338 :
1339 0 : if((value & (flag->mask() >> flag->pos())) != value)
1340 : {
1341 : throw invalid_number(
1342 : "Value \""
1343 0 : + std::to_string(value)
1344 0 : + "\" does not fit in flag field \""
1345 0 : + flag->full_name()
1346 0 : + "\".");
1347 : }
1348 :
1349 : // some day we may want to optimize better, but this is the easiest
1350 : // right now
1351 : //
1352 0 : uint64_t v(get_uinteger(f->field_name()));
1353 0 : v &= ~flag->mask();
1354 0 : v |= value << flag->pos();
1355 0 : set_uinteger(f->field_name(), v);
1356 0 : }
1357 :
1358 :
1359 0 : int512_t structure::get_large_integer(std::string const & field_name) const
1360 : {
1361 0 : auto f(get_field(field_name));
1362 :
1363 0 : verify_size(f->type(), f->size());
1364 :
1365 0 : int512_t result;
1366 0 : switch(f->type())
1367 : {
1368 0 : case struct_type_t::STRUCT_TYPE_INT8:
1369 0 : f_buffer->pread(&result.f_value, sizeof(int8_t), f->offset());
1370 0 : result.f_value[0] = static_cast<int8_t>(result.f_value[0]); // sign extend
1371 0 : sign_extend_64bit:
1372 0 : result.f_value[1] = static_cast<int64_t>(result.f_value[0]) < 0
1373 0 : ? -1
1374 : : 0;
1375 0 : result.f_value[2] = result.f_value[1];
1376 0 : result.f_value[3] = result.f_value[1];
1377 0 : result.f_value[4] = result.f_value[1];
1378 0 : result.f_value[5] = result.f_value[1];
1379 0 : result.f_value[6] = result.f_value[1];
1380 0 : result.f_high_value = result.f_value[1];
1381 0 : return result;
1382 :
1383 0 : case struct_type_t::STRUCT_TYPE_INT16:
1384 0 : f_buffer->pread(&result.f_value, sizeof(int16_t), f->offset());
1385 0 : result.f_value[0] = static_cast<int16_t>(result.f_value[0]); // sign extend
1386 0 : goto sign_extend_64bit;
1387 :
1388 0 : case struct_type_t::STRUCT_TYPE_INT32:
1389 0 : f_buffer->pread(&result.f_value, sizeof(int32_t), f->offset());
1390 0 : result.f_value[0] = static_cast<int32_t>(result.f_value[0]); // sign extend
1391 0 : goto sign_extend_64bit;
1392 :
1393 0 : case struct_type_t::STRUCT_TYPE_INT64:
1394 0 : f_buffer->pread(&result.f_value, sizeof(int64_t), f->offset());
1395 0 : result.f_value[0] = static_cast<int64_t>(result.f_value[0]); // sign extend
1396 0 : goto sign_extend_64bit;
1397 :
1398 0 : case struct_type_t::STRUCT_TYPE_INT128:
1399 0 : f_buffer->pread(&result.f_value, sizeof(int64_t) * 2, f->offset());
1400 :
1401 0 : result.f_value[2] = static_cast<int64_t>(result.f_value[1]) < 0
1402 0 : ? -1
1403 : : 0;
1404 0 : result.f_value[3] = result.f_value[2];
1405 0 : result.f_value[4] = result.f_value[2];
1406 0 : result.f_value[5] = result.f_value[2];
1407 0 : result.f_value[6] = result.f_value[2];
1408 0 : result.f_high_value = result.f_value[2];
1409 0 : return result;
1410 :
1411 0 : case struct_type_t::STRUCT_TYPE_INT256:
1412 0 : f_buffer->pread(&result.f_value, sizeof(int64_t) * 4, f->offset());
1413 :
1414 0 : result.f_value[4] = static_cast<int64_t>(result.f_value[3]) < 0
1415 0 : ? -1
1416 : : 0;
1417 0 : result.f_value[5] = result.f_value[4];
1418 0 : result.f_value[6] = result.f_value[4];
1419 0 : result.f_high_value = result.f_value[4];
1420 0 : return result;
1421 :
1422 0 : case struct_type_t::STRUCT_TYPE_INT512:
1423 0 : f_buffer->pread(&result.f_value, sizeof(int64_t) * 8, f->offset());
1424 0 : return result;
1425 :
1426 0 : default:
1427 : throw type_mismatch(
1428 : "This description type is \""
1429 0 : + to_string(f->type())
1430 0 : + "\" but we expected one of \""
1431 0 : + to_string(struct_type_t::STRUCT_TYPE_INT8)
1432 0 : + ", "
1433 0 : + to_string(struct_type_t::STRUCT_TYPE_INT16)
1434 0 : + ", "
1435 0 : + to_string(struct_type_t::STRUCT_TYPE_INT32)
1436 0 : + ", "
1437 0 : + to_string(struct_type_t::STRUCT_TYPE_INT64)
1438 0 : + ", "
1439 0 : + to_string(struct_type_t::STRUCT_TYPE_INT128)
1440 0 : + ", "
1441 0 : + to_string(struct_type_t::STRUCT_TYPE_INT256)
1442 0 : + ", "
1443 0 : + to_string(struct_type_t::STRUCT_TYPE_INT512)
1444 0 : + "\".");
1445 :
1446 : }
1447 : }
1448 :
1449 :
1450 0 : void structure::set_large_integer(std::string const & field_name, int512_t value)
1451 : {
1452 0 : auto f(get_field(field_name));
1453 :
1454 0 : verify_size(f->type(), f->size());
1455 :
1456 0 : switch(f->type())
1457 : {
1458 0 : case struct_type_t::STRUCT_TYPE_INT8:
1459 : case struct_type_t::STRUCT_TYPE_INT16:
1460 : case struct_type_t::STRUCT_TYPE_INT32:
1461 : case struct_type_t::STRUCT_TYPE_INT64:
1462 : case struct_type_t::STRUCT_TYPE_INT128:
1463 : case struct_type_t::STRUCT_TYPE_INT256:
1464 : case struct_type_t::STRUCT_TYPE_INT512:
1465 0 : f_buffer->pwrite(value.f_value, f->size(), f->offset());
1466 0 : return;
1467 :
1468 0 : default:
1469 : throw type_mismatch(
1470 : "This description type is \""
1471 0 : + to_string(f->type())
1472 0 : + "\" but we expected one of \""
1473 0 : + to_string(struct_type_t::STRUCT_TYPE_INT8)
1474 0 : + ", "
1475 0 : + to_string(struct_type_t::STRUCT_TYPE_INT16)
1476 0 : + ", "
1477 0 : + to_string(struct_type_t::STRUCT_TYPE_INT32)
1478 0 : + ", "
1479 0 : + to_string(struct_type_t::STRUCT_TYPE_INT64)
1480 0 : + ", "
1481 0 : + to_string(struct_type_t::STRUCT_TYPE_INT128)
1482 0 : + ", "
1483 0 : + to_string(struct_type_t::STRUCT_TYPE_INT256)
1484 0 : + ", "
1485 0 : + to_string(struct_type_t::STRUCT_TYPE_INT512)
1486 0 : + "\".");
1487 :
1488 : }
1489 : }
1490 :
1491 :
1492 0 : uint512_t structure::get_large_uinteger(std::string const & field_name) const
1493 : {
1494 0 : auto f(get_field(field_name));
1495 :
1496 0 : verify_size(f->type(), f->size());
1497 :
1498 0 : uint512_t result;
1499 0 : switch(f->type())
1500 : {
1501 0 : case struct_type_t::STRUCT_TYPE_BITS8:
1502 : case struct_type_t::STRUCT_TYPE_UINT8:
1503 : case struct_type_t::STRUCT_TYPE_BITS16:
1504 : case struct_type_t::STRUCT_TYPE_UINT16:
1505 : case struct_type_t::STRUCT_TYPE_BITS32:
1506 : case struct_type_t::STRUCT_TYPE_UINT32:
1507 : case struct_type_t::STRUCT_TYPE_BITS64:
1508 : case struct_type_t::STRUCT_TYPE_UINT64:
1509 : case struct_type_t::STRUCT_TYPE_REFERENCE:
1510 : case struct_type_t::STRUCT_TYPE_OID:
1511 : case struct_type_t::STRUCT_TYPE_TIME:
1512 : case struct_type_t::STRUCT_TYPE_MSTIME:
1513 : case struct_type_t::STRUCT_TYPE_USTIME:
1514 : case struct_type_t::STRUCT_TYPE_UINT128:
1515 : case struct_type_t::STRUCT_TYPE_UINT256:
1516 : case struct_type_t::STRUCT_TYPE_UINT512:
1517 0 : f_buffer->pread(&result.f_value, f->size(), f->offset());
1518 0 : break;
1519 :
1520 0 : default:
1521 : throw type_mismatch(
1522 : "This description type is \""
1523 0 : + to_string(f->type())
1524 0 : + "\" but we expected one of \""
1525 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS8)
1526 0 : + ", "
1527 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS16)
1528 0 : + ", "
1529 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS32)
1530 0 : + ", "
1531 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS64)
1532 0 : + ", "
1533 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT8)
1534 0 : + ", "
1535 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT16)
1536 0 : + ", "
1537 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT32)
1538 0 : + ", "
1539 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT64)
1540 0 : + ", "
1541 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT128)
1542 0 : + ", "
1543 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT256)
1544 0 : + ", "
1545 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT512)
1546 0 : + ", "
1547 0 : + to_string(struct_type_t::STRUCT_TYPE_REFERENCE)
1548 0 : + ", "
1549 0 : + to_string(struct_type_t::STRUCT_TYPE_OID)
1550 0 : + ", "
1551 0 : + to_string(struct_type_t::STRUCT_TYPE_TIME)
1552 0 : + ", "
1553 0 : + to_string(struct_type_t::STRUCT_TYPE_MSTIME)
1554 0 : + ", "
1555 0 : + to_string(struct_type_t::STRUCT_TYPE_USTIME)
1556 0 : + "\".");
1557 :
1558 : }
1559 :
1560 0 : return result;
1561 : }
1562 :
1563 :
1564 10 : void structure::set_large_uinteger(std::string const & field_name, uint512_t value)
1565 : {
1566 20 : auto f(get_field(field_name));
1567 :
1568 10 : verify_size(f->type(), f->size());
1569 :
1570 10 : switch(f->type())
1571 : {
1572 10 : case struct_type_t::STRUCT_TYPE_BITS8:
1573 : case struct_type_t::STRUCT_TYPE_BITS16:
1574 : case struct_type_t::STRUCT_TYPE_BITS32:
1575 : case struct_type_t::STRUCT_TYPE_BITS64:
1576 : case struct_type_t::STRUCT_TYPE_UINT8:
1577 : case struct_type_t::STRUCT_TYPE_UINT16:
1578 : case struct_type_t::STRUCT_TYPE_UINT32:
1579 : case struct_type_t::STRUCT_TYPE_UINT64:
1580 : case struct_type_t::STRUCT_TYPE_UINT128:
1581 : case struct_type_t::STRUCT_TYPE_UINT256:
1582 : case struct_type_t::STRUCT_TYPE_UINT512:
1583 : case struct_type_t::STRUCT_TYPE_REFERENCE:
1584 : case struct_type_t::STRUCT_TYPE_OID:
1585 : case struct_type_t::STRUCT_TYPE_TIME:
1586 : case struct_type_t::STRUCT_TYPE_MSTIME:
1587 : case struct_type_t::STRUCT_TYPE_USTIME:
1588 10 : f_buffer->pwrite(value.f_value, f->size(), f->offset());
1589 10 : break;
1590 :
1591 0 : default:
1592 : throw type_mismatch(
1593 : "This description type is \""
1594 0 : + to_string(f->type())
1595 0 : + "\" but we expected one of \""
1596 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS8)
1597 0 : + ", "
1598 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS16)
1599 0 : + ", "
1600 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS32)
1601 0 : + ", "
1602 0 : + to_string(struct_type_t::STRUCT_TYPE_BITS64)
1603 0 : + ", "
1604 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT8)
1605 0 : + ", "
1606 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT16)
1607 0 : + ", "
1608 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT32)
1609 0 : + ", "
1610 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT64)
1611 0 : + ", "
1612 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT128)
1613 0 : + ", "
1614 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT256)
1615 0 : + ", "
1616 0 : + to_string(struct_type_t::STRUCT_TYPE_UINT512)
1617 0 : + ", "
1618 0 : + to_string(struct_type_t::STRUCT_TYPE_REFERENCE)
1619 0 : + ", "
1620 0 : + to_string(struct_type_t::STRUCT_TYPE_OID)
1621 0 : + ", "
1622 0 : + to_string(struct_type_t::STRUCT_TYPE_TIME)
1623 0 : + ", "
1624 0 : + to_string(struct_type_t::STRUCT_TYPE_MSTIME)
1625 0 : + ", "
1626 0 : + to_string(struct_type_t::STRUCT_TYPE_USTIME)
1627 0 : + "\".");
1628 :
1629 : }
1630 10 : }
1631 :
1632 :
1633 0 : float structure::get_float32(std::string const & field_name) const
1634 : {
1635 0 : auto f(get_field(field_name, struct_type_t::STRUCT_TYPE_FLOAT32));
1636 :
1637 0 : verify_size(struct_type_t::STRUCT_TYPE_FLOAT32, f->size());
1638 :
1639 : float result;
1640 0 : f_buffer->pread(&result, sizeof(float), f->offset());
1641 0 : return result;
1642 : }
1643 :
1644 :
1645 0 : void structure::set_float32(std::string const & field_name, float value)
1646 : {
1647 0 : auto f(get_field(field_name, struct_type_t::STRUCT_TYPE_FLOAT32));
1648 :
1649 0 : verify_size(struct_type_t::STRUCT_TYPE_FLOAT32, f->size());
1650 :
1651 0 : f_buffer->pwrite(&value, sizeof(float), f->offset());
1652 0 : }
1653 :
1654 :
1655 0 : double structure::get_float64(std::string const & field_name) const
1656 : {
1657 0 : auto f(get_field(field_name, struct_type_t::STRUCT_TYPE_FLOAT64));
1658 :
1659 0 : verify_size(struct_type_t::STRUCT_TYPE_FLOAT64, f->size());
1660 :
1661 : double result;
1662 0 : f_buffer->pread(&result, sizeof(double), f->offset());
1663 0 : return result;
1664 : }
1665 :
1666 :
1667 0 : void structure::set_float64(std::string const & field_name, double value)
1668 : {
1669 0 : auto f(get_field(field_name, struct_type_t::STRUCT_TYPE_FLOAT64));
1670 :
1671 0 : verify_size(struct_type_t::STRUCT_TYPE_FLOAT64, f->size());
1672 :
1673 0 : f_buffer->pwrite(&value, sizeof(double), f->offset());
1674 0 : }
1675 :
1676 :
1677 0 : long double structure::get_float128(std::string const & field_name) const
1678 : {
1679 0 : auto f(get_field(field_name, struct_type_t::STRUCT_TYPE_FLOAT128));
1680 :
1681 0 : verify_size(struct_type_t::STRUCT_TYPE_FLOAT128, f->size());
1682 :
1683 : long double result;
1684 0 : f_buffer->pread(&result, sizeof(long double), f->offset());
1685 0 : return result;
1686 : }
1687 :
1688 :
1689 0 : void structure::set_float128(std::string const & field_name, long double value)
1690 : {
1691 0 : auto f(get_field(field_name, struct_type_t::STRUCT_TYPE_FLOAT128));
1692 :
1693 0 : verify_size(struct_type_t::STRUCT_TYPE_FLOAT128, f->size());
1694 :
1695 0 : f_buffer->pwrite(&value, sizeof(long double), f->offset());
1696 0 : }
1697 :
1698 :
1699 1 : std::string structure::get_string(std::string const & field_name) const
1700 : {
1701 2 : auto f(get_field(field_name));
1702 :
1703 1 : switch(f->type())
1704 : {
1705 1 : case struct_type_t::STRUCT_TYPE_P8STRING:
1706 : case struct_type_t::STRUCT_TYPE_P16STRING:
1707 : case struct_type_t::STRUCT_TYPE_P32STRING:
1708 1 : break;
1709 :
1710 0 : default:
1711 : throw string_not_terminated(
1712 : "This field was expected to be a string it is a \""
1713 0 : + to_string(f->type())
1714 0 : + "\" instead.");
1715 :
1716 : }
1717 :
1718 1 : ssize_t const field_size(f->type_field_size());
1719 :
1720 : // TBD: should we ignore this check in release mode?
1721 1 : std::uint32_t length(0);
1722 1 : f_buffer->pread(&length, field_size, f->offset());
1723 : // in big endian we have to swap the bytes in length if field_size != 4
1724 1 : if(length != f->size())
1725 : {
1726 : throw snapdatabase_logic_error(
1727 : "The size of this string field ("
1728 0 : + std::to_string(f->size())
1729 0 : + ") is different from the size found in the file ("
1730 0 : + std::to_string(field_size)
1731 0 : + ").");
1732 : }
1733 :
1734 1 : std::string result(length, '\0');
1735 1 : f_buffer->pread(result.data(), length, f->offset() + field_size);
1736 2 : return result;
1737 : }
1738 :
1739 :
1740 22 : void structure::set_string(std::string const & field_name, std::string const & value)
1741 : {
1742 44 : auto f(get_field(field_name));
1743 :
1744 22 : switch(f->type())
1745 : {
1746 22 : case struct_type_t::STRUCT_TYPE_P8STRING:
1747 : case struct_type_t::STRUCT_TYPE_P16STRING:
1748 : case struct_type_t::STRUCT_TYPE_P32STRING:
1749 22 : break;
1750 :
1751 0 : default:
1752 : throw string_not_terminated(
1753 : "This field was expected to be a string it is a \""
1754 0 : + to_string(f->type())
1755 0 : + "\" instead.");
1756 :
1757 : }
1758 :
1759 22 : ssize_t const field_size(f->type_field_size());
1760 :
1761 : // check the length
1762 : //
1763 : // WARNING: the pread() works as is in little endian, in big endian
1764 : // we would have to "bswap" the bytes
1765 : //
1766 22 : uint32_t length(0);
1767 22 : f_buffer->pread(&length, field_size, f->offset());
1768 22 : if(length != f->size())
1769 : {
1770 : // TODO: handle the difference (i.e. enlarge/shrink)
1771 : //
1772 : throw invalid_size(
1773 : "This existing string size and field size do not match; found "
1774 0 : + std::to_string(length)
1775 0 : + ", expected "
1776 0 : + std::to_string(f->size())
1777 0 : + " instead.");
1778 : }
1779 :
1780 22 : uint32_t const size(value.length());
1781 22 : uint64_t const max_size(1ULL << (field_size * 8));
1782 22 : if(size >= max_size)
1783 : {
1784 : throw invalid_size(
1785 : "The input string is too large for this string field ("
1786 0 : + std::to_string(size)
1787 0 : + " >= "
1788 0 : + std::to_string(max_size)
1789 0 : + ").");
1790 : }
1791 :
1792 22 : if(size == length)
1793 : {
1794 : // just do a write of the string
1795 : // (the size remains the same)
1796 : //
1797 10 : f_buffer->pwrite(value.data(), size, f->offset() + field_size);
1798 : }
1799 12 : else if(size > length)
1800 : {
1801 12 : f_buffer->pwrite(&size, field_size, f->offset());
1802 12 : f_buffer->pwrite(value.data(), length, f->offset() + field_size);
1803 12 : f_buffer->pinsert(value.data() + length, size - length, f->offset() + field_size + length);
1804 : }
1805 : else //if(size < length)
1806 : {
1807 0 : f_buffer->pwrite(&size, field_size, f->offset());
1808 0 : f_buffer->pwrite(value.data(), size, f->offset() + field_size);
1809 0 : f_buffer->perase(length - size, f->offset() + field_size + size);
1810 : }
1811 :
1812 22 : f->set_size(size);
1813 22 : adjust_offsets(f->offset(), size - length);
1814 :
1815 22 : verify_buffer_size();
1816 22 : }
1817 :
1818 :
1819 0 : structure::pointer_t structure::get_structure(std::string const & field_name) const
1820 : {
1821 0 : auto f(get_field(field_name, struct_type_t::STRUCT_TYPE_STRUCTURE));
1822 :
1823 0 : if(f->sub_structures().size() != 1)
1824 : {
1825 : throw invalid_size(
1826 : "A structure requires a sub_structure vector of size 1 (got "
1827 0 : + std::to_string(f->sub_structures().size())
1828 0 : + " instead).");
1829 : }
1830 :
1831 0 : return (*f)[0];
1832 : }
1833 :
1834 :
1835 0 : void structure::set_structure(std::string const & field_name, structure::pointer_t & value)
1836 : {
1837 0 : auto f(get_field(field_name, struct_type_t::STRUCT_TYPE_STRUCTURE));
1838 :
1839 0 : if(f->sub_structures().size() != 1)
1840 : {
1841 : throw invalid_size(
1842 : "A structure requires a sub_structure vector of size 1 (got "
1843 0 : + std::to_string(f->sub_structures().size())
1844 0 : + " instead).");
1845 : }
1846 :
1847 0 : f->sub_structures()[0] = value;
1848 0 : }
1849 :
1850 :
1851 0 : structure::vector_t structure::get_array(std::string const & field_name) const
1852 : {
1853 0 : auto f(get_field(field_name));
1854 :
1855 0 : switch(f->type())
1856 : {
1857 0 : case struct_type_t::STRUCT_TYPE_ARRAY8:
1858 : case struct_type_t::STRUCT_TYPE_ARRAY16:
1859 : case struct_type_t::STRUCT_TYPE_ARRAY32:
1860 0 : break;
1861 :
1862 0 : default:
1863 : throw type_mismatch(
1864 : "The get_array() function expected a STRUCT_TYPE_ARRAY<size> field instead of \""
1865 0 : + to_string(f->type())
1866 0 : + "\".");
1867 :
1868 : }
1869 :
1870 0 : return f->sub_structures();
1871 : }
1872 :
1873 :
1874 10 : structure::pointer_t structure::new_array_item(std::string const & field_name)
1875 : {
1876 20 : auto f(get_field(field_name));
1877 :
1878 10 : uint64_t size(0);
1879 10 : uint64_t max(0);
1880 10 : switch(f->type())
1881 : {
1882 0 : case struct_type_t::STRUCT_TYPE_ARRAY8:
1883 0 : f_buffer->pread(&size, sizeof(uint8_t), f->offset());
1884 0 : max = 1ULL << 8;
1885 0 : break;
1886 :
1887 10 : case struct_type_t::STRUCT_TYPE_ARRAY16:
1888 10 : f_buffer->pread(&size, sizeof(uint16_t), f->offset());
1889 10 : max = 1ULL << 16;
1890 10 : break;
1891 :
1892 0 : case struct_type_t::STRUCT_TYPE_ARRAY32:
1893 0 : f_buffer->pread(&size, sizeof(uint32_t), f->offset());
1894 0 : max = 1ULL << 32;
1895 0 : break;
1896 :
1897 0 : default:
1898 : throw type_mismatch(
1899 : "The new_array_item() function expected a STRUCT_TYPE_ARRAY<size> field instead of \""
1900 0 : + to_string(f->type())
1901 0 : + "\".");
1902 :
1903 : }
1904 :
1905 : // make sure we can add another item
1906 : //
1907 10 : ++size;
1908 10 : if(size >= max)
1909 : {
1910 : throw snapdatabase_out_of_range(
1911 : "The new_array_item() function cannot be used because the array is already full with "
1912 0 : + std::to_string(max)
1913 0 : + " items.");
1914 : }
1915 :
1916 10 : reference_t offset(0);
1917 20 : field_t::pointer_t n(f->next());
1918 10 : if(n == nullptr)
1919 : {
1920 : // no next, add item at the very end
1921 : //
1922 10 : offset = get_current_size();
1923 : }
1924 : else
1925 : {
1926 : // insert item just before the next field
1927 : //
1928 0 : offset = n->offset();
1929 : }
1930 :
1931 : // create the structure and define the offsets before we specify
1932 : // the buffer (this is very important because we need the size of
1933 : // that new buffer and that is knonwn only after the parse() function
1934 : // returns)
1935 : //
1936 20 : structure::pointer_t s(std::make_shared<structure>(f->description()->f_sub_description, shared_from_this()));
1937 10 : reference_t const new_offset(s->parse_descriptions(offset));
1938 :
1939 : // now add the buffer area for that new sub-structure
1940 : //
1941 10 : size_t const add(s->get_current_size());
1942 20 : std::vector<std::uint8_t> value(add, 0);
1943 10 : f_buffer->pinsert(value.data(), add, offset);
1944 10 : s->set_virtual_buffer(f_buffer, offset);
1945 :
1946 : // increment the array counter and save it
1947 : //
1948 10 : switch(f->type())
1949 : {
1950 0 : case struct_type_t::STRUCT_TYPE_ARRAY8:
1951 0 : f_buffer->pwrite(&size, sizeof(uint8_t), f->offset());
1952 0 : break;
1953 :
1954 10 : case struct_type_t::STRUCT_TYPE_ARRAY16:
1955 10 : f_buffer->pwrite(&size, sizeof(uint16_t), f->offset());
1956 10 : break;
1957 :
1958 0 : case struct_type_t::STRUCT_TYPE_ARRAY32:
1959 0 : f_buffer->pwrite(&size, sizeof(uint32_t), f->offset());
1960 0 : break;
1961 :
1962 0 : default:
1963 : // ignore, we already throw above
1964 0 : break;
1965 :
1966 : }
1967 :
1968 10 : if(new_offset - offset != add)
1969 : {
1970 : }
1971 :
1972 10 : adjust_offsets(offset, new_offset - offset);
1973 :
1974 : // WARNING: for the adjust_offsets() to work properly we MUST have this
1975 : // push_back() after it; otherwise the sub-fields would also
1976 : // get moved
1977 10 : f->sub_structures().push_back(s);
1978 :
1979 10 : verify_buffer_size();
1980 :
1981 20 : return s;
1982 : }
1983 :
1984 :
1985 2 : void structure::set_array(std::string const & field_name, structure::vector_t const & value)
1986 : {
1987 4 : auto f(get_field(field_name));
1988 :
1989 2 : switch(f->type())
1990 : {
1991 2 : case struct_type_t::STRUCT_TYPE_ARRAY8:
1992 : case struct_type_t::STRUCT_TYPE_ARRAY16:
1993 : case struct_type_t::STRUCT_TYPE_ARRAY32:
1994 2 : break;
1995 :
1996 0 : default:
1997 : throw type_mismatch(
1998 : "The set_array() function expected a STRUCT_TYPE_ARRAY<size> field instead of \""
1999 0 : + to_string(f->type())
2000 0 : + "\".");
2001 :
2002 : }
2003 :
2004 2 : f->set_sub_structures(value);
2005 2 : }
2006 :
2007 :
2008 0 : buffer_t structure::get_buffer(std::string const & field_name) const
2009 : {
2010 0 : auto f(get_field(field_name));
2011 :
2012 0 : switch(f->type())
2013 : {
2014 0 : case struct_type_t::STRUCT_TYPE_BUFFER8:
2015 : case struct_type_t::STRUCT_TYPE_BUFFER16:
2016 : case struct_type_t::STRUCT_TYPE_BUFFER32:
2017 0 : break;
2018 :
2019 0 : default:
2020 : throw type_mismatch(
2021 : "The get_buffer() function expected a STRUCT_TYPE_BUFFER<size> field instead of \""
2022 0 : + to_string(f->type())
2023 0 : + "\".");
2024 :
2025 : }
2026 :
2027 0 : ssize_t const field_size(f->type_field_size());
2028 0 : uint32_t size(0);
2029 0 : f_buffer->pread(&size, field_size, f->offset());
2030 0 : if(size != f->size())
2031 : {
2032 : throw invalid_size(
2033 : "This existing buffer size and field size do not match; found "
2034 0 : + std::to_string(size)
2035 0 : + ", expected "
2036 0 : + std::to_string(f->size())
2037 0 : + " instead.");
2038 : }
2039 :
2040 0 : buffer_t result;
2041 0 : result.resize(size);
2042 0 : f_buffer->pread(result.data(), size, f->offset() + field_size);
2043 0 : return result;
2044 : }
2045 :
2046 :
2047 40 : void structure::set_buffer(std::string const & field_name, buffer_t const & value)
2048 : {
2049 80 : auto f(get_field(field_name));
2050 :
2051 40 : switch(f->type())
2052 : {
2053 40 : case struct_type_t::STRUCT_TYPE_BUFFER8:
2054 : case struct_type_t::STRUCT_TYPE_BUFFER16:
2055 : case struct_type_t::STRUCT_TYPE_BUFFER32:
2056 40 : break;
2057 :
2058 0 : default:
2059 : throw type_mismatch(
2060 : "The set_buffer() function expected a STRUCT_TYPE_BUFFER<size> field instead of \""
2061 0 : + to_string(f->type())
2062 0 : + "\".");
2063 :
2064 : }
2065 :
2066 40 : ssize_t const field_size(f->type_field_size());
2067 40 : uint64_t const max(1ULL << (field_size * 8));
2068 40 : uint64_t const size(value.size());
2069 40 : if(size >= max)
2070 : {
2071 : throw snapdatabase_out_of_range(
2072 : "Size of input buffer ("
2073 0 : + std::to_string(size)
2074 0 : + ") too large to send it to the buffer; the maximum permitted by this field is "
2075 0 : + std::to_string(max - 1ULL)
2076 0 : + ".");
2077 : }
2078 :
2079 40 : if(f->size() > size)
2080 : {
2081 : // existing buffer too large, make it the right size (smaller)
2082 : //
2083 0 : f_buffer->perase(f->size() - size, f->offset() + field_size + size);
2084 :
2085 0 : f_buffer->pwrite(&size, field_size, f->offset());
2086 0 : f_buffer->pwrite(value.data(), size, f->offset() + field_size);
2087 0 : f->set_size(size);
2088 : }
2089 40 : else if(f->size() < size)
2090 : {
2091 : // existing buffer too small, enlarge it
2092 : //
2093 : // |* |
2094 : // | <------> |
2095 : // | <--------->|
2096 : // ^^ ^ ^
2097 : // || | |
2098 : // || | +----- new space (pinsert)
2099 : // || |
2100 : // || +---- existing space (pwrite)
2101 : // ||
2102 : // |+------ buffer size
2103 : // |
2104 : // +----- f->f_offset
2105 : //
2106 : // Size of each element is:
2107 : //
2108 : // buffer size -- field_size
2109 : // existing space -- f->size()
2110 : // new space -- value.size() - f->size()
2111 : //
2112 :
2113 7 : f_buffer->pwrite(&size, field_size, f->offset());
2114 :
2115 7 : f_buffer->pwrite(value.data(), f->size(), f->offset() + field_size);
2116 :
2117 7 : f_buffer->pinsert(value.data() + f->size(), size - f->size(), f->offset() + field_size + f->size());
2118 :
2119 7 : f->set_size(size);
2120 : }
2121 : else
2122 : {
2123 : // same size, just overwrite
2124 : //
2125 33 : f_buffer->pwrite(value.data(), size, f->offset() + field_size);
2126 : }
2127 40 : }
2128 :
2129 :
2130 185 : std::uint64_t structure::parse() const
2131 : {
2132 185 : if(f_fields_by_name.empty())
2133 : {
2134 9 : f_original_size = parse_descriptions(f_start_offset);
2135 : }
2136 :
2137 185 : return f_original_size;
2138 : }
2139 :
2140 :
2141 22 : std::uint64_t structure::parse_descriptions(std::uint64_t offset) const
2142 : {
2143 44 : field_t::pointer_t previous;
2144 192 : for(struct_description_t const * def(f_descriptions);
2145 192 : def->f_type != struct_type_t::STRUCT_TYPE_END;
2146 : ++def)
2147 : {
2148 340 : std::string field_name(def->f_field_name);
2149 :
2150 340 : field_t::pointer_t f(std::make_shared<field_t>(def));
2151 170 : if(previous != nullptr)
2152 : {
2153 148 : previous->set_next(f);
2154 148 : f->set_previous(previous);
2155 : }
2156 170 : f->set_offset(offset);
2157 170 : bool has_sub_defs(false);
2158 170 : size_t bit_field(0);
2159 170 : switch(def->f_type)
2160 : {
2161 0 : case struct_type_t::STRUCT_TYPE_VOID:
2162 0 : break;
2163 :
2164 0 : case struct_type_t::STRUCT_TYPE_BITS8:
2165 0 : bit_field = 8;
2166 : #if __cplusplus >= 201700
2167 : [[fallthrough]];
2168 : #endif
2169 1 : case struct_type_t::STRUCT_TYPE_INT8:
2170 : case struct_type_t::STRUCT_TYPE_UINT8:
2171 1 : f->set_size(1);
2172 1 : offset += 1;
2173 1 : break;
2174 :
2175 0 : case struct_type_t::STRUCT_TYPE_BITS16:
2176 0 : bit_field = 16;
2177 : #if __cplusplus >= 201700
2178 : [[fallthrough]];
2179 : #endif
2180 21 : case struct_type_t::STRUCT_TYPE_INT16:
2181 : case struct_type_t::STRUCT_TYPE_UINT16:
2182 21 : f->set_size(2);
2183 21 : offset += 2;
2184 21 : break;
2185 :
2186 11 : case struct_type_t::STRUCT_TYPE_BITS32:
2187 11 : bit_field = 32;
2188 : #if __cplusplus >= 201700
2189 : [[fallthrough]];
2190 : #endif
2191 53 : case struct_type_t::STRUCT_TYPE_INT32:
2192 : case struct_type_t::STRUCT_TYPE_UINT32:
2193 : case struct_type_t::STRUCT_TYPE_FLOAT32:
2194 : case struct_type_t::STRUCT_TYPE_VERSION:
2195 53 : f->set_size(4);
2196 53 : offset += 4;
2197 53 : break;
2198 :
2199 1 : case struct_type_t::STRUCT_TYPE_BITS64:
2200 1 : bit_field = 64;
2201 : #if __cplusplus >= 201700
2202 : [[fallthrough]];
2203 : #endif
2204 17 : case struct_type_t::STRUCT_TYPE_INT64:
2205 : case struct_type_t::STRUCT_TYPE_UINT64:
2206 : case struct_type_t::STRUCT_TYPE_FLOAT64:
2207 : case struct_type_t::STRUCT_TYPE_REFERENCE:
2208 : case struct_type_t::STRUCT_TYPE_OID:
2209 : case struct_type_t::STRUCT_TYPE_TIME:
2210 : case struct_type_t::STRUCT_TYPE_MSTIME:
2211 : case struct_type_t::STRUCT_TYPE_USTIME:
2212 17 : f->set_size(8);
2213 17 : offset += 8;
2214 17 : break;
2215 :
2216 0 : case struct_type_t::STRUCT_TYPE_BITS128:
2217 0 : bit_field = 128;
2218 : #if __cplusplus >= 201700
2219 : [[fallthrough]];
2220 : #endif
2221 10 : case struct_type_t::STRUCT_TYPE_INT128:
2222 : case struct_type_t::STRUCT_TYPE_UINT128:
2223 : case struct_type_t::STRUCT_TYPE_FLOAT128:
2224 10 : f->set_size(16);
2225 10 : offset += 16;
2226 10 : break;
2227 :
2228 0 : case struct_type_t::STRUCT_TYPE_BITS256:
2229 0 : bit_field = 256;
2230 : #if __cplusplus >= 201700
2231 : [[fallthrough]];
2232 : #endif
2233 0 : case struct_type_t::STRUCT_TYPE_INT256:
2234 : case struct_type_t::STRUCT_TYPE_UINT256:
2235 0 : f->set_size(32);
2236 0 : offset += 32;
2237 0 : break;
2238 :
2239 0 : case struct_type_t::STRUCT_TYPE_BITS512:
2240 0 : bit_field = 512;
2241 : #if __cplusplus >= 201700
2242 : [[fallthrough]];
2243 : #endif
2244 0 : case struct_type_t::STRUCT_TYPE_INT512:
2245 : case struct_type_t::STRUCT_TYPE_UINT512:
2246 0 : f->set_size(64);
2247 0 : offset += 64;
2248 0 : break;
2249 :
2250 12 : case struct_type_t::STRUCT_TYPE_P8STRING:
2251 : case struct_type_t::STRUCT_TYPE_BUFFER8:
2252 12 : f->add_flags(field_t::FIELD_FLAG_VARIABLE_SIZE);
2253 12 : offset += 1;
2254 24 : if(f_buffer != nullptr
2255 12 : && f_buffer->count_buffers() != 0)
2256 : {
2257 : uint8_t sz;
2258 0 : f_buffer->pread(&sz, 1, offset);
2259 0 : f->set_size(sz);
2260 : }
2261 12 : break;
2262 :
2263 10 : case struct_type_t::STRUCT_TYPE_P16STRING:
2264 : case struct_type_t::STRUCT_TYPE_BUFFER16:
2265 10 : f->add_flags(field_t::FIELD_FLAG_VARIABLE_SIZE);
2266 10 : offset += 2;
2267 20 : if(f_buffer != nullptr
2268 10 : && f_buffer->count_buffers() != 0)
2269 : {
2270 : uint16_t sz;
2271 0 : f_buffer->pread(&sz, 2, offset);
2272 0 : f->set_size(sz);
2273 : }
2274 10 : break;
2275 :
2276 40 : case struct_type_t::STRUCT_TYPE_P32STRING:
2277 : case struct_type_t::STRUCT_TYPE_BUFFER32:
2278 40 : f->add_flags(field_t::FIELD_FLAG_VARIABLE_SIZE);
2279 40 : offset += 4;
2280 80 : if(f_buffer != nullptr
2281 40 : && f_buffer->count_buffers() != 0)
2282 : {
2283 : uint32_t sz;
2284 0 : f_buffer->pread(&sz, 4, offset);
2285 0 : f->set_size(sz);
2286 0 : offset += sz;
2287 : }
2288 40 : break;
2289 :
2290 3 : case struct_type_t::STRUCT_TYPE_STRUCTURE:
2291 : // here f_size is a count, not a byte size
2292 : //
2293 : // note that some of the fields within the structure may be
2294 : // of variable size but we can't mark the structure itself
2295 : // as being of variable size
2296 : //
2297 3 : f->set_size(1);
2298 3 : has_sub_defs = true;
2299 3 : break;
2300 :
2301 0 : case struct_type_t::STRUCT_TYPE_ARRAY8:
2302 : // here f_size is a count, not a byte size
2303 : //
2304 0 : f->add_flags(field_t::FIELD_FLAG_VARIABLE_SIZE);
2305 0 : offset += 1;
2306 0 : if(f_buffer != nullptr
2307 0 : && f_buffer->count_buffers() != 0)
2308 : {
2309 : uint8_t sz;
2310 0 : f_buffer->pread(&sz, 1, offset);
2311 0 : f->set_size(sz);
2312 : }
2313 0 : has_sub_defs = true;
2314 0 : break;
2315 :
2316 3 : case struct_type_t::STRUCT_TYPE_ARRAY16:
2317 : // here f_size is a count, not a byte size
2318 : //
2319 3 : f->add_flags(field_t::FIELD_FLAG_VARIABLE_SIZE);
2320 3 : offset += 2;
2321 6 : if(f_buffer != nullptr
2322 3 : && f_buffer->count_buffers() != 0)
2323 : {
2324 : uint16_t sz;
2325 0 : f_buffer->pread(&sz, 1, offset);
2326 0 : f->set_size(sz);
2327 : }
2328 3 : has_sub_defs = true;
2329 3 : break;
2330 :
2331 0 : case struct_type_t::STRUCT_TYPE_ARRAY32:
2332 : // here f_size is a count, not a byte size
2333 : //
2334 0 : f->add_flags(field_t::FIELD_FLAG_VARIABLE_SIZE);
2335 0 : offset += 4;
2336 0 : if(f_buffer != nullptr
2337 0 : && f_buffer->count_buffers() != 0)
2338 : {
2339 : uint32_t sz;
2340 0 : f_buffer->pread(&sz, 4, offset);
2341 0 : f->set_size(sz);
2342 : }
2343 0 : has_sub_defs = true;
2344 0 : break;
2345 :
2346 0 : case struct_type_t::STRUCT_TYPE_END:
2347 : case struct_type_t::STRUCT_TYPE_RENAMED:
2348 0 : throw invalid_size("This field does not offer a size which can be queried.");
2349 :
2350 : }
2351 :
2352 340 : if(f_buffer != nullptr
2353 44 : && f_buffer->count_buffers() != 0
2354 196 : && offset > f_buffer->size())
2355 : {
2356 : throw invalid_size(
2357 : "Field \""
2358 0 : + field_name
2359 0 : + "\" is too large for the specified data buffer.");
2360 : }
2361 :
2362 170 : if(def->f_sub_description != nullptr)
2363 : {
2364 6 : if(!has_sub_defs)
2365 : {
2366 : throw snapdatabase_logic_error(
2367 : "Field \""
2368 0 : + field_name
2369 0 : + "\" has its \"f_sub_description\" field set to a pointer when its type doesn't allow it.");
2370 : }
2371 :
2372 12 : pointer_t me(const_cast<structure *>(this)->shared_from_this());
2373 6 : f->sub_structures().reserve(f->size());
2374 9 : for(size_t idx(0); idx < f->size(); ++idx)
2375 : {
2376 6 : pointer_t s(std::make_shared<structure>(def->f_sub_description, me));
2377 3 : s->set_virtual_buffer(f_buffer, offset);
2378 3 : offset = s->parse_descriptions(offset);
2379 3 : f->sub_structures().push_back(s);
2380 : }
2381 : }
2382 164 : else if(has_sub_defs)
2383 : {
2384 : throw snapdatabase_logic_error(
2385 : "Field \""
2386 0 : + field_name
2387 0 : + "\" is expected to have its \"f_sub_description\" field set to a pointer but it's nullptr right now.");
2388 : }
2389 164 : else if(bit_field > 0)
2390 : {
2391 12 : std::string::size_type pos(field_name.find('='));
2392 12 : if(pos != std::string::npos)
2393 : {
2394 : // TODO: add support for 128, 256, and 512 at some point
2395 : // (if it becomes useful)
2396 : //
2397 12 : if(bit_field > 64)
2398 : {
2399 0 : bit_field = 64;
2400 : }
2401 :
2402 12 : size_t bit_pos(0);
2403 12 : std::string::size_type end(pos);
2404 42 : do
2405 : {
2406 54 : std::string::size_type start(end + 1);
2407 54 : if(start >= field_name.size()) // allows for the list to end with a '/'
2408 : {
2409 0 : break;
2410 : }
2411 54 : end = field_name.find_first_of(":/", start);
2412 54 : std::int64_t size(1);
2413 108 : std::string flag_name;
2414 54 : if(end == std::string::npos)
2415 : {
2416 : // no ':' or '/', we found the last flag
2417 : // and it has a size of 1
2418 : //
2419 2 : flag_name = field_name.substr(start);
2420 : }
2421 : else
2422 : {
2423 52 : flag_name = field_name.substr(start, end - start);
2424 :
2425 : // name:size separator?
2426 : //
2427 52 : if(field_name[end] == ':')
2428 : {
2429 11 : start = end + 1;
2430 :
2431 22 : std::string size_str;
2432 11 : end = field_name.find_first_of(":/", start);
2433 11 : if(end == std::string::npos)
2434 : {
2435 : // no '/', we found the last position
2436 : //
2437 10 : size_str = field_name.substr(start);
2438 : }
2439 1 : else if(field_name[end] == '/')
2440 : {
2441 1 : size_str = field_name.substr(start, end - start);
2442 : }
2443 : else
2444 : {
2445 : throw invalid_size(
2446 : "The size of bit field \""
2447 0 : + flag_name
2448 0 : + "\" includes two colons.");
2449 : }
2450 :
2451 11 : if(!advgetopt::validator_integer::convert_string(size_str, size))
2452 : {
2453 : throw invalid_size(
2454 : "The size ("
2455 0 : + size_str
2456 0 : + ") of this bit field \""
2457 0 : + flag_name
2458 0 : + "\" is invalid.");
2459 : }
2460 11 : if(bit_field <= 0)
2461 : {
2462 : throw invalid_size(
2463 : "The size of a bit field must be positive. \""
2464 0 : + flag_name
2465 0 : + "\" was given "
2466 0 : + std::to_string(bit_field)
2467 0 : + " instead.");
2468 : }
2469 11 : if(bit_pos + size > bit_field)
2470 : {
2471 : throw invalid_size(
2472 : "The total number of bits used by bit field \""
2473 0 : + flag_name
2474 0 : + "\" overflows the maximum allowed of "
2475 0 : + std::to_string(bit_field)
2476 0 : + ".");
2477 : }
2478 : }
2479 : }
2480 108 : flag_definition::pointer_t bits(std::make_shared<flag_definition>(field_name, flag_name, bit_pos, size));
2481 54 : f->add_flag_definition(flag_name, bits);
2482 :
2483 54 : bit_pos += size;
2484 : }
2485 54 : while(end != std::string::npos);
2486 :
2487 12 : field_name = field_name.substr(0, pos);
2488 : }
2489 : }
2490 :
2491 170 : const_cast<structure *>(this)->f_fields_by_name[field_name] = f;
2492 :
2493 170 : previous = f;
2494 : }
2495 :
2496 44 : return offset;
2497 : }
2498 :
2499 :
2500 32 : void structure::adjust_offsets(reference_t offset_cutoff, std::int64_t diff)
2501 : {
2502 32 : if(diff == 0)
2503 : {
2504 10 : return;
2505 : }
2506 :
2507 : // we need to adjust all the offsets after 'offset_cutoff'
2508 : // and to do that we need to start from the very top of the
2509 : // set of structures
2510 : //
2511 44 : pointer_t s(shared_from_this());
2512 : for(;;)
2513 : {
2514 42 : pointer_t p(s->f_parent.lock());
2515 32 : if(p == nullptr)
2516 : {
2517 22 : break;
2518 : }
2519 10 : s = p;
2520 10 : }
2521 :
2522 : // we can't use auto to a recursive lambda function
2523 : //
2524 : typedef std::function<void(pointer_t)> func_t;
2525 122 : func_t adjust = [&](pointer_t p)
2526 : {
2527 1495 : for(auto const & f : p->f_fields_by_name)
2528 : {
2529 1373 : if(f.second->offset() > offset_cutoff)
2530 : {
2531 108 : f.second->adjust_offset(diff);
2532 : }
2533 :
2534 1473 : for(auto const & sub : f.second->sub_structures())
2535 : {
2536 100 : adjust(sub);
2537 : }
2538 : }
2539 166 : };
2540 :
2541 22 : adjust(s);
2542 : }
2543 :
2544 :
2545 32 : void structure::verify_buffer_size()
2546 : {
2547 : #ifdef _DEBUG
2548 32 : if(f_buffer != nullptr)
2549 : {
2550 64 : pointer_t s;
2551 32 : for(s = shared_from_this(); s->parent() != nullptr; s = s->parent());
2552 32 : if(f_buffer->size() != s->get_current_size())
2553 : {
2554 : throw snapdatabase_logic_error(
2555 : "Buffer ("
2556 0 : + std::to_string(f_buffer->size())
2557 0 : + ") and current ("
2558 0 : + std::to_string(get_current_size())
2559 0 : + ") sizes do not match.");
2560 : }
2561 : }
2562 : #endif
2563 32 : }
2564 :
2565 :
2566 :
2567 0 : std::ostream & operator << (std::ostream & out, version_t const & v)
2568 : {
2569 0 : return out << v.to_string();
2570 : }
2571 :
2572 :
2573 :
2574 6 : } // namespace snapdatabase
2575 : // vim: ts=4 sw=4 et
|