1#pragma once
2
3#include <algorithm> // reverse
4#include <array> // array
5#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
6#include <cstring> // memcpy
7#include <limits> // numeric_limits
8#include <string> // string
9
10#include <nlohmann/detail/input/binary_reader.hpp>
11#include <nlohmann/detail/macro_scope.hpp>
12#include <nlohmann/detail/output/output_adapters.hpp>
13
14namespace nlohmann
15{
16namespace detail
17{
18///////////////////
19// binary writer //
20///////////////////
21
22/*!
23@brief serialization to CBOR and MessagePack values
24*/
25template<typename BasicJsonType, typename CharType>
26class binary_writer
27{
28 using string_t = typename BasicJsonType::string_t;
29
30 public:
31 /*!
32 @brief create a binary writer
33
34 @param[in] adapter output adapter to write to
35 */
36 explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
37 {
38 assert(oa);
39 }
40
41 /*!
42 @param[in] j JSON value to serialize
43 @pre j.type() == value_t::object
44 */
45 void write_bson(const BasicJsonType& j)
46 {
47 switch (j.type())
48 {
49 case value_t::object:
50 {
51 write_bson_object(*j.m_value.object);
52 break;
53 }
54
55 default:
56 {
57 JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name())));
58 }
59 }
60 }
61
62 /*!
63 @param[in] j JSON value to serialize
64 */
65 void write_cbor(const BasicJsonType& j)
66 {
67 switch (j.type())
68 {
69 case value_t::null:
70 {
71 oa->write_character(to_char_type(0xF6));
72 break;
73 }
74
75 case value_t::boolean:
76 {
77 oa->write_character(j.m_value.boolean
78 ? to_char_type(0xF5)
79 : to_char_type(0xF4));
80 break;
81 }
82
83 case value_t::number_integer:
84 {
85 if (j.m_value.number_integer >= 0)
86 {
87 // CBOR does not differentiate between positive signed
88 // integers and unsigned integers. Therefore, we used the
89 // code from the value_t::number_unsigned case here.
90 if (j.m_value.number_integer <= 0x17)
91 {
92 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
93 }
94 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
95 {
96 oa->write_character(to_char_type(0x18));
97 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
98 }
99 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
100 {
101 oa->write_character(to_char_type(0x19));
102 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
103 }
104 else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
105 {
106 oa->write_character(to_char_type(0x1A));
107 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
108 }
109 else
110 {
111 oa->write_character(to_char_type(0x1B));
112 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
113 }
114 }
115 else
116 {
117 // The conversions below encode the sign in the first
118 // byte, and the value is converted to a positive number.
119 const auto positive_number = -1 - j.m_value.number_integer;
120 if (j.m_value.number_integer >= -24)
121 {
122 write_number(static_cast<std::uint8_t>(0x20 + positive_number));
123 }
124 else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
125 {
126 oa->write_character(to_char_type(0x38));
127 write_number(static_cast<std::uint8_t>(positive_number));
128 }
129 else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
130 {
131 oa->write_character(to_char_type(0x39));
132 write_number(static_cast<std::uint16_t>(positive_number));
133 }
134 else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
135 {
136 oa->write_character(to_char_type(0x3A));
137 write_number(static_cast<std::uint32_t>(positive_number));
138 }
139 else
140 {
141 oa->write_character(to_char_type(0x3B));
142 write_number(static_cast<std::uint64_t>(positive_number));
143 }
144 }
145 break;
146 }
147
148 case value_t::number_unsigned:
149 {
150 if (j.m_value.number_unsigned <= 0x17)
151 {
152 write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
153 }
154 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
155 {
156 oa->write_character(to_char_type(0x18));
157 write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
158 }
159 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
160 {
161 oa->write_character(to_char_type(0x19));
162 write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
163 }
164 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
165 {
166 oa->write_character(to_char_type(0x1A));
167 write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
168 }
169 else
170 {
171 oa->write_character(to_char_type(0x1B));
172 write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
173 }
174 break;
175 }
176
177 case value_t::number_float:
178 {
179 oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
180 write_number(j.m_value.number_float);
181 break;
182 }
183
184 case value_t::string:
185 {
186 // step 1: write control byte and the string length
187 const auto N = j.m_value.string->size();
188 if (N <= 0x17)
189 {
190 write_number(static_cast<std::uint8_t>(0x60 + N));
191 }
192 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
193 {
194 oa->write_character(to_char_type(0x78));
195 write_number(static_cast<std::uint8_t>(N));
196 }
197 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
198 {
199 oa->write_character(to_char_type(0x79));
200 write_number(static_cast<std::uint16_t>(N));
201 }
202 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
203 {
204 oa->write_character(to_char_type(0x7A));
205 write_number(static_cast<std::uint32_t>(N));
206 }
207 // LCOV_EXCL_START
208 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
209 {
210 oa->write_character(to_char_type(0x7B));
211 write_number(static_cast<std::uint64_t>(N));
212 }
213 // LCOV_EXCL_STOP
214
215 // step 2: write the string
216 oa->write_characters(
217 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
218 j.m_value.string->size());
219 break;
220 }
221
222 case value_t::array:
223 {
224 // step 1: write control byte and the array size
225 const auto N = j.m_value.array->size();
226 if (N <= 0x17)
227 {
228 write_number(static_cast<std::uint8_t>(0x80 + N));
229 }
230 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
231 {
232 oa->write_character(to_char_type(0x98));
233 write_number(static_cast<std::uint8_t>(N));
234 }
235 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
236 {
237 oa->write_character(to_char_type(0x99));
238 write_number(static_cast<std::uint16_t>(N));
239 }
240 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
241 {
242 oa->write_character(to_char_type(0x9A));
243 write_number(static_cast<std::uint32_t>(N));
244 }
245 // LCOV_EXCL_START
246 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
247 {
248 oa->write_character(to_char_type(0x9B));
249 write_number(static_cast<std::uint64_t>(N));
250 }
251 // LCOV_EXCL_STOP
252
253 // step 2: write each element
254 for (const auto& el : *j.m_value.array)
255 {
256 write_cbor(el);
257 }
258 break;
259 }
260
261 case value_t::object:
262 {
263 // step 1: write control byte and the object size
264 const auto N = j.m_value.object->size();
265 if (N <= 0x17)
266 {
267 write_number(static_cast<std::uint8_t>(0xA0 + N));
268 }
269 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
270 {
271 oa->write_character(to_char_type(0xB8));
272 write_number(static_cast<std::uint8_t>(N));
273 }
274 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
275 {
276 oa->write_character(to_char_type(0xB9));
277 write_number(static_cast<std::uint16_t>(N));
278 }
279 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
280 {
281 oa->write_character(to_char_type(0xBA));
282 write_number(static_cast<std::uint32_t>(N));
283 }
284 // LCOV_EXCL_START
285 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
286 {
287 oa->write_character(to_char_type(0xBB));
288 write_number(static_cast<std::uint64_t>(N));
289 }
290 // LCOV_EXCL_STOP
291
292 // step 2: write each element
293 for (const auto& el : *j.m_value.object)
294 {
295 write_cbor(el.first);
296 write_cbor(el.second);
297 }
298 break;
299 }
300
301 default:
302 break;
303 }
304 }
305
306 /*!
307 @param[in] j JSON value to serialize
308 */
309 void write_msgpack(const BasicJsonType& j)
310 {
311 switch (j.type())
312 {
313 case value_t::null: // nil
314 {
315 oa->write_character(to_char_type(0xC0));
316 break;
317 }
318
319 case value_t::boolean: // true and false
320 {
321 oa->write_character(j.m_value.boolean
322 ? to_char_type(0xC3)
323 : to_char_type(0xC2));
324 break;
325 }
326
327 case value_t::number_integer:
328 {
329 if (j.m_value.number_integer >= 0)
330 {
331 // MessagePack does not differentiate between positive
332 // signed integers and unsigned integers. Therefore, we used
333 // the code from the value_t::number_unsigned case here.
334 if (j.m_value.number_unsigned < 128)
335 {
336 // positive fixnum
337 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
338 }
339 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
340 {
341 // uint 8
342 oa->write_character(to_char_type(0xCC));
343 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
344 }
345 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
346 {
347 // uint 16
348 oa->write_character(to_char_type(0xCD));
349 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
350 }
351 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
352 {
353 // uint 32
354 oa->write_character(to_char_type(0xCE));
355 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
356 }
357 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
358 {
359 // uint 64
360 oa->write_character(to_char_type(0xCF));
361 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
362 }
363 }
364 else
365 {
366 if (j.m_value.number_integer >= -32)
367 {
368 // negative fixnum
369 write_number(static_cast<std::int8_t>(j.m_value.number_integer));
370 }
371 else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() and
372 j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
373 {
374 // int 8
375 oa->write_character(to_char_type(0xD0));
376 write_number(static_cast<std::int8_t>(j.m_value.number_integer));
377 }
378 else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and
379 j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
380 {
381 // int 16
382 oa->write_character(to_char_type(0xD1));
383 write_number(static_cast<std::int16_t>(j.m_value.number_integer));
384 }
385 else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and
386 j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
387 {
388 // int 32
389 oa->write_character(to_char_type(0xD2));
390 write_number(static_cast<std::int32_t>(j.m_value.number_integer));
391 }
392 else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and
393 j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
394 {
395 // int 64
396 oa->write_character(to_char_type(0xD3));
397 write_number(static_cast<std::int64_t>(j.m_value.number_integer));
398 }
399 }
400 break;
401 }
402
403 case value_t::number_unsigned:
404 {
405 if (j.m_value.number_unsigned < 128)
406 {
407 // positive fixnum
408 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
409 }
410 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
411 {
412 // uint 8
413 oa->write_character(to_char_type(0xCC));
414 write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
415 }
416 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
417 {
418 // uint 16
419 oa->write_character(to_char_type(0xCD));
420 write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
421 }
422 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
423 {
424 // uint 32
425 oa->write_character(to_char_type(0xCE));
426 write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
427 }
428 else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
429 {
430 // uint 64
431 oa->write_character(to_char_type(0xCF));
432 write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
433 }
434 break;
435 }
436
437 case value_t::number_float:
438 {
439 oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
440 write_number(j.m_value.number_float);
441 break;
442 }
443
444 case value_t::string:
445 {
446 // step 1: write control byte and the string length
447 const auto N = j.m_value.string->size();
448 if (N <= 31)
449 {
450 // fixstr
451 write_number(static_cast<std::uint8_t>(0xA0 | N));
452 }
453 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
454 {
455 // str 8
456 oa->write_character(to_char_type(0xD9));
457 write_number(static_cast<std::uint8_t>(N));
458 }
459 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
460 {
461 // str 16
462 oa->write_character(to_char_type(0xDA));
463 write_number(static_cast<std::uint16_t>(N));
464 }
465 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
466 {
467 // str 32
468 oa->write_character(to_char_type(0xDB));
469 write_number(static_cast<std::uint32_t>(N));
470 }
471
472 // step 2: write the string
473 oa->write_characters(
474 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
475 j.m_value.string->size());
476 break;
477 }
478
479 case value_t::array:
480 {
481 // step 1: write control byte and the array size
482 const auto N = j.m_value.array->size();
483 if (N <= 15)
484 {
485 // fixarray
486 write_number(static_cast<std::uint8_t>(0x90 | N));
487 }
488 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
489 {
490 // array 16
491 oa->write_character(to_char_type(0xDC));
492 write_number(static_cast<std::uint16_t>(N));
493 }
494 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
495 {
496 // array 32
497 oa->write_character(to_char_type(0xDD));
498 write_number(static_cast<std::uint32_t>(N));
499 }
500
501 // step 2: write each element
502 for (const auto& el : *j.m_value.array)
503 {
504 write_msgpack(el);
505 }
506 break;
507 }
508
509 case value_t::object:
510 {
511 // step 1: write control byte and the object size
512 const auto N = j.m_value.object->size();
513 if (N <= 15)
514 {
515 // fixmap
516 write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
517 }
518 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
519 {
520 // map 16
521 oa->write_character(to_char_type(0xDE));
522 write_number(static_cast<std::uint16_t>(N));
523 }
524 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
525 {
526 // map 32
527 oa->write_character(to_char_type(0xDF));
528 write_number(static_cast<std::uint32_t>(N));
529 }
530
531 // step 2: write each element
532 for (const auto& el : *j.m_value.object)
533 {
534 write_msgpack(el.first);
535 write_msgpack(el.second);
536 }
537 break;
538 }
539
540 default:
541 break;
542 }
543 }
544
545 /*!
546 @param[in] j JSON value to serialize
547 @param[in] use_count whether to use '#' prefixes (optimized format)
548 @param[in] use_type whether to use '$' prefixes (optimized format)
549 @param[in] add_prefix whether prefixes need to be used for this value
550 */
551 void write_ubjson(const BasicJsonType& j, const bool use_count,
552 const bool use_type, const bool add_prefix = true)
553 {
554 switch (j.type())
555 {
556 case value_t::null:
557 {
558 if (add_prefix)
559 {
560 oa->write_character(to_char_type('Z'));
561 }
562 break;
563 }
564
565 case value_t::boolean:
566 {
567 if (add_prefix)
568 {
569 oa->write_character(j.m_value.boolean
570 ? to_char_type('T')
571 : to_char_type('F'));
572 }
573 break;
574 }
575
576 case value_t::number_integer:
577 {
578 write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
579 break;
580 }
581
582 case value_t::number_unsigned:
583 {
584 write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
585 break;
586 }
587
588 case value_t::number_float:
589 {
590 write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);
591 break;
592 }
593
594 case value_t::string:
595 {
596 if (add_prefix)
597 {
598 oa->write_character(to_char_type('S'));
599 }
600 write_number_with_ubjson_prefix(j.m_value.string->size(), true);
601 oa->write_characters(
602 reinterpret_cast<const CharType*>(j.m_value.string->c_str()),
603 j.m_value.string->size());
604 break;
605 }
606
607 case value_t::array:
608 {
609 if (add_prefix)
610 {
611 oa->write_character(to_char_type('['));
612 }
613
614 bool prefix_required = true;
615 if (use_type and not j.m_value.array->empty())
616 {
617 assert(use_count);
618 const CharType first_prefix = ubjson_prefix(j.front());
619 const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
620 [this, first_prefix](const BasicJsonType & v)
621 {
622 return ubjson_prefix(v) == first_prefix;
623 });
624
625 if (same_prefix)
626 {
627 prefix_required = false;
628 oa->write_character(to_char_type('$'));
629 oa->write_character(first_prefix);
630 }
631 }
632
633 if (use_count)
634 {
635 oa->write_character(to_char_type('#'));
636 write_number_with_ubjson_prefix(j.m_value.array->size(), true);
637 }
638
639 for (const auto& el : *j.m_value.array)
640 {
641 write_ubjson(el, use_count, use_type, prefix_required);
642 }
643
644 if (not use_count)
645 {
646 oa->write_character(to_char_type(']'));
647 }
648
649 break;
650 }
651
652 case value_t::object:
653 {
654 if (add_prefix)
655 {
656 oa->write_character(to_char_type('{'));
657 }
658
659 bool prefix_required = true;
660 if (use_type and not j.m_value.object->empty())
661 {
662 assert(use_count);
663 const CharType first_prefix = ubjson_prefix(j.front());
664 const bool same_prefix = std::all_of(j.begin(), j.end(),
665 [this, first_prefix](const BasicJsonType & v)
666 {
667 return ubjson_prefix(v) == first_prefix;
668 });
669
670 if (same_prefix)
671 {
672 prefix_required = false;
673 oa->write_character(to_char_type('$'));
674 oa->write_character(first_prefix);
675 }
676 }
677
678 if (use_count)
679 {
680 oa->write_character(to_char_type('#'));
681 write_number_with_ubjson_prefix(j.m_value.object->size(), true);
682 }
683
684 for (const auto& el : *j.m_value.object)
685 {
686 write_number_with_ubjson_prefix(el.first.size(), true);
687 oa->write_characters(
688 reinterpret_cast<const CharType*>(el.first.c_str()),
689 el.first.size());
690 write_ubjson(el.second, use_count, use_type, prefix_required);
691 }
692
693 if (not use_count)
694 {
695 oa->write_character(to_char_type('}'));
696 }
697
698 break;
699 }
700
701 default:
702 break;
703 }
704 }
705
706 private:
707 //////////
708 // BSON //
709 //////////
710
711 /*!
712 @return The size of a BSON document entry header, including the id marker
713 and the entry name size (and its null-terminator).
714 */
715 static std::size_t calc_bson_entry_header_size(const string_t& name)
716 {
717 const auto it = name.find(static_cast<typename string_t::value_type>(0));
718 if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
719 {
720 JSON_THROW(out_of_range::create(409,
721 "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")"));
722 }
723
724 return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
725 }
726
727 /*!
728 @brief Writes the given @a element_type and @a name to the output adapter
729 */
730 void write_bson_entry_header(const string_t& name,
731 const std::uint8_t element_type)
732 {
733 oa->write_character(to_char_type(element_type)); // boolean
734 oa->write_characters(
735 reinterpret_cast<const CharType*>(name.c_str()),
736 name.size() + 1u);
737 }
738
739 /*!
740 @brief Writes a BSON element with key @a name and boolean value @a value
741 */
742 void write_bson_boolean(const string_t& name,
743 const bool value)
744 {
745 write_bson_entry_header(name, 0x08);
746 oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
747 }
748
749 /*!
750 @brief Writes a BSON element with key @a name and double value @a value
751 */
752 void write_bson_double(const string_t& name,
753 const double value)
754 {
755 write_bson_entry_header(name, 0x01);
756 write_number<double, true>(value);
757 }
758
759 /*!
760 @return The size of the BSON-encoded string in @a value
761 */
762 static std::size_t calc_bson_string_size(const string_t& value)
763 {
764 return sizeof(std::int32_t) + value.size() + 1ul;
765 }
766
767 /*!
768 @brief Writes a BSON element with key @a name and string value @a value
769 */
770 void write_bson_string(const string_t& name,
771 const string_t& value)
772 {
773 write_bson_entry_header(name, 0x02);
774
775 write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));
776 oa->write_characters(
777 reinterpret_cast<const CharType*>(value.c_str()),
778 value.size() + 1);
779 }
780
781 /*!
782 @brief Writes a BSON element with key @a name and null value
783 */
784 void write_bson_null(const string_t& name)
785 {
786 write_bson_entry_header(name, 0x0A);
787 }
788
789 /*!
790 @return The size of the BSON-encoded integer @a value
791 */
792 static std::size_t calc_bson_integer_size(const std::int64_t value)
793 {
794 return (std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)()
795 ? sizeof(std::int32_t)
796 : sizeof(std::int64_t);
797 }
798
799 /*!
800 @brief Writes a BSON element with key @a name and integer @a value
801 */
802 void write_bson_integer(const string_t& name,
803 const std::int64_t value)
804 {
805 if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())
806 {
807 write_bson_entry_header(name, 0x10); // int32
808 write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
809 }
810 else
811 {
812 write_bson_entry_header(name, 0x12); // int64
813 write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
814 }
815 }
816
817 /*!
818 @return The size of the BSON-encoded unsigned integer in @a j
819 */
820 static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
821 {
822 return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
823 ? sizeof(std::int32_t)
824 : sizeof(std::int64_t);
825 }
826
827 /*!
828 @brief Writes a BSON element with key @a name and unsigned @a value
829 */
830 void write_bson_unsigned(const string_t& name,
831 const std::uint64_t value)
832 {
833 if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
834 {
835 write_bson_entry_header(name, 0x10 /* int32 */);
836 write_number<std::int32_t, true>(static_cast<std::int32_t>(value));
837 }
838 else if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
839 {
840 write_bson_entry_header(name, 0x12 /* int64 */);
841 write_number<std::int64_t, true>(static_cast<std::int64_t>(value));
842 }
843 else
844 {
845 JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(value) + " cannot be represented by BSON as it does not fit int64"));
846 }
847 }
848
849 /*!
850 @brief Writes a BSON element with key @a name and object @a value
851 */
852 void write_bson_object_entry(const string_t& name,
853 const typename BasicJsonType::object_t& value)
854 {
855 write_bson_entry_header(name, 0x03); // object
856 write_bson_object(value);
857 }
858
859 /*!
860 @return The size of the BSON-encoded array @a value
861 */
862 static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
863 {
864 std::size_t array_index = 0ul;
865
866 const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), 0ul, [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
867 {
868 return result + calc_bson_element_size(std::to_string(array_index++), el);
869 });
870
871 return sizeof(std::int32_t) + embedded_document_size + 1ul;
872 }
873
874 /*!
875 @brief Writes a BSON element with key @a name and array @a value
876 */
877 void write_bson_array(const string_t& name,
878 const typename BasicJsonType::array_t& value)
879 {
880 write_bson_entry_header(name, 0x04); // array
881 write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_array_size(value)));
882
883 std::size_t array_index = 0ul;
884
885 for (const auto& el : value)
886 {
887 write_bson_element(std::to_string(array_index++), el);
888 }
889
890 oa->write_character(to_char_type(0x00));
891 }
892
893 /*!
894 @brief Calculates the size necessary to serialize the JSON value @a j with its @a name
895 @return The calculated size for the BSON document entry for @a j with the given @a name.
896 */
897 static std::size_t calc_bson_element_size(const string_t& name,
898 const BasicJsonType& j)
899 {
900 const auto header_size = calc_bson_entry_header_size(name);
901 switch (j.type())
902 {
903 case value_t::object:
904 return header_size + calc_bson_object_size(*j.m_value.object);
905
906 case value_t::array:
907 return header_size + calc_bson_array_size(*j.m_value.array);
908
909 case value_t::boolean:
910 return header_size + 1ul;
911
912 case value_t::number_float:
913 return header_size + 8ul;
914
915 case value_t::number_integer:
916 return header_size + calc_bson_integer_size(j.m_value.number_integer);
917
918 case value_t::number_unsigned:
919 return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);
920
921 case value_t::string:
922 return header_size + calc_bson_string_size(*j.m_value.string);
923
924 case value_t::null:
925 return header_size + 0ul;
926
927 // LCOV_EXCL_START
928 default:
929 assert(false);
930 return 0ul;
931 // LCOV_EXCL_STOP
932 }
933 }
934
935 /*!
936 @brief Serializes the JSON value @a j to BSON and associates it with the
937 key @a name.
938 @param name The name to associate with the JSON entity @a j within the
939 current BSON document
940 @return The size of the BSON entry
941 */
942 void write_bson_element(const string_t& name,
943 const BasicJsonType& j)
944 {
945 switch (j.type())
946 {
947 case value_t::object:
948 return write_bson_object_entry(name, *j.m_value.object);
949
950 case value_t::array:
951 return write_bson_array(name, *j.m_value.array);
952
953 case value_t::boolean:
954 return write_bson_boolean(name, j.m_value.boolean);
955
956 case value_t::number_float:
957 return write_bson_double(name, j.m_value.number_float);
958
959 case value_t::number_integer:
960 return write_bson_integer(name, j.m_value.number_integer);
961
962 case value_t::number_unsigned:
963 return write_bson_unsigned(name, j.m_value.number_unsigned);
964
965 case value_t::string:
966 return write_bson_string(name, *j.m_value.string);
967
968 case value_t::null:
969 return write_bson_null(name);
970
971 // LCOV_EXCL_START
972 default:
973 assert(false);
974 return;
975 // LCOV_EXCL_STOP
976 }
977 }
978
979 /*!
980 @brief Calculates the size of the BSON serialization of the given
981 JSON-object @a j.
982 @param[in] j JSON value to serialize
983 @pre j.type() == value_t::object
984 */
985 static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
986 {
987 std::size_t document_size = std::accumulate(value.begin(), value.end(), 0ul,
988 [](size_t result, const typename BasicJsonType::object_t::value_type & el)
989 {
990 return result += calc_bson_element_size(el.first, el.second);
991 });
992
993 return sizeof(std::int32_t) + document_size + 1ul;
994 }
995
996 /*!
997 @param[in] j JSON value to serialize
998 @pre j.type() == value_t::object
999 */
1000 void write_bson_object(const typename BasicJsonType::object_t& value)
1001 {
1002 write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_object_size(value)));
1003
1004 for (const auto& el : value)
1005 {
1006 write_bson_element(el.first, el.second);
1007 }
1008
1009 oa->write_character(to_char_type(0x00));
1010 }
1011
1012 //////////
1013 // CBOR //
1014 //////////
1015
1016 static constexpr CharType get_cbor_float_prefix(float /*unused*/)
1017 {
1018 return to_char_type(0xFA); // Single-Precision Float
1019 }
1020
1021 static constexpr CharType get_cbor_float_prefix(double /*unused*/)
1022 {
1023 return to_char_type(0xFB); // Double-Precision Float
1024 }
1025
1026 /////////////
1027 // MsgPack //
1028 /////////////
1029
1030 static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
1031 {
1032 return to_char_type(0xCA); // float 32
1033 }
1034
1035 static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
1036 {
1037 return to_char_type(0xCB); // float 64
1038 }
1039
1040 ////////////
1041 // UBJSON //
1042 ////////////
1043
1044 // UBJSON: write number (floating point)
1045 template<typename NumberType, typename std::enable_if<
1046 std::is_floating_point<NumberType>::value, int>::type = 0>
1047 void write_number_with_ubjson_prefix(const NumberType n,
1048 const bool add_prefix)
1049 {
1050 if (add_prefix)
1051 {
1052 oa->write_character(get_ubjson_float_prefix(n));
1053 }
1054 write_number(n);
1055 }
1056
1057 // UBJSON: write number (unsigned integer)
1058 template<typename NumberType, typename std::enable_if<
1059 std::is_unsigned<NumberType>::value, int>::type = 0>
1060 void write_number_with_ubjson_prefix(const NumberType n,
1061 const bool add_prefix)
1062 {
1063 if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
1064 {
1065 if (add_prefix)
1066 {
1067 oa->write_character(to_char_type('i')); // int8
1068 }
1069 write_number(static_cast<std::uint8_t>(n));
1070 }
1071 else if (n <= (std::numeric_limits<std::uint8_t>::max)())
1072 {
1073 if (add_prefix)
1074 {
1075 oa->write_character(to_char_type('U')); // uint8
1076 }
1077 write_number(static_cast<std::uint8_t>(n));
1078 }
1079 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
1080 {
1081 if (add_prefix)
1082 {
1083 oa->write_character(to_char_type('I')); // int16
1084 }
1085 write_number(static_cast<std::int16_t>(n));
1086 }
1087 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1088 {
1089 if (add_prefix)
1090 {
1091 oa->write_character(to_char_type('l')); // int32
1092 }
1093 write_number(static_cast<std::int32_t>(n));
1094 }
1095 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
1096 {
1097 if (add_prefix)
1098 {
1099 oa->write_character(to_char_type('L')); // int64
1100 }
1101 write_number(static_cast<std::int64_t>(n));
1102 }
1103 else
1104 {
1105 JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64"));
1106 }
1107 }
1108
1109 // UBJSON: write number (signed integer)
1110 template<typename NumberType, typename std::enable_if<
1111 std::is_signed<NumberType>::value and
1112 not std::is_floating_point<NumberType>::value, int>::type = 0>
1113 void write_number_with_ubjson_prefix(const NumberType n,
1114 const bool add_prefix)
1115 {
1116 if ((std::numeric_limits<std::int8_t>::min)() <= n and n <= (std::numeric_limits<std::int8_t>::max)())
1117 {
1118 if (add_prefix)
1119 {
1120 oa->write_character(to_char_type('i')); // int8
1121 }
1122 write_number(static_cast<std::int8_t>(n));
1123 }
1124 else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n and n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
1125 {
1126 if (add_prefix)
1127 {
1128 oa->write_character(to_char_type('U')); // uint8
1129 }
1130 write_number(static_cast<std::uint8_t>(n));
1131 }
1132 else if ((std::numeric_limits<std::int16_t>::min)() <= n and n <= (std::numeric_limits<std::int16_t>::max)())
1133 {
1134 if (add_prefix)
1135 {
1136 oa->write_character(to_char_type('I')); // int16
1137 }
1138 write_number(static_cast<std::int16_t>(n));
1139 }
1140 else if ((std::numeric_limits<std::int32_t>::min)() <= n and n <= (std::numeric_limits<std::int32_t>::max)())
1141 {
1142 if (add_prefix)
1143 {
1144 oa->write_character(to_char_type('l')); // int32
1145 }
1146 write_number(static_cast<std::int32_t>(n));
1147 }
1148 else if ((std::numeric_limits<std::int64_t>::min)() <= n and n <= (std::numeric_limits<std::int64_t>::max)())
1149 {
1150 if (add_prefix)
1151 {
1152 oa->write_character(to_char_type('L')); // int64
1153 }
1154 write_number(static_cast<std::int64_t>(n));
1155 }
1156 // LCOV_EXCL_START
1157 else
1158 {
1159 JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(n) + " cannot be represented by UBJSON as it does not fit int64"));
1160 }
1161 // LCOV_EXCL_STOP
1162 }
1163
1164 /*!
1165 @brief determine the type prefix of container values
1166
1167 @note This function does not need to be 100% accurate when it comes to
1168 integer limits. In case a number exceeds the limits of int64_t,
1169 this will be detected by a later call to function
1170 write_number_with_ubjson_prefix. Therefore, we return 'L' for any
1171 value that does not fit the previous limits.
1172 */
1173 CharType ubjson_prefix(const BasicJsonType& j) const noexcept
1174 {
1175 switch (j.type())
1176 {
1177 case value_t::null:
1178 return 'Z';
1179
1180 case value_t::boolean:
1181 return j.m_value.boolean ? 'T' : 'F';
1182
1183 case value_t::number_integer:
1184 {
1185 if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
1186 {
1187 return 'i';
1188 }
1189 if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
1190 {
1191 return 'U';
1192 }
1193 if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
1194 {
1195 return 'I';
1196 }
1197 if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
1198 {
1199 return 'l';
1200 }
1201 // no check and assume int64_t (see note above)
1202 return 'L';
1203 }
1204
1205 case value_t::number_unsigned:
1206 {
1207 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
1208 {
1209 return 'i';
1210 }
1211 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
1212 {
1213 return 'U';
1214 }
1215 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
1216 {
1217 return 'I';
1218 }
1219 if (j.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
1220 {
1221 return 'l';
1222 }
1223 // no check and assume int64_t (see note above)
1224 return 'L';
1225 }
1226
1227 case value_t::number_float:
1228 return get_ubjson_float_prefix(j.m_value.number_float);
1229
1230 case value_t::string:
1231 return 'S';
1232
1233 case value_t::array:
1234 return '[';
1235
1236 case value_t::object:
1237 return '{';
1238
1239 default: // discarded values
1240 return 'N';
1241 }
1242 }
1243
1244 static constexpr CharType get_ubjson_float_prefix(float /*unused*/)
1245 {
1246 return 'd'; // float 32
1247 }
1248
1249 static constexpr CharType get_ubjson_float_prefix(double /*unused*/)
1250 {
1251 return 'D'; // float 64
1252 }
1253
1254 ///////////////////////
1255 // Utility functions //
1256 ///////////////////////
1257
1258 /*
1259 @brief write a number to output input
1260 @param[in] n number of type @a NumberType
1261 @tparam NumberType the type of the number
1262 @tparam OutputIsLittleEndian Set to true if output data is
1263 required to be little endian
1264
1265 @note This function needs to respect the system's endianess, because bytes
1266 in CBOR, MessagePack, and UBJSON are stored in network order (big
1267 endian) and therefore need reordering on little endian systems.
1268 */
1269 template<typename NumberType, bool OutputIsLittleEndian = false>
1270 void write_number(const NumberType n)
1271 {
1272 // step 1: write number to array of length NumberType
1273 std::array<CharType, sizeof(NumberType)> vec;
1274 std::memcpy(vec.data(), &n, sizeof(NumberType));
1275
1276 // step 2: write array to output (with possible reordering)
1277 if (is_little_endian != OutputIsLittleEndian)
1278 {
1279 // reverse byte order prior to conversion if necessary
1280 std::reverse(vec.begin(), vec.end());
1281 }
1282
1283 oa->write_characters(vec.data(), sizeof(NumberType));
1284 }
1285
1286 public:
1287 // The following to_char_type functions are implement the conversion
1288 // between uint8_t and CharType. In case CharType is not unsigned,
1289 // such a conversion is required to allow values greater than 128.
1290 // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
1291 template < typename C = CharType,
1292 enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >
1293 static constexpr CharType to_char_type(std::uint8_t x) noexcept
1294 {
1295 return *reinterpret_cast<char*>(&x);
1296 }
1297
1298 template < typename C = CharType,
1299 enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >
1300 static CharType to_char_type(std::uint8_t x) noexcept
1301 {
1302 static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
1303 static_assert(std::is_pod<CharType>::value, "CharType must be POD");
1304 CharType result;
1305 std::memcpy(&result, &x, sizeof(x));
1306 return result;
1307 }
1308
1309 template<typename C = CharType,
1310 enable_if_t<std::is_unsigned<C>::value>* = nullptr>
1311 static constexpr CharType to_char_type(std::uint8_t x) noexcept
1312 {
1313 return x;
1314 }
1315
1316 template < typename InputCharType, typename C = CharType,
1317 enable_if_t <
1318 std::is_signed<C>::value and
1319 std::is_signed<char>::value and
1320 std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
1321 > * = nullptr >
1322 static constexpr CharType to_char_type(InputCharType x) noexcept
1323 {
1324 return x;
1325 }
1326
1327 private:
1328 /// whether we can assume little endianess
1329 const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
1330
1331 /// the output
1332 output_adapter_t<CharType> oa = nullptr;
1333};
1334} // namespace detail
1335} // namespace nlohmann
1336