aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons_ext/msgpack
diff options
context:
space:
mode:
Diffstat (limited to 'include/jsoncons_ext/msgpack')
-rw-r--r--include/jsoncons_ext/msgpack/decode_msgpack.hpp202
-rw-r--r--include/jsoncons_ext/msgpack/encode_msgpack.hpp142
-rw-r--r--include/jsoncons_ext/msgpack/msgpack.hpp24
-rw-r--r--include/jsoncons_ext/msgpack/msgpack_cursor.hpp343
-rw-r--r--include/jsoncons_ext/msgpack/msgpack_cursor2.hpp259
-rw-r--r--include/jsoncons_ext/msgpack/msgpack_encoder.hpp753
-rw-r--r--include/jsoncons_ext/msgpack/msgpack_error.hpp94
-rw-r--r--include/jsoncons_ext/msgpack/msgpack_options.hpp74
-rw-r--r--include/jsoncons_ext/msgpack/msgpack_parser.hpp748
-rw-r--r--include/jsoncons_ext/msgpack/msgpack_reader.hpp116
-rw-r--r--include/jsoncons_ext/msgpack/msgpack_type.hpp63
11 files changed, 2818 insertions, 0 deletions
diff --git a/include/jsoncons_ext/msgpack/decode_msgpack.hpp b/include/jsoncons_ext/msgpack/decode_msgpack.hpp
new file mode 100644
index 0000000..614af3d
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/decode_msgpack.hpp
@@ -0,0 +1,202 @@
+// Copyright 2013 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_MSGPACK_DECODE_MSGPACK_HPP
+#define JSONCONS_MSGPACK_DECODE_MSGPACK_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <type_traits> // std::enable_if
+#include <istream> // std::basic_istream
+#include <jsoncons/json.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/msgpack/msgpack_encoder.hpp>
+#include <jsoncons_ext/msgpack/msgpack_reader.hpp>
+#include <jsoncons_ext/msgpack/msgpack_cursor.hpp>
+
+namespace jsoncons {
+namespace msgpack {
+
+ 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_msgpack(const Source& v,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_msgpack_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_msgpack(const Source& v,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ basic_msgpack_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_msgpack(std::istream& is,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ msgpack_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_msgpack(std::istream& is,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ basic_msgpack_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_msgpack(InputIt first, InputIt last,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_msgpack_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_msgpack(InputIt first, InputIt last,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ basic_msgpack_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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const Source& v,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ json_decoder<T,TempAllocator> decoder(temp_alloc);
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_msgpack_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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const Source& v,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ basic_msgpack_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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ std::istream& is,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ json_decoder<T,TempAllocator> decoder(temp_alloc);
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_msgpack_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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ std::istream& is,
+ const msgpack_decode_options& options = msgpack_decode_options())
+ {
+ basic_msgpack_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;
+ }
+
+} // msgpack
+} // jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/msgpack/encode_msgpack.hpp b/include/jsoncons_ext/msgpack/encode_msgpack.hpp
new file mode 100644
index 0000000..10a61e0
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/encode_msgpack.hpp
@@ -0,0 +1,142 @@
+// Copyright 2013 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_MSGPACK_ENCODE_MSGPACK_HPP
+#define JSONCONS_MSGPACK_ENCODE_MSGPACK_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <type_traits> // std::enable_if
+#include <istream> // std::basic_istream
+#include <jsoncons/json.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/msgpack/msgpack_encoder.hpp>
+#include <jsoncons_ext/msgpack/msgpack_reader.hpp>
+
+namespace jsoncons {
+namespace msgpack {
+
+ 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_msgpack(const T& j,
+ Container& v,
+ const msgpack_encode_options& options = msgpack_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_msgpack_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_msgpack(const T& val,
+ Container& v,
+ const msgpack_encode_options& options = msgpack_encode_options())
+ {
+ basic_msgpack_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));
+ }
+ }
+
+ template<class T>
+ typename std::enable_if<type_traits::is_basic_json<T>::value,void>::type
+ encode_msgpack(const T& j,
+ std::ostream& os,
+ const msgpack_encode_options& options = msgpack_encode_options())
+ {
+ using char_type = typename T::char_type;
+ msgpack_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_msgpack(const T& val,
+ std::ostream& os,
+ const msgpack_encode_options& options = msgpack_encode_options())
+ {
+ msgpack_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));
+ }
+ }
+
+ // with temp_allocator_arg_t
+
+ 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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc, const T& j,
+ Container& v,
+ const msgpack_encode_options& options = msgpack_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_msgpack_encoder<jsoncons::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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& val, Container& v,
+ const msgpack_encode_options& options = msgpack_encode_options())
+ {
+ basic_msgpack_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));
+ }
+ }
+
+ template<class T,class TempAllocator>
+ typename std::enable_if<type_traits::is_basic_json<T>::value,void>::type
+ encode_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& j,
+ std::ostream& os,
+ const msgpack_encode_options& options = msgpack_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_msgpack_encoder<jsoncons::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_msgpack(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& val,
+ std::ostream& os,
+ const msgpack_encode_options& options = msgpack_encode_options())
+ {
+ basic_msgpack_encoder<jsoncons::binary_stream_sink,TempAllocator> encoder(os, options, temp_alloc);
+ std::error_code ec;
+ encode_traits<T,char>::encode(val, encoder, json(), ec);
+ if (ec)
+ {
+ JSONCONS_THROW(ser_error(ec));
+ }
+ }
+
+} // msgpack
+} // jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/msgpack/msgpack.hpp b/include/jsoncons_ext/msgpack/msgpack.hpp
new file mode 100644
index 0000000..307aad2
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack.hpp
@@ -0,0 +1,24 @@
+// Copyright 2013 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_MSGPACK_MSGPACK_HPP
+#define JSONCONS_MSGPACK_MSGPACK_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <type_traits> // std::enable_if
+#include <istream> // std::basic_istream
+#include <jsoncons/json.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/msgpack/msgpack_encoder.hpp>
+#include <jsoncons_ext/msgpack/msgpack_reader.hpp>
+#include <jsoncons_ext/msgpack/msgpack_cursor.hpp>
+#include <jsoncons_ext/msgpack/encode_msgpack.hpp>
+#include <jsoncons_ext/msgpack/decode_msgpack.hpp>
+
+#endif
+
diff --git a/include/jsoncons_ext/msgpack/msgpack_cursor.hpp b/include/jsoncons_ext/msgpack/msgpack_cursor.hpp
new file mode 100644
index 0000000..a813429
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack_cursor.hpp
@@ -0,0 +1,343 @@
+// 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_MSGPACK_MSGPACK_CURSOR_HPP
+#define JSONCONS_MSGPACK_MSGPACK_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/msgpack/msgpack_parser.hpp>
+
+namespace jsoncons {
+namespace msgpack {
+
+template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>>
+class basic_msgpack_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_msgpack_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_msgpack_cursor(const basic_msgpack_cursor&) = delete;
+ basic_msgpack_cursor& operator=(const basic_msgpack_cursor&) = delete;
+
+public:
+ using string_view_type = string_view;
+
+ template <class Sourceable>
+ basic_msgpack_cursor(Sourceable&& source,
+ const msgpack_decode_options& options = msgpack_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_msgpack_cursor(Sourceable&& source,
+ std::error_code& ec)
+ : basic_msgpack_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ msgpack_decode_options(),
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_msgpack_cursor(Sourceable&& source,
+ const msgpack_decode_options& options,
+ std::error_code& ec)
+ : basic_msgpack_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ options,
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_msgpack_cursor(std::allocator_arg_t, const Allocator& alloc,
+ Sourceable&& source,
+ const msgpack_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();
+ }
+
+ 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_msgpack_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_msgpack_cursor(Sourceable&& source,
+ std::function<bool(const staj_event&, const ser_context&)> filter,
+ const msgpack_decode_options& options = msgpack_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_msgpack_cursor(Sourceable&& source,
+ std::function<bool(const staj_event&, const ser_context&)> filter,
+ std::error_code& ec)
+ : basic_msgpack_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source), filter, ec)
+ {
+ }
+
+ template <class Sourceable>
+ JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
+ basic_msgpack_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 msgpack_stream_cursor = basic_msgpack_cursor<jsoncons::binary_stream_source>;
+using msgpack_bytes_cursor = basic_msgpack_cursor<jsoncons::bytes_source>;
+
+} // namespace msgpack
+} // namespace jsoncons
+
+#endif
+
diff --git a/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp b/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp
new file mode 100644
index 0000000..8fce1ca
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp
@@ -0,0 +1,259 @@
+// 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_MSGPACK_MSGPACK_CURSOR2_HPP
+#define JSONCONS_MSGPACK_MSGPACK_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/msgpack/msgpack_parser.hpp>
+
+namespace jsoncons {
+namespace msgpack {
+
+ template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>>
+ class basic_msgpack_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_msgpack_parser<Source,Allocator> parser_;
+ basic_staj2_visitor<char_type> cursor_visitor_;
+ bool eof_;
+
+ // Noncopyable and nonmoveable
+ basic_msgpack_cursor2(const basic_msgpack_cursor2&) = delete;
+ basic_msgpack_cursor2& operator=(const basic_msgpack_cursor2&) = delete;
+
+ public:
+ using string_view_type = string_view;
+
+ template <class Sourceable>
+ basic_msgpack_cursor2(Sourceable&& source,
+ const msgpack_decode_options& options = msgpack_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_msgpack_cursor2(Sourceable&& source,
+ std::error_code& ec)
+ : basic_msgpack_cursor2(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ msgpack_decode_options(),
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_msgpack_cursor2(Sourceable&& source,
+ const msgpack_decode_options& options,
+ std::error_code& ec)
+ : basic_msgpack_cursor2(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ options,
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_msgpack_cursor2(std::allocator_arg_t, const Allocator& alloc,
+ Sourceable&& source,
+ const msgpack_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();
+ }
+
+ 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_msgpack_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 msgpack_stream_cursor2 = basic_msgpack_cursor2<jsoncons::binary_stream_source>;
+ using msgpack_bytes_cursor2 = basic_msgpack_cursor2<jsoncons::bytes_source>;
+
+} // namespace msgpack
+} // namespace jsoncons
+
+#endif
+
diff --git a/include/jsoncons_ext/msgpack/msgpack_encoder.hpp b/include/jsoncons_ext/msgpack/msgpack_encoder.hpp
new file mode 100644
index 0000000..34e882b
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack_encoder.hpp
@@ -0,0 +1,753 @@
+// 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_MSGPACK_MSGPACK_ENCODER_HPP
+#define JSONCONS_MSGPACK_MSGPACK_ENCODER_HPP
+
+#include <string>
+#include <vector>
+#include <limits> // std::numeric_limits
+#include <memory>
+#include <utility> // std::move
+#include <jsoncons/json_exception.hpp>
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons/sink.hpp>
+#include <jsoncons/detail/parse_number.hpp>
+#include <jsoncons_ext/msgpack/msgpack_type.hpp>
+#include <jsoncons_ext/msgpack/msgpack_error.hpp>
+#include <jsoncons_ext/msgpack/msgpack_options.hpp>
+
+namespace jsoncons {
+namespace msgpack {
+
+ enum class msgpack_container_type {object, array};
+
+ template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>>
+ class basic_msgpack_encoder final : public basic_json_visitor<char>
+ {
+ enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 };
+
+ static constexpr int64_t nanos_in_milli = 1000000;
+ static constexpr int64_t nanos_in_second = 1000000000;
+ static constexpr int64_t millis_in_second = 1000;
+ public:
+ using allocator_type = Allocator;
+ using char_type = char;
+ using typename basic_json_visitor<char>::string_view_type;
+ using sink_type = Sink;
+
+ private:
+ struct stack_item
+ {
+ msgpack_container_type type_;
+ std::size_t length_;
+ std::size_t count_;
+
+ stack_item(msgpack_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_ == msgpack_container_type::object;
+ }
+ };
+
+ Sink sink_;
+ const msgpack_encode_options options_;
+ allocator_type alloc_;
+
+ std::vector<stack_item> stack_;
+ int nesting_depth_;
+
+ // Noncopyable and nonmoveable
+ basic_msgpack_encoder(const basic_msgpack_encoder&) = delete;
+ basic_msgpack_encoder& operator=(const basic_msgpack_encoder&) = delete;
+ public:
+ explicit basic_msgpack_encoder(Sink&& sink,
+ const Allocator& alloc = Allocator())
+ : basic_msgpack_encoder(std::forward<Sink>(sink), msgpack_encode_options(), alloc)
+ {
+ }
+
+ explicit basic_msgpack_encoder(Sink&& sink,
+ const msgpack_encode_options& options,
+ const Allocator& alloc = Allocator())
+ : sink_(std::forward<Sink>(sink)),
+ options_(options),
+ alloc_(alloc),
+ nesting_depth_(0)
+ {
+ }
+
+ ~basic_msgpack_encoder() noexcept
+ {
+ sink_.flush();
+ }
+
+ void reset()
+ {
+ stack_.clear();
+ 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
+ {
+ ec = msgpack_errc::object_length_required;
+ return false;
+ }
+
+ 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 = msgpack_errc::max_nesting_depth_exceeded;
+ return false;
+ }
+ stack_.emplace_back(msgpack_container_type::object, length);
+
+ if (length <= 15)
+ {
+ // fixmap
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixmap_base_type | (length & 0xf));
+ }
+ else if (length <= 65535)
+ {
+ // map 16
+ sink_.push_back(jsoncons::msgpack::msgpack_type::map16_type);
+ binary::native_to_big(static_cast<uint16_t>(length),
+ std::back_inserter(sink_));
+ }
+ else if (length <= 4294967295)
+ {
+ // map 32
+ sink_.push_back(jsoncons::msgpack::msgpack_type::map32_type);
+ binary::native_to_big(static_cast<uint32_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().count() < stack_.back().length())
+ {
+ ec = msgpack_errc::too_few_items;
+ return false;
+ }
+ else if (stack_.back().count() > stack_.back().length())
+ {
+ ec = msgpack_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
+ {
+ ec = msgpack_errc::array_length_required;
+ return false;
+ }
+
+ 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 = msgpack_errc::max_nesting_depth_exceeded;
+ return false;
+ }
+ stack_.emplace_back(msgpack_container_type::array, length);
+ if (length <= 15)
+ {
+ // fixarray
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixarray_base_type | (length & 0xf));
+ }
+ else if (length <= (std::numeric_limits<uint16_t>::max)())
+ {
+ // array 16
+ sink_.push_back(jsoncons::msgpack::msgpack_type::array16_type);
+ binary::native_to_big(static_cast<uint16_t>(length),std::back_inserter(sink_));
+ }
+ else if (length <= (std::numeric_limits<uint32_t>::max)())
+ {
+ // array 32
+ sink_.push_back(jsoncons::msgpack::msgpack_type::array32_type);
+ binary::native_to_big(static_cast<uint32_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().count() < stack_.back().length())
+ {
+ ec = msgpack_errc::too_few_items;
+ return false;
+ }
+ else if (stack_.back().count() > stack_.back().length())
+ {
+ ec = msgpack_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_value(name);
+ return true;
+ }
+
+ bool visit_null(semantic_tag, const ser_context&, std::error_code&) override
+ {
+ // nil
+ sink_.push_back(jsoncons::msgpack::msgpack_type::nil_type);
+ end_value();
+ return true;
+ }
+
+ void write_timestamp(int64_t seconds, int64_t nanoseconds)
+ {
+ if ((seconds >> 34) == 0)
+ {
+ uint64_t data64 = (nanoseconds << 34) | seconds;
+ if ((data64 & 0xffffffff00000000L) == 0)
+ {
+ // timestamp 32
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type);
+ sink_.push_back(0xff);
+ binary::native_to_big(static_cast<uint32_t>(data64), std::back_inserter(sink_));
+ }
+ else
+ {
+ // timestamp 64
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type);
+ sink_.push_back(0xff);
+ binary::native_to_big(static_cast<uint64_t>(data64), std::back_inserter(sink_));
+ }
+ }
+ else
+ {
+ // timestamp 96
+ sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type);
+ sink_.push_back(0x0c); // 12
+ sink_.push_back(0xff);
+ binary::native_to_big(static_cast<uint32_t>(nanoseconds), std::back_inserter(sink_));
+ binary::native_to_big(static_cast<uint64_t>(seconds), std::back_inserter(sink_));
+ }
+ }
+
+ bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) override
+ {
+ switch (tag)
+ {
+ case semantic_tag::epoch_second:
+ {
+ int64_t seconds;
+ auto result = jsoncons::detail::to_integer(sv.data(), sv.length(), seconds);
+ if (!result)
+ {
+ ec = msgpack_errc::invalid_timestamp;
+ return false;
+ }
+ write_timestamp(seconds, 0);
+ break;
+ }
+ case semantic_tag::epoch_milli:
+ {
+ bigint n = bigint::from_string(sv.data(), sv.length());
+ if (n != 0)
+ {
+ bigint q;
+ bigint rem;
+ n.divide(millis_in_second, q, rem, true);
+ int64_t seconds = static_cast<int64_t>(q);
+ int64_t nanoseconds = static_cast<int64_t>(rem) * nanos_in_milli;
+ if (nanoseconds < 0)
+ {
+ nanoseconds = -nanoseconds;
+ }
+ write_timestamp(seconds, nanoseconds);
+ }
+ else
+ {
+ write_timestamp(0, 0);
+ }
+ break;
+ }
+ case semantic_tag::epoch_nano:
+ {
+ bigint n = bigint::from_string(sv.data(), sv.length());
+ if (n != 0)
+ {
+ bigint q;
+ bigint rem;
+ n.divide(nanos_in_second, q, rem, true);
+ int64_t seconds = static_cast<int64_t>(q);
+ int64_t nanoseconds = static_cast<int64_t>(rem);
+ if (nanoseconds < 0)
+ {
+ nanoseconds = -nanoseconds;
+ }
+ write_timestamp(seconds, nanoseconds);
+ }
+ else
+ {
+ write_timestamp(0, 0);
+ }
+ break;
+ }
+ default:
+ {
+ write_string_value(sv);
+ end_value();
+ break;
+ }
+ }
+ return true;
+ }
+
+ void write_string_value(const string_view_type& sv)
+ {
+ auto sink = unicode_traits::validate(sv.data(), sv.size());
+ if (sink.ec != unicode_traits::conv_errc())
+ {
+ JSONCONS_THROW(ser_error(msgpack_errc::invalid_utf8_text_string));
+ }
+
+ const size_t length = sv.length();
+ if (length <= 31)
+ {
+ // fixstr stores a byte array whose length is upto 31 bytes
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixstr_base_type | static_cast<uint8_t>(length));
+ }
+ else if (length <= (std::numeric_limits<uint8_t>::max)())
+ {
+ // str 8 stores a byte array whose length is upto (2^8)-1 bytes
+ sink_.push_back(jsoncons::msgpack::msgpack_type::str8_type);
+ sink_.push_back(static_cast<uint8_t>(length));
+ }
+ else if (length <= (std::numeric_limits<uint16_t>::max)())
+ {
+ // str 16 stores a byte array whose length is upto (2^16)-1 bytes
+ sink_.push_back(jsoncons::msgpack::msgpack_type::str16_type);
+ binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
+ }
+ else if (length <= (std::numeric_limits<uint32_t>::max)())
+ {
+ // str 32 stores a byte array whose length is upto (2^32)-1 bytes
+ sink_.push_back(jsoncons::msgpack::msgpack_type::str32_type);
+ binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
+ }
+
+ for (auto c : sv)
+ {
+ sink_.push_back(c);
+ }
+ }
+
+ bool visit_byte_string(const byte_string_view& b,
+ semantic_tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+
+ const std::size_t length = b.size();
+ if (length <= (std::numeric_limits<uint8_t>::max)())
+ {
+ // bin 8 stores a byte array whose length is upto (2^8)-1 bytes
+ sink_.push_back(jsoncons::msgpack::msgpack_type::bin8_type);
+ sink_.push_back(static_cast<uint8_t>(length));
+ }
+ else if (length <= (std::numeric_limits<uint16_t>::max)())
+ {
+ // bin 16 stores a byte array whose length is upto (2^16)-1 bytes
+ sink_.push_back(jsoncons::msgpack::msgpack_type::bin16_type);
+ binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
+ }
+ else if (length <= (std::numeric_limits<uint32_t>::max)())
+ {
+ // bin 32 stores a byte array whose length is upto (2^32)-1 bytes
+ sink_.push_back(jsoncons::msgpack::msgpack_type::bin32_type);
+ binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
+ }
+
+ for (auto c : b)
+ {
+ sink_.push_back(c);
+ }
+
+ end_value();
+ return true;
+ }
+
+ bool visit_byte_string(const byte_string_view& b,
+ uint64_t ext_tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ const std::size_t length = b.size();
+ switch (length)
+ {
+ case 1:
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixext1_type);
+ sink_.push_back(static_cast<uint8_t>(ext_tag));
+ break;
+ case 2:
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixext2_type);
+ sink_.push_back(static_cast<uint8_t>(ext_tag));
+ break;
+ case 4:
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixext4_type);
+ sink_.push_back(static_cast<uint8_t>(ext_tag));
+ break;
+ case 8:
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixext8_type);
+ sink_.push_back(static_cast<uint8_t>(ext_tag));
+ break;
+ case 16:
+ sink_.push_back(jsoncons::msgpack::msgpack_type::fixext16_type);
+ sink_.push_back(static_cast<uint8_t>(ext_tag));
+ break;
+ default:
+ if (length <= (std::numeric_limits<uint8_t>::max)())
+ {
+ sink_.push_back(jsoncons::msgpack::msgpack_type::ext8_type);
+ sink_.push_back(static_cast<uint8_t>(length));
+ sink_.push_back(static_cast<uint8_t>(ext_tag));
+ }
+ else if (length <= (std::numeric_limits<uint16_t>::max)())
+ {
+ sink_.push_back(jsoncons::msgpack::msgpack_type::ext16_type);
+ binary::native_to_big(static_cast<uint16_t>(length), std::back_inserter(sink_));
+ sink_.push_back(static_cast<uint8_t>(ext_tag));
+ }
+ else if (length <= (std::numeric_limits<uint32_t>::max)())
+ {
+ sink_.push_back(jsoncons::msgpack::msgpack_type::ext32_type);
+ binary::native_to_big(static_cast<uint32_t>(length),std::back_inserter(sink_));
+ sink_.push_back(static_cast<uint8_t>(ext_tag));
+ }
+ break;
+ }
+
+ for (auto c : b)
+ {
+ sink_.push_back(c);
+ }
+
+ end_value();
+ return true;
+ }
+
+ bool visit_double(double val,
+ semantic_tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ float valf = (float)val;
+ if ((double)valf == val)
+ {
+ // float 32
+ sink_.push_back(jsoncons::msgpack::msgpack_type::float32_type);
+ binary::native_to_big(valf,std::back_inserter(sink_));
+ }
+ else
+ {
+ // float 64
+ sink_.push_back(jsoncons::msgpack::msgpack_type::float64_type);
+ binary::native_to_big(val,std::back_inserter(sink_));
+ }
+
+ // write double
+
+ end_value();
+ return true;
+ }
+
+ bool visit_int64(int64_t val,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (tag)
+ {
+ case semantic_tag::epoch_second:
+ write_timestamp(val, 0);
+ break;
+ case semantic_tag::epoch_milli:
+ {
+ if (val != 0)
+ {
+ auto dv = std::div(val,millis_in_second);
+ int64_t seconds = dv.quot;
+ int64_t nanoseconds = dv.rem*nanos_in_milli;
+ if (nanoseconds < 0)
+ {
+ nanoseconds = -nanoseconds;
+ }
+ write_timestamp(seconds, nanoseconds);
+ }
+ else
+ {
+ write_timestamp(0, 0);
+ }
+ break;
+ }
+ case semantic_tag::epoch_nano:
+ {
+ if (val != 0)
+ {
+ auto dv = std::div(val,static_cast<int64_t>(nanos_in_second));
+ int64_t seconds = dv.quot;
+ int64_t nanoseconds = dv.rem;
+ if (nanoseconds < 0)
+ {
+ nanoseconds = -nanoseconds;
+ }
+ write_timestamp(seconds, nanoseconds);
+ }
+ else
+ {
+ write_timestamp(0, 0);
+ }
+ break;
+ }
+ default:
+ {
+ if (val >= 0)
+ {
+ if (val <= 0x7f)
+ {
+ // positive fixnum stores 7-bit positive integer
+ sink_.push_back(static_cast<uint8_t>(val));
+ }
+ else if (val <= (std::numeric_limits<uint8_t>::max)())
+ {
+ // uint 8 stores a 8-bit unsigned integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type);
+ sink_.push_back(static_cast<uint8_t>(val));
+ }
+ else if (val <= (std::numeric_limits<uint16_t>::max)())
+ {
+ // uint 16 stores a 16-bit big-endian unsigned integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type);
+ binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_));
+ }
+ else if (val <= (std::numeric_limits<uint32_t>::max)())
+ {
+ // uint 32 stores a 32-bit big-endian unsigned integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type);
+ binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_));
+ }
+ else if (val <= (std::numeric_limits<int64_t>::max)())
+ {
+ // int 64 stores a 64-bit big-endian signed integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type);
+ binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_));
+ }
+ }
+ else
+ {
+ if (val >= -32)
+ {
+ // negative fixnum stores 5-bit negative integer
+ binary::native_to_big(static_cast<int8_t>(val), std::back_inserter(sink_));
+ }
+ else if (val >= (std::numeric_limits<int8_t>::lowest)())
+ {
+ // int 8 stores a 8-bit signed integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::int8_type);
+ binary::native_to_big(static_cast<int8_t>(val),std::back_inserter(sink_));
+ }
+ else if (val >= (std::numeric_limits<int16_t>::lowest)())
+ {
+ // int 16 stores a 16-bit big-endian signed integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::int16_type);
+ binary::native_to_big(static_cast<int16_t>(val),std::back_inserter(sink_));
+ }
+ else if (val >= (std::numeric_limits<int32_t>::lowest)())
+ {
+ // int 32 stores a 32-bit big-endian signed integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::int32_type);
+ binary::native_to_big(static_cast<int32_t>(val),std::back_inserter(sink_));
+ }
+ else if (val >= (std::numeric_limits<int64_t>::lowest)())
+ {
+ // int 64 stores a 64-bit big-endian signed integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::int64_type);
+ binary::native_to_big(static_cast<int64_t>(val),std::back_inserter(sink_));
+ }
+ }
+ }
+ break;
+ }
+ end_value();
+ return true;
+ }
+
+ bool visit_uint64(uint64_t val,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code&) override
+ {
+ switch (tag)
+ {
+ case semantic_tag::epoch_second:
+ write_timestamp(static_cast<int64_t>(val), 0);
+ break;
+ case semantic_tag::epoch_milli:
+ {
+ if (val != 0)
+ {
+ auto dv = std::div(static_cast<int64_t>(val), static_cast<int64_t>(millis_in_second));
+ int64_t seconds = dv.quot;
+ int64_t nanoseconds = dv.rem*nanos_in_milli;
+ if (nanoseconds < 0)
+ {
+ nanoseconds = -nanoseconds;
+ }
+ write_timestamp(seconds, nanoseconds);
+ }
+ else
+ {
+ write_timestamp(0, 0);
+ }
+ break;
+ }
+ case semantic_tag::epoch_nano:
+ {
+ if (val != 0)
+ {
+ auto dv = std::div(static_cast<int64_t>(val), static_cast<int64_t>(nanos_in_second));
+ int64_t seconds = dv.quot;
+ int64_t nanoseconds = dv.rem;
+ if (nanoseconds < 0)
+ {
+ nanoseconds = -nanoseconds;
+ }
+ write_timestamp(seconds, nanoseconds);
+ }
+ else
+ {
+ write_timestamp(0, 0);
+ }
+ break;
+ }
+ default:
+ {
+ if (val <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))
+ {
+ // positive fixnum stores 7-bit positive integer
+ sink_.push_back(static_cast<uint8_t>(val));
+ }
+ else if (val <= (std::numeric_limits<uint8_t>::max)())
+ {
+ // uint 8 stores a 8-bit unsigned integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::uint8_type);
+ sink_.push_back(static_cast<uint8_t>(val));
+ }
+ else if (val <= (std::numeric_limits<uint16_t>::max)())
+ {
+ // uint 16 stores a 16-bit big-endian unsigned integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::uint16_type);
+ binary::native_to_big(static_cast<uint16_t>(val),std::back_inserter(sink_));
+ }
+ else if (val <= (std::numeric_limits<uint32_t>::max)())
+ {
+ // uint 32 stores a 32-bit big-endian unsigned integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::uint32_type);
+ binary::native_to_big(static_cast<uint32_t>(val),std::back_inserter(sink_));
+ }
+ else if (val <= (std::numeric_limits<uint64_t>::max)())
+ {
+ // uint 64 stores a 64-bit big-endian unsigned integer
+ sink_.push_back(jsoncons::msgpack::msgpack_type::uint64_type);
+ binary::native_to_big(static_cast<uint64_t>(val),std::back_inserter(sink_));
+ }
+ break;
+ }
+ }
+ end_value();
+ return true;
+ }
+
+ bool visit_bool(bool val, semantic_tag, const ser_context&, std::error_code&) override
+ {
+ // true and false
+ sink_.push_back(static_cast<uint8_t>(val ? jsoncons::msgpack::msgpack_type::true_type : jsoncons::msgpack::msgpack_type::false_type));
+
+ end_value();
+ return true;
+ }
+
+ void end_value()
+ {
+ if (!stack_.empty())
+ {
+ ++stack_.back().count_;
+ }
+ }
+ };
+
+ using msgpack_stream_encoder = basic_msgpack_encoder<jsoncons::binary_stream_sink>;
+ using msgpack_bytes_encoder = basic_msgpack_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>;
+
+ #if !defined(JSONCONS_NO_DEPRECATED)
+ JSONCONS_DEPRECATED_MSG("Instead, use msgpack_bytes_encoder") typedef msgpack_bytes_encoder msgpack_bytes_serializer;
+
+ template<class Sink=jsoncons::binary_stream_sink>
+ using basic_msgpack_serializer = basic_msgpack_encoder<Sink>;
+
+ JSONCONS_DEPRECATED_MSG("Instead, use msgpack_stream_encoder") typedef msgpack_stream_encoder msgpack_encoder;
+ JSONCONS_DEPRECATED_MSG("Instead, use msgpack_stream_encoder") typedef msgpack_stream_encoder msgpack_serializer;
+ JSONCONS_DEPRECATED_MSG("Instead, use msgpack_bytes_encoder") typedef msgpack_bytes_encoder msgpack_buffer_serializer;
+ #endif
+
+} // namespace msgpack
+} // namespace jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/msgpack/msgpack_error.hpp b/include/jsoncons_ext/msgpack/msgpack_error.hpp
new file mode 100644
index 0000000..80c76b6
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack_error.hpp
@@ -0,0 +1,94 @@
+/// 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_MSGPACK_MSGPACK_ERROR_HPP
+#define JSONCONS_MSGPACK_MSGPACK_ERROR_HPP
+
+#include <system_error>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+namespace jsoncons { namespace msgpack {
+
+enum class msgpack_errc
+{
+ success = 0,
+ unexpected_eof = 1,
+ source_error,
+ invalid_utf8_text_string,
+ array_length_required,
+ object_length_required,
+ too_many_items,
+ too_few_items,
+ max_nesting_depth_exceeded,
+ length_is_negative,
+ invalid_timestamp,
+ unknown_type
+};
+
+class msgpack_error_category_impl
+ : public std::error_category
+{
+public:
+ const char* name() const noexcept override
+ {
+ return "jsoncons/msgpack";
+ }
+ std::string message(int ev) const override
+ {
+ switch (static_cast<msgpack_errc>(ev))
+ {
+ case msgpack_errc::unexpected_eof:
+ return "Unexpected end of file";
+ case msgpack_errc::source_error:
+ return "Source error";
+ case msgpack_errc::invalid_utf8_text_string:
+ return "Illegal UTF-8 encoding in text string";
+ case msgpack_errc::array_length_required:
+ return "MessagePack encoder requires array length";
+ case msgpack_errc::object_length_required:
+ return "MessagePack encoder requires object length";
+ case msgpack_errc::too_many_items:
+ return "Too many items were added to a MessagePack object or array";
+ case msgpack_errc::too_few_items:
+ return "Too few items were added to a MessagePack object or array";
+ case msgpack_errc::max_nesting_depth_exceeded:
+ return "Data item nesting exceeds limit in options";
+ case msgpack_errc::length_is_negative:
+ return "Request for the length of an array, map or string returned a negative result";
+ case msgpack_errc::invalid_timestamp:
+ return "Invalid timestamp";
+ case msgpack_errc::unknown_type:
+ return "An unknown type was found in the stream";
+ default:
+ return "Unknown MessagePack parser error";
+ }
+ }
+};
+
+inline
+const std::error_category& msgpack_error_category()
+{
+ static msgpack_error_category_impl instance;
+ return instance;
+}
+
+inline
+std::error_code make_error_code(msgpack_errc e)
+{
+ return std::error_code(static_cast<int>(e),msgpack_error_category());
+}
+
+
+}}
+
+namespace std {
+ template<>
+ struct is_error_code_enum<jsoncons::msgpack::msgpack_errc> : public true_type
+ {
+ };
+}
+
+#endif
diff --git a/include/jsoncons_ext/msgpack/msgpack_options.hpp b/include/jsoncons_ext/msgpack/msgpack_options.hpp
new file mode 100644
index 0000000..17bddf1
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack_options.hpp
@@ -0,0 +1,74 @@
+// 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_MSGPACK_MSGPACK_OPTIONS_HPP
+#define JSONCONS_MSGPACK_MSGPACK_OPTIONS_HPP
+
+#include <string>
+#include <limits> // std::numeric_limits
+#include <cwchar>
+#include <jsoncons/json_exception.hpp>
+
+namespace jsoncons { namespace msgpack {
+
+class msgpack_options;
+
+class msgpack_options_common
+{
+ friend class msgpack_options;
+
+ int max_nesting_depth_;
+protected:
+ virtual ~msgpack_options_common() = default;
+
+ msgpack_options_common()
+ : max_nesting_depth_(1024)
+ {
+ }
+
+ msgpack_options_common(const msgpack_options_common&) = default;
+ msgpack_options_common& operator=(const msgpack_options_common&) = default;
+ msgpack_options_common(msgpack_options_common&&) = default;
+ msgpack_options_common& operator=(msgpack_options_common&&) = default;
+public:
+ int max_nesting_depth() const
+ {
+ return max_nesting_depth_;
+ }
+};
+
+class msgpack_decode_options : public virtual msgpack_options_common
+{
+ friend class msgpack_options;
+public:
+ msgpack_decode_options()
+ {
+ }
+};
+
+class msgpack_encode_options : public virtual msgpack_options_common
+{
+ friend class msgpack_options;
+public:
+ msgpack_encode_options()
+ {
+ }
+};
+
+class msgpack_options final : public msgpack_decode_options, public msgpack_encode_options
+{
+public:
+ using msgpack_options_common::max_nesting_depth;
+
+ msgpack_options& max_nesting_depth(int value)
+ {
+ this->max_nesting_depth_ = value;
+ return *this;
+ }
+};
+
+}}
+#endif
diff --git a/include/jsoncons_ext/msgpack/msgpack_parser.hpp b/include/jsoncons_ext/msgpack/msgpack_parser.hpp
new file mode 100644
index 0000000..cf2d507
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack_parser.hpp
@@ -0,0 +1,748 @@
+// 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_MSGPACK_MSGPACK_PARSER_HPP
+#define JSONCONS_MSGPACK_MSGPACK_PARSER_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <utility> // std::move
+#include <jsoncons/json.hpp>
+#include <jsoncons/source.hpp>
+#include <jsoncons/bigint.hpp>
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/msgpack/msgpack_type.hpp>
+#include <jsoncons_ext/msgpack/msgpack_error.hpp>
+#include <jsoncons_ext/msgpack/msgpack_options.hpp>
+#include <jsoncons/json_visitor2.hpp>
+
+namespace jsoncons { namespace msgpack {
+
+enum class parse_mode {root,accept,array,map_key,map_value};
+
+struct parse_state
+{
+ parse_mode mode;
+ std::size_t length;
+ std::size_t index;
+
+ parse_state(parse_mode mode, std::size_t length) noexcept
+ : mode(mode), length(length), index(0)
+ {
+ }
+
+ parse_state(const parse_state&) = default;
+ parse_state(parse_state&&) = default;
+};
+
+template <class Source,class Allocator=std::allocator<char>>
+class basic_msgpack_parser : public ser_context
+{
+ using char_type = char;
+ using char_traits_type = std::char_traits<char>;
+ using temp_allocator_type = Allocator;
+ using char_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<char_type>;
+ using byte_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<uint8_t>;
+ using int64_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<int64_t>;
+ using parse_state_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<parse_state>;
+
+ static constexpr int64_t nanos_in_second = 1000000000;
+
+ Source source_;
+ msgpack_decode_options options_;
+ bool more_;
+ bool done_;
+ std::basic_string<char,std::char_traits<char>,char_allocator_type> text_buffer_;
+ std::vector<uint8_t,byte_allocator_type> bytes_buffer_;
+ std::vector<parse_state,parse_state_allocator_type> state_stack_;
+ int nesting_depth_;
+
+public:
+ template <class Sourceable>
+ basic_msgpack_parser(Sourceable&& source,
+ const msgpack_decode_options& options = msgpack_decode_options(),
+ const Allocator alloc = Allocator())
+ : source_(std::forward<Sourceable>(source)),
+ options_(options),
+ more_(true),
+ done_(false),
+ text_buffer_(alloc),
+ bytes_buffer_(alloc),
+ state_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();
+ state_stack_.clear();
+ state_stack_.emplace_back(parse_mode::root,0);
+ 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::array:
+ {
+ if (state_stack_.back().index < state_stack_.back().length)
+ {
+ ++state_stack_.back().index;
+ read_item(visitor, ec);
+ if (ec)
+ {
+ return;
+ }
+ }
+ else
+ {
+ end_array(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);
+ if (ec)
+ {
+ return;
+ }
+ }
+ else
+ {
+ end_object(visitor, ec);
+ }
+ break;
+ }
+ case parse_mode::map_value:
+ {
+ state_stack_.back().mode = parse_mode::map_key;
+ read_item(visitor, ec);
+ if (ec)
+ {
+ return;
+ }
+ break;
+ }
+ case parse_mode::root:
+ {
+ state_stack_.back().mode = parse_mode::accept;
+ read_item(visitor, ec);
+ if (ec)
+ {
+ return;
+ }
+ 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)
+ {
+ if (source_.is_error())
+ {
+ ec = msgpack_errc::source_error;
+ more_ = false;
+ return;
+ }
+
+ uint8_t type;
+ if (source_.read(&type, 1) == 0)
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ if (type <= 0xbf)
+ {
+ if (type <= 0x7f)
+ {
+ // positive fixint
+ more_ = visitor.uint64_value(type, semantic_tag::none, *this, ec);
+ }
+ else if (type <= 0x8f)
+ {
+ begin_object(visitor,type,ec); // fixmap
+ }
+ else if (type <= 0x9f)
+ {
+ begin_array(visitor,type,ec); // fixarray
+ }
+ else
+ {
+ // fixstr
+ const size_t len = type & 0x1f;
+
+ text_buffer_.clear();
+
+ if (source_reader<Source>::read(source_,text_buffer_,len) != static_cast<std::size_t>(len))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ auto result = unicode_traits::validate(text_buffer_.data(),text_buffer_.size());
+ if (result.ec != unicode_traits::conv_errc())
+ {
+ ec = msgpack_errc::invalid_utf8_text_string;
+ more_ = false;
+ return;
+ }
+ more_ = visitor.string_value(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), semantic_tag::none, *this, ec);
+ }
+ }
+ else if (type >= 0xe0)
+ {
+ // negative fixint
+ more_ = visitor.int64_value(static_cast<int8_t>(type), semantic_tag::none, *this, ec);
+ }
+ else
+ {
+ switch (type)
+ {
+ case jsoncons::msgpack::msgpack_type::nil_type:
+ {
+ more_ = visitor.null_value(semantic_tag::none, *this, ec);
+ break;
+ }
+ case jsoncons::msgpack::msgpack_type::true_type:
+ {
+ more_ = visitor.bool_value(true, semantic_tag::none, *this, ec);
+ break;
+ }
+ case jsoncons::msgpack::msgpack_type::false_type:
+ {
+ more_ = visitor.bool_value(false, semantic_tag::none, *this, ec);
+ break;
+ }
+ case jsoncons::msgpack::msgpack_type::float32_type:
+ {
+ uint8_t buf[sizeof(float)];
+ if (source_.read(buf, sizeof(float)) != sizeof(float))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ float val = binary::big_to_native<float>(buf, sizeof(buf));
+ more_ = visitor.double_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::float64_type:
+ {
+ uint8_t buf[sizeof(double)];
+ if (source_.read(buf, sizeof(double)) != sizeof(double))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ double val = binary::big_to_native<double>(buf, sizeof(buf));
+ more_ = visitor.double_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::uint8_type:
+ {
+ uint8_t b;
+ if (source_.read(&b, 1) == 0)
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ more_ = visitor.uint64_value(b, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::uint16_type:
+ {
+ uint8_t buf[sizeof(uint16_t)];
+ if (source_.read(buf, sizeof(uint16_t)) !=sizeof(uint16_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint16_t val = binary::big_to_native<uint16_t>(buf, sizeof(buf));
+ more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::uint32_type:
+ {
+ uint8_t buf[sizeof(uint32_t)];
+ if (source_.read(buf, sizeof(uint32_t)) != sizeof(uint32_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint32_t val = binary::big_to_native<uint32_t>(buf, sizeof(buf));
+ more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::uint64_type:
+ {
+ uint8_t buf[sizeof(uint64_t)];
+ if (source_.read(buf, sizeof(uint64_t)) != sizeof(uint64_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint64_t val = binary::big_to_native<uint64_t>(buf, sizeof(buf));
+ more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::int8_type:
+ {
+ uint8_t buf[sizeof(int8_t)];
+ if (source_.read(buf, sizeof(int8_t)) != sizeof(int8_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ int8_t val = binary::big_to_native<int8_t>(buf, sizeof(buf));
+ more_ = visitor.int64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::int16_type:
+ {
+ uint8_t buf[sizeof(int16_t)];
+ if (source_.read(buf, sizeof(int16_t)) != sizeof(int16_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ int16_t val = binary::big_to_native<int16_t>(buf, sizeof(buf));
+ more_ = visitor.int64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::int32_type:
+ {
+ uint8_t buf[sizeof(int32_t)];
+ if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ int32_t val = binary::big_to_native<int32_t>(buf, sizeof(buf));
+ more_ = visitor.int64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::int64_type:
+ {
+ uint8_t buf[sizeof(int64_t)];
+ if (source_.read(buf, sizeof(int64_t)) != sizeof(int64_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ int64_t val = binary::big_to_native<int64_t>(buf, sizeof(buf));
+ more_ = visitor.int64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::str8_type:
+ case jsoncons::msgpack::msgpack_type::str16_type:
+ case jsoncons::msgpack::msgpack_type::str32_type:
+ {
+ std::size_t len = get_size(type, ec);
+ if (!more_)
+ {
+ return;
+ }
+
+ text_buffer_.clear();
+ if (source_reader<Source>::read(source_,text_buffer_,len) != static_cast<std::size_t>(len))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ auto result = unicode_traits::validate(text_buffer_.data(),text_buffer_.size());
+ if (result.ec != unicode_traits::conv_errc())
+ {
+ ec = msgpack_errc::invalid_utf8_text_string;
+ more_ = false;
+ return;
+ }
+ more_ = visitor.string_value(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::bin8_type:
+ case jsoncons::msgpack::msgpack_type::bin16_type:
+ case jsoncons::msgpack::msgpack_type::bin32_type:
+ {
+ std::size_t len = get_size(type,ec);
+ if (!more_)
+ {
+ return;
+ }
+ bytes_buffer_.clear();
+ if (source_reader<Source>::read(source_,bytes_buffer_,len) != static_cast<std::size_t>(len))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ more_ = visitor.byte_string_value(byte_string_view(bytes_buffer_.data(),bytes_buffer_.size()),
+ semantic_tag::none,
+ *this,
+ ec);
+ break;
+ }
+ case jsoncons::msgpack::msgpack_type::fixext1_type:
+ case jsoncons::msgpack::msgpack_type::fixext2_type:
+ case jsoncons::msgpack::msgpack_type::fixext4_type:
+ case jsoncons::msgpack::msgpack_type::fixext8_type:
+ case jsoncons::msgpack::msgpack_type::fixext16_type:
+ case jsoncons::msgpack::msgpack_type::ext8_type:
+ case jsoncons::msgpack::msgpack_type::ext16_type:
+ case jsoncons::msgpack::msgpack_type::ext32_type:
+ {
+ std::size_t len = get_size(type,ec);
+ if (!more_)
+ {
+ return;
+ }
+
+ // type
+ uint8_t buf[sizeof(int8_t)];
+ if (source_.read(buf, sizeof(int8_t)) != sizeof(int8_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ int8_t ext_type = binary::big_to_native<int8_t>(buf, sizeof(buf));
+
+ bool is_timestamp = false;
+ if (ext_type == -1)
+ {
+ is_timestamp = true;;
+ }
+
+ // payload
+ if (is_timestamp && len == 4)
+ {
+ uint8_t buf32[sizeof(uint32_t)];
+ if (source_.read(buf32, sizeof(uint32_t)) != sizeof(uint32_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint32_t val = binary::big_to_native<uint32_t>(buf32, sizeof(buf32));
+ more_ = visitor.uint64_value(val, semantic_tag::epoch_second, *this, ec);
+ }
+ else if (is_timestamp && len == 8)
+ {
+ uint8_t buf64[sizeof(uint64_t)];
+ if (source_.read(buf64, sizeof(uint64_t)) != sizeof(uint64_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint64_t data64 = binary::big_to_native<uint64_t>(buf64, sizeof(buf64));
+ uint64_t sec = data64 & 0x00000003ffffffffL;
+ uint64_t nsec = data64 >> 34;
+
+ bigint nano(sec);
+ nano *= uint64_t(nanos_in_second);
+ nano += nsec;
+ text_buffer_.clear();
+ nano.write_string(text_buffer_);
+ more_ = visitor.string_value(text_buffer_, semantic_tag::epoch_nano, *this, ec);
+ if (!more_) return;
+ }
+ else if (is_timestamp && len == 12)
+ {
+ uint8_t buf1[sizeof(uint32_t)];
+ if (source_.read(buf1, sizeof(uint32_t)) != sizeof(uint32_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint32_t nsec = binary::big_to_native<uint32_t>(buf1, sizeof(buf1));
+
+ uint8_t buf2[sizeof(int64_t)];
+ if (source_.read(buf2, sizeof(int64_t)) != sizeof(int64_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ int64_t sec = binary::big_to_native<int64_t>(buf2, sizeof(buf2));
+
+ bigint nano(sec);
+
+ nano *= uint64_t(nanos_in_second);
+
+ if (nano < 0)
+ {
+ nano -= nsec;
+ }
+ else
+ {
+ nano += nsec;
+ }
+
+ text_buffer_.clear();
+ nano.write_string(text_buffer_);
+ more_ = visitor.string_value(text_buffer_, semantic_tag::epoch_nano, *this, ec);
+ if (!more_) return;
+ }
+ else
+ {
+ bytes_buffer_.clear();
+ if (source_reader<Source>::read(source_,bytes_buffer_,len) != static_cast<std::size_t>(len))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ more_ = visitor.byte_string_value(byte_string_view(bytes_buffer_.data(),bytes_buffer_.size()),
+ static_cast<uint8_t>(ext_type),
+ *this,
+ ec);
+ }
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::array16_type:
+ case jsoncons::msgpack::msgpack_type::array32_type:
+ {
+ begin_array(visitor,type,ec);
+ break;
+ }
+
+ case jsoncons::msgpack::msgpack_type::map16_type :
+ case jsoncons::msgpack::msgpack_type::map32_type :
+ {
+ begin_object(visitor, type, ec);
+ break;
+ }
+
+ default:
+ {
+ ec = msgpack_errc::unknown_type;
+ more_ = false;
+ return;
+ }
+ }
+ }
+ }
+
+ void begin_array(json_visitor2& visitor, uint8_t type, std::error_code& ec)
+ {
+ if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
+ {
+ ec = msgpack_errc::max_nesting_depth_exceeded;
+ more_ = false;
+ return;
+ }
+ std::size_t length = get_size(type, ec);
+ if (!more_)
+ {
+ return;
+ }
+ state_stack_.emplace_back(parse_mode::array,length);
+ more_ = visitor.begin_array(length, semantic_tag::none, *this, ec);
+ }
+
+ void end_array(json_visitor2& visitor, std::error_code& ec)
+ {
+ --nesting_depth_;
+
+ more_ = visitor.end_array(*this, ec);
+ state_stack_.pop_back();
+ }
+
+ void begin_object(json_visitor2& visitor, uint8_t type, std::error_code& ec)
+ {
+ if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
+ {
+ ec = msgpack_errc::max_nesting_depth_exceeded;
+ more_ = false;
+ return;
+ }
+ std::size_t length = get_size(type, ec);
+ if (!more_)
+ {
+ return;
+ }
+ state_stack_.emplace_back(parse_mode::map_key,length);
+ more_ = visitor.begin_object(length, semantic_tag::none, *this, ec);
+ }
+
+ void end_object(json_visitor2& visitor, std::error_code& ec)
+ {
+ --nesting_depth_;
+ more_ = visitor.end_object(*this, ec);
+ state_stack_.pop_back();
+ }
+
+ std::size_t get_size(uint8_t type, std::error_code& ec)
+ {
+ switch (type)
+ {
+ case jsoncons::msgpack::msgpack_type::str8_type:
+ case jsoncons::msgpack::msgpack_type::bin8_type:
+ case jsoncons::msgpack::msgpack_type::ext8_type:
+ {
+ uint8_t buf[sizeof(int8_t)];
+ if (source_.read(buf, sizeof(int8_t)) != sizeof(int8_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return 0;
+ }
+ uint8_t len = binary::big_to_native<uint8_t>(buf, sizeof(buf));
+ return static_cast<std::size_t>(len);
+ }
+
+ case jsoncons::msgpack::msgpack_type::str16_type:
+ case jsoncons::msgpack::msgpack_type::bin16_type:
+ case jsoncons::msgpack::msgpack_type::ext16_type:
+ case jsoncons::msgpack::msgpack_type::array16_type:
+ case jsoncons::msgpack::msgpack_type::map16_type:
+ {
+ uint8_t buf[sizeof(int16_t)];
+ if (source_.read(buf, sizeof(int16_t)) != sizeof(int16_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return 0;
+ }
+ uint16_t len = binary::big_to_native<uint16_t>(buf, sizeof(buf));
+ return static_cast<std::size_t>(len);
+ }
+
+ case jsoncons::msgpack::msgpack_type::str32_type:
+ case jsoncons::msgpack::msgpack_type::bin32_type:
+ case jsoncons::msgpack::msgpack_type::ext32_type:
+ case jsoncons::msgpack::msgpack_type::array32_type:
+ case jsoncons::msgpack::msgpack_type::map32_type :
+ {
+ uint8_t buf[sizeof(int32_t)];
+ if (source_.read(buf, sizeof(int32_t)) != sizeof(int32_t))
+ {
+ ec = msgpack_errc::unexpected_eof;
+ more_ = false;
+ return 0;
+ }
+ uint32_t len = binary::big_to_native<uint32_t>(buf, sizeof(buf));
+ return static_cast<std::size_t>(len);
+ }
+ case jsoncons::msgpack::msgpack_type::fixext1_type:
+ return 1;
+ case jsoncons::msgpack::msgpack_type::fixext2_type:
+ return 2;
+ case jsoncons::msgpack::msgpack_type::fixext4_type:
+ return 4;
+ case jsoncons::msgpack::msgpack_type::fixext8_type:
+ return 8;
+ case jsoncons::msgpack::msgpack_type::fixext16_type:
+ return 16;
+ default:
+ if ((type > 0x8f && type <= 0x9f) // fixarray
+ || (type > 0x7f && type <= 0x8f) // fixmap
+ )
+ {
+ return type & 0x0f;
+ }
+ else
+ {
+ ec = msgpack_errc::unknown_type;
+ more_ = false;
+ return 0;
+ }
+ break;
+ }
+ }
+};
+
+}}
+
+#endif
diff --git a/include/jsoncons_ext/msgpack/msgpack_reader.hpp b/include/jsoncons_ext/msgpack/msgpack_reader.hpp
new file mode 100644
index 0000000..c0d788a
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack_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_MSGPACK_MSGPACK_READER_HPP
+#define JSONCONS_MSGPACK_MSGPACK_READER_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <utility> // std::move
+#include <jsoncons/json.hpp>
+#include <jsoncons/source.hpp>
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/config/jsoncons_config.hpp>
+#include <jsoncons_ext/msgpack/msgpack_type.hpp>
+#include <jsoncons_ext/msgpack/msgpack_error.hpp>
+#include <jsoncons_ext/msgpack/msgpack_parser.hpp>
+
+namespace jsoncons { namespace msgpack {
+
+template <class Source,class Allocator=std::allocator<char>>
+class basic_msgpack_reader
+{
+ using char_type = char;
+
+ basic_msgpack_parser<Source,Allocator> parser_;
+ basic_json_visitor2_to_visitor_adaptor<char_type,Allocator> adaptor_;
+ json_visitor2& visitor_;
+public:
+ template <class Sourceable>
+ basic_msgpack_reader(Sourceable&& source,
+ json_visitor& visitor,
+ const Allocator alloc)
+ : basic_msgpack_reader(std::forward<Sourceable>(source),
+ visitor,
+ msgpack_decode_options(),
+ alloc)
+ {
+ }
+
+ template <class Sourceable>
+ basic_msgpack_reader(Sourceable&& source,
+ json_visitor& visitor,
+ const msgpack_decode_options& options = msgpack_decode_options(),
+ const Allocator alloc=Allocator())
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ adaptor_(visitor, alloc), visitor_(adaptor_)
+ {
+ }
+ template <class Sourceable>
+ basic_msgpack_reader(Sourceable&& source,
+ json_visitor2& visitor,
+ const Allocator alloc)
+ : basic_msgpack_reader(std::forward<Sourceable>(source),
+ visitor,
+ msgpack_decode_options(),
+ alloc)
+ {
+ }
+
+ template <class Sourceable>
+ basic_msgpack_reader(Sourceable&& source,
+ json_visitor2& visitor,
+ const msgpack_decode_options& options = msgpack_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 msgpack_stream_reader = basic_msgpack_reader<jsoncons::binary_stream_source>;
+
+using msgpack_bytes_reader = basic_msgpack_reader<jsoncons::bytes_source>;
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+JSONCONS_DEPRECATED_MSG("Instead, use msgpack_stream_reader") typedef msgpack_stream_reader msgpack_reader;
+JSONCONS_DEPRECATED_MSG("Instead, use msgpack_bytes_reader") typedef msgpack_bytes_reader msgpack_buffer_reader;
+#endif
+
+}}
+
+#endif
diff --git a/include/jsoncons_ext/msgpack/msgpack_type.hpp b/include/jsoncons_ext/msgpack/msgpack_type.hpp
new file mode 100644
index 0000000..aa9f8fd
--- /dev/null
+++ b/include/jsoncons_ext/msgpack/msgpack_type.hpp
@@ -0,0 +1,63 @@
+// Copyright 2013 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_MSGPACK_MSGPACK_TYPE_HPP
+#define JSONCONS_MSGPACK_MSGPACK_TYPE_HPP
+
+#include <string>
+#include <memory>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+namespace jsoncons { namespace msgpack {
+
+ namespace msgpack_type
+ {
+ const uint8_t positive_fixint_base_type = 0x00;
+ const uint8_t nil_type = 0xc0;
+ const uint8_t false_type = 0xc2;
+ const uint8_t true_type = 0xc3;
+ const uint8_t float32_type = 0xca;
+ const uint8_t float64_type = 0xcb;
+ const uint8_t uint8_type = 0xcc;
+ const uint8_t uint16_type = 0xcd;
+ const uint8_t uint32_type = 0xce;
+ const uint8_t uint64_type = 0xcf;
+ const uint8_t int8_type = 0xd0;
+ const uint8_t int16_type = 0xd1;
+ const uint8_t int32_type = 0xd2;
+ const uint8_t int64_type = 0xd3;
+
+ const uint8_t fixmap_base_type = 0x80;
+ const uint8_t fixarray_base_type = 0x90;
+ const uint8_t fixstr_base_type = 0xa0;
+ const uint8_t str8_type = 0xd9;
+ const uint8_t str16_type = 0xda;
+ const uint8_t str32_type = 0xdb;
+
+ const uint8_t bin8_type = 0xc4; // 0xC4
+ const uint8_t bin16_type = 0xc5;
+ const uint8_t bin32_type = 0xc6;
+
+ const uint8_t fixext1_type = 0xd4;
+ const uint8_t fixext2_type = 0xd5;
+ const uint8_t fixext4_type = 0xd6;
+ const uint8_t fixext8_type = 0xd7;
+ const uint8_t fixext16_type = 0xd8;
+ const uint8_t ext8_type = 0xc7; // 0xC4
+ const uint8_t ext16_type = 0xc8;
+ const uint8_t ext32_type = 0xc9;
+
+ const uint8_t array16_type = 0xdc;
+ const uint8_t array32_type = 0xdd;
+ const uint8_t map16_type = 0xde;
+ const uint8_t map32_type = 0xdf;
+ const uint8_t negative_fixint_base_type = 0xe0;
+ }
+
+} // namespace msgpack
+} // namespace jsoncons
+
+#endif