// Copyright 2018 Daniel Parker // Distributed under the Boost license, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See https://github.com/danielaparker/jsoncons for latest version #ifndef JSONCONS_CBOR_CBOR_ENCODER_HPP #define JSONCONS_CBOR_CBOR_ENCODER_HPP #include #include #include // std::numeric_limits #include #include // std::move #include // jsoncons::ser_error #include #include #include #include #include #include namespace jsoncons { namespace cbor { enum class cbor_container_type {object, indefinite_length_object, array, indefinite_length_array}; template> class basic_cbor_encoder final : public basic_json_visitor { using super_type = basic_json_visitor; enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 }; enum class hexfloat_parse_state { start, expect_0, expect_x, integer, exp1, exp2, fraction1 }; static constexpr int64_t nanos_in_second = 1000000000; static constexpr int64_t millis_in_second = 1000; public: using allocator_type = Allocator; using sink_type = Sink; using typename super_type::char_type; using typename super_type::string_view_type; private: using char_allocator_type = typename std::allocator_traits:: template rebind_alloc; using byte_allocator_type = typename std::allocator_traits:: template rebind_alloc; using string_type = std::basic_string,char_allocator_type>; using byte_string_type = basic_byte_string; struct stack_item { cbor_container_type type_; std::size_t length_; std::size_t count_; stack_item(cbor_container_type type, std::size_t length = 0) noexcept : type_(type), length_(length), count_(0) { } std::size_t length() const { return length_; } std::size_t count() const { return count_; } bool is_object() const { return type_ == cbor_container_type::object || type_ == cbor_container_type::indefinite_length_object; } bool is_indefinite_length() const { return type_ == cbor_container_type::indefinite_length_array || type_ == cbor_container_type::indefinite_length_object; } }; typedef typename std::allocator_traits:: template rebind_alloc> string_size_allocator_type; typedef typename std::allocator_traits:: template rebind_alloc> byte_string_size_allocator_type; typedef typename std::allocator_traits:: template rebind_alloc stack_item_allocator_type; Sink sink_; const cbor_encode_options options_; allocator_type alloc_; std::vector stack_; std::map,string_size_allocator_type> stringref_map_; std::map,byte_string_size_allocator_type> bytestringref_map_; std::size_t next_stringref_ = 0; int nesting_depth_; // Noncopyable and nonmoveable basic_cbor_encoder(const basic_cbor_encoder&) = delete; basic_cbor_encoder& operator=(const basic_cbor_encoder&) = delete; public: explicit basic_cbor_encoder(Sink&& sink, const Allocator& alloc = Allocator()) : basic_cbor_encoder(std::forward(sink), cbor_encode_options(), alloc) { } basic_cbor_encoder(Sink&& sink, const cbor_encode_options& options, const Allocator& alloc = Allocator()) : sink_(std::forward(sink)), options_(options), alloc_(alloc), stack_(alloc), #if !defined(JSONCONS_NO_MAP_CONS_TAKES_ALLOCATOR) stringref_map_(alloc), bytestringref_map_(alloc), #endif nesting_depth_(0) { if (options.pack_strings()) { write_tag(256); } } ~basic_cbor_encoder() noexcept { JSONCONS_TRY { sink_.flush(); } JSONCONS_CATCH(...) { } } void reset() { stack_.clear(); stringref_map_.clear(); bytestringref_map_.clear(); next_stringref_ = 0; nesting_depth_ = 0; } void reset(Sink&& sink) { sink_ = std::move(sink); reset(); } private: // Implementing methods void visit_flush() override { sink_.flush(); } bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override { if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) { ec = cbor_errc::max_nesting_depth_exceeded; return false; } stack_.emplace_back(cbor_container_type::indefinite_length_object); sink_.push_back(0xbf); return true; } bool visit_begin_object(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override { if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) { ec = cbor_errc::max_nesting_depth_exceeded; return false; } stack_.emplace_back(cbor_container_type::object, length); if (length <= 0x17) { binary::native_to_big(static_cast(0xa0 + length), std::back_inserter(sink_)); } else if (length <= 0xff) { binary::native_to_big(static_cast(0xb8), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffff) { binary::native_to_big(static_cast(0xb9), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffffffff) { binary::native_to_big(static_cast(0xba), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffffffffffffffff) { binary::native_to_big(static_cast(0xbb), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } return true; } bool visit_end_object(const ser_context&, std::error_code& ec) override { JSONCONS_ASSERT(!stack_.empty()); --nesting_depth_; if (stack_.back().is_indefinite_length()) { sink_.push_back(0xff); } else { if (stack_.back().count() < stack_.back().length()) { ec = cbor_errc::too_few_items; return false; } if (stack_.back().count() > stack_.back().length()) { ec = cbor_errc::too_many_items; return false; } } stack_.pop_back(); end_value(); return true; } bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override { if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) { ec = cbor_errc::max_nesting_depth_exceeded; return false; } stack_.emplace_back(cbor_container_type::indefinite_length_array); sink_.push_back(0x9f); return true; } bool visit_begin_array(std::size_t length, semantic_tag, const ser_context&, std::error_code& ec) override { if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth())) { ec = cbor_errc::max_nesting_depth_exceeded; return false; } stack_.emplace_back(cbor_container_type::array, length); if (length <= 0x17) { binary::native_to_big(static_cast(0x80 + length), std::back_inserter(sink_)); } else if (length <= 0xff) { binary::native_to_big(static_cast(0x98), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffff) { binary::native_to_big(static_cast(0x99), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffffffff) { binary::native_to_big(static_cast(0x9a), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffffffffffffffff) { binary::native_to_big(static_cast(0x9b), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } return true; } bool visit_end_array(const ser_context&, std::error_code& ec) override { JSONCONS_ASSERT(!stack_.empty()); --nesting_depth_; if (stack_.back().is_indefinite_length()) { sink_.push_back(0xff); } else { if (stack_.back().count() < stack_.back().length()) { ec = cbor_errc::too_few_items; return false; } if (stack_.back().count() > stack_.back().length()) { ec = cbor_errc::too_many_items; return false; } } stack_.pop_back(); end_value(); return true; } bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override { write_string(name); return true; } bool visit_null(semantic_tag tag, const ser_context&, std::error_code&) override { if (tag == semantic_tag::undefined) { sink_.push_back(0xf7); } else { sink_.push_back(0xf6); } end_value(); return true; } void write_string(const string_view& sv) { auto sink = unicode_traits::validate(sv.data(), sv.size()); if (sink.ec != unicode_traits::conv_errc()) { JSONCONS_THROW(ser_error(cbor_errc::invalid_utf8_text_string)); } if (options_.pack_strings() && sv.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_)) { string_type s(sv.data(), sv.size(), alloc_); auto it = stringref_map_.find(s); if (it == stringref_map_.end()) { stringref_map_.emplace(std::make_pair(std::move(s), next_stringref_++)); write_utf8_string(sv); } else { write_tag(25); write_uint64_value(it->second); } } else { write_utf8_string(sv); } } void write_utf8_string(const string_view& sv) { const size_t length = sv.size(); if (length <= 0x17) { // fixstr stores a byte array whose length is upto 31 bytes binary::native_to_big(static_cast(0x60 + length), std::back_inserter(sink_)); } else if (length <= 0xff) { binary::native_to_big(static_cast(0x78), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffff) { binary::native_to_big(static_cast(0x79), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffffffff) { binary::native_to_big(static_cast(0x7a), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffffffffffffffff) { binary::native_to_big(static_cast(0x7b), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } for (auto c : sv) { sink_.push_back(c); } } void write_bignum(bigint& n) { bool is_neg = n < 0; if (is_neg) { n = - n -1; } int signum; std::vector data; n.write_bytes_be(signum, data); std::size_t length = data.size(); if (is_neg) { write_tag(3); } else { write_tag(2); } if (length <= 0x17) { // fixstr stores a byte array whose length is upto 31 bytes binary::native_to_big(static_cast(0x40 + length), std::back_inserter(sink_)); } else if (length <= 0xff) { binary::native_to_big(static_cast(0x58), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffff) { binary::native_to_big(static_cast(0x59), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffffffff) { binary::native_to_big(static_cast(0x5a), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } else if (length <= 0xffffffffffffffff) { binary::native_to_big(static_cast(0x5b), std::back_inserter(sink_)); binary::native_to_big(static_cast(length), std::back_inserter(sink_)); } for (auto c : data) { sink_.push_back(c); } } bool write_decimal_value(const string_view_type& sv, const ser_context& context, std::error_code& ec) { bool more = true; decimal_parse_state state = decimal_parse_state::start; std::basic_string s; std::basic_string exponent; int64_t scale = 0; for (auto c : sv) { switch (state) { case decimal_parse_state::start: { switch (c) { case '-': s.push_back(c); state = decimal_parse_state::integer; break; case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': s.push_back(c); state = decimal_parse_state::integer; break; default: { ec = cbor_errc::invalid_decimal_fraction; return false; } } break; } case decimal_parse_state::integer: { switch (c) { case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': s.push_back(c); break; case 'e': case 'E': state = decimal_parse_state::exp1; break; case '.': state = decimal_parse_state::fraction1; break; default: { ec = cbor_errc::invalid_decimal_fraction; return false; } } break; } case decimal_parse_state::exp1: { switch (c) { case '+': state = decimal_parse_state::exp2; break; case '-': exponent.push_back(c); state = decimal_parse_state::exp2; break; case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': exponent.push_back(c); state = decimal_parse_state::exp2; break; default: { ec = cbor_errc::invalid_decimal_fraction; return false; } } break; } case decimal_parse_state::exp2: { switch (c) { case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': exponent.push_back(c); break; default: { ec = cbor_errc::invalid_decimal_fraction; return false; } } break; } case decimal_parse_state::fraction1: { switch (c) { case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': s.push_back(c); --scale; break; default: { ec = cbor_errc::invalid_decimal_fraction; return false; } } break; } } } write_tag(4); more = visit_begin_array((std::size_t)2, semantic_tag::none, context, ec); if (!more) {return more;} if (exponent.length() > 0) { int64_t val; auto r = jsoncons::detail::to_integer(exponent.data(), exponent.length(), val); if (!r) { ec = r.error_code(); return false; } scale += val; } more = visit_int64(scale, semantic_tag::none, context, ec); if (!more) {return more;} int64_t val{ 0 }; auto r = jsoncons::detail::to_integer(s.data(),s.length(), val); if (r) { more = visit_int64(val, semantic_tag::none, context, ec); if (!more) {return more;} } else if (r.error_code() == jsoncons::detail::to_integer_errc::overflow) { bigint n = bigint::from_string(s.data(), s.length()); write_bignum(n); end_value(); } else { ec = r.error_code(); return false; } more = visit_end_array(context, ec); return more; } bool write_hexfloat_value(const string_view_type& sv, const ser_context& context, std::error_code& ec) { bool more = true; hexfloat_parse_state state = hexfloat_parse_state::start; std::basic_string s; std::basic_string exponent; int64_t scale = 0; for (auto c : sv) { switch (state) { case hexfloat_parse_state::start: { switch (c) { case '-': s.push_back(c); state = hexfloat_parse_state::expect_0; break; case '0': state = hexfloat_parse_state::expect_x; break; default: { ec = cbor_errc::invalid_bigfloat; return false; } } break; } case hexfloat_parse_state::expect_0: { switch (c) { case '0': state = hexfloat_parse_state::expect_x; break; default: { ec = cbor_errc::invalid_bigfloat; return false; } } break; } case hexfloat_parse_state::expect_x: { switch (c) { case 'x': case 'X': state = hexfloat_parse_state::integer; break; default: { ec = cbor_errc::invalid_bigfloat; return false; } } break; } case hexfloat_parse_state::integer: { switch (c) { case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': s.push_back(c); break; case 'p': case 'P': state = hexfloat_parse_state::exp1; break; case '.': state = hexfloat_parse_state::fraction1; break; default: { ec = cbor_errc::invalid_bigfloat; return false; } } break; } case hexfloat_parse_state::exp1: { switch (c) { case '+': state = hexfloat_parse_state::exp2; break; case '-': exponent.push_back(c); state = hexfloat_parse_state::exp2; break; case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': exponent.push_back(c); state = hexfloat_parse_state::exp2; break; default: { ec = cbor_errc::invalid_bigfloat; return false; } } break; } case hexfloat_parse_state::exp2: { switch (c) { case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': exponent.push_back(c); break; default: { ec = cbor_errc::invalid_bigfloat; return false; } } break; } case hexfloat_parse_state::fraction1: { switch (c) { case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9':case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': s.push_back(c); scale -= 4; break; default: { ec = cbor_errc::invalid_bigfloat; return false; } } break; } } } write_tag(5); more = visit_begin_array((std::size_t)2, semantic_tag::none, context, ec); if (!more) return more; if (exponent.length() > 0) { int64_t val{ 0 }; auto r = jsoncons::detail::base16_to_integer(exponent.data(), exponent.length(), val); if (!r) { ec = r.error_code(); return false; } scale += val; } more = visit_int64(scale, semantic_tag::none, context, ec); if (!more) return more; int64_t val{ 0 }; auto r = jsoncons::detail::base16_to_integer(s.data(),s.length(), val); if (r) { more = visit_int64(val, semantic_tag::none, context, ec); if (!more) return more; } else if (r.error_code() == jsoncons::detail::to_integer_errc::overflow) { bigint n = bigint::from_string_radix(s.data(), s.length(), 16); write_bignum(n); end_value(); } else { JSONCONS_THROW(json_runtime_error(r.error_code().message())); } return visit_end_array(context, ec); } bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context& context, std::error_code& ec) override { switch (tag) { case semantic_tag::bigint: { bigint n = bigint::from_string(sv.data(), sv.length()); write_bignum(n); end_value(); break; } case semantic_tag::bigdec: { return write_decimal_value(sv, context, ec); } case semantic_tag::bigfloat: { return write_hexfloat_value(sv, context, ec); } case semantic_tag::datetime: { write_tag(0); write_string(sv); end_value(); break; } case semantic_tag::uri: { write_tag(32); write_string(sv); end_value(); break; } case semantic_tag::base64url: { write_tag(33); write_string(sv); end_value(); break; } case semantic_tag::base64: { write_tag(34); write_string(sv); end_value(); break; } default: { write_string(sv); end_value(); break; } } return true; } bool visit_byte_string(const byte_string_view& b, semantic_tag tag, const ser_context&, std::error_code&) override { byte_string_chars_format encoding_hint; switch (tag) { case semantic_tag::base16: encoding_hint = byte_string_chars_format::base16; break; case semantic_tag::base64: encoding_hint = byte_string_chars_format::base64; break; case semantic_tag::base64url: encoding_hint = byte_string_chars_format::base64url; break; default: encoding_hint = byte_string_chars_format::none; break; } switch (encoding_hint) { case byte_string_chars_format::base64url: write_tag(21); break; case byte_string_chars_format::base64: write_tag(22); break; case byte_string_chars_format::base16: write_tag(23); break; default: break; } if (options_.pack_strings() && b.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_)) { byte_string_type bs(b.data(), b.size(), alloc_); auto it = bytestringref_map_.find(bs); if (it == bytestringref_map_.end()) { bytestringref_map_.emplace(std::make_pair(bs, next_stringref_++)); write_byte_string_value(bs); } else { write_tag(25); write_uint64_value(it->second); } } else { write_byte_string_value(b); } end_value(); return true; } bool visit_byte_string(const byte_string_view& b, uint64_t ext_tag, const ser_context&, std::error_code&) override { if (options_.pack_strings() && b.size() >= jsoncons::cbor::detail::min_length_for_stringref(next_stringref_)) { byte_string_type bs(b.data(), b.size(), alloc_); auto it = bytestringref_map_.find(bs); if (it == bytestringref_map_.end()) { bytestringref_map_.emplace(std::make_pair(bs, next_stringref_++)); write_tag(ext_tag); write_byte_string_value(bs); } else { write_tag(25); write_uint64_value(it->second); } } else { write_tag(ext_tag); write_byte_string_value(b); } end_value(); return true; } void write_byte_string_value(const byte_string_view& b) { if (b.size() <= 0x17) { // fixstr stores a byte array whose length is upto 31 bytes binary::native_to_big(static_cast(0x40 + b.size()), std::back_inserter(sink_)); } else if (b.size() <= 0xff) { binary::native_to_big(static_cast(0x58), std::back_inserter(sink_)); binary::native_to_big(static_cast(b.size()), std::back_inserter(sink_)); } else if (b.size() <= 0xffff) { binary::native_to_big(static_cast(0x59), std::back_inserter(sink_)); binary::native_to_big(static_cast(b.size()), std::back_inserter(sink_)); } else if (b.size() <= 0xffffffff) { binary::native_to_big(static_cast(0x5a), std::back_inserter(sink_)); binary::native_to_big(static_cast(b.size()), std::back_inserter(sink_)); } else // if (b.size() <= 0xffffffffffffffff) { binary::native_to_big(static_cast(0x5b), std::back_inserter(sink_)); binary::native_to_big(static_cast(b.size()), std::back_inserter(sink_)); } for (auto c : b) { sink_.push_back(c); } } bool visit_double(double val, semantic_tag tag, const ser_context&, std::error_code&) override { switch (tag) { case semantic_tag::epoch_second: write_tag(1); break; case semantic_tag::epoch_milli: write_tag(1); if (val != 0) { val /= millis_in_second; } break; case semantic_tag::epoch_nano: write_tag(1); if (val != 0) { val /= nanos_in_second; } break; default: break; } float valf = (float)val; if ((double)valf == val) { binary::native_to_big(static_cast(0xfa), std::back_inserter(sink_)); binary::native_to_big(valf, std::back_inserter(sink_)); } else { binary::native_to_big(static_cast(0xfb), std::back_inserter(sink_)); binary::native_to_big(val, std::back_inserter(sink_)); } // write double end_value(); return true; } bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { switch (tag) { case semantic_tag::epoch_milli: case semantic_tag::epoch_nano: return visit_double(static_cast(value), tag, context, ec); case semantic_tag::epoch_second: write_tag(1); break; default: break; } if (value >= 0) { if (value <= 0x17) { binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } else if (value <= (std::numeric_limits::max)()) { binary::native_to_big(static_cast(0x18), std::back_inserter(sink_)); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } else if (value <= (std::numeric_limits::max)()) { binary::native_to_big(static_cast(0x19), std::back_inserter(sink_)); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } else if (value <= (std::numeric_limits::max)()) { binary::native_to_big(static_cast(0x1a), std::back_inserter(sink_)); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } else if (value <= (std::numeric_limits::max)()) { binary::native_to_big(static_cast(0x1b), std::back_inserter(sink_)); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } } else { const auto posnum = -1 - value; if (value >= -24) { binary::native_to_big(static_cast(0x20 + posnum), std::back_inserter(sink_)); } else if (posnum <= (std::numeric_limits::max)()) { binary::native_to_big(static_cast(0x38), std::back_inserter(sink_)); binary::native_to_big(static_cast(posnum), std::back_inserter(sink_)); } else if (posnum <= (std::numeric_limits::max)()) { binary::native_to_big(static_cast(0x39), std::back_inserter(sink_)); binary::native_to_big(static_cast(posnum), std::back_inserter(sink_)); } else if (posnum <= (std::numeric_limits::max)()) { binary::native_to_big(static_cast(0x3a), std::back_inserter(sink_)); binary::native_to_big(static_cast(posnum), std::back_inserter(sink_)); } else if (posnum <= (std::numeric_limits::max)()) { binary::native_to_big(static_cast(0x3b), std::back_inserter(sink_)); binary::native_to_big(static_cast(posnum), std::back_inserter(sink_)); } } end_value(); return true; } bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override { switch (tag) { case semantic_tag::epoch_milli: case semantic_tag::epoch_nano: return visit_double(static_cast(value), tag, context, ec); case semantic_tag::epoch_second: write_tag(1); break; default: break; } write_uint64_value(value); end_value(); return true; } void write_tag(uint64_t value) { if (value <= 0x17) { sink_.push_back(0xc0 | static_cast(value)); } else if (value <=(std::numeric_limits::max)()) { sink_.push_back(0xd8); sink_.push_back(static_cast(value)); } else if (value <=(std::numeric_limits::max)()) { sink_.push_back(0xd9); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } else if (value <=(std::numeric_limits::max)()) { sink_.push_back(0xda); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } else { sink_.push_back(0xdb); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } } void write_uint64_value(uint64_t value) { if (value <= 0x17) { sink_.push_back(static_cast(value)); } else if (value <=(std::numeric_limits::max)()) { sink_.push_back(static_cast(0x18)); sink_.push_back(static_cast(value)); } else if (value <=(std::numeric_limits::max)()) { sink_.push_back(static_cast(0x19)); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } else if (value <=(std::numeric_limits::max)()) { sink_.push_back(static_cast(0x1a)); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } else if (value <=(std::numeric_limits::max)()) { sink_.push_back(static_cast(0x1b)); binary::native_to_big(static_cast(value), std::back_inserter(sink_)); } } bool visit_bool(bool value, semantic_tag, const ser_context&, std::error_code&) override { if (value) { sink_.push_back(0xf5); } else { sink_.push_back(0xf4); } end_value(); return true; } bool visit_typed_array(const jsoncons::span& v, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { switch (tag) { case semantic_tag::clamped: write_tag(0x44); break; default: write_tag(0x40); break; } write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(v.size(), semantic_tag::none, context, ec); for (auto p = v.begin(); more && p != v.end(); ++p) { more = this->uint64_value(*p, tag, context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), uint16_t(), tag); std::vector v(data.size()*sizeof(uint16_t)); std::memcpy(v.data(),data.data(),data.size()*sizeof(uint16_t)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none, context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->uint64_value(*p, tag, context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), uint32_t(), tag); std::vector v(data.size()*sizeof(uint32_t)); std::memcpy(v.data(), data.data(), data.size()*sizeof(uint32_t)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none, context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->uint64_value(*p, semantic_tag::none, context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), uint64_t(), tag); std::vector v(data.size()*sizeof(uint64_t)); std::memcpy(v.data(), data.data(), data.size()*sizeof(uint64_t)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none, context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->uint64_value(*p,semantic_tag::none,context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_tag(0x48); std::vector v(data.size()*sizeof(int8_t)); std::memcpy(v.data(), data.data(), data.size()*sizeof(int8_t)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->int64_value(*p,semantic_tag::none,context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), int16_t(), tag); std::vector v(data.size()*sizeof(int16_t)); std::memcpy(v.data(), data.data(), data.size()*sizeof(int16_t)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->int64_value(*p,semantic_tag::none,context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), int32_t(), tag); std::vector v(data.size()*sizeof(int32_t)); std::memcpy(v.data(), data.data(), data.size()*sizeof(int32_t)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->int64_value(*p,semantic_tag::none,context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), int64_t(), tag); std::vector v(data.size()*sizeof(int64_t)); std::memcpy(v.data(), data.data(), data.size()*sizeof(int64_t)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->int64_value(*p,semantic_tag::none,context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(half_arg_t, const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), half_arg, tag); std::vector v(data.size()*sizeof(uint16_t)); std::memcpy(v.data(),data.data(),data.size()*sizeof(uint16_t)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none, context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->half_value(*p, tag, context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), float(), tag); std::vector v(data.size()*sizeof(float)); std::memcpy(v.data(), data.data(), data.size()*sizeof(float)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->double_value(*p,semantic_tag::none,context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } bool visit_typed_array(const jsoncons::span& data, semantic_tag tag, const ser_context& context, std::error_code& ec) override { if (options_.use_typed_arrays()) { write_typed_array_tag(std::integral_constant(), double(), tag); std::vector v(data.size()*sizeof(double)); std::memcpy(v.data(), data.data(), data.size()*sizeof(double)); write_byte_string_value(byte_string_view(v)); return true; } else { bool more = this->begin_array(data.size(), semantic_tag::none,context, ec); for (auto p = data.begin(); more && p != data.end(); ++p) { more = this->double_value(*p,semantic_tag::none,context, ec); } if (more) { more = this->end_array(context, ec); } return more; } } /* bool visit_typed_array(const jsoncons::span&, semantic_tag, const ser_context&, std::error_code&) override { return true; } */ bool visit_begin_multi_dim(const jsoncons::span& shape, semantic_tag tag, const ser_context& context, std::error_code& ec) override { switch (tag) { case semantic_tag::multi_dim_column_major: write_tag(1040); break; default: write_tag(40); break; } bool more = visit_begin_array(2, semantic_tag::none, context, ec); if (more) more = visit_begin_array(shape.size(), semantic_tag::none, context, ec); for (auto it = shape.begin(); more && it != shape.end(); ++it) { more = visit_uint64(*it, semantic_tag::none, context, ec); } if (more) { more = visit_end_array(context, ec); } return more; } bool visit_end_multi_dim(const ser_context& context, std::error_code& ec) override { bool more = visit_end_array(context, ec); return more; } void write_typed_array_tag(std::true_type, uint16_t, semantic_tag) { write_tag(0x41); // big endian } void write_typed_array_tag(std::false_type, uint16_t, semantic_tag) { write_tag(0x45); } void write_typed_array_tag(std::true_type, uint32_t, semantic_tag) { write_tag(0x42); // big endian } void write_typed_array_tag(std::false_type, uint32_t, semantic_tag) { write_tag(0x46); // little endian } void write_typed_array_tag(std::true_type, uint64_t, semantic_tag) { write_tag(0x43); // big endian } void write_typed_array_tag(std::false_type, uint64_t, semantic_tag) { write_tag(0x47); // little endian } void write_typed_array_tag(std::true_type, int16_t, semantic_tag) { write_tag(0x49); // big endian } void write_typed_array_tag(std::false_type, int16_t, semantic_tag) { write_tag(0x4d); // little endian } void write_typed_array_tag(std::true_type, int32_t, semantic_tag) { write_tag(0x4a); // big endian } void write_typed_array_tag(std::false_type, int32_t, semantic_tag) { write_tag(0x4e); // little endian } void write_typed_array_tag(std::true_type, int64_t, semantic_tag) { write_tag(0x4b); // big endian } void write_typed_array_tag(std::false_type, int64_t, semantic_tag) { write_tag(0x4f); // little endian } void write_typed_array_tag(std::true_type, half_arg_t, semantic_tag) { write_tag(0x50); } void write_typed_array_tag(std::false_type, half_arg_t, semantic_tag) { write_tag(0x54); } void write_typed_array_tag(std::true_type, float, semantic_tag) { write_tag(0x51); // big endian } void write_typed_array_tag(std::false_type, float, semantic_tag) { write_tag(0x55); // little endian } void write_typed_array_tag(std::true_type, double, semantic_tag) { write_tag(0x52); // big endian } void write_typed_array_tag(std::false_type, double, semantic_tag) { write_tag(0x56); // little endian } void end_value() { if (!stack_.empty()) { ++stack_.back().count_; } } }; using cbor_stream_encoder = basic_cbor_encoder; using cbor_bytes_encoder = basic_cbor_encoder>>; #if !defined(JSONCONS_NO_DEPRECATED) JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_encoder") typedef cbor_bytes_encoder cbor_bytes_serializer; template using basic_cbor_serializer = basic_cbor_encoder; JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_encoder") typedef cbor_stream_encoder cbor_encoder; JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_encoder") typedef cbor_stream_encoder cbor_serializer; JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_encoder") typedef cbor_bytes_encoder cbor_buffer_serializer; #endif }} #endif