LCOV - code coverage report
Current view: top level - home/snapwebsites/snapcpp/snapwebsites/snapdatabase/snapdatabase/data - structure.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 450 1164 38.7 %
Date: 2019-12-15 17:13:15 Functions: 49 84 58.3 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13