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
|