aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons_ext/cbor
diff options
context:
space:
mode:
authorRichard <q@1bpm.net>2022-09-04 00:32:56 +0100
committerRichard <q@1bpm.net>2022-09-04 00:32:56 +0100
commit1d055261b4144dbf86b2658437015b15d4dd9bff (patch)
tree6049b19d1bf953a650383de1a5e438b8b82679f6 /include/jsoncons_ext/cbor
downloadcsound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.tar.gz
csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.tar.bz2
csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.zip
initial
Diffstat (limited to 'include/jsoncons_ext/cbor')
-rw-r--r--include/jsoncons_ext/cbor/cbor.hpp26
-rw-r--r--include/jsoncons_ext/cbor/cbor_cursor.hpp351
-rw-r--r--include/jsoncons_ext/cbor/cbor_cursor2.hpp265
-rw-r--r--include/jsoncons_ext/cbor/cbor_detail.hpp93
-rw-r--r--include/jsoncons_ext/cbor/cbor_encoder.hpp1766
-rw-r--r--include/jsoncons_ext/cbor/cbor_error.hpp105
-rw-r--r--include/jsoncons_ext/cbor/cbor_options.hpp113
-rw-r--r--include/jsoncons_ext/cbor/cbor_parser.hpp1942
-rw-r--r--include/jsoncons_ext/cbor/cbor_reader.hpp116
-rw-r--r--include/jsoncons_ext/cbor/decode_cbor.hpp203
-rw-r--r--include/jsoncons_ext/cbor/encode_cbor.hpp151
11 files changed, 5131 insertions, 0 deletions
diff --git a/include/jsoncons_ext/cbor/cbor.hpp b/include/jsoncons_ext/cbor/cbor.hpp
new file mode 100644
index 0000000..3f7329f
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor.hpp
@@ -0,0 +1,26 @@
+// Copyright 2017 Daniel Parkerstd
+// 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_HPP
+#define JSONCONS_CBOR_CBOR_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <type_traits> // std::enable_if
+#include <istream> // std::basic_istream
+#include <jsoncons/json.hpp>
+#include <jsoncons/json_filter.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/cbor/cbor_reader.hpp>
+#include <jsoncons_ext/cbor/cbor_cursor.hpp>
+#include <jsoncons_ext/cbor/cbor_encoder.hpp>
+#include <jsoncons_ext/cbor/encode_cbor.hpp>
+#include <jsoncons_ext/cbor/decode_cbor.hpp>
+
+#endif
+
diff --git a/include/jsoncons_ext/cbor/cbor_cursor.hpp b/include/jsoncons_ext/cbor/cbor_cursor.hpp
new file mode 100644
index 0000000..af0d1a8
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_cursor.hpp
@@ -0,0 +1,351 @@
+// 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_CURSOR_HPP
+#define JSONCONS_CBOR_CBOR_CURSOR_HPP
+
+#include <memory> // std::allocator
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <system_error>
+#include <ios>
+#include <istream> // std::basic_istream
+#include <jsoncons/byte_string.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/json_exception.hpp>
+#include <jsoncons/staj_cursor.hpp>
+#include <jsoncons/source.hpp>
+#include <jsoncons_ext/cbor/cbor_parser.hpp>
+
+namespace jsoncons {
+namespace cbor {
+
+template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>>
+class basic_cbor_cursor : public basic_staj_cursor<char>, private virtual ser_context
+{
+public:
+ using source_type = Source;
+ using char_type = char;
+ using allocator_type = Allocator;
+private:
+ basic_cbor_parser<Source,Allocator> parser_;
+ basic_staj_visitor<char_type> cursor_visitor_;
+ basic_json_visitor2_to_visitor_adaptor<char_type,Allocator> cursor_handler_adaptor_;
+ bool eof_;
+
+ // Noncopyable and nonmoveable
+ basic_cbor_cursor(const basic_cbor_cursor&) = delete;
+ basic_cbor_cursor& operator=(const basic_cbor_cursor&) = delete;
+
+public:
+ using string_view_type = string_view;
+
+ template <class Sourceable>
+ basic_cbor_cursor(Sourceable&& source,
+ const cbor_decode_options& options = cbor_decode_options(),
+ const Allocator& alloc = Allocator())
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ cursor_visitor_(accept_all),
+ cursor_handler_adaptor_(cursor_visitor_, alloc),
+ eof_(false)
+ {
+ if (!done())
+ {
+ next();
+ }
+ }
+
+ // Constructors that set parse error codes
+
+ template <class Sourceable>
+ basic_cbor_cursor(Sourceable&& source,
+ std::error_code& ec)
+ : basic_cbor_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ cbor_decode_options(),
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_cbor_cursor(Sourceable&& source,
+ const cbor_decode_options& options,
+ std::error_code& ec)
+ : basic_cbor_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ options,
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_cbor_cursor(std::allocator_arg_t, const Allocator& alloc,
+ Sourceable&& source,
+ const cbor_decode_options& options,
+ std::error_code& ec)
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ cursor_visitor_(accept_all),
+ cursor_handler_adaptor_(cursor_visitor_, alloc),
+ eof_(false)
+ {
+ if (!done())
+ {
+ next(ec);
+ }
+ }
+
+ void reset()
+ {
+ parser_.reset();
+ cursor_visitor_.reset();
+ cursor_handler_adaptor_.reset();
+ eof_ = false;
+ if (!done())
+ {
+ next();
+ }
+ }
+
+ template <class Sourceable>
+ void reset(Sourceable&& source)
+ {
+ parser_.reset(std::forward<Sourceable>(source));
+ cursor_visitor_.reset();
+ cursor_handler_adaptor_.reset();
+ eof_ = false;
+ if (!done())
+ {
+ next();
+ }
+ }
+
+ void reset(std::error_code& ec)
+ {
+ parser_.reset();
+ cursor_visitor_.reset();
+ cursor_handler_adaptor_.reset();
+ eof_ = false;
+ if (!done())
+ {
+ next(ec);
+ }
+ }
+
+ template <class Sourceable>
+ void reset(Sourceable&& source, std::error_code& ec)
+ {
+ parser_.reset(std::forward<Sourceable>(source));
+ cursor_visitor_.reset();
+ cursor_handler_adaptor_.reset();
+ eof_ = false;
+ if (!done())
+ {
+ next(ec);
+ }
+ }
+
+ bool done() const override
+ {
+ return parser_.done();
+ }
+
+ bool is_typed_array() const
+ {
+ return cursor_visitor_.is_typed_array();
+ }
+
+ const staj_event& current() const override
+ {
+ return cursor_visitor_.event();
+ }
+
+ void read_to(basic_json_visitor<char_type>& visitor) override
+ {
+ std::error_code ec;
+ read_to(visitor, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
+ }
+ }
+
+ void read_to(basic_json_visitor<char_type>& visitor,
+ std::error_code& ec) override
+ {
+ if (cursor_visitor_.dump(visitor, *this, ec))
+ {
+ read_next(visitor, ec);
+ }
+ }
+
+ void next() override
+ {
+ std::error_code ec;
+ next(ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
+ }
+ }
+
+ void next(std::error_code& ec) override
+ {
+ read_next(ec);
+ }
+
+ const ser_context& context() const override
+ {
+ return *this;
+ }
+
+ bool eof() const
+ {
+ return eof_;
+ }
+
+ std::size_t line() const override
+ {
+ return parser_.line();
+ }
+
+ std::size_t column() const override
+ {
+ return parser_.column();
+ }
+
+ friend
+ staj_filter_view operator|(basic_cbor_cursor& cursor,
+ std::function<bool(const staj_event&, const ser_context&)> pred)
+ {
+ return staj_filter_view(cursor, pred);
+ }
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+
+ template <class Sourceable>
+ JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
+ basic_cbor_cursor(Sourceable&& source,
+ std::function<bool(const staj_event&, const ser_context&)> filter,
+ const cbor_decode_options& options = cbor_decode_options(),
+ const Allocator& alloc = Allocator())
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ cursor_visitor_(filter),
+ cursor_handler_adaptor_(cursor_visitor_, alloc),
+ eof_(false)
+ {
+ if (!done())
+ {
+ next();
+ }
+ }
+
+ template <class Sourceable>
+ JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
+ basic_cbor_cursor(Sourceable&& source,
+ std::function<bool(const staj_event&, const ser_context&)> filter,
+ std::error_code& ec)
+ : basic_cbor_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source), filter, ec)
+ {
+ }
+
+ template <class Sourceable>
+ JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
+ basic_cbor_cursor(std::allocator_arg_t, const Allocator& alloc,
+ Sourceable&& source,
+ std::function<bool(const staj_event&, const ser_context&)> filter,
+ std::error_code& ec)
+ : parser_(std::forward<Sourceable>(source), alloc),
+ cursor_visitor_(filter),
+ cursor_handler_adaptor_(cursor_visitor_, alloc),
+ eof_(false)
+ {
+ if (!done())
+ {
+ next(ec);
+ }
+ }
+
+ JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<char_type>&)")
+ void read(basic_json_visitor<char_type>& visitor)
+ {
+ read_to(visitor);
+ }
+
+ JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<char_type>&, std::error_code&)")
+ void read(basic_json_visitor<char_type>& visitor,
+ std::error_code& ec)
+ {
+ read_to(visitor, ec);
+ }
+#endif
+private:
+ static bool accept_all(const staj_event&, const ser_context&)
+ {
+ return true;
+ }
+
+ void read_next(std::error_code& ec)
+ {
+ if (cursor_visitor_.in_available())
+ {
+ cursor_visitor_.send_available(ec);
+ }
+ else
+ {
+ parser_.restart();
+ while (!parser_.stopped())
+ {
+ parser_.parse(cursor_handler_adaptor_, ec);
+ if (ec) return;
+ }
+ }
+ }
+
+ void read_next(basic_json_visitor<char_type>& visitor, std::error_code& ec)
+ {
+ {
+ struct resource_wrapper
+ {
+ basic_json_visitor2_to_visitor_adaptor<char_type,Allocator>& adaptor;
+ basic_json_visitor<char_type>& original;
+
+ resource_wrapper(basic_json_visitor2_to_visitor_adaptor<char_type,Allocator>& adaptor,
+ basic_json_visitor<char_type>& visitor)
+ : adaptor(adaptor), original(adaptor.destination())
+ {
+ adaptor.destination(visitor);
+ }
+
+ ~resource_wrapper()
+ {
+ adaptor.destination(original);
+ }
+ } wrapper(cursor_handler_adaptor_, visitor);
+
+ parser_.restart();
+ while (!parser_.stopped())
+ {
+ parser_.parse(cursor_handler_adaptor_, ec);
+ if (ec)
+ {
+ return;
+ }
+ }
+ }
+ }
+};
+
+using cbor_stream_cursor = basic_cbor_cursor<jsoncons::binary_stream_source>;
+using cbor_bytes_cursor = basic_cbor_cursor<jsoncons::bytes_source>;
+
+} // namespace cbor
+} // namespace jsoncons
+
+#endif
+
diff --git a/include/jsoncons_ext/cbor/cbor_cursor2.hpp b/include/jsoncons_ext/cbor/cbor_cursor2.hpp
new file mode 100644
index 0000000..eee7445
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_cursor2.hpp
@@ -0,0 +1,265 @@
+// 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_CURSOR2_HPP
+#define JSONCONS_CBOR_CBOR_CURSOR2_HPP
+
+#include <memory> // std::allocator
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <system_error>
+#include <ios>
+#include <istream> // std::basic_istream
+#include <jsoncons/byte_string.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/json_visitor2.hpp>
+#include <jsoncons/json_exception.hpp>
+#include <jsoncons/staj2_cursor.hpp>
+#include <jsoncons/source.hpp>
+#include <jsoncons_ext/cbor/cbor_parser.hpp>
+
+namespace jsoncons {
+namespace cbor {
+
+ template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>>
+ class basic_cbor_cursor2 : public basic_staj2_cursor<char>, private virtual ser_context
+ {
+ public:
+ using source_type = Source;
+ using char_type = char;
+ using allocator_type = Allocator;
+ private:
+ basic_cbor_parser<Source,Allocator> parser_;
+ basic_staj2_visitor<char_type> cursor_visitor_;
+ bool eof_;
+
+ // Noncopyable and nonmoveable
+ basic_cbor_cursor2(const basic_cbor_cursor2&) = delete;
+ basic_cbor_cursor2& operator=(const basic_cbor_cursor2&) = delete;
+
+ public:
+ using string_view_type = string_view;
+
+ template <class Sourceable>
+ basic_cbor_cursor2(Sourceable&& source,
+ const cbor_decode_options& options = cbor_decode_options(),
+ const Allocator& alloc = Allocator())
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ cursor_visitor_(accept_all),
+ eof_(false)
+ {
+ if (!done())
+ {
+ next();
+ }
+ }
+
+ // Constructors that set parse error codes
+
+ template <class Sourceable>
+ basic_cbor_cursor2(Sourceable&& source,
+ std::error_code& ec)
+ : basic_cbor_cursor2(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ cbor_decode_options(),
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_cbor_cursor2(Sourceable&& source,
+ const cbor_decode_options& options,
+ std::error_code& ec)
+ : basic_cbor_cursor2(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ options,
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_cbor_cursor2(std::allocator_arg_t, const Allocator& alloc,
+ Sourceable&& source,
+ const cbor_decode_options& options,
+ std::error_code& ec)
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ cursor_visitor_(accept_all),
+ eof_(false)
+ {
+ if (!done())
+ {
+ next(ec);
+ }
+ }
+
+ void reset()
+ {
+ parser_.reset();
+ cursor_visitor_.reset();
+ eof_ = false;
+ if (!done())
+ {
+ next();
+ }
+ }
+
+ template <class Sourceable>
+ void reset(Sourceable&& source)
+ {
+ parser_.reset(std::forward<Sourceable>(source));
+ cursor_visitor_.reset();
+ eof_ = false;
+ if (!done())
+ {
+ next();
+ }
+ }
+
+ void reset(std::error_code& ec)
+ {
+ parser_.reset();
+ cursor_visitor_.reset();
+ eof_ = false;
+ if (!done())
+ {
+ next(ec);
+ }
+ }
+
+ template <class Sourceable>
+ void reset(Sourceable&& source, std::error_code& ec)
+ {
+ parser_.reset(std::forward<Sourceable>(source));
+ cursor_visitor_.reset();
+ eof_ = false;
+ if (!done())
+ {
+ next(ec);
+ }
+ }
+
+ bool done() const override
+ {
+ return parser_.done();
+ }
+
+ bool is_typed_array() const
+ {
+ return cursor_visitor_.is_typed_array();
+ }
+
+ const staj2_event& current() const override
+ {
+ return cursor_visitor_.event();
+ }
+
+ void read_to(basic_json_visitor2<char_type>& visitor) override
+ {
+ std::error_code ec;
+ read_to(visitor, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
+ }
+ }
+
+ void read_to(basic_json_visitor2<char_type>& visitor,
+ std::error_code& ec) override
+ {
+ if (cursor_visitor_.dump(visitor, *this, ec))
+ {
+ read_next(visitor, ec);
+ }
+ }
+
+ void next() override
+ {
+ std::error_code ec;
+ next(ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
+ }
+ }
+
+ void next(std::error_code& ec) override
+ {
+ read_next(ec);
+ }
+
+ const ser_context& context() const override
+ {
+ return *this;
+ }
+
+ bool eof() const
+ {
+ return eof_;
+ }
+
+ std::size_t line() const override
+ {
+ return parser_.line();
+ }
+
+ std::size_t column() const override
+ {
+ return parser_.column();
+ }
+
+ friend
+ staj2_filter_view operator|(basic_cbor_cursor2& cursor,
+ std::function<bool(const staj2_event&, const ser_context&)> pred)
+ {
+ return staj2_filter_view(cursor, pred);
+ }
+
+ private:
+ static bool accept_all(const staj2_event&, const ser_context&)
+ {
+ return true;
+ }
+
+ void read_next(std::error_code& ec)
+ {
+ if (cursor_visitor_.in_available())
+ {
+ cursor_visitor_.send_available(ec);
+ }
+ else
+ {
+ parser_.restart();
+ while (!parser_.stopped())
+ {
+ parser_.parse(cursor_visitor_, ec);
+ if (ec) return;
+ }
+ }
+ }
+
+ void read_next(basic_json_visitor2<char_type>& visitor, std::error_code& ec)
+ {
+ parser_.restart();
+ while (!parser_.stopped())
+ {
+ parser_.parse(visitor, ec);
+ if (ec)
+ {
+ return;
+ }
+ }
+ }
+ };
+
+ using cbor_stream_cursor2 = basic_cbor_cursor2<jsoncons::binary_stream_source>;
+ using cbor_bytes_cursor2 = basic_cbor_cursor2<jsoncons::bytes_source>;
+
+} // namespace cbor
+} // namespace jsoncons
+
+#endif
+
diff --git a/include/jsoncons_ext/cbor/cbor_detail.hpp b/include/jsoncons_ext/cbor/cbor_detail.hpp
new file mode 100644
index 0000000..9acfc3c
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_detail.hpp
@@ -0,0 +1,93 @@
+// Copyright 2017 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_DETAIL_HPP
+#define JSONCONS_CBOR_CBOR_DETAIL_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <iterator> // std::forward_iterator_tag
+#include <limits> // std::numeric_limits
+#include <utility> // std::move
+#include <jsoncons/json.hpp>
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+// 0x00..0x17 (0..23)
+#define JSONCONS_CBOR_0x00_0x17 \
+ 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x09:case 0x0a:case 0x0b:case 0x0c:case 0x0d:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16:case 0x17
+
+#define JSONCONS_CBOR_ARRAY_TAGS \
+ 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47:case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f:case 0x50:case 0x51:case 0x52:case 0x53:case 0x54:case 0x55:case 0x56:case 0x57
+
+namespace jsoncons { namespace cbor { namespace detail {
+
+//const uint8_t cbor_array_tags_010_mask = 0b11100000;
+//const uint8_t cbor_array_tags_f_mask = 0b00010000;
+//const uint8_t cbor_array_tags_s_mask = 0b00001000;
+//const uint8_t cbor_array_tags_e_mask = 0b00000100;
+//const uint8_t cbor_array_tags_ll_mask = 0b00000011;
+
+const uint8_t cbor_array_tags_010_mask = 0xE0;
+const uint8_t cbor_array_tags_f_mask = 0x10;
+const uint8_t cbor_array_tags_s_mask = 0x08;
+const uint8_t cbor_array_tags_e_mask = 0x04;
+const uint8_t cbor_array_tags_ll_mask = 0x03;
+
+const uint8_t cbor_array_tags_010_shift = 5;
+const uint8_t cbor_array_tags_f_shift = 4;
+const uint8_t cbor_array_tags_s_shift = 3;
+const uint8_t cbor_array_tags_e_shift = 2;
+const uint8_t cbor_array_tags_ll_shift = 0;
+
+enum class cbor_major_type : uint8_t
+{
+ unsigned_integer = 0x00,
+ negative_integer = 0x01,
+ byte_string = 0x02,
+ text_string = 0x03,
+ array = 0x04,
+ map = 0x05,
+ semantic_tag = 0x06,
+ simple = 0x7
+};
+
+namespace additional_info
+{
+ const uint8_t indefinite_length = 0x1f;
+}
+
+inline
+size_t min_length_for_stringref(uint64_t index)
+{
+ std::size_t n;
+ if (index <= 23)
+ {
+ n = 3;
+ }
+ else if (index <= 255)
+ {
+ n = 4;
+ }
+ else if (index <= 65535)
+ {
+ n = 5;
+ }
+ else if (index <= 4294967295)
+ {
+ n = 7;
+ }
+ else
+ {
+ n = 11;
+ }
+ return n;
+}
+
+}}}
+
+#endif
diff --git a/include/jsoncons_ext/cbor/cbor_encoder.hpp b/include/jsoncons_ext/cbor/cbor_encoder.hpp
new file mode 100644
index 0000000..f4699ee
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_encoder.hpp
@@ -0,0 +1,1766 @@
+// 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 <string>
+#include <vector>
+#include <limits> // std::numeric_limits
+#include <memory>
+#include <utility> // std::move
+#include <jsoncons/json_exception.hpp> // jsoncons::ser_error
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/sink.hpp>
+#include <jsoncons/detail/parse_number.hpp>
+#include <jsoncons_ext/cbor/cbor_error.hpp>
+#include <jsoncons_ext/cbor/cbor_options.hpp>
+
+namespace jsoncons { namespace cbor {
+
+enum class cbor_container_type {object, indefinite_length_object, array, indefinite_length_array};
+
+template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>>
+class basic_cbor_encoder final : public basic_json_visitor<char>
+{
+ using super_type = basic_json_visitor<char>;
+
+ 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<allocator_type>:: template rebind_alloc<char_type>;
+ using byte_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint8_t>;
+
+ using string_type = std::basic_string<char_type,std::char_traits<char_type>,char_allocator_type>;
+ using byte_string_type = basic_byte_string<byte_allocator_type>;
+
+ 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<allocator_type>:: template rebind_alloc<std::pair<const string_type,size_t>> string_size_allocator_type;
+ typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const byte_string_type,size_t>> byte_string_size_allocator_type;
+ typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<stack_item> stack_item_allocator_type;
+
+ Sink sink_;
+ const cbor_encode_options options_;
+ allocator_type alloc_;
+
+ std::vector<stack_item,stack_item_allocator_type> stack_;
+ std::map<string_type,size_t,std::less<string_type>,string_size_allocator_type> stringref_map_;
+ std::map<byte_string_type,size_t,std::less<byte_string_type>,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>(sink), cbor_encode_options(), alloc)
+ {
+ }
+ basic_cbor_encoder(Sink&& sink,
+ const cbor_encode_options& options,
+ const Allocator& alloc = Allocator())
+ : sink_(std::forward<Sink>(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<uint8_t>(0xa0 + length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xb8),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xb9),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xba),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0xbb),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(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<uint8_t>(0x80 + length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x98),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x99),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x9a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x9b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(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<uint8_t>(0x60 + length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x78),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x79),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x7a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x7b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(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<uint8_t> 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<uint8_t>(0x40 + length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x58),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x59),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x5a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x5b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(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<char> s;
+ std::basic_string<char> 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<char> s;
+ std::basic_string<char> 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<std::invalid_argument>(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<uint8_t>(0x40 + b.size()),
+ std::back_inserter(sink_));
+ }
+ else if (b.size() <= 0xff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x58),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(b.size()),
+ std::back_inserter(sink_));
+ }
+ else if (b.size() <= 0xffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x59),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(b.size()),
+ std::back_inserter(sink_));
+ }
+ else if (b.size() <= 0xffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x5a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(b.size()),
+ std::back_inserter(sink_));
+ }
+ else // if (b.size() <= 0xffffffffffffffff)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x5b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(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<uint8_t>(0xfa),
+ std::back_inserter(sink_));
+ binary::native_to_big(valf, std::back_inserter(sink_));
+ }
+ else
+ {
+ binary::native_to_big(static_cast<uint8_t>(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<double>(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<uint8_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <= (std::numeric_limits<uint8_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x18),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <= (std::numeric_limits<uint16_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x19),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <= (std::numeric_limits<uint32_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x1a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <= (std::numeric_limits<int64_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x1b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<int64_t>(value),
+ std::back_inserter(sink_));
+ }
+ } else
+ {
+ const auto posnum = -1 - value;
+ if (value >= -24)
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x20 + posnum),
+ std::back_inserter(sink_));
+ }
+ else if (posnum <= (std::numeric_limits<uint8_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x38),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint8_t>(posnum),
+ std::back_inserter(sink_));
+ }
+ else if (posnum <= (std::numeric_limits<uint16_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x39),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint16_t>(posnum),
+ std::back_inserter(sink_));
+ }
+ else if (posnum <= (std::numeric_limits<uint32_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x3a),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint32_t>(posnum),
+ std::back_inserter(sink_));
+ }
+ else if (posnum <= (std::numeric_limits<int64_t>::max)())
+ {
+ binary::native_to_big(static_cast<uint8_t>(0x3b),
+ std::back_inserter(sink_));
+ binary::native_to_big(static_cast<int64_t>(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<double>(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<uint8_t>(value));
+ }
+ else if (value <=(std::numeric_limits<uint8_t>::max)())
+ {
+ sink_.push_back(0xd8);
+ sink_.push_back(static_cast<uint8_t>(value));
+ }
+ else if (value <=(std::numeric_limits<uint16_t>::max)())
+ {
+ sink_.push_back(0xd9);
+ binary::native_to_big(static_cast<uint16_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <=(std::numeric_limits<uint32_t>::max)())
+ {
+ sink_.push_back(0xda);
+ binary::native_to_big(static_cast<uint32_t>(value),
+ std::back_inserter(sink_));
+ }
+ else
+ {
+ sink_.push_back(0xdb);
+ binary::native_to_big(static_cast<uint64_t>(value),
+ std::back_inserter(sink_));
+ }
+ }
+
+ void write_uint64_value(uint64_t value)
+ {
+ if (value <= 0x17)
+ {
+ sink_.push_back(static_cast<uint8_t>(value));
+ }
+ else if (value <=(std::numeric_limits<uint8_t>::max)())
+ {
+ sink_.push_back(static_cast<uint8_t>(0x18));
+ sink_.push_back(static_cast<uint8_t>(value));
+ }
+ else if (value <=(std::numeric_limits<uint16_t>::max)())
+ {
+ sink_.push_back(static_cast<uint8_t>(0x19));
+ binary::native_to_big(static_cast<uint16_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <=(std::numeric_limits<uint32_t>::max)())
+ {
+ sink_.push_back(static_cast<uint8_t>(0x1a));
+ binary::native_to_big(static_cast<uint32_t>(value),
+ std::back_inserter(sink_));
+ }
+ else if (value <=(std::numeric_limits<uint64_t>::max)())
+ {
+ sink_.push_back(static_cast<uint8_t>(0x1b));
+ binary::native_to_big(static_cast<uint64_t>(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<const uint8_t>& 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<const uint16_t>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ uint16_t(),
+ tag);
+ std::vector<uint8_t> 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<const uint32_t>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ uint32_t(),
+ tag);
+ std::vector<uint8_t> 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<const uint64_t>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ uint64_t(),
+ tag);
+ std::vector<uint8_t> 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<const int8_t>& data,
+ semantic_tag,
+ const ser_context& context,
+ std::error_code& ec) override
+ {
+ if (options_.use_typed_arrays())
+ {
+ write_tag(0x48);
+ std::vector<uint8_t> 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<const int16_t>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ int16_t(),
+ tag);
+ std::vector<uint8_t> 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<const int32_t>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ int32_t(),
+ tag);
+ std::vector<uint8_t> 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<const int64_t>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ int64_t(),
+ tag);
+ std::vector<uint8_t> 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<const uint16_t>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ half_arg,
+ tag);
+ std::vector<uint8_t> 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<const float>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ float(),
+ tag);
+ std::vector<uint8_t> 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<const double>& 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<bool, jsoncons::endian::native == jsoncons::endian::big>(),
+ double(),
+ tag);
+ std::vector<uint8_t> 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<const float128_type>&,
+ semantic_tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ return true;
+ }
+*/
+ bool visit_begin_multi_dim(const jsoncons::span<const size_t>& 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<jsoncons::binary_stream_sink>;
+using cbor_bytes_encoder = basic_cbor_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>;
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_encoder") typedef cbor_bytes_encoder cbor_bytes_serializer;
+
+template<class Sink=jsoncons::binary_stream_sink>
+using basic_cbor_serializer = basic_cbor_encoder<Sink>;
+
+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
diff --git a/include/jsoncons_ext/cbor/cbor_error.hpp b/include/jsoncons_ext/cbor/cbor_error.hpp
new file mode 100644
index 0000000..a7a6626
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_error.hpp
@@ -0,0 +1,105 @@
+/// 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_ERROR_HPP
+#define JSONCONS_CBOR_CBOR_ERROR_HPP
+
+#include <system_error>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/json_exception.hpp> // jsoncons::ser_error
+
+namespace jsoncons { namespace cbor {
+
+enum class cbor_errc
+{
+ success = 0,
+ unexpected_eof,
+ source_error,
+ invalid_decimal_fraction,
+ invalid_bigfloat,
+ invalid_utf8_text_string,
+ too_many_items,
+ too_few_items,
+ number_too_large,
+ stringref_too_large,
+ max_nesting_depth_exceeded,
+ unknown_type,
+ illegal_chunked_string
+};
+
+class cbor_error_category_impl
+ : public std::error_category
+{
+public:
+ const char* name() const noexcept override
+ {
+ return "jsoncons/cbor";
+ }
+ std::string message(int ev) const override
+ {
+ switch (static_cast<cbor_errc>(ev))
+ {
+ case cbor_errc::unexpected_eof:
+ return "Unexpected end of file";
+ case cbor_errc::source_error:
+ return "Source error";
+ case cbor_errc::invalid_decimal_fraction:
+ return "Invalid decimal fraction";
+ case cbor_errc::invalid_bigfloat:
+ return "Invalid bigfloat";
+ case cbor_errc::invalid_utf8_text_string:
+ return "Illegal UTF-8 encoding in text string";
+ case cbor_errc::too_many_items:
+ return "Too many items were added to a CBOR map or array of known length";
+ case cbor_errc::too_few_items:
+ return "Too few items were added to a CBOR map or array of known length";
+ case cbor_errc::number_too_large:
+ return "Number exceeds implementation limits";
+ case cbor_errc::stringref_too_large:
+ return "stringref exceeds stringref map size";
+ case cbor_errc::max_nesting_depth_exceeded:
+ return "Data item nesting exceeds limit in options";
+ case cbor_errc::unknown_type:
+ return "An unknown type was found in the stream";
+ case cbor_errc::illegal_chunked_string:
+ return "An illegal type was found while parsing an indefinite length string";
+ default:
+ return "Unknown CBOR parser error";
+ }
+ }
+};
+
+inline
+const std::error_category& cbor_error_category()
+{
+ static cbor_error_category_impl instance;
+ return instance;
+}
+
+inline
+std::error_code make_error_code(cbor_errc e)
+{
+ return std::error_code(static_cast<int>(e),cbor_error_category());
+}
+
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+
+JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_error;
+JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_decode_error;
+JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_reader_errc;
+#endif
+
+}}
+
+namespace std {
+ template<>
+ struct is_error_code_enum<jsoncons::cbor::cbor_errc> : public true_type
+ {
+ };
+}
+
+#endif
diff --git a/include/jsoncons_ext/cbor/cbor_options.hpp b/include/jsoncons_ext/cbor/cbor_options.hpp
new file mode 100644
index 0000000..1de4a4e
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_options.hpp
@@ -0,0 +1,113 @@
+// Copyright 2019 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_OPTIONS_HPP
+#define JSONCONS_CBOR_CBOR_OPTIONS_HPP
+
+#include <string>
+#include <limits> // std::numeric_limits
+#include <cwchar>
+#include <jsoncons/json_exception.hpp>
+#include <jsoncons_ext/cbor/cbor_detail.hpp>
+
+namespace jsoncons { namespace cbor {
+
+class cbor_options;
+
+class cbor_options_common
+{
+ friend class cbor_options;
+
+ int max_nesting_depth_;
+protected:
+ virtual ~cbor_options_common() = default;
+
+ cbor_options_common()
+ : max_nesting_depth_(1024)
+ {
+ }
+
+ cbor_options_common(const cbor_options_common&) = default;
+ cbor_options_common& operator=(const cbor_options_common&) = default;
+ cbor_options_common(cbor_options_common&&) = default;
+ cbor_options_common& operator=(cbor_options_common&&) = default;
+public:
+ int max_nesting_depth() const
+ {
+ return max_nesting_depth_;
+ }
+};
+
+class cbor_decode_options : public virtual cbor_options_common
+{
+ friend class cbor_options;
+public:
+ cbor_decode_options()
+ {
+ }
+};
+
+class cbor_encode_options : public virtual cbor_options_common
+{
+ friend class cbor_options;
+
+ bool use_stringref_;
+ bool use_typed_arrays_;
+public:
+ cbor_encode_options()
+ : use_stringref_(false),
+ use_typed_arrays_(false)
+ {
+ }
+
+ bool pack_strings() const
+ {
+ return use_stringref_;
+ }
+
+ bool use_typed_arrays() const
+ {
+ return use_typed_arrays_;
+ }
+};
+
+class cbor_options final : public cbor_decode_options, public cbor_encode_options
+{
+public:
+ using cbor_options_common::max_nesting_depth;
+ using cbor_encode_options::pack_strings;
+ using cbor_encode_options::use_typed_arrays;
+
+ cbor_options& max_nesting_depth(int value)
+ {
+ this->max_nesting_depth_ = value;
+ return *this;
+ }
+
+ cbor_options& pack_strings(bool value)
+ {
+ this->use_stringref_ = value;
+ return *this;
+ }
+
+ cbor_options& use_typed_arrays(bool value)
+ {
+ this->use_typed_arrays_ = value;
+ return *this;
+ }
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+ JSONCONS_DEPRECATED_MSG("Instead, use use_typed_arrays(bool)")
+ cbor_options& enable_typed_arrays(bool value)
+ {
+ this->use_typed_arrays_ = value;
+ return *this;
+ }
+#endif
+};
+
+}}
+#endif
diff --git a/include/jsoncons_ext/cbor/cbor_parser.hpp b/include/jsoncons_ext/cbor/cbor_parser.hpp
new file mode 100644
index 0000000..f3d03bb
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_parser.hpp
@@ -0,0 +1,1942 @@
+// Copyright 2017 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_PARSER_HPP
+#define JSONCONS_CBOR_CBOR_PARSER_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <utility> // std::move
+#include <bitset> // std::bitset
+#include <jsoncons/json.hpp>
+#include <jsoncons/source.hpp>
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/cbor/cbor_error.hpp>
+#include <jsoncons_ext/cbor/cbor_detail.hpp>
+#include <jsoncons_ext/cbor/cbor_options.hpp>
+#include <jsoncons/json_visitor2.hpp>
+
+namespace jsoncons { namespace cbor {
+
+enum class parse_mode {root,accept,array,indefinite_array,map_key,map_value,indefinite_map_key,indefinite_map_value,multi_dim};
+
+struct mapped_string
+{
+ jsoncons::cbor::detail::cbor_major_type type;
+ std::string s;
+ std::vector<uint8_t> bytes;
+
+ mapped_string(const std::string& s)
+ : type(jsoncons::cbor::detail::cbor_major_type::text_string), s(s)
+ {
+ }
+
+ mapped_string(std::string&& s)
+ : type(jsoncons::cbor::detail::cbor_major_type::text_string), s(std::move(s))
+ {
+ }
+
+ mapped_string(const std::vector<uint8_t>& bytes)
+ : type(jsoncons::cbor::detail::cbor_major_type::byte_string), bytes(bytes)
+ {
+ }
+
+ mapped_string(std::vector<uint8_t>&& bytes)
+ : type(jsoncons::cbor::detail::cbor_major_type::byte_string), bytes(std::move(bytes))
+ {
+ }
+
+ mapped_string(const mapped_string&) = default;
+
+ mapped_string(mapped_string&&) = default;
+
+ mapped_string& operator=(const mapped_string&) = default;
+
+ mapped_string& operator=(mapped_string&&) = default;
+};
+
+struct parse_state
+{
+ parse_mode mode;
+ std::size_t length;
+ std::size_t index;
+ bool pop_stringref_map_stack;
+
+ parse_state(parse_mode mode, std::size_t length, bool pop_stringref_map_stack = false) noexcept
+ : mode(mode), length(length), index(0), pop_stringref_map_stack(pop_stringref_map_stack)
+ {
+ }
+
+ parse_state(const parse_state&) = default;
+ parse_state(parse_state&&) = default;
+};
+
+template <class Source,class Allocator=std::allocator<char>>
+class basic_cbor_parser : public ser_context
+{
+ using char_type = char;
+ using char_traits_type = std::char_traits<char>;
+ using allocator_type = Allocator;
+ using char_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<char_type>;
+ using byte_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint8_t>;
+ using tag_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint64_t>;
+ using parse_state_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<parse_state>;
+ using stringref_map = std::vector<mapped_string>;
+ using stringref_map_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<stringref_map>;
+
+ using string_type = std::basic_string<char_type,char_traits_type,char_allocator_type>;
+
+ enum {stringref_tag, // 25
+ stringref_namespace_tag, // 256
+ item_tag,
+ num_of_tags};
+
+ std::bitset<num_of_tags> other_tags_;
+
+ allocator_type alloc_;
+ Source source_;
+ cbor_decode_options options_;
+
+ bool more_;
+ bool done_;
+ string_type text_buffer_;
+ std::vector<uint8_t,byte_allocator_type> bytes_buffer_;
+ uint64_t item_tag_;
+ std::vector<parse_state,parse_state_allocator_type> state_stack_;
+ std::vector<uint8_t,byte_allocator_type> typed_array_;
+ std::vector<std::size_t> shape_;
+ std::size_t index_; // TODO: Never used!
+ std::vector<stringref_map,stringref_map_allocator_type> stringref_map_stack_;
+ int nesting_depth_;
+
+ struct read_byte_string_from_buffer
+ {
+ byte_string_view bytes;
+
+ read_byte_string_from_buffer(const byte_string_view& b)
+ : bytes(b)
+ {
+ }
+ template <class Container>
+ void operator()(Container& c, std::error_code&)
+ {
+ c.clear();
+ c.reserve(bytes.size());
+ for (auto b : bytes)
+ {
+ c.push_back(b);
+ }
+ }
+ };
+
+ struct read_byte_string_from_source
+ {
+ basic_cbor_parser<Source,Allocator>* source;
+
+ read_byte_string_from_source(basic_cbor_parser<Source,Allocator>* source)
+ : source(source)
+ {
+ }
+ template <class Container>
+ void operator()(Container& c, std::error_code& ec)
+ {
+ source->read_byte_string(c,ec);
+ }
+ };
+
+public:
+ template <class Sourceable>
+ basic_cbor_parser(Sourceable&& source,
+ const cbor_decode_options& options = cbor_decode_options(),
+ const Allocator alloc = Allocator())
+ : alloc_(alloc),
+ source_(std::forward<Sourceable>(source)),
+ options_(options),
+ more_(true),
+ done_(false),
+ text_buffer_(alloc),
+ bytes_buffer_(alloc),
+ item_tag_(0),
+ state_stack_(alloc),
+ typed_array_(alloc),
+ index_(0),
+ stringref_map_stack_(alloc),
+ nesting_depth_(0)
+ {
+ state_stack_.emplace_back(parse_mode::root,0);
+ }
+
+ void restart()
+ {
+ more_ = true;
+ }
+
+ void reset()
+ {
+ more_ = true;
+ done_ = false;
+ text_buffer_.clear();
+ bytes_buffer_.clear();
+ item_tag_ = 0;
+ state_stack_.clear();
+ state_stack_.emplace_back(parse_mode::root,0);
+ typed_array_.clear();
+ stringref_map_stack_.clear();
+ nesting_depth_ = 0;
+ }
+
+ template <class Sourceable>
+ void reset(Sourceable&& source)
+ {
+ source_ = std::forward<Sourceable>(source);
+ reset();
+ }
+
+ bool done() const
+ {
+ return done_;
+ }
+
+ bool stopped() const
+ {
+ return !more_;
+ }
+
+ std::size_t line() const override
+ {
+ return 0;
+ }
+
+ std::size_t column() const override
+ {
+ return source_.position();
+ }
+
+ void parse(json_visitor2& visitor, std::error_code& ec)
+ {
+ while (!done_ && more_)
+ {
+ switch (state_stack_.back().mode)
+ {
+ case parse_mode::multi_dim:
+ {
+ if (state_stack_.back().index == 0)
+ {
+ ++state_stack_.back().index;
+ read_item(visitor, ec);
+ }
+ else
+ {
+ produce_end_multi_dim(visitor, ec);
+ }
+ break;
+ }
+ case parse_mode::array:
+ {
+ if (state_stack_.back().index < state_stack_.back().length)
+ {
+ ++state_stack_.back().index;
+ read_item(visitor, ec);
+ }
+ else
+ {
+ end_array(visitor, ec);
+ }
+ break;
+ }
+ case parse_mode::indefinite_array:
+ {
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ if (c.value == 0xff)
+ {
+ source_.ignore(1);
+ end_array(visitor, ec);
+ }
+ else
+ {
+ read_item(visitor, ec);
+ }
+ break;
+ }
+ case parse_mode::map_key:
+ {
+ if (state_stack_.back().index < state_stack_.back().length)
+ {
+ ++state_stack_.back().index;
+ state_stack_.back().mode = parse_mode::map_value;
+ read_item(visitor, ec);
+ }
+ else
+ {
+ end_object(visitor, ec);
+ }
+ break;
+ }
+ case parse_mode::map_value:
+ {
+ state_stack_.back().mode = parse_mode::map_key;
+ read_item(visitor, ec);
+ break;
+ }
+ case parse_mode::indefinite_map_key:
+ {
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ if (c.value == 0xff)
+ {
+ source_.ignore(1);
+ end_object(visitor, ec);
+ }
+ else
+ {
+ state_stack_.back().mode = parse_mode::indefinite_map_value;
+ read_item(visitor, ec);
+ }
+ break;
+ }
+ case parse_mode::indefinite_map_value:
+ {
+ state_stack_.back().mode = parse_mode::indefinite_map_key;
+ read_item(visitor, ec);
+ break;
+ }
+ case parse_mode::root:
+ {
+ state_stack_.back().mode = parse_mode::accept;
+ read_item(visitor, ec);
+ break;
+ }
+ case parse_mode::accept:
+ {
+ JSONCONS_ASSERT(state_stack_.size() == 1);
+ state_stack_.clear();
+ more_ = false;
+ done_ = true;
+ visitor.flush();
+ break;
+ }
+ }
+ }
+ }
+private:
+ void read_item(json_visitor2& visitor, std::error_code& ec)
+ {
+ read_tags(ec);
+ if (!more_)
+ {
+ return;
+ }
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value);
+ uint8_t info = get_additional_information_value(c.value);
+
+ switch (major_type)
+ {
+ case jsoncons::cbor::detail::cbor_major_type::unsigned_integer:
+ {
+ uint64_t val = get_uint64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ if (!stringref_map_stack_.empty() && other_tags_[stringref_tag])
+ {
+ other_tags_[stringref_tag] = false;
+ if (val >= stringref_map_stack_.back().size())
+ {
+ ec = cbor_errc::stringref_too_large;
+ more_ = false;
+ return;
+ }
+ stringref_map::size_type index = (stringref_map::size_type)val;
+ if (index != val)
+ {
+ ec = cbor_errc::number_too_large;
+ more_ = false;
+ return;
+ }
+ auto& str = stringref_map_stack_.back().at(index);
+ switch (str.type)
+ {
+ case jsoncons::cbor::detail::cbor_major_type::text_string:
+ {
+ handle_string(visitor, jsoncons::basic_string_view<char>(str.s.data(),str.s.length()),ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::byte_string:
+ {
+ read_byte_string_from_buffer read(byte_string_view(str.bytes));
+ write_byte_string(read, visitor, ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ default:
+ JSONCONS_UNREACHABLE();
+ break;
+ }
+ }
+ else
+ {
+ semantic_tag tag = semantic_tag::none;
+ if (other_tags_[item_tag])
+ {
+ if (item_tag_ == 1)
+ {
+ tag = semantic_tag::epoch_second;
+ }
+ other_tags_[item_tag] = false;
+ }
+ more_ = visitor.uint64_value(val, tag, *this, ec);
+ }
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::negative_integer:
+ {
+ int64_t val = get_int64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ semantic_tag tag = semantic_tag::none;
+ if (other_tags_[item_tag])
+ {
+ if (item_tag_ == 1)
+ {
+ tag = semantic_tag::epoch_second;
+ }
+ other_tags_[item_tag] = false;
+ }
+ more_ = visitor.int64_value(val, tag, *this, ec);
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::byte_string:
+ {
+ read_byte_string_from_source read(this);
+ write_byte_string(read, visitor, ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::text_string:
+ {
+ text_buffer_.clear();
+ read_text_string(text_buffer_, ec);
+ if (ec)
+ {
+ return;
+ }
+ auto result = unicode_traits::validate(text_buffer_.data(),text_buffer_.size());
+ if (result.ec != unicode_traits::conv_errc())
+ {
+ ec = cbor_errc::invalid_utf8_text_string;
+ more_ = false;
+ return;
+ }
+ handle_string(visitor, jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()),ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::semantic_tag:
+ {
+ JSONCONS_UNREACHABLE();
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::simple:
+ {
+ switch (info)
+ {
+ case 0x14:
+ more_ = visitor.bool_value(false, semantic_tag::none, *this, ec);
+ source_.ignore(1);
+ break;
+ case 0x15:
+ more_ = visitor.bool_value(true, semantic_tag::none, *this, ec);
+ source_.ignore(1);
+ break;
+ case 0x16:
+ more_ = visitor.null_value(semantic_tag::none, *this, ec);
+ source_.ignore(1);
+ break;
+ case 0x17:
+ more_ = visitor.null_value(semantic_tag::undefined, *this, ec);
+ source_.ignore(1);
+ break;
+ case 0x19: // Half-Precision Float (two-byte IEEE 754)
+ {
+ uint64_t val = get_uint64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ more_ = visitor.half_value(static_cast<uint16_t>(val), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x1a: // Single-Precision Float (four-byte IEEE 754)
+ case 0x1b: // Double-Precision Float (eight-byte IEEE 754)
+ {
+ double val = get_double(ec);
+ if (ec)
+ {
+ return;
+ }
+ semantic_tag tag = semantic_tag::none;
+ if (other_tags_[item_tag])
+ {
+ if (item_tag_ == 1)
+ {
+ tag = semantic_tag::epoch_second;
+ }
+ other_tags_[item_tag] = false;
+ }
+ more_ = visitor.double_value(val, tag, *this, ec);
+ break;
+ }
+ default:
+ {
+ ec = cbor_errc::unknown_type;
+ more_ = false;
+ return;
+ }
+ }
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::array:
+ {
+ if (other_tags_[item_tag])
+ {
+ switch (item_tag_)
+ {
+ case 0x04:
+ text_buffer_.clear();
+ read_decimal_fraction(text_buffer_, ec);
+ if (ec)
+ {
+ return;
+ }
+ more_ = visitor.string_value(text_buffer_, semantic_tag::bigdec, *this, ec);
+ break;
+ case 0x05:
+ text_buffer_.clear();
+ read_bigfloat(text_buffer_, ec);
+ if (ec)
+ {
+ return;
+ }
+ more_ = visitor.string_value(text_buffer_, semantic_tag::bigfloat, *this, ec);
+ break;
+ case 40: // row major storage
+ produce_begin_multi_dim(visitor, semantic_tag::multi_dim_row_major, ec);
+ break;
+ case 1040: // column major storage
+ produce_begin_multi_dim(visitor, semantic_tag::multi_dim_column_major, ec);
+ break;
+ default:
+ begin_array(visitor, info, ec);
+ break;
+ }
+ other_tags_[item_tag] = false;
+ }
+ else
+ {
+ begin_array(visitor, info, ec);
+ }
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::map:
+ {
+ begin_object(visitor, info, ec);
+ break;
+ }
+ default:
+ break;
+ }
+ other_tags_[item_tag] = false;
+ }
+
+ void begin_array(json_visitor2& visitor, uint8_t info, std::error_code& ec)
+ {
+ if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
+ {
+ ec = cbor_errc::max_nesting_depth_exceeded;
+ more_ = false;
+ return;
+ }
+ semantic_tag tag = semantic_tag::none;
+ bool pop_stringref_map_stack = false;
+ if (other_tags_[stringref_namespace_tag])
+ {
+ stringref_map_stack_.emplace_back(alloc_);
+ other_tags_[stringref_namespace_tag] = false;
+ pop_stringref_map_stack = true;
+ }
+ switch (info)
+ {
+ case jsoncons::cbor::detail::additional_info::indefinite_length:
+ {
+ state_stack_.emplace_back(parse_mode::indefinite_array,0,pop_stringref_map_stack);
+ more_ = visitor.begin_array(tag, *this, ec);
+ source_.ignore(1);
+ break;
+ }
+ default: // definite length
+ {
+ std::size_t len = get_size(ec);
+ if (!more_)
+ {
+ return;
+ }
+ state_stack_.emplace_back(parse_mode::array,len,pop_stringref_map_stack);
+ more_ = visitor.begin_array(len, tag, *this, ec);
+ break;
+ }
+ }
+ }
+
+ void end_array(json_visitor2& visitor, std::error_code& ec)
+ {
+ --nesting_depth_;
+
+ more_ = visitor.end_array(*this, ec);
+ if (state_stack_.back().pop_stringref_map_stack)
+ {
+ stringref_map_stack_.pop_back();
+ }
+ state_stack_.pop_back();
+ }
+
+ void begin_object(json_visitor2& visitor, uint8_t info, std::error_code& ec)
+ {
+ if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
+ {
+ ec = cbor_errc::max_nesting_depth_exceeded;
+ more_ = false;
+ return;
+ }
+ bool pop_stringref_map_stack = false;
+ if (other_tags_[stringref_namespace_tag])
+ {
+ stringref_map_stack_.emplace_back(alloc_);
+ other_tags_[stringref_namespace_tag] = false;
+ pop_stringref_map_stack = true;
+ }
+ switch (info)
+ {
+ case jsoncons::cbor::detail::additional_info::indefinite_length:
+ {
+ state_stack_.emplace_back(parse_mode::indefinite_map_key,0,pop_stringref_map_stack);
+ more_ = visitor.begin_object(semantic_tag::none, *this, ec);
+ source_.ignore(1);
+ break;
+ }
+ default: // definite_length
+ {
+ std::size_t len = get_size(ec);
+ if (!more_)
+ {
+ return;
+ }
+ state_stack_.emplace_back(parse_mode::map_key,len,pop_stringref_map_stack);
+ more_ = visitor.begin_object(len, semantic_tag::none, *this, ec);
+ break;
+ }
+ }
+ }
+
+ void end_object(json_visitor2& visitor, std::error_code& ec)
+ {
+ --nesting_depth_;
+ more_ = visitor.end_object(*this, ec);
+ if (state_stack_.back().pop_stringref_map_stack)
+ {
+ stringref_map_stack_.pop_back();
+ }
+ state_stack_.pop_back();
+ }
+
+ void read_text_string(string_type& s, std::error_code& ec)
+ {
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value);
+ uint8_t info = get_additional_information_value(c.value);
+
+ JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::text_string);
+ auto func = [&s](Source& source, std::size_t length, std::error_code& ec) -> bool
+ {
+ if (source_reader<Source>::read(source, s, length) != length)
+ {
+ ec = cbor_errc::unexpected_eof;
+ return false;
+ }
+ return true;
+ };
+ iterate_string_chunks(func, major_type, ec);
+ if (!stringref_map_stack_.empty() &&
+ info != jsoncons::cbor::detail::additional_info::indefinite_length &&
+ s.length() >= jsoncons::cbor::detail::min_length_for_stringref(stringref_map_stack_.back().size()))
+ {
+ stringref_map_stack_.back().emplace_back(s);
+ }
+ }
+
+ std::size_t get_size(std::error_code& ec)
+ {
+ uint64_t u = get_uint64_value(ec);
+ if (!more_)
+ {
+ return 0;
+ }
+ std::size_t len = static_cast<std::size_t>(u);
+ if (len != u)
+ {
+ ec = cbor_errc::number_too_large;
+ more_ = false;
+ }
+ return len;
+ }
+
+ bool read_byte_string(std::vector<uint8_t,byte_allocator_type>& v, std::error_code& ec)
+ {
+ bool more = true;
+ v.clear();
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more = false;
+ return more;
+ }
+ jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value);
+ uint8_t info = get_additional_information_value(c.value);
+
+ JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::byte_string);
+
+ switch(info)
+ {
+ case jsoncons::cbor::detail::additional_info::indefinite_length:
+ {
+ auto func = [&v,&more](Source& source, std::size_t length, std::error_code& ec) -> bool
+ {
+ if (source_reader<Source>::read(source, v, length) != length)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more = false;
+ return more;
+ }
+ return true;
+ };
+ iterate_string_chunks(func, major_type, ec);
+ break;
+ }
+ default:
+ {
+ std::size_t length = get_size(ec);
+ if (ec)
+ {
+ more = false;
+ return more;
+ }
+ if (source_reader<Source>::read(source_, v, length) != length)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more = false;
+ return more;
+ }
+ if (!stringref_map_stack_.empty() &&
+ v.size() >= jsoncons::cbor::detail::min_length_for_stringref(stringref_map_stack_.back().size()))
+ {
+ stringref_map_stack_.back().emplace_back(v);
+ }
+ break;
+ }
+ }
+ return more;
+ }
+
+ template <class Function>
+ void iterate_string_chunks(Function& func, jsoncons::cbor::detail::cbor_major_type type, std::error_code& ec)
+ {
+ int nesting_level = 0;
+
+ bool done = false;
+ while (!done)
+ {
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ if (nesting_level > 0 && c.value == 0xff)
+ {
+ --nesting_level;
+ if (nesting_level == 0)
+ {
+ done = true;
+ }
+ source_.ignore(1);
+ continue;
+ }
+
+ jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value);
+ if (major_type != type)
+ {
+ ec = cbor_errc::illegal_chunked_string;
+ more_ = false;
+ return;
+ }
+ uint8_t info = get_additional_information_value(c.value);
+
+ switch (info)
+ {
+ case jsoncons::cbor::detail::additional_info::indefinite_length:
+ {
+ ++nesting_level;
+ source_.ignore(1);
+ break;
+ }
+ default: // definite length
+ {
+ std::size_t length = get_size(ec);
+ if (!more_)
+ {
+ return;
+ }
+ more_ = func(source_, length, ec);
+ if (!more_)
+ {
+ return;
+ }
+ if (nesting_level == 0)
+ {
+ done = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ uint64_t get_uint64_value(std::error_code& ec)
+ {
+ uint64_t val = 0;
+
+ uint8_t initial_b;
+ if (source_.read(&initial_b, 1) == 0)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return 0;
+ }
+ uint8_t info = get_additional_information_value(initial_b);
+ switch (info)
+ {
+ case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23)
+ {
+ val = info;
+ break;
+ }
+
+ case 0x18: // Unsigned integer (one-byte uint8_t follows)
+ {
+ uint8_t b;
+ if (source_.read(&b, 1) == 0)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return val;
+ }
+ val = b;
+ break;
+ }
+
+ case 0x19: // Unsigned integer (two-byte uint16_t follows)
+ {
+ uint8_t buf[sizeof(uint16_t)];
+ source_.read(buf, sizeof(uint16_t));
+ val = binary::big_to_native<uint16_t>(buf, sizeof(buf));
+ break;
+ }
+
+ case 0x1a: // Unsigned integer (four-byte uint32_t follows)
+ {
+ uint8_t buf[sizeof(uint32_t)];
+ source_.read(buf, sizeof(uint32_t));
+ val = binary::big_to_native<uint32_t>(buf, sizeof(buf));
+ break;
+ }
+
+ case 0x1b: // Unsigned integer (eight-byte uint64_t follows)
+ {
+ uint8_t buf[sizeof(uint64_t)];
+ source_.read(buf, sizeof(uint64_t));
+ val = binary::big_to_native<uint64_t>(buf, sizeof(buf));
+ break;
+ }
+ default:
+ break;
+ }
+ return val;
+ }
+
+ int64_t get_int64_value(std::error_code& ec)
+ {
+ int64_t val = 0;
+
+ auto ch = source_.peek();
+ if (ch.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return val;
+ }
+
+ jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(ch.value);
+ uint8_t info = get_additional_information_value(ch.value);
+ switch (major_type)
+ {
+ case jsoncons::cbor::detail::cbor_major_type::negative_integer:
+ source_.ignore(1);
+ switch (info)
+ {
+ case JSONCONS_CBOR_0x00_0x17: // 0x00..0x17 (0..23)
+ {
+ val = static_cast<int8_t>(- 1 - info);
+ break;
+ }
+ case 0x18: // Negative integer (one-byte uint8_t follows)
+ {
+ uint8_t b;
+ if (source_.read(&b, 1) == 0)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return val;
+ }
+ val = static_cast<int64_t>(-1) - static_cast<int64_t>(b);
+ break;
+ }
+
+ case 0x19: // Negative integer -1-n (two-byte uint16_t follows)
+ {
+ uint8_t buf[sizeof(uint16_t)];
+ if (source_.read(buf, sizeof(uint16_t)) != sizeof(uint16_t))
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return val;
+ }
+ auto x = binary::big_to_native<uint16_t>(buf, sizeof(buf));
+ val = static_cast<int64_t>(-1)- x;
+ break;
+ }
+
+ case 0x1a: // Negative integer -1-n (four-byte uint32_t follows)
+ {
+ uint8_t buf[sizeof(uint32_t)];
+ if (source_.read(buf, sizeof(uint32_t)) != sizeof(uint32_t))
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return val;
+ }
+ auto x = binary::big_to_native<uint32_t>(buf, sizeof(buf));
+ val = static_cast<int64_t>(-1)- x;
+ break;
+ }
+
+ case 0x1b: // Negative integer -1-n (eight-byte uint64_t follows)
+ {
+ uint8_t buf[sizeof(uint64_t)];
+ if (source_.read(buf, sizeof(uint64_t)) != sizeof(uint64_t))
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return val;
+ }
+ auto x = binary::big_to_native<uint64_t>(buf, sizeof(buf));
+ val = static_cast<int64_t>(-1)- static_cast<int64_t>(x);
+ break;
+ }
+ }
+ break;
+
+ case jsoncons::cbor::detail::cbor_major_type::unsigned_integer:
+ {
+ uint64_t x = get_uint64_value(ec);
+ if (ec)
+ {
+ return 0;
+ }
+ if (x <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
+ {
+ val = x;
+ }
+ else
+ {
+ // error;
+ }
+
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return val;
+ }
+
+ double get_double(std::error_code& ec)
+ {
+ double val = 0;
+
+ uint8_t b;
+ if (source_.read(&b, 1) == 0)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return 0;
+ }
+ uint8_t info = get_additional_information_value(b);
+ switch (info)
+ {
+ case 0x1a: // Single-Precision Float (four-byte IEEE 754)
+ {
+ uint8_t buf[sizeof(float)];
+ if (source_.read(buf, sizeof(float)) !=sizeof(float))
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return 0;
+ }
+ val = binary::big_to_native<float>(buf, sizeof(buf));
+ break;
+ }
+
+ case 0x1b: // Double-Precision Float (eight-byte IEEE 754)
+ {
+ uint8_t buf[sizeof(double)];
+ if (source_.read(buf, sizeof(double)) != sizeof(double))
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return 0;
+ }
+ val = binary::big_to_native<double>(buf, sizeof(buf));
+ break;
+ }
+ default:
+ break;
+ }
+
+ return val;
+ }
+
+ void read_decimal_fraction(string_type& result, std::error_code& ec)
+ {
+ std::size_t size = get_size(ec);
+ if (!more_)
+ {
+ return;
+ }
+ if (size != 2)
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ more_ = false;
+ return;
+ }
+
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ int64_t exponent = 0;
+ switch (get_major_type(c.value))
+ {
+ case jsoncons::cbor::detail::cbor_major_type::unsigned_integer:
+ {
+ exponent = get_uint64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::negative_integer:
+ {
+ exponent = get_int64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ default:
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ more_ = false;
+ return;
+ }
+ }
+
+ string_type s;
+
+ c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ switch (get_major_type(c.value))
+ {
+ case jsoncons::cbor::detail::cbor_major_type::unsigned_integer:
+ {
+ uint64_t val = get_uint64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ jsoncons::detail::from_integer(val, s);
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::negative_integer:
+ {
+ int64_t val = get_int64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ jsoncons::detail::from_integer(val, s);
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::semantic_tag:
+ {
+ uint8_t b;
+ if (source_.read(&b, 1) == 0)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint8_t tag = get_additional_information_value(b);
+ c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ if (get_major_type(c.value) == jsoncons::cbor::detail::cbor_major_type::byte_string)
+ {
+ bytes_buffer_.clear();
+ read_byte_string(bytes_buffer_, ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ if (tag == 2)
+ {
+ bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size());
+ n.write_string(s);
+ }
+ else if (tag == 3)
+ {
+ bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size());
+ n = -1 - n;
+ n.write_string(s);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ more_ = false;
+ return;
+ }
+ }
+
+ if (s.size() >= static_cast<std::size_t>((std::numeric_limits<int32_t>::max)()) ||
+ exponent >= (std::numeric_limits<int32_t>::max)() ||
+ exponent <= (std::numeric_limits<int32_t>::min)())
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ more_ = false;
+ return;
+ }
+ else if (s.size() > 0)
+ {
+ if (s[0] == '-')
+ {
+ result.push_back('-');
+ jsoncons::detail::prettify_string(s.c_str()+1, s.size()-1, (int)exponent, -4, 17, result);
+ }
+ else
+ {
+ jsoncons::detail::prettify_string(s.c_str(), s.size(), (int)exponent, -4, 17, result);
+ }
+ }
+ else
+ {
+ ec = cbor_errc::invalid_decimal_fraction;
+ more_ = false;
+ return;
+ }
+ }
+
+ void read_bigfloat(string_type& s, std::error_code& ec)
+ {
+ std::size_t size = get_size(ec);
+ if (!more_)
+ {
+ return;
+ }
+ if (size != 2)
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ more_ = false;
+ return;
+ }
+
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ int64_t exponent = 0;
+ switch (get_major_type(c.value))
+ {
+ case jsoncons::cbor::detail::cbor_major_type::unsigned_integer:
+ {
+ exponent = get_uint64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::negative_integer:
+ {
+ exponent = get_int64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ more_ = false;
+ return;
+ }
+ }
+
+ c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ switch (get_major_type(c.value))
+ {
+ case jsoncons::cbor::detail::cbor_major_type::unsigned_integer:
+ {
+ uint64_t val = get_uint64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ s.push_back('0');
+ s.push_back('x');
+ jsoncons::detail::integer_to_string_hex(val, s);
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::negative_integer:
+ {
+ int64_t val = get_int64_value(ec);
+ if (ec)
+ {
+ return;
+ }
+ s.push_back('-');
+ s.push_back('0');
+ s.push_back('x');
+ jsoncons::detail::integer_to_string_hex(static_cast<uint64_t>(-val), s);
+ break;
+ }
+ case jsoncons::cbor::detail::cbor_major_type::semantic_tag:
+ {
+ uint8_t b;
+ if (source_.read(&b, 1) == 0)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint8_t tag = get_additional_information_value(b);
+
+ c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ if (get_major_type(c.value) == jsoncons::cbor::detail::cbor_major_type::byte_string)
+ {
+ bytes_buffer_.clear();
+ more_ = read_byte_string(bytes_buffer_, ec);
+ if (!more_)
+ {
+ return;
+ }
+ if (tag == 2)
+ {
+ s.push_back('0');
+ s.push_back('x');
+ bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size());
+ n.write_string_hex(s);
+ }
+ else if (tag == 3)
+ {
+ s.push_back('-');
+ s.push_back('0');
+ bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size());
+ n = -1 - n;
+ n.write_string_hex(s);
+ s[2] = 'x'; // overwrite minus
+ }
+ }
+ break;
+ }
+ default:
+ {
+ ec = cbor_errc::invalid_bigfloat;
+ more_ = false;
+ return;
+ }
+ }
+
+ s.push_back('p');
+ if (exponent >=0)
+ {
+ jsoncons::detail::integer_to_string_hex(static_cast<uint64_t>(exponent), s);
+ }
+ else
+ {
+ s.push_back('-');
+ jsoncons::detail::integer_to_string_hex(static_cast<uint64_t>(-exponent), s);
+ }
+ }
+
+ static jsoncons::cbor::detail::cbor_major_type get_major_type(uint8_t type)
+ {
+ static constexpr uint8_t major_type_shift = 0x05;
+ uint8_t value = type >> major_type_shift;
+ return static_cast<jsoncons::cbor::detail::cbor_major_type>(value);
+ }
+
+ static uint8_t get_additional_information_value(uint8_t type)
+ {
+ static constexpr uint8_t additional_information_mask = (1U << 5) - 1;
+ uint8_t value = type & additional_information_mask;
+ return value;
+ }
+
+ void read_tags(std::error_code& ec)
+ {
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(c.value);
+
+ while (major_type == jsoncons::cbor::detail::cbor_major_type::semantic_tag)
+ {
+ uint64_t val = get_uint64_value(ec);
+ if (!more_)
+ {
+ return;
+ }
+ switch(val)
+ {
+ case 25: // stringref
+ other_tags_[stringref_tag] = true;
+ break;
+ case 256: // stringref-namespace
+ other_tags_[stringref_namespace_tag] = true;
+ break;
+ default:
+ other_tags_[item_tag] = true;
+ item_tag_ = val;
+ break;
+ }
+ c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ major_type = get_major_type(c.value);
+ }
+ }
+
+ void handle_string(json_visitor2& visitor, const jsoncons::basic_string_view<char>& v, std::error_code& ec)
+ {
+ semantic_tag tag = semantic_tag::none;
+ if (other_tags_[item_tag])
+ {
+ switch (item_tag_)
+ {
+ case 0:
+ tag = semantic_tag::datetime;
+ break;
+ case 32:
+ tag = semantic_tag::uri;
+ break;
+ case 33:
+ tag = semantic_tag::base64url;
+ break;
+ case 34:
+ tag = semantic_tag::base64;
+ break;
+ default:
+ break;
+ }
+ other_tags_[item_tag] = false;
+ }
+ more_ = visitor.string_value(v, tag, *this, ec);
+ }
+
+ static jsoncons::endian get_typed_array_endianness(const uint8_t tag)
+ {
+ return ((tag & detail::cbor_array_tags_e_mask) >> detail::cbor_array_tags_e_shift) == 0 ? jsoncons::endian::big : jsoncons::endian::little;
+ }
+
+ static std::size_t get_typed_array_bytes_per_element(const uint8_t tag)
+ {
+ const uint8_t f = (tag & detail::cbor_array_tags_f_mask) >> detail::cbor_array_tags_f_shift;
+ const uint8_t ll = (tag & detail::cbor_array_tags_ll_mask) >> detail::cbor_array_tags_ll_shift;
+
+ return std::size_t(1) << (f + ll);
+ }
+
+ template <typename Read>
+ void write_byte_string(Read read, json_visitor2& visitor, std::error_code& ec)
+ {
+ if (other_tags_[item_tag])
+ {
+ switch (item_tag_)
+ {
+ case 0x2:
+ {
+ bytes_buffer_.clear();
+ read(bytes_buffer_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size());
+ text_buffer_.clear();
+ n.write_string(text_buffer_);
+ more_ = visitor.string_value(text_buffer_, semantic_tag::bigint, *this, ec);
+ break;
+ }
+ case 0x3:
+ {
+ bytes_buffer_.clear();
+ read(bytes_buffer_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ bigint n = bigint::from_bytes_be(1, bytes_buffer_.data(), bytes_buffer_.size());
+ n = -1 - n;
+ text_buffer_.clear();
+ n.write_string(text_buffer_);
+ more_ = visitor.string_value(text_buffer_, semantic_tag::bigint, *this, ec);
+ break;
+ }
+ case 0x15:
+ {
+ read(bytes_buffer_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ more_ = visitor.byte_string_value(bytes_buffer_, semantic_tag::base64url, *this, ec);
+ break;
+ }
+ case 0x16:
+ {
+ read(bytes_buffer_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ more_ = visitor.byte_string_value(bytes_buffer_, semantic_tag::base64, *this, ec);
+ break;
+ }
+ case 0x17:
+ {
+ read(bytes_buffer_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ more_ = visitor.byte_string_value(bytes_buffer_, semantic_tag::base16, *this, ec);
+ break;
+ }
+ case 0x40:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ uint8_t* data = reinterpret_cast<uint8_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size();
+ more_ = visitor.typed_array(jsoncons::span<const uint8_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x44:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ uint8_t* data = reinterpret_cast<uint8_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size();
+ more_ = visitor.typed_array(jsoncons::span<const uint8_t>(data,size), semantic_tag::clamped, *this, ec);
+ break;
+ }
+ case 0x41:
+ case 0x45:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ uint16_t* data = reinterpret_cast<uint16_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<uint16_t>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(jsoncons::span<const uint16_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x42:
+ case 0x46:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ uint32_t* data = reinterpret_cast<uint32_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<uint32_t>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(jsoncons::span<const uint32_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x43:
+ case 0x47:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ uint64_t* data = reinterpret_cast<uint64_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<uint64_t>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(jsoncons::span<const uint64_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x48:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ int8_t* data = reinterpret_cast<int8_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size();
+ more_ = visitor.typed_array(jsoncons::span<const int8_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x49:
+ case 0x4d:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ int16_t* data = reinterpret_cast<int16_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<int16_t>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(jsoncons::span<const int16_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x4a:
+ case 0x4e:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ int32_t* data = reinterpret_cast<int32_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<int32_t>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(jsoncons::span<const int32_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x4b:
+ case 0x4f:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ int64_t* data = reinterpret_cast<int64_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<int64_t>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(jsoncons::span<const int64_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x50:
+ case 0x54:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ uint16_t* data = reinterpret_cast<uint16_t*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<uint16_t>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(half_arg, jsoncons::span<const uint16_t>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x51:
+ case 0x55:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ float* data = reinterpret_cast<float*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<float>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(jsoncons::span<const float>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ case 0x52:
+ case 0x56:
+ {
+ typed_array_.clear();
+ read(typed_array_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ const uint8_t tag = (uint8_t)item_tag_;
+ jsoncons::endian e = get_typed_array_endianness(tag);
+ const size_t bytes_per_elem = get_typed_array_bytes_per_element(tag);
+
+ double* data = reinterpret_cast<double*>(typed_array_.data());
+ std::size_t size = typed_array_.size()/bytes_per_elem;
+
+ if (e != jsoncons::endian::native)
+ {
+ for (std::size_t i = 0; i < size; ++i)
+ {
+ data[i] = binary::byte_swap<double>(data[i]);
+ }
+ }
+ more_ = visitor.typed_array(jsoncons::span<const double>(data,size), semantic_tag::none, *this, ec);
+ break;
+ }
+ default:
+ {
+ read(bytes_buffer_,ec);
+ if (ec)
+ {
+ more_ = false;
+ return;
+ }
+ more_ = visitor.byte_string_value(bytes_buffer_, item_tag_, *this, ec);
+ break;
+ }
+ }
+ other_tags_[item_tag] = false;
+ }
+ else
+ {
+ read(bytes_buffer_,ec);
+ if (ec)
+ {
+ return;
+ }
+ more_ = visitor.byte_string_value(bytes_buffer_, semantic_tag::none, *this, ec);
+ }
+ }
+
+ void produce_begin_multi_dim(json_visitor2& visitor,
+ semantic_tag tag,
+ std::error_code& ec)
+ {
+ uint8_t b;
+ if (source_.read(&b, 1) == 0)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ jsoncons::cbor::detail::cbor_major_type major_type = get_major_type(b);
+ JSONCONS_ASSERT(major_type == jsoncons::cbor::detail::cbor_major_type::array);
+ uint8_t info = get_additional_information_value(b);
+
+ read_shape(info, ec);
+ if (ec)
+ {
+ return;
+ }
+
+ state_stack_.emplace_back(parse_mode::multi_dim, 0);
+ more_ = visitor.begin_multi_dim(shape_, tag, *this, ec);
+ }
+
+ void produce_end_multi_dim(json_visitor2& visitor, std::error_code& ec)
+ {
+ more_ = visitor.end_multi_dim(*this, ec);
+ state_stack_.pop_back();
+ }
+
+ void read_shape(uint8_t info, std::error_code& ec)
+ {
+ shape_.clear();
+ switch (info)
+ {
+ case jsoncons::cbor::detail::additional_info::indefinite_length:
+ {
+ while (true)
+ {
+ auto c = source_.peek();
+ if (c.eof)
+ {
+ ec = cbor_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ if (c.value == 0xff)
+ {
+ source_.ignore(1);
+ }
+ else
+ {
+ std::size_t dim = get_size(ec);
+ if (!more_)
+ {
+ return;
+ }
+ shape_.push_back(dim);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ std::size_t size = get_size(ec);
+ if (!more_)
+ {
+ return;
+ }
+ for (std::size_t i = 0; more_ && i < size; ++i)
+ {
+ std::size_t dim = get_size(ec);
+ if (!more_)
+ {
+ return;
+ }
+ shape_.push_back(dim);
+ }
+ break;
+ }
+ }
+ }
+};
+
+}}
+
+#endif
diff --git a/include/jsoncons_ext/cbor/cbor_reader.hpp b/include/jsoncons_ext/cbor/cbor_reader.hpp
new file mode 100644
index 0000000..a46a52e
--- /dev/null
+++ b/include/jsoncons_ext/cbor/cbor_reader.hpp
@@ -0,0 +1,116 @@
+// Copyright 2017 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_READER_HPP
+#define JSONCONS_CBOR_CBOR_READER_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <utility> // std::move
+#include <jsoncons/json.hpp>
+#include <jsoncons/source.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/cbor/cbor_encoder.hpp>
+#include <jsoncons_ext/cbor/cbor_error.hpp>
+#include <jsoncons_ext/cbor/cbor_detail.hpp>
+#include <jsoncons_ext/cbor/cbor_parser.hpp>
+
+namespace jsoncons { namespace cbor {
+
+template <class Source,class Allocator=std::allocator<char>>
+class basic_cbor_reader
+{
+ using char_type = char;
+
+ basic_cbor_parser<Source,Allocator> parser_;
+ basic_json_visitor2_to_visitor_adaptor<char_type,Allocator> adaptor_;
+ json_visitor2& visitor_;
+public:
+ template <class Sourceable>
+ basic_cbor_reader(Sourceable&& source,
+ json_visitor& visitor,
+ const Allocator alloc)
+ : basic_cbor_reader(std::forward<Sourceable>(source),
+ visitor,
+ cbor_decode_options(),
+ alloc)
+ {
+ }
+
+ template <class Sourceable>
+ basic_cbor_reader(Sourceable&& source,
+ json_visitor& visitor,
+ const cbor_decode_options& options = cbor_decode_options(),
+ const Allocator alloc=Allocator())
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ adaptor_(visitor, alloc), visitor_(adaptor_)
+ {
+ }
+ template <class Sourceable>
+ basic_cbor_reader(Sourceable&& source,
+ json_visitor2& visitor,
+ const Allocator alloc)
+ : basic_cbor_reader(std::forward<Sourceable>(source),
+ visitor,
+ cbor_decode_options(),
+ alloc)
+ {
+ }
+
+ template <class Sourceable>
+ basic_cbor_reader(Sourceable&& source,
+ json_visitor2& visitor,
+ const cbor_decode_options& options = cbor_decode_options(),
+ const Allocator alloc=Allocator())
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ visitor_(visitor)
+ {
+ }
+
+ void read()
+ {
+ std::error_code ec;
+ read(ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec,line(),column()));
+ }
+ }
+
+ void read(std::error_code& ec)
+ {
+ parser_.reset();
+ parser_.parse(visitor_, ec);
+ if (ec)
+ {
+ return;
+ }
+ }
+
+ std::size_t line() const
+ {
+ return parser_.line();
+ }
+
+ std::size_t column() const
+ {
+ return parser_.column();
+ }
+};
+
+using cbor_stream_reader = basic_cbor_reader<jsoncons::binary_stream_source>;
+
+using cbor_bytes_reader = basic_cbor_reader<jsoncons::bytes_source>;
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_reader") typedef cbor_stream_reader cbor_reader;
+JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_reader") typedef cbor_bytes_reader cbor_buffer_reader;
+#endif
+
+}}
+
+#endif
diff --git a/include/jsoncons_ext/cbor/decode_cbor.hpp b/include/jsoncons_ext/cbor/decode_cbor.hpp
new file mode 100644
index 0000000..ab5c913
--- /dev/null
+++ b/include/jsoncons_ext/cbor/decode_cbor.hpp
@@ -0,0 +1,203 @@
+// Copyright 2017 Daniel Parkerstd
+// 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_DECODE_CBOR_HPP
+#define JSONCONS_CBOR_DECODE_CBOR_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <type_traits> // std::enable_if
+#include <istream> // std::basic_istream
+#include <jsoncons/json.hpp>
+#include <jsoncons/json_filter.hpp>
+#include <jsoncons/decode_traits.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/cbor/cbor_reader.hpp>
+#include <jsoncons_ext/cbor/cbor_cursor.hpp>
+
+namespace jsoncons {
+namespace cbor {
+
+ template<class T, class Source>
+ typename std::enable_if<type_traits::is_basic_json<T>::value &&
+ type_traits::is_byte_sequence<Source>::value,T>::type
+ decode_cbor(const Source& v,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_cbor_reader<jsoncons::bytes_source> reader(v, adaptor, options);
+ reader.read();
+ if (!decoder.is_valid())
+ {
+ JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
+ }
+ return decoder.get_result();
+ }
+
+ template<class T, class Source>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value &&
+ type_traits::is_byte_sequence<Source>::value,T>::type
+ decode_cbor(const Source& v,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ basic_cbor_cursor<bytes_source> cursor(v, options);
+ json_decoder<basic_json<char,sorted_policy>> decoder{};
+
+ std::error_code ec;
+ T val = decode_traits<T,char>::decode(cursor, decoder, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
+ }
+ return val;
+ }
+
+ template<class T>
+ typename std::enable_if<type_traits::is_basic_json<T>::value,T>::type
+ decode_cbor(std::istream& is,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ cbor_stream_reader reader(is, adaptor, options);
+ reader.read();
+ if (!decoder.is_valid())
+ {
+ JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
+ }
+ return decoder.get_result();
+ }
+
+ template<class T>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value,T>::type
+ decode_cbor(std::istream& is,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ basic_cbor_cursor<binary_stream_source> cursor(is, options);
+ json_decoder<basic_json<char,sorted_policy>> decoder{};
+
+ std::error_code ec;
+ T val = decode_traits<T,char>::decode(cursor, decoder, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
+ }
+ return val;
+ }
+
+ template<class T, class InputIt>
+ typename std::enable_if<type_traits::is_basic_json<T>::value,T>::type
+ decode_cbor(InputIt first, InputIt last,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_cbor_reader<binary_iterator_source<InputIt>> reader(binary_iterator_source<InputIt>(first, last), adaptor, options);
+ reader.read();
+ if (!decoder.is_valid())
+ {
+ JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
+ }
+ return decoder.get_result();
+ }
+
+ template<class T, class InputIt>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value,T>::type
+ decode_cbor(InputIt first, InputIt last,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ basic_cbor_cursor<binary_iterator_source<InputIt>> cursor(binary_iterator_source<InputIt>(first, last), options);
+ json_decoder<basic_json<char,sorted_policy>> decoder{};
+
+ std::error_code ec;
+ T val = decode_traits<T,char>::decode(cursor, decoder, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
+ }
+ return val;
+ }
+
+ // With leading allocator parameter
+
+ template<class T, class Source, class TempAllocator>
+ typename std::enable_if<type_traits::is_basic_json<T>::value &&
+ type_traits::is_byte_sequence<Source>::value,T>::type
+ decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const Source& v,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ json_decoder<T,TempAllocator> decoder(temp_alloc);
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_cbor_reader<jsoncons::bytes_source,TempAllocator> reader(v, adaptor, options, temp_alloc);
+ reader.read();
+ if (!decoder.is_valid())
+ {
+ JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
+ }
+ return decoder.get_result();
+ }
+
+ template<class T, class Source, class TempAllocator>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value &&
+ type_traits::is_byte_sequence<Source>::value,T>::type
+ decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const Source& v,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ basic_cbor_cursor<bytes_source,TempAllocator> cursor(v, options, temp_alloc);
+ json_decoder<basic_json<char,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc);
+
+ std::error_code ec;
+ T val = decode_traits<T,char>::decode(cursor, decoder, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
+ }
+ return val;
+ }
+
+ template<class T,class TempAllocator>
+ typename std::enable_if<type_traits::is_basic_json<T>::value,T>::type
+ decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ std::istream& is,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ json_decoder<T,TempAllocator> decoder(temp_alloc);
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_cbor_reader<jsoncons::binary_stream_source,TempAllocator> reader(is, adaptor, options, temp_alloc);
+ reader.read();
+ if (!decoder.is_valid())
+ {
+ JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
+ }
+ return decoder.get_result();
+ }
+
+ template<class T,class TempAllocator>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value,T>::type
+ decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ std::istream& is,
+ const cbor_decode_options& options = cbor_decode_options())
+ {
+ basic_cbor_cursor<binary_stream_source,TempAllocator> cursor(is, options, temp_alloc);
+ json_decoder<basic_json<char,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc);
+
+ std::error_code ec;
+ T val = decode_traits<T,char>::decode(cursor, decoder, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
+ }
+ return val;
+ }
+
+} // namespace cbor
+} // namespace jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/cbor/encode_cbor.hpp b/include/jsoncons_ext/cbor/encode_cbor.hpp
new file mode 100644
index 0000000..8576f1c
--- /dev/null
+++ b/include/jsoncons_ext/cbor/encode_cbor.hpp
@@ -0,0 +1,151 @@
+// Copyright 2017 Daniel Parkerstd
+// 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_ENCODE_CBOR_HPP
+#define JSONCONS_CBOR_ENCODE_CBOR_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <type_traits> // std::enable_if
+#include <istream> // std::basic_istream
+#include <jsoncons/json.hpp>
+#include <jsoncons/json_filter.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/encode_traits.hpp>
+#include <jsoncons_ext/cbor/cbor_encoder.hpp>
+
+namespace jsoncons {
+namespace cbor {
+
+ // to bytes
+
+ template<class T, class Container>
+ typename std::enable_if<type_traits::is_basic_json<T>::value &&
+ type_traits::is_back_insertable_byte_container<Container>::value,void>::type
+ encode_cbor(const T& j,
+ Container& v,
+ const cbor_encode_options& options = cbor_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_cbor_encoder<jsoncons::bytes_sink<Container>> encoder(v, options);
+ auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
+ j.dump(adaptor);
+ }
+
+ template<class T, class Container>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value &&
+ type_traits::is_back_insertable_byte_container<Container>::value,void>::type
+ encode_cbor(const T& val, Container& v,
+ const cbor_encode_options& options = cbor_encode_options())
+ {
+ basic_cbor_encoder<jsoncons::bytes_sink<Container>> encoder(v, options);
+ std::error_code ec;
+ encode_traits<T,char>::encode(val, encoder, json(), ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec));
+ }
+ }
+
+ // stream
+
+ template<class T>
+ typename std::enable_if<type_traits::is_basic_json<T>::value,void>::type
+ encode_cbor(const T& j,
+ std::ostream& os,
+ const cbor_encode_options& options = cbor_encode_options())
+ {
+ using char_type = typename T::char_type;
+ cbor_stream_encoder encoder(os, options);
+ auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
+ j.dump(adaptor);
+ }
+
+ template<class T>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value,void>::type
+ encode_cbor(const T& val,
+ std::ostream& os,
+ const cbor_encode_options& options = cbor_encode_options())
+ {
+ cbor_stream_encoder encoder(os, options);
+ std::error_code ec;
+ encode_traits<T,char>::encode(val, encoder, json(), ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec));
+ }
+ }
+
+ // temp_allocator_arg
+
+ // to bytes
+
+ template<class T, class Container, class TempAllocator>
+ typename std::enable_if<type_traits::is_basic_json<T>::value &&
+ type_traits::is_back_insertable_byte_container<Container>::value,void>::type
+ encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& j,
+ Container& v,
+ const cbor_encode_options& options = cbor_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_cbor_encoder<bytes_sink<Container>,TempAllocator> encoder(v, options, temp_alloc);
+ auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
+ j.dump(adaptor);
+ }
+
+ template<class T, class Container, class TempAllocator>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value &&
+ type_traits::is_back_insertable_byte_container<Container>::value,void>::type
+ encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& val,
+ Container& v,
+ const cbor_encode_options& options = cbor_encode_options())
+ {
+ basic_cbor_encoder<jsoncons::bytes_sink<Container>,TempAllocator> encoder(v, options, temp_alloc);
+ std::error_code ec;
+ encode_traits<T,char>::encode(val, encoder, json(), ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec));
+ }
+ }
+
+ // stream
+
+ template<class T,class TempAllocator>
+ typename std::enable_if<type_traits::is_basic_json<T>::value,void>::type
+ encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& j,
+ std::ostream& os,
+ const cbor_encode_options& options = cbor_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_cbor_encoder<binary_stream_sink,TempAllocator> encoder(os, options, temp_alloc);
+ auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
+ j.dump(adaptor);
+ }
+
+ template<class T,class TempAllocator>
+ typename std::enable_if<!type_traits::is_basic_json<T>::value,void>::type
+ encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& val,
+ std::ostream& os,
+ const cbor_encode_options& options = cbor_encode_options())
+ {
+ std::error_code ec;
+ encode_cbor(temp_allocator_arg, temp_alloc, val, os, options, ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec));
+ }
+ }
+
+} // namespace cbor
+} // namespace jsoncons
+
+#endif