Horizon
binary_writer.hpp
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 
14 namespace nlohmann
15 {
16 namespace detail
17 {
19 // binary writer //
21 
25 template<typename BasicJsonType, typename CharType>
27 {
28  using string_t = typename BasicJsonType::string_t;
29 
30  public:
36  explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)
37  {
38  assert(oa);
39  }
40 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
577  {
578  write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);
579  break;
580  }
581 
583  {
584  write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);
585  break;
586  }
587 
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:
708  // BSON //
710 
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 
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 
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 
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 
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 
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 
784  void write_bson_null(const string_t& name)
785  {
786  write_bson_entry_header(name, 0x0A);
787  }
788 
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 
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 
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 
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 
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 
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 
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 
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 
913  return header_size + 8ul;
914 
916  return header_size + calc_bson_integer_size(j.m_value.number_integer);
917 
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 
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 
957  return write_bson_double(name, j.m_value.number_float);
958 
960  return write_bson_integer(name, j.m_value.number_integer);
961 
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 
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 
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 
1013  // CBOR //
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 
1027  // MsgPack //
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 
1041  // UBJSON //
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 
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 
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 
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 
1255  // Utility functions //
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:
1329  const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();
1330 
1332  output_adapter_t<CharType> oa = nullptr;
1333 };
1334 } // namespace detail
1335 } // namespace nlohmann
nlohmann::detail::binary_writer::write_cbor
void write_cbor(const BasicJsonType &j)
Definition: binary_writer.hpp:65
nlohmann::detail::value_t::null
@ null
null value
libzip::uint8_t
zip_uint8_t uint8_t
zip_uint8_t typedef.
Definition: zip.hpp:78
nlohmann::detail::value_t::object
@ object
object (unordered set of name/value pairs)
nlohmann::detail::binary_writer::write_msgpack
void write_msgpack(const BasicJsonType &j)
Definition: binary_writer.hpp:309
nlohmann::detail::binary_writer::write_ubjson
void write_ubjson(const BasicJsonType &j, const bool use_count, const bool use_type, const bool add_prefix=true)
Definition: binary_writer.hpp:551
nlohmann
namespace for Niels Lohmann
Definition: adl_serializer.hpp:9
nlohmann::detail::binary_writer
serialization to CBOR and MessagePack values
Definition: binary_writer.hpp:27
libzip::uint32_t
zip_uint32_t uint32_t
zip_uint32_t typedef.
Definition: zip.hpp:98
nlohmann::detail::value_t::number_float
@ number_float
number value (floating-point)
nlohmann::detail::value_t::number_integer
@ number_integer
number value (signed integer)
libzip::int32_t
zip_int32_t int32_t
zip_int32_t typedef.
Definition: zip.hpp:93
nlohmann::detail::value_t::string
@ string
string value
nlohmann::detail::binary_reader::little_endianess
static constexpr bool little_endianess(int num=1) noexcept
determine system byte order
Definition: binary_reader.hpp:128
libzip::int64_t
zip_int64_t int64_t
zip_int64_t typedef.
Definition: zip.hpp:103
nlohmann::detail::output_adapter_t
std::shared_ptr< output_adapter_protocol< CharType > > output_adapter_t
a type to simplify interfaces
Definition: output_adapters.hpp:27
nlohmann::detail::value_t::number_unsigned
@ number_unsigned
number value (unsigned integer)
nlohmann::detail::value_t::array
@ array
array (ordered collection of values)
nlohmann::detail::value_t::boolean
@ boolean
boolean value
libzip::int8_t
zip_int8_t int8_t
zip_int8_t typedef.
Definition: zip.hpp:73
libzip::int16_t
zip_int16_t int16_t
zip_int16_t typedef.
Definition: zip.hpp:83
libzip::uint16_t
zip_uint16_t uint16_t
zip_uint16_t typedef.
Definition: zip.hpp:88
nlohmann::detail::binary_writer::binary_writer
binary_writer(output_adapter_t< CharType > adapter)
create a binary writer
Definition: binary_writer.hpp:36
nlohmann::detail::binary_writer::write_bson
void write_bson(const BasicJsonType &j)
Definition: binary_writer.hpp:45
libzip::uint64_t
zip_uint64_t uint64_t
zip_uint64_t_t typedef.
Definition: zip.hpp:108