LCOV - code coverage report
Current view: top level - home/snapwebsites/snapcpp/snapwebsites/snapdatabase/snapdatabase/data - convert.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 137 471 29.1 %
Date: 2019-12-15 17:13:15 Functions: 9 26 34.6 %
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 Various convertions between data types.
      23             :  *
      24             :  * At this point, we mainly want to convert a structure data type to a string
      25             :  * and vice versa. This is useful to convert values defined in the XML file
      26             :  * such as the default value.
      27             :  *
      28             :  * We also have functions to convert strings to integers of 8, 16, 32, 64,
      29             :  * 128, 256, and 512 bits.
      30             :  */
      31             : 
      32             : // self
      33             : //
      34             : #include    "snapdatabase/data/convert.h"
      35             : 
      36             : 
      37             : // boost lib
      38             : //
      39             : #include    <boost/algorithm/string.hpp>
      40             : 
      41             : 
      42             : // C++ lib
      43             : //
      44             : #include    <iostream>
      45             : 
      46             : 
      47             : // last include
      48             : //
      49             : #include    <snapdev/poison.h>
      50             : 
      51             : 
      52             : 
      53             : namespace snapdatabase
      54             : {
      55             : 
      56             : 
      57             : 
      58             : namespace
      59             : {
      60             : 
      61             : enum class number_type_t
      62             : {
      63             :     NUMBER_TYPE_BINARY,
      64             :     NUMBER_TYPE_OCTAL,
      65             :     NUMBER_TYPE_DECIMAL,
      66             :     NUMBER_TYPE_HEXADECIMAL
      67             : };
      68             : 
      69             : 
      70             : struct name_to_size_multiplicator_t
      71             : {
      72             :     char const *        f_name = nullptr;
      73             :     uint512_t           f_multiplicator = uint512_t();
      74             : };
      75             : 
      76             : #define NAME_TO_SIZE_MULTIPLICATOR(name, lo, hi) \
      77             :                         { name, { lo, hi, 0, 0, 0, 0, 0, 0 } }
      78             : 
      79           2 : name_to_size_multiplicator_t const g_size_name_to_multiplicator[] =
      80             : {
      81             :     // WARNING: Keep in alphabetical order
      82             :     //
      83             :     NAME_TO_SIZE_MULTIPLICATOR("BB",        0x9FD0803CE8000000ULL,  0x00000000033B2E3C  ),  // 1000^9
      84             :     NAME_TO_SIZE_MULTIPLICATOR("BRBI",      0,                      0x0000000004000000  ),  // 2^90 = 1024^9
      85             :     NAME_TO_SIZE_MULTIPLICATOR("BRBIB",     0,                      0x0000000004000000  ),  // 2^90 = 1024^9
      86             :     NAME_TO_SIZE_MULTIPLICATOR("BRONTO",    0x9FD0803CE8000000ULL,  0x00000000033B2E3C  ),  // 1000^9
      87             :     NAME_TO_SIZE_MULTIPLICATOR("EB",        1000000000000000000ULL, 0                   ),  // 1000^6
      88             :     NAME_TO_SIZE_MULTIPLICATOR("EIB",       0x1000000000000000ULL,  0                   ),  // 2^60 = 1024^6
      89             :     NAME_TO_SIZE_MULTIPLICATOR("EXA",       1000000000000000000ULL, 0                   ),  // 1000^6
      90             :     NAME_TO_SIZE_MULTIPLICATOR("EXBI",      0x1000000000000000ULL,  0                   ),  // 2^60 = 1024^6
      91             :     NAME_TO_SIZE_MULTIPLICATOR("GB",        1000000000ULL,          0                   ),  // 1000^3
      92             :     NAME_TO_SIZE_MULTIPLICATOR("GEBI",      0,                      0x0000001000000000  ),  // 2^100 = 1024^10
      93             :     NAME_TO_SIZE_MULTIPLICATOR("GEOP",      0x4674EDEA40000000,     0x0000000C9F2C9CD0  ),  // 1000^10
      94             :     NAME_TO_SIZE_MULTIPLICATOR("GIB",       0x0000000040000000ULL,  0                   ),  // 2^30 = 1024^3
      95             :     NAME_TO_SIZE_MULTIPLICATOR("GIBI",      0x0000000040000000ULL,  0                   ),  // 2^30 = 1024^3
      96             :     NAME_TO_SIZE_MULTIPLICATOR("GIGA",      1000000000ULL,          0                   ),  // 1000^3
      97             :     NAME_TO_SIZE_MULTIPLICATOR("KB",        1000ULL,                0                   ),  // 1000^1
      98             :     NAME_TO_SIZE_MULTIPLICATOR("KIB",       0x0000000000000400ULL,  0                   ),  // 2^10 = 1024^1
      99             :     NAME_TO_SIZE_MULTIPLICATOR("KIBI",      0x0000000000000400ULL,  0                   ),  // 2^10 = 1024^1
     100             :     NAME_TO_SIZE_MULTIPLICATOR("KILO",      1000ULL,                0                   ),  // 1000^1
     101             :     NAME_TO_SIZE_MULTIPLICATOR("MB",        1000000ULL,             0                   ),  // 1000^2
     102             :     NAME_TO_SIZE_MULTIPLICATOR("MEBI",      0x0000000000100000ULL,  0                   ),  // 2^20 = 1024^2
     103             :     NAME_TO_SIZE_MULTIPLICATOR("MEGA",      1000000ULL,             0                   ),  // 1000^2
     104             :     NAME_TO_SIZE_MULTIPLICATOR("MIB",       0x0000000000100000ULL,  0                   ),  // 2^20 = 1024^2
     105             :     NAME_TO_SIZE_MULTIPLICATOR("PB",        1000000000000000ULL,    0                   ),  // 1000^5
     106             :     NAME_TO_SIZE_MULTIPLICATOR("PEBI",      0x0004000000000000ULL,  0                   ),  // 2^50 = 1024^5
     107             :     NAME_TO_SIZE_MULTIPLICATOR("PETA",      1000000000000000ULL,    0                   ),  // 1000^5
     108             :     NAME_TO_SIZE_MULTIPLICATOR("PIB",       0x0004000000000000ULL,  0                   ),  // 2^50 = 1024^5
     109             :     NAME_TO_SIZE_MULTIPLICATOR("TB",        1000000000000ULL,       0                   ),  // 1000^4
     110             :     NAME_TO_SIZE_MULTIPLICATOR("TEBI",      0x0000010000000000ULL,  0                   ),  // 2^40 = 1024^4
     111             :     NAME_TO_SIZE_MULTIPLICATOR("TERA",      1000000000000ULL,       0                   ),  // 1000^4
     112             :     NAME_TO_SIZE_MULTIPLICATOR("TIB",       0x0000010000000000ULL,  0                   ),  // 2^40 = 1024^4
     113             :     NAME_TO_SIZE_MULTIPLICATOR("YB",        0x1BCECCEDA1000000,     0x000000000000D3C2  ),  // 1000^8
     114             :     NAME_TO_SIZE_MULTIPLICATOR("YIB",       0,                      0x0000000000010000  ),  // 2^80 = 1024^8
     115             :     NAME_TO_SIZE_MULTIPLICATOR("YOBI",      0,                      0x0000000000010000  ),  // 2^80 = 1024^8
     116             :     NAME_TO_SIZE_MULTIPLICATOR("YOTTA",     0x1BCECCEDA1000000,     0x000000000000D3C2  ),  // 1000^8
     117             :     NAME_TO_SIZE_MULTIPLICATOR("ZB",        0x35C9ADC5DEA00000,     0x0000000000000036  ),  // 1000^7
     118             :     NAME_TO_SIZE_MULTIPLICATOR("ZEBI",      0,                      0x0000000000000040  ),  // 2^70 = 1024^7
     119             :     NAME_TO_SIZE_MULTIPLICATOR("ZETTA",     0x35C9ADC5DEA00000,     0x0000000000000036  ),  // 1000^7
     120             :     NAME_TO_SIZE_MULTIPLICATOR("ZIB",       0,                      0x0000000000000040  ),  // 2^70 = 1024^7
     121           2 : };
     122             : 
     123             : 
     124           2 : uint512_t size_to_multiplicator(char const * s)
     125             : {
     126             : #ifdef _DEBUG
     127             :     // verify in debug because if not in order we can't do a binary search
     128          76 :     for(size_t idx(1);
     129          76 :         idx < sizeof(g_size_name_to_multiplicator) / sizeof(g_size_name_to_multiplicator[0]);
     130             :         ++idx)
     131             :     {
     132          74 :         if(strcmp(g_size_name_to_multiplicator[idx - 1].f_name
     133          74 :                 , g_size_name_to_multiplicator[idx].f_name) >= 0)
     134             :         {
     135             :             throw snapdatabase_logic_error(
     136             :                       "names in g_name_to_struct_type area not in alphabetical order: "
     137           0 :                     + std::string(g_size_name_to_multiplicator[idx - 1].f_name)
     138           0 :                     + " >= "
     139           0 :                     + g_size_name_to_multiplicator[idx].f_name
     140           0 :                     + " (position: "
     141           0 :                     + std::to_string(idx)
     142           0 :                     + ").");
     143             :         }
     144             :     }
     145             : #endif
     146             : 
     147           4 :     std::string size(s);
     148           2 :     boost::algorithm::trim(size);
     149             : 
     150             :     // keep case of first character only
     151             :     //
     152           2 :     boost::algorithm::to_upper(size);
     153             : 
     154             :     // remove the word "byte[s]" if present
     155             :     //
     156           4 :     if(size.length() >= 5
     157           2 :     && size.compare(size.length() - 5, 5, "BYTES") == 0)
     158             :     {
     159           0 :         size = size.substr(0, size.length() - 5);
     160             :     }
     161           4 :     else if(size.length() >= 4
     162           2 :          && size.compare(size.length() - 4, 4, "BYTE") == 0)
     163             :     {
     164           0 :         size = size.substr(0, size.length() - 4);
     165             :     }
     166           2 :     boost::algorithm::trim(size);
     167             : 
     168           2 :     if(!size.empty())
     169             :     {
     170           2 :         int j(sizeof(g_size_name_to_multiplicator) / sizeof(g_size_name_to_multiplicator[0]));
     171           2 :         int i(0);
     172          18 :         while(i < j)
     173             :         {
     174          10 :             int const p((j - i) / 2 + i);
     175          10 :             int const r(size.compare(g_size_name_to_multiplicator[p].f_name));
     176          10 :             if(r > 0)
     177             :             {
     178           6 :                 i = p + 1;
     179             :             }
     180           4 :             else if(r < 0)
     181             :             {
     182           2 :                 j = p;
     183             :             }
     184             :             else
     185             :             {
     186           2 :                 return g_size_name_to_multiplicator[p].f_multiplicator;
     187             :             }
     188             :         }
     189             :     }
     190             : 
     191           0 :     uint512_t one;
     192           0 :     one.f_value[0] = 1;
     193           0 :     return one;
     194             : }
     195             : 
     196             : 
     197     1038893 : uint512_t string_to_int(std::string const & number, bool accept_negative_values, unit_t unit)
     198             : {
     199     1038893 :     bool negative(false);
     200     1038893 :     char const * n(number.c_str());
     201     1038895 :     while(std::isspace(*n))
     202             :     {
     203           1 :         ++n;
     204             :     }
     205     1038893 :     if(*n == '+')
     206             :     {
     207           0 :         ++n;
     208             :     }
     209     1038893 :     else if(*n == '-')
     210             :     {
     211           2 :         if(!accept_negative_values)
     212             :         {
     213             :             throw invalid_number(
     214             :                       "Negative values are not accepted, \""
     215           0 :                     + number
     216           0 :                     + "\" is not valid.");
     217             :         }
     218             : 
     219           2 :         ++n;
     220           2 :         negative = true;
     221             :     }
     222     1038893 :     uint512_t result;
     223     1038893 :     bool expect_quote(false);
     224     1038893 :     number_type_t t(number_type_t::NUMBER_TYPE_DECIMAL);
     225     1038893 :     if(*n == '0')
     226             :     {
     227      593650 :         if(n[1] == 'x'
     228      445237 :         || n[1] == 'X')
     229             :         {
     230      296824 :             n += 2;
     231      296824 :             t = number_type_t::NUMBER_TYPE_HEXADECIMAL;
     232             :         }
     233      296826 :         else if(n[1] == 'b'
     234      148415 :              || n[1] == 'B')
     235             :         {
     236      296822 :             n += 2;
     237      296822 :             t = number_type_t::NUMBER_TYPE_BINARY;
     238             :         }
     239             :         else
     240             :         {
     241           4 :             ++n;
     242           4 :             t = number_type_t::NUMBER_TYPE_OCTAL;
     243             :         }
     244             :     }
     245      445243 :     else if(*n == 'x'
     246      296832 :          || *n == 'X')
     247             :     {
     248      296822 :         if(n[1] == '\'')
     249             :         {
     250      296822 :             n += 2;
     251      296822 :             t = number_type_t::NUMBER_TYPE_HEXADECIMAL;
     252      296822 :             expect_quote = true;
     253             :         }
     254             :     }
     255             : 
     256     1038893 :     switch(t)
     257             :     {
     258     9325308 :     case number_type_t::NUMBER_TYPE_BINARY:
     259    18353794 :         while(*n >= '0' && *n <= '1')
     260             :         {
     261     9028486 :             uint512_t digit;
     262     9028486 :             digit.f_value[0] = *n - '0';
     263             : 
     264             :             // do result * 2 with one add
     265     9028486 :             result += result;       // x2
     266             : 
     267     9028486 :             result += digit;
     268     9028486 :             ++n;
     269     9028486 :         }
     270      296822 :         break;
     271             : 
     272           4 :     case number_type_t::NUMBER_TYPE_OCTAL:
     273           4 :         while(*n >= '0' && *n <= '7')
     274             :         {
     275           0 :             uint512_t digit;
     276           0 :             digit.f_value[0] = *n - '0';
     277             : 
     278             :             // do result * 8 with a few adds
     279           0 :             result += result;       // x2
     280           0 :             result += result;       // x4
     281           0 :             result += result;       // x8
     282             : 
     283           0 :             result += digit;
     284           0 :             ++n;
     285           0 :         }
     286           4 :         break;
     287             : 
     288     1567592 :     case number_type_t::NUMBER_TYPE_DECIMAL:
     289     2986763 :         while(*n >= '0' && *n <= '9')
     290             :         {
     291     1419171 :             uint512_t digit;
     292     1419171 :             digit.f_value[0] = *n - '0';
     293             : 
     294             :             // do result * 10 with a few adds
     295     1419171 :             result += result;       // x2
     296     1419171 :             uint512_t eight(result);
     297     1419171 :             eight += eight;         // x4
     298     1419171 :             eight += eight;         // x8
     299     1419171 :             result += eight;        // x2 + x8 = x10
     300             : 
     301     1419171 :             result += digit;
     302     1419171 :             ++n;
     303     1419171 :         }
     304      148421 :         break;
     305             : 
     306     5216854 :     case number_type_t::NUMBER_TYPE_HEXADECIMAL:
     307             :         for(;;)
     308             :         {
     309     5216854 :             uint512_t digit;
     310     5216854 :             if(*n >= '0' && *n <= '9')
     311             :             {
     312     2875540 :                 digit.f_value[0] = *n - '0';
     313             :             }
     314     2341314 :             else if((*n >= 'a' && *n <= 'f') || (*n >= 'A' && *n <= 'F'))
     315             :             {
     316     1747668 :                 digit.f_value[0] = (*n & 0x5F) - ('A' - 10);
     317             :             }
     318             :             else
     319             :             {
     320             :                 break;
     321             :             }
     322             : 
     323             :             // do result * 16 with a few adds
     324     4623208 :             result += result;       // x2
     325     4623208 :             result += result;       // x4
     326     4623208 :             result += result;       // x8
     327     4623208 :             result += result;       // x16
     328             : 
     329     4623208 :             result += digit;
     330     4623208 :             ++n;
     331     4623208 :         }
     332      593646 :         break;
     333             : 
     334             :     }
     335             : 
     336     1038893 :     if(expect_quote)
     337             :     {
     338      296822 :         if(*n != '\'')
     339             :         {
     340             :             throw invalid_number(
     341             :                       "Closing quote missing in \""
     342           0 :                     + number
     343           0 :                     + "\".");
     344             :         }
     345      296822 :         ++n;
     346             :     }
     347             : 
     348     1038893 :     while(std::isspace(*n))
     349             :     {
     350           0 :         ++n;
     351             :     }
     352             : 
     353     1038893 :     if(*n != '\0')
     354             :     {
     355           2 :         uint512_t multiplicator;
     356           2 :         switch(unit)
     357             :         {
     358           0 :         case unit_t::UNIT_NONE:
     359             :             throw invalid_number(
     360             :                       "Could not convert number \""
     361           0 :                     + number
     362           0 :                     + "\" to a valid uint512_t value.");
     363             : 
     364           2 :         case unit_t::UNIT_SIZE:
     365           2 :             multiplicator = size_to_multiplicator(n);
     366           2 :             break;
     367             : 
     368             :         }
     369             : 
     370           2 :         result *= multiplicator;
     371             :     }
     372             : 
     373     1038893 :     return negative ? -result : result;
     374             : }
     375             : 
     376             : 
     377           3 : buffer_t string_to_uinteger(std::string const & value, size_t max_size)
     378             : {
     379           3 :     buffer_t result;
     380           3 :     uint512_t const n(string_to_int(value, false, unit_t::UNIT_NONE));
     381             : 
     382           3 :     if(max_size != 512 && n.bit_size() > max_size)
     383             :     {
     384             :         throw snapdatabase_out_of_range(
     385             :                   "Number \""
     386           0 :                 + value
     387           0 :                 + "\" too large for an "
     388           0 :                 + std::to_string(max_size)
     389           0 :                 + " bit value.");
     390             :     }
     391             : 
     392           9 :     result.insert(result.end()
     393             :                 , reinterpret_cast<uint8_t const *>(&n.f_value)
     394           9 :                 , reinterpret_cast<uint8_t const *>(&n.f_value) + max_size / 8);
     395             : 
     396           3 :     return result;
     397             : }
     398             : 
     399             : 
     400           0 : std::string uinteger_to_string(buffer_t value, int bytes_for_size, int base)
     401             : {
     402           0 :     if(value.size() > static_cast<size_t>(bytes_for_size))
     403             :     {
     404             :         throw snapdatabase_out_of_range(
     405             :                   "Value too large ("
     406           0 :                 + std::to_string(value.size() * 8)
     407           0 :                 + ") for this field (max: "
     408           0 :                 + std::to_string(bytes_for_size * 8)
     409           0 :                 + ").");
     410             :     }
     411             : 
     412           0 :     uint512_t v;
     413           0 :     std::memcpy(reinterpret_cast<uint8_t *>(v.f_value), reinterpret_cast<uint8_t *>(value.data()), value.size());
     414             : 
     415           0 :     if(v.is_zero())
     416             :     {
     417           0 :         return std::string("0");
     418             :     }
     419             : 
     420           0 :     char const * intro("");
     421           0 :     std::string result;
     422           0 :     switch(base)
     423             :     {
     424           0 :     case 2:
     425           0 :         while(!v.is_zero())
     426             :         {
     427           0 :             result += (v.f_value[0] & 1) + '0';
     428           0 :             v.lsr(1);
     429             :         }
     430           0 :         intro = "0b";
     431           0 :         break;
     432             : 
     433           0 :     case 8:
     434           0 :         while(!v.is_zero())
     435             :         {
     436           0 :             result += (v.f_value[0] & 7) + '0';
     437           0 :             v.lsr(3);
     438             :         }
     439           0 :         intro = "0";
     440           0 :         break;
     441             : 
     442           0 :     case 10:
     443             :         {
     444           0 :             uint512_t remainder;
     445           0 :             uint512_t ten;
     446           0 :             ten.f_value[0] = 10;
     447           0 :             while(!v.is_zero())
     448             :             {
     449           0 :                 v.div(ten, remainder);
     450           0 :                 result += remainder.f_value[0] + '0';
     451           0 :             }
     452             :         }
     453           0 :         break;
     454             : 
     455           0 :     case 16:
     456           0 :         while(!v.is_zero())
     457             :         {
     458           0 :             int const digit(v.f_value[0]);
     459           0 :             if(digit >= 10)
     460             :             {
     461           0 :                 result += digit + 'A';
     462             :             }
     463             :             else
     464             :             {
     465           0 :                 result += digit + '0';
     466             :             }
     467           0 :             v.lsr(4);
     468             :         }
     469           0 :         intro = "0x";
     470           0 :         break;
     471             : 
     472             :     }
     473             : 
     474           0 :     std::reverse(result.begin(), result.end());
     475           0 :     return intro + result;
     476             : }
     477             : 
     478             : 
     479           3 : buffer_t string_to_integer(std::string const & value, size_t max_size)
     480             : {
     481           3 :     buffer_t result;
     482           3 :     int512_t const n(string_to_int(value, true, unit_t::UNIT_NONE));
     483             : 
     484           3 :     if(max_size != 512 && n.bit_size() > max_size)
     485             :     {
     486             :         throw snapdatabase_out_of_range(
     487             :                   "Number \""
     488           0 :                 + value
     489           0 :                 + "\" too large for a signed "
     490           0 :                 + std::to_string(max_size)
     491           0 :                 + " bit value.");
     492             :     }
     493             : 
     494           9 :     result.insert(result.end()
     495             :                 , reinterpret_cast<uint8_t const *>(&n.f_value)
     496           9 :                 , reinterpret_cast<uint8_t const *>(&n.f_value) + max_size / 8);
     497             : 
     498           3 :     return result;
     499             : }
     500             : 
     501             : 
     502           0 : std::string integer_to_string(buffer_t value, int bytes_for_size, int base)
     503             : {
     504           0 :     if(static_cast<int8_t>(value.data()[value.size() - 1]) < 0)
     505             :     {
     506             :         // TODO: this is a tad bit ugly... (i.e. triple memcpy()!!!)
     507             :         //
     508           0 :         int512_t v;
     509           0 :         std::memcpy(v.f_value, value.data(), value.size());
     510           0 :         v = -v;
     511           0 :         buffer_t neg(reinterpret_cast<uint8_t const *>(v.f_value), reinterpret_cast<uint8_t const *>(v.f_value + 8));
     512           0 :         return "-" + uinteger_to_string(neg, bytes_for_size, base);
     513             :     }
     514             :     else
     515             :     {
     516           0 :         return uinteger_to_string(value, bytes_for_size, base);
     517             :     }
     518             : }
     519             : 
     520             : 
     521             : 
     522             : template<typename T>
     523           0 : buffer_t string_to_float(std::string const & value, std::function<T(char const *, char **)> f)
     524             : {
     525           0 :     buffer_t result;
     526           0 :     char * e(nullptr);
     527           0 :     errno = 0;
     528           0 :     T r(f(value.c_str(), &e));
     529           0 :     if(errno == ERANGE)
     530             :     {
     531             :         throw snapdatabase_out_of_range(
     532             :                   "Floating point number \""
     533             :                 + value
     534           0 :                 + "\" out of range.");
     535             :     }
     536             : 
     537             :     // ignore ending spaces
     538             :     //
     539           0 :     while(std::isspace(*e))
     540             :     {
     541           0 :         ++e;
     542             :     }
     543             : 
     544           0 :     if(*e != '\0')
     545             :     {
     546             :         throw invalid_number(
     547             :                   "Floating point number \""
     548             :                 + value
     549           0 :                 + "\" includes invalid numbers.");
     550             :     }
     551             : 
     552           0 :     result.insert(result.end()
     553             :                 , reinterpret_cast<uint8_t *>(&r)
     554             :                 , reinterpret_cast<uint8_t *>(&r) + sizeof(r));
     555             : 
     556           0 :     return result;
     557             : }
     558             : 
     559             : 
     560             : template<typename T>
     561           0 : std::string float_to_string(buffer_t value)
     562             : {
     563             :     // TBD: we may want to specify the format
     564           0 :     if(value.size() != sizeof(T))
     565             :     {
     566             :         throw snapdatabase_out_of_range(
     567             :                   "Value buffer has an unexpected size ("
     568             :                 + std::to_string(value.size())
     569             :                 + ") for this field (expected floating point size: "
     570             :                   BOOST_PP_STRINGIZE(sizeof(T))
     571           0 :                   ").");
     572             :     }
     573           0 :     std::ostringstream ss;
     574           0 :     ss << *reinterpret_cast<T *>(value.data());
     575           0 :     return ss.str();
     576             : }
     577             : 
     578             : 
     579           0 : buffer_t string_to_version(std::string const & value)
     580             : {
     581           0 :     buffer_t result;
     582           0 :     std::string::size_type const pos(value.find('.'));
     583           0 :     if(pos == std::string::npos)
     584             :     {
     585             :         throw snapdatabase_out_of_range(
     586             :                   "Version \""
     587           0 :                 + value
     588           0 :                 + "\" must include a period (.) between the major and minor numbers.");
     589             :     }
     590             : 
     591             :     // allow a 'v' or 'V' introducer as in 'v1.3'
     592             :     //
     593           0 :     std::string::size_type skip(0);
     594           0 :     while(skip < value.length() && std::isspace(value[skip]))
     595             :     {
     596           0 :         ++skip;
     597             :     }
     598           0 :     if(skip < value.length() && (value[skip] == 'v' || value[skip] == 'V'))
     599             :     {
     600           0 :         ++skip;
     601             :     }
     602             : 
     603           0 :     std::string const version_major(value.substr(skip, pos));
     604           0 :     std::string const version_minor(value.substr(pos + 1));
     605             : 
     606           0 :     uint512_t const a(string_to_int(version_major, false, unit_t::UNIT_NONE));
     607           0 :     uint512_t const b(string_to_int(version_minor, false, unit_t::UNIT_NONE));
     608             : 
     609           0 :     if(a.bit_size() > 16
     610           0 :     || b.bit_size() > 16)
     611             :     {
     612             :         throw snapdatabase_out_of_range(
     613             :                   "One or both of the major or minor numbers from version \""
     614           0 :                 + value
     615           0 :                 + "\" are too large for a version number (max. is 65535).");
     616             :     }
     617             : 
     618           0 :     version_t const v(a.f_value[0], b.f_value[0]);
     619           0 :     uint32_t const binary(v.to_binary());
     620             : 
     621           0 :     result.insert(result.end()
     622             :                 , reinterpret_cast<uint8_t const *>(&binary)
     623           0 :                 , reinterpret_cast<uint8_t const *>(&binary) + sizeof(binary));
     624             : 
     625           0 :     return result;
     626             : }
     627             : 
     628             : 
     629           0 : std::string version_to_string(buffer_t value)
     630             : {
     631           0 :     if(value.size() != 4)
     632             :     {
     633             :         throw snapdatabase_out_of_range(
     634             :                   "A buffer representing a version must be exactly 4 bytes, not "
     635           0 :                 + std::to_string(value.size())
     636           0 :                 + ".");
     637             :     }
     638           0 :     version_t v(*reinterpret_cast<uint32_t *>(value.data()));
     639           0 :     return v.to_string();
     640             : }
     641             : 
     642             : 
     643           0 : buffer_t cstring_to_buffer(std::string const & value)
     644             : {
     645           0 :     buffer_t result;
     646           0 :     result.insert(result.end(), value.begin(), value.end());
     647             : 
     648             :     // null terminated
     649           0 :     char zero(0);
     650           0 :     result.insert(result.end(), reinterpret_cast<uint8_t *>(&zero),  reinterpret_cast<uint8_t *>(&zero) + sizeof(zero));
     651             : 
     652           0 :     return result;
     653             : }
     654             : 
     655             : 
     656           0 : std::string buffer_to_cstring(buffer_t const & value)
     657             : {
     658           0 :     if(value.empty())
     659             :     {
     660             :         throw snapdatabase_out_of_range(
     661           0 :                   "A C-String cannot be saved in an empty buffer ('\\0' missing).");
     662             :     }
     663             : 
     664           0 :     if(value[value.size() - 1] != '\0')
     665             :     {
     666             :         throw snapdatabase_out_of_range(
     667           0 :                   "C-String last byte cannot be anything else than '\\0'.");
     668             :     }
     669             : 
     670           0 :     return std::string(value.data(), value.data() + value.size() - 1);
     671             : }
     672             : 
     673             : 
     674           0 : buffer_t string_to_buffer(std::string const & value, size_t bytes_for_size)
     675             : {
     676           0 :     buffer_t result;
     677           0 :     uint32_t size(value.length());
     678             : 
     679           0 :     uint64_t max_size(1ULL << bytes_for_size * 8);
     680             : 
     681           0 :     if(size >= max_size)
     682             :     {
     683             :         throw snapdatabase_out_of_range(
     684             :                   "String too long ("
     685           0 :                 + std::to_string(size)
     686           0 :                 + ") for this field (max: "
     687           0 :                 + std::to_string(max_size)
     688           0 :                 + ").");
     689             :     }
     690             : 
     691             :     // WARNING: this copy works in Little Endian only
     692             :     //
     693           0 :     result.insert(result.end(), reinterpret_cast<uint8_t *>(&size),  reinterpret_cast<uint8_t *>(&size) + bytes_for_size);
     694             : 
     695           0 :     result.insert(result.end(), value.begin(), value.end());
     696             : 
     697           0 :     return result;
     698             : }
     699             : 
     700             : 
     701           0 : std::string buffer_to_string(buffer_t value, size_t bytes_for_size)
     702             : {
     703           0 :     if(value.size() < bytes_for_size)
     704             :     {
     705             :         throw snapdatabase_out_of_range(
     706             :                   "Buffer too small to incorporate the P-String size ("
     707           0 :                 + std::to_string(value.size())
     708           0 :                 + ", expected at least: "
     709           0 :                 + std::to_string(bytes_for_size)
     710           0 :                 + ").");
     711             :     }
     712             : 
     713           0 :     uint32_t size(0);
     714           0 :     memcpy(&size, value.data(), bytes_for_size);
     715             : 
     716           0 :     if(bytes_for_size + size > value.size())
     717             :     {
     718             :         throw snapdatabase_out_of_range(
     719             :                   "Buffer too small for the P-String characters (size: "
     720           0 :                 + std::to_string(size)
     721           0 :                 + ", character bytes in buffer: "
     722           0 :                 + std::to_string(value.size() - bytes_for_size)
     723           0 :                 + ").");
     724             :     }
     725             : 
     726           0 :     return std::string(value.data() + bytes_for_size, value.data() + bytes_for_size + size);
     727             : }
     728             : 
     729             : 
     730             : // TODO: add support for getdate()
     731           0 : buffer_t string_to_unix_time(std::string value, int fraction)
     732             : {
     733             :     struct tm t;
     734           0 :     memset(&t, 0, sizeof(t));
     735           0 :     std::string format("%Y-%m-%dT%T");
     736           0 :     std::string::size_type const pos(value.find('.'));
     737           0 :     int f(0);
     738           0 :     if(pos != std::string::npos)
     739             :     {
     740           0 :         std::string date_time(value.substr(0, pos));
     741           0 :         std::string::size_type zone(value.find_first_of("+-"));
     742           0 :         if(zone == std::string::npos)
     743             :         {
     744           0 :             zone = value.size();
     745             :         }
     746             :         else
     747             :         {
     748           0 :             format += "%z";
     749           0 :             date_time += value.substr(zone);
     750             :         }
     751           0 :         std::string frac(value.substr(pos, zone - pos));
     752           0 :         f = std::atoi(frac.c_str());
     753           0 :         if(f < 0
     754           0 :         || f >= fraction)
     755             :         {
     756             :             throw snapdatabase_out_of_range(
     757             :                       "Time fraction is out of bounds in \""
     758           0 :                     + value
     759           0 :                     + "\".");
     760             :         }
     761             : 
     762           0 :         strptime(date_time.c_str(), format.c_str(), &t);
     763             :     }
     764             :     else
     765             :     {
     766           0 :         std::string::size_type zone(value.find_first_of("+-"));
     767           0 :         if(zone != std::string::npos)
     768             :         {
     769           0 :             format += "%z";
     770             :         }
     771             : 
     772           0 :         strptime(value.c_str(), format.c_str(), &t);
     773             :     }
     774             : 
     775           0 :     time_t v(mktime(&t));
     776           0 :     uint64_t with_fraction(v * fraction + f);
     777             : 
     778           0 :     return buffer_t(reinterpret_cast<uint8_t const *>(&with_fraction), reinterpret_cast<uint8_t const *>(&with_fraction + 1));
     779             : }
     780             : 
     781             : 
     782           0 : std::string unix_time_to_string(buffer_t value, int fraction)
     783             : {
     784             :     uint64_t time;
     785           0 :     if(value.size() != sizeof(time))
     786             :     {
     787             :         throw snapdatabase_out_of_range(
     788             :                   "Buffer size is invalid for a time value (size: "
     789           0 :                 + std::to_string(value.size())
     790           0 :                 + ", expected size: "
     791           0 :                 + std::to_string(sizeof(time))
     792           0 :                 + ").");
     793             :     }
     794           0 :     memcpy(&time, value.data(), sizeof(time));
     795           0 :     time_t const v(time / fraction);
     796             :     struct tm t;
     797           0 :     gmtime_r(&v, &t);
     798             : 
     799             :     char buf[256];
     800           0 :     strftime(buf, sizeof(buf) - 1, "%FT%T", &t);
     801           0 :     buf[sizeof(buf) - 1] = '\0';
     802             : 
     803           0 :     std::string result(buf);
     804             : 
     805           0 :     if(fraction != 1)
     806             :     {
     807           0 :         result += ".";
     808           0 :         std::string frac(std::to_string(time % fraction));
     809           0 :         size_t sz(fraction == 1000 ? 3 : 6);
     810           0 :         while(frac.size() < sz)
     811             :         {
     812           0 :             frac = '0' + frac;
     813             :         }
     814           0 :         result += frac;
     815             :     }
     816             : 
     817           0 :     return result + "+0000";
     818             : }
     819             : 
     820             : 
     821             : } // no name namespace
     822             : 
     823             : 
     824             : 
     825             : 
     826             : 
     827           6 : buffer_t string_to_typed_buffer(struct_type_t type, std::string const & value)
     828             : {
     829           6 :     switch(type)
     830             :     {
     831           0 :     case struct_type_t::STRUCT_TYPE_BITS8:
     832             :     case struct_type_t::STRUCT_TYPE_UINT8:
     833           0 :         return string_to_uinteger(value, 8);
     834             : 
     835           3 :     case struct_type_t::STRUCT_TYPE_BITS16:
     836             :     case struct_type_t::STRUCT_TYPE_UINT16:
     837           3 :         return string_to_uinteger(value, 16);
     838             : 
     839           0 :     case struct_type_t::STRUCT_TYPE_BITS32:
     840             :     case struct_type_t::STRUCT_TYPE_UINT32:
     841           0 :         return string_to_uinteger(value, 32);
     842             : 
     843           0 :     case struct_type_t::STRUCT_TYPE_BITS64:
     844             :     case struct_type_t::STRUCT_TYPE_UINT64:
     845             :     case struct_type_t::STRUCT_TYPE_OID:
     846             :     case struct_type_t::STRUCT_TYPE_REFERENCE:
     847           0 :         return string_to_uinteger(value, 64);
     848             : 
     849           0 :     case struct_type_t::STRUCT_TYPE_BITS128:
     850             :     case struct_type_t::STRUCT_TYPE_UINT128:
     851           0 :         return string_to_uinteger(value, 128);
     852             : 
     853           0 :     case struct_type_t::STRUCT_TYPE_BITS256:
     854             :     case struct_type_t::STRUCT_TYPE_UINT256:
     855           0 :         return string_to_uinteger(value, 256);
     856             : 
     857           0 :     case struct_type_t::STRUCT_TYPE_BITS512:
     858             :     case struct_type_t::STRUCT_TYPE_UINT512:
     859           0 :         return string_to_uinteger(value, 512);
     860             : 
     861           0 :     case struct_type_t::STRUCT_TYPE_INT8:
     862           0 :         return string_to_integer(value, 8);
     863             : 
     864           3 :     case struct_type_t::STRUCT_TYPE_INT16:
     865           3 :         return string_to_integer(value, 16);
     866             : 
     867           0 :     case struct_type_t::STRUCT_TYPE_INT32:
     868           0 :         return string_to_integer(value, 32);
     869             : 
     870           0 :     case struct_type_t::STRUCT_TYPE_INT64:
     871           0 :         return string_to_integer(value, 64);
     872             : 
     873           0 :     case struct_type_t::STRUCT_TYPE_INT128:
     874           0 :         return string_to_integer(value, 128);
     875             : 
     876           0 :     case struct_type_t::STRUCT_TYPE_INT256:
     877           0 :         return string_to_integer(value, 256);
     878             : 
     879           0 :     case struct_type_t::STRUCT_TYPE_INT512:
     880           0 :         return string_to_integer(value, 512);
     881             : 
     882           0 :     case struct_type_t::STRUCT_TYPE_FLOAT32:
     883           0 :         return string_to_float<float>(value, std::strtof);
     884             : 
     885           0 :     case struct_type_t::STRUCT_TYPE_FLOAT64:
     886           0 :         return string_to_float<double>(value, std::strtod);
     887             : 
     888           0 :     case struct_type_t::STRUCT_TYPE_FLOAT128:
     889           0 :         return string_to_float<long double>(value, std::strtold);
     890             : 
     891           0 :     case struct_type_t::STRUCT_TYPE_VERSION:
     892           0 :         return string_to_version(value);
     893             : 
     894           0 :     case struct_type_t::STRUCT_TYPE_TIME:
     895           0 :         return string_to_unix_time(value, 1);
     896             : 
     897           0 :     case struct_type_t::STRUCT_TYPE_MSTIME:
     898           0 :         return string_to_unix_time(value, 1000);
     899             : 
     900           0 :     case struct_type_t::STRUCT_TYPE_USTIME:
     901           0 :         return string_to_unix_time(value, 1000000);
     902             : 
     903           0 :     case struct_type_t::STRUCT_TYPE_P8STRING:
     904           0 :         return string_to_buffer(value, 1);
     905             : 
     906           0 :     case struct_type_t::STRUCT_TYPE_P16STRING:
     907           0 :         return string_to_buffer(value, 2);
     908             : 
     909           0 :     case struct_type_t::STRUCT_TYPE_P32STRING:
     910           0 :         return string_to_buffer(value, 4);
     911             : 
     912           0 :     case struct_type_t::STRUCT_TYPE_BUFFER8:
     913             :     case struct_type_t::STRUCT_TYPE_BUFFER16:
     914             :     case struct_type_t::STRUCT_TYPE_BUFFER32:
     915           0 :         throw snapdatabase_logic_error("Conversion not yet implemented...");
     916             : 
     917           0 :     default:
     918             :         //struct_type_t::STRUCT_TYPE_ARRAY8:
     919             :         //struct_type_t::STRUCT_TYPE_ARRAY16:
     920             :         //struct_type_t::STRUCT_TYPE_ARRAY32:
     921             :         //struct_type_t::STRUCT_TYPE_STRUCTURE:
     922             :         //struct_type_t::STRUCT_TYPE_END
     923             :         //struct_type_t::STRUCT_TYPE_VOID
     924             :         //struct_type_t::STRUCT_TYPE_RENAMED
     925             :         throw snapdatabase_logic_error(
     926             :               "Unexpected structure type ("
     927           0 :             + std::to_string(static_cast<int>(type))
     928           0 :             + ") to convert a string to a buffer");
     929             : 
     930             :     }
     931             : }
     932             : 
     933             : 
     934           0 : std::string typed_buffer_to_string(struct_type_t type, buffer_t value, int base)
     935             : {
     936           0 :     switch(type)
     937             :     {
     938           0 :     case struct_type_t::STRUCT_TYPE_BITS8:
     939             :     case struct_type_t::STRUCT_TYPE_UINT8:
     940           0 :         return uinteger_to_string(value, 8, base);
     941             : 
     942           0 :     case struct_type_t::STRUCT_TYPE_BITS16:
     943             :     case struct_type_t::STRUCT_TYPE_UINT16:
     944           0 :         return uinteger_to_string(value, 16, base);
     945             : 
     946           0 :     case struct_type_t::STRUCT_TYPE_BITS32:
     947             :     case struct_type_t::STRUCT_TYPE_UINT32:
     948           0 :         return uinteger_to_string(value, 32, base);
     949             : 
     950           0 :     case struct_type_t::STRUCT_TYPE_BITS64:
     951             :     case struct_type_t::STRUCT_TYPE_UINT64:
     952             :     case struct_type_t::STRUCT_TYPE_REFERENCE:
     953             :     case struct_type_t::STRUCT_TYPE_OID:
     954           0 :         return uinteger_to_string(value, 64, base);
     955             : 
     956           0 :     case struct_type_t::STRUCT_TYPE_BITS128:
     957             :     case struct_type_t::STRUCT_TYPE_UINT128:
     958           0 :         return uinteger_to_string(value, 128, base);
     959             : 
     960           0 :     case struct_type_t::STRUCT_TYPE_BITS256:
     961             :     case struct_type_t::STRUCT_TYPE_UINT256:
     962           0 :         return uinteger_to_string(value, 256, base);
     963             : 
     964           0 :     case struct_type_t::STRUCT_TYPE_BITS512:
     965             :     case struct_type_t::STRUCT_TYPE_UINT512:
     966           0 :         return uinteger_to_string(value, 512, base);
     967             : 
     968           0 :     case struct_type_t::STRUCT_TYPE_INT8:
     969           0 :         return integer_to_string(value, 8, base);
     970             : 
     971           0 :     case struct_type_t::STRUCT_TYPE_INT16:
     972           0 :         return integer_to_string(value, 16, base);
     973             : 
     974           0 :     case struct_type_t::STRUCT_TYPE_INT32:
     975           0 :         return integer_to_string(value, 32, base);
     976             : 
     977           0 :     case struct_type_t::STRUCT_TYPE_INT64:
     978           0 :         return integer_to_string(value, 64, base);
     979             : 
     980           0 :     case struct_type_t::STRUCT_TYPE_INT128:
     981           0 :         return integer_to_string(value, 128, base);
     982             : 
     983           0 :     case struct_type_t::STRUCT_TYPE_INT256:
     984           0 :         return integer_to_string(value, 256, base);
     985             : 
     986           0 :     case struct_type_t::STRUCT_TYPE_INT512:
     987           0 :         return integer_to_string(value, 512, base);
     988             : 
     989           0 :     case struct_type_t::STRUCT_TYPE_FLOAT32:
     990           0 :         return float_to_string<float>(value);
     991             : 
     992           0 :     case struct_type_t::STRUCT_TYPE_FLOAT64:
     993           0 :         return float_to_string<double>(value);
     994             : 
     995           0 :     case struct_type_t::STRUCT_TYPE_FLOAT128:
     996           0 :         return float_to_string<long double>(value);
     997             : 
     998           0 :     case struct_type_t::STRUCT_TYPE_VERSION:
     999           0 :         return version_to_string(value);
    1000             : 
    1001           0 :     case struct_type_t::STRUCT_TYPE_TIME:
    1002           0 :         return unix_time_to_string(value, 1);
    1003             : 
    1004           0 :     case struct_type_t::STRUCT_TYPE_MSTIME:
    1005           0 :         return unix_time_to_string(value, 1000);
    1006             : 
    1007           0 :     case struct_type_t::STRUCT_TYPE_USTIME:
    1008           0 :         return unix_time_to_string(value, 1000000);
    1009             : 
    1010           0 :     case struct_type_t::STRUCT_TYPE_P8STRING:
    1011           0 :         return buffer_to_string(value, 1);
    1012             : 
    1013           0 :     case struct_type_t::STRUCT_TYPE_P16STRING:
    1014           0 :         return buffer_to_string(value, 2);
    1015             : 
    1016           0 :     case struct_type_t::STRUCT_TYPE_P32STRING:
    1017           0 :         return buffer_to_string(value, 4);
    1018             : 
    1019           0 :     case struct_type_t::STRUCT_TYPE_BUFFER8:
    1020             :     case struct_type_t::STRUCT_TYPE_BUFFER16:
    1021             :     case struct_type_t::STRUCT_TYPE_BUFFER32:
    1022           0 :         throw snapdatabase_logic_error("Conversion not yet implemented...");
    1023             : 
    1024           0 :     default:
    1025             :         //struct_type_t::STRUCT_TYPE_STRUCTURE:
    1026             :         //struct_type_t::STRUCT_TYPE_ARRAY8:
    1027             :         //struct_type_t::STRUCT_TYPE_ARRAY16:
    1028             :         //struct_type_t::STRUCT_TYPE_ARRAY32:
    1029             :         //struct_type_t::STRUCT_TYPE_END
    1030             :         //struct_type_t::STRUCT_TYPE_VOID
    1031             :         //struct_type_t::STRUCT_TYPE_RENAMED
    1032             :         throw snapdatabase_logic_error(
    1033             :               "Unexpected structure type ("
    1034           0 :             + std::to_string(static_cast<int>(type))
    1035           0 :             + ") to convert a string to a buffer");
    1036             : 
    1037             :     }
    1038             : }
    1039             : 
    1040             : 
    1041     1038882 : int64_t convert_to_int(std::string const & value, size_t max_size, unit_t unit)
    1042             : {
    1043     1038882 :     int512_t n(string_to_int(value, true, unit));
    1044             : 
    1045     1038882 :     if(n.bit_size() > max_size)
    1046             :     {
    1047             :         throw snapdatabase_out_of_range(
    1048             :                   "Number \""
    1049           0 :                 + value
    1050           0 :                 + "\" too large for a signed "
    1051           0 :                 + std::to_string(max_size)
    1052           0 :                 + " bit value.");
    1053             :     }
    1054             : 
    1055     1038882 :     return n.f_value[0];
    1056             : }
    1057             : 
    1058             : 
    1059           5 : uint64_t convert_to_uint(std::string const & value, size_t max_size, unit_t unit)
    1060             : {
    1061           5 :     uint512_t n(string_to_int(value, false, unit));
    1062             : 
    1063           5 :     if(n.bit_size() > max_size)
    1064             :     {
    1065             :         throw snapdatabase_out_of_range(
    1066             :                   "Number \""
    1067           0 :                 + value
    1068           0 :                 + "\" too large for a signed "
    1069           0 :                 + std::to_string(max_size)
    1070           0 :                 + " bit value.");
    1071             :     }
    1072             : 
    1073           5 :     return n.f_value[0];
    1074             : }
    1075             : 
    1076             : 
    1077             : 
    1078           6 : } // namespace snapdatabase
    1079             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13