aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons_ext/bson
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/bson
downloadcsound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.tar.gz
csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.tar.bz2
csound-json-1d055261b4144dbf86b2658437015b15d4dd9bff.zip
initial
Diffstat (limited to 'include/jsoncons_ext/bson')
-rw-r--r--include/jsoncons_ext/bson/bson.hpp23
-rw-r--r--include/jsoncons_ext/bson/bson_cursor.hpp320
-rw-r--r--include/jsoncons_ext/bson/bson_decimal128.hpp865
-rw-r--r--include/jsoncons_ext/bson/bson_decimal128.hpp.bak816
-rw-r--r--include/jsoncons_ext/bson/bson_encoder.hpp585
-rw-r--r--include/jsoncons_ext/bson/bson_error.hpp103
-rw-r--r--include/jsoncons_ext/bson/bson_oid.hpp245
-rw-r--r--include/jsoncons_ext/bson/bson_options.hpp75
-rw-r--r--include/jsoncons_ext/bson/bson_parser.hpp645
-rw-r--r--include/jsoncons_ext/bson/bson_reader.hpp92
-rw-r--r--include/jsoncons_ext/bson/bson_type.hpp44
-rw-r--r--include/jsoncons_ext/bson/decode_bson.hpp201
-rw-r--r--include/jsoncons_ext/bson/encode_bson.hpp144
13 files changed, 4158 insertions, 0 deletions
diff --git a/include/jsoncons_ext/bson/bson.hpp b/include/jsoncons_ext/bson/bson.hpp
new file mode 100644
index 0000000..ec3192d
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson.hpp
@@ -0,0 +1,23 @@
+// 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_BSON_BSON_HPP
+#define JSONCONS_BSON_BSON_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/bson/bson_encoder.hpp>
+#include <jsoncons_ext/bson/bson_reader.hpp>
+#include <jsoncons_ext/bson/bson_cursor.hpp>
+#include <jsoncons_ext/bson/encode_bson.hpp>
+#include <jsoncons_ext/bson/decode_bson.hpp>
+
+#endif
diff --git a/include/jsoncons_ext/bson/bson_cursor.hpp b/include/jsoncons_ext/bson/bson_cursor.hpp
new file mode 100644
index 0000000..8baee53
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_cursor.hpp
@@ -0,0 +1,320 @@
+// 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_BSON_BSON_CURSOR_HPP
+#define JSONCONS_BSON_BSON_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/bson/bson_parser.hpp>
+
+namespace jsoncons {
+namespace bson {
+
+template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>>
+class basic_bson_cursor : public basic_staj_cursor<char>, private virtual ser_context
+{
+ using super_type = basic_staj_cursor<char>;
+public:
+ using source_type = Source;
+ using char_type = char;
+ using allocator_type = Allocator;
+private:
+ basic_bson_parser<Source,Allocator> parser_;
+ basic_staj_visitor<char_type> cursor_visitor_;
+ bool eof_;
+
+ // Noncopyable and nonmoveable
+ basic_bson_cursor(const basic_bson_cursor&) = delete;
+ basic_bson_cursor& operator=(const basic_bson_cursor&) = delete;
+
+public:
+ using string_view_type = string_view;
+
+ template <class Sourceable>
+ basic_bson_cursor(Sourceable&& source,
+ const bson_decode_options& options = bson_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_bson_cursor(Sourceable&& source,
+ std::error_code& ec)
+ : basic_bson_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ bson_decode_options(),
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_bson_cursor(Sourceable&& source,
+ const bson_decode_options& options,
+ std::error_code& ec)
+ : basic_bson_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source),
+ options,
+ ec)
+ {
+ }
+
+ template <class Sourceable>
+ basic_bson_cursor(std::allocator_arg_t, const Allocator& alloc,
+ Sourceable&& source,
+ const bson_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();
+ }
+
+ void array_expected(std::error_code& ec) override
+ {
+ if (cursor_visitor_.event().event_type() == staj_event_type::begin_object)
+ {
+ parser_.array_expected(cursor_visitor_, ec);
+ }
+ else
+ {
+ super_type::array_expected(ec);
+ }
+ }
+
+ 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 (staj_to_saj_event(cursor_visitor_.event(), 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_bson_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_bson_cursor(Sourceable&& source,
+ std::function<bool(const staj_event&, const ser_context&)> filter,
+ std::error_code& ec)
+ : basic_bson_cursor(std::allocator_arg, Allocator(),
+ std::forward<Sourceable>(source), filter, ec)
+ {
+ }
+
+ template <class Sourceable>
+ JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
+ basic_bson_cursor(Sourceable&& source,
+ std::function<bool(const staj_event&, const ser_context&)> filter,
+ const bson_decode_options& options = bson_decode_options(),
+ const Allocator& alloc = Allocator())
+ : parser_(std::forward<Sourceable>(source), options, alloc),
+ cursor_visitor_(filter),
+ eof_(false)
+ {
+ if (!done())
+ {
+ next();
+ }
+ }
+
+ template <class Sourceable>
+ JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
+ basic_bson_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),
+ 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)
+ {
+ parser_.restart();
+ while (!parser_.stopped())
+ {
+ parser_.parse(cursor_visitor_, ec);
+ if (ec) return;
+ }
+ }
+
+ void read_next(basic_json_visitor<char_type>& visitor, std::error_code& ec)
+ {
+ parser_.restart();
+ while (!parser_.stopped())
+ {
+ parser_.parse(visitor, ec);
+ if (ec) return;
+ }
+ }
+};
+
+using bson_stream_cursor = basic_bson_cursor<jsoncons::binary_stream_source>;
+using bson_bytes_cursor = basic_bson_cursor<jsoncons::bytes_source>;
+
+} // namespace bson
+} // namespace jsoncons
+
+#endif
+
diff --git a/include/jsoncons_ext/bson/bson_decimal128.hpp b/include/jsoncons_ext/bson/bson_decimal128.hpp
new file mode 100644
index 0000000..b487a04
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_decimal128.hpp
@@ -0,0 +1,865 @@
+#ifndef JSONCONS_BSON_BSON_DECIMAL128_HPP
+#define JSONCONS_BSON_BSON_DECIMAL128_HPP
+
+/*
+ * Implements decimal128_to_chars and decimal128_from_chars
+ *
+ * Based on the libjson functions bson_decimal128_to_string
+ * and bson_decimal128_from_string_w_len, available at
+ * https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-decimal128.h
+ * and https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-decimal128.c
+ *
+*/
+
+/*
+ * Copyright 2015 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <cstring>
+#include <ctype.h>
+#include <system_error>
+#include <algorithm>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+namespace jsoncons { namespace bson {
+
+ struct decimal128_to_chars_result
+ {
+ char* ptr;
+ std::errc ec;
+ };
+
+ struct decimal128_from_chars_result
+ {
+ const char* ptr;
+ std::errc ec;
+ };
+
+/**
+ * BSON_DECIMAL128_STRING:
+ *
+ * The length of a decimal128 string (with null terminator).
+ *
+ * 1 for the sign
+ * 35 for digits and radix
+ * 2 for exponent indicator and sign
+ * 4 for exponent digits
+ */
+#define BSON_DECIMAL128_STRING 43
+
+ struct TP1
+ {
+ uint64_t low;
+ uint64_t high;
+
+ constexpr TP1() : low(0), high(0) {}
+ constexpr TP1(uint64_t hi, uint64_t lo) : low(lo), high(hi) {}
+ };
+ struct TP2
+ {
+ uint64_t high;
+ uint64_t low;
+
+ constexpr TP2() : high(0), low(0) {}
+ constexpr TP2(uint64_t hi, uint64_t lo) : high(hi), low(lo) {}
+ };
+
+ typedef std::conditional<
+ jsoncons::endian::native == jsoncons::endian::little,
+ TP1,
+ TP2
+ >::type decimal128_t;
+
+ inline
+ bool operator==(const decimal128_t& lhs, const decimal128_t& rhs)
+ {
+ return lhs.high == rhs.high && lhs.low == rhs.low;
+ }
+
+ inline
+ bool operator!=(const decimal128_t& lhs, const decimal128_t& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ struct decimal128_limits
+ {
+ // The length of a decimal128 string (without null terminator).
+ //
+ // 1 for the sign
+ // 35 for digits and radix
+ // 2 for exponent indicator and sign
+ // 4 for exponent digits
+ static constexpr int buf_size = 42;
+ static constexpr int exponent_max = 6111;
+ static constexpr int exponent_min = -6176;
+ static constexpr int exponent_bias = 6176;
+ static constexpr int max_digits = 34;
+
+ static constexpr decimal128_t nan() {return decimal128_t(0x7c00000000000000ull, 0);}
+ static constexpr decimal128_t infinity() {return decimal128_t(0x7800000000000000ull, 0);}
+ static constexpr decimal128_t neg_infinity() {return decimal128_t(0x7800000000000000ull + 0x8000000000000000ull, 0);}
+ };
+
+ inline
+ bool is_nan(decimal128_t dec) { return dec == decimal128_limits::nan(); }
+
+ inline
+ bool is_inf(decimal128_t dec) { return dec == decimal128_limits::infinity(); }
+
+ inline
+ bool is_neg_inf(decimal128_t dec) { return dec == decimal128_limits::neg_infinity(); }
+
+ /**
+ * bson_uint128_t:
+ *
+ * This struct represents a 128 bit integer.
+ */
+ typedef struct {
+ uint32_t parts[4]; /* 32-bit words stored high to low. */
+ } bson_uint128_t;
+
+ typedef struct {
+ uint64_t high, low;
+ } bson_uint128_6464_t;
+
+ namespace detail {
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * bson_uint128_divide1B --
+ *
+ * This function divides a #bson_uint128_t by 1000000000 (1 billion) and
+ * computes the quotient and remainder.
+ *
+ * The remainder will contain 9 decimal digits for conversion to string.
+ *
+ * @value The #bson_uint128_t operand.
+ * @quotient A pointer to store the #bson_uint128_t quotient.
+ * @rem A pointer to store the #uint64_t remainder.
+ *
+ * Returns:
+ * The quotient at @quotient and the remainder at @rem.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ void bson_uint128_divide1B (bson_uint128_t value, /* IN */
+ bson_uint128_t *quotient, /* OUT */
+ uint32_t *rem) /* OUT */
+ {
+ const uint32_t DIVISOR = 1000 * 1000 * 1000;
+ uint64_t _rem = 0;
+ int i = 0;
+
+ if (!value.parts[0] && !value.parts[1] && !value.parts[2] &&
+ !value.parts[3]) {
+ *quotient = value;
+ *rem = 0;
+ return;
+ }
+
+ for (i = 0; i <= 3; i++) {
+ _rem <<= 32; /* Adjust remainder to match value of next dividend */
+ _rem += value.parts[i]; /* Add the divided to _rem */
+ value.parts[i] = (uint32_t) (_rem / DIVISOR);
+ _rem %= DIVISOR; /* Store the remainder */
+ }
+
+ *quotient = value;
+ *rem = (uint32_t) _rem;
+ }
+
+ /**
+ *-------------------------------------------------------------------------
+ *
+ * mul64x64 --
+ *
+ * This function multiplies two &uint64_t into a &bson_uint128_6464_t.
+ *
+ * Returns:
+ * The product of @left and @right.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ inline
+ void mul_64x64 (uint64_t left, /* IN */
+ uint64_t right, /* IN */
+ bson_uint128_6464_t *product) /* OUT */
+ {
+ uint64_t left_high, left_low, right_high, right_low, product_high,
+ product_mid, product_mid2, product_low;
+ bson_uint128_6464_t rt = {0,0};
+
+ if (!left && !right) {
+ *product = rt;
+ return;
+ }
+
+ left_high = left >> 32;
+ left_low = (uint32_t) left;
+ right_high = right >> 32;
+ right_low = (uint32_t) right;
+
+ product_high = left_high * right_high;
+ product_mid = left_high * right_low;
+ product_mid2 = left_low * right_high;
+ product_low = left_low * right_low;
+
+ product_high += product_mid >> 32;
+ product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32);
+
+ product_high = product_high + (product_mid >> 32);
+ product_low = (product_mid << 32) + (uint32_t) product_low;
+
+ rt.high = product_high;
+ rt.low = product_low;
+ *product = rt;
+ }
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * dec128_tolower --
+ *
+ * This function converts the ASCII character @c to lowercase. It is locale
+ * insensitive (unlike the stdlib tolower).
+ *
+ * Returns:
+ * The lowercased character.
+ */
+
+ inline
+ char dec128_tolower (char c)
+ {
+ if (isupper (c)) {
+ c += 32;
+ }
+
+ return c;
+ }
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * dec128_istreq --
+ *
+ * This function compares the null-terminated *ASCII* strings @a and @b
+ * for case-insensitive equality.
+ *
+ * Returns:
+ * true if the strings are equal, false otherwise.
+ */
+
+ inline
+ bool dec128_istreq (const char* a, const char* lasta,
+ const char* b, const char* lastb)
+ {
+ while (!(a == lasta && b == lastb))
+ {
+ // strings are different lengths
+ if (a == lasta || b == lastb)
+ {
+ return false;
+ }
+
+ if (dec128_tolower (*a) != dec128_tolower (*b)) {
+ return false;
+ }
+
+ a++;
+ b++;
+ }
+
+ return true;
+ }
+
+ } // namespace detail
+
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * decimal128_to_chars --
+ *
+ * This function converts a BID formatted decimal128 value to string,
+ * accepting a &decimal128_t as @dec. The string is stored at @str.
+ *
+ * @dec : The BID formatted decimal to convert.
+ * @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING
+ *characters.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ decimal128_to_chars_result decimal128_to_chars(char* first, char* last, const decimal128_t& dec)
+ {
+ const std::string bson_decimal128_inf = "Infinity";
+ const std::string bson_decimal128_nan = "NaN";
+
+ const uint32_t combination_mask = 0x1f; /* Extract least significant 5 bits */
+ const uint32_t exponent_mask = 0x3fff; /* Extract least significant 14 bits */
+ const uint32_t combination_infinity = 30; /* Value of combination field for Inf */
+ const uint32_t combination_nan = 31; /* Value of combination field for NaN */
+ const uint32_t exponent_bias = 6176; /* decimal128 exponent bias */
+
+ char* str_out = first; /* output pointer in string */
+ char significand_str[35]; /* decoded significand digits */
+
+ /* Note: bits in this routine are referred to starting at 0, */
+ /* from the sign bit, towards the coefficient. */
+ uint32_t high; /* bits 0 - 31 */
+ uint32_t midh; /* bits 32 - 63 */
+ uint32_t midl; /* bits 64 - 95 */
+ uint32_t low; /* bits 96 - 127 */
+ uint32_t combination; /* bits 1 - 5 */
+ uint32_t biased_exponent; /* decoded biased exponent (14 bits) */
+ uint32_t significand_digits = 0; /* the number of significand digits */
+ uint32_t significand[36] = {0}; /* the base-10 digits in the significand */
+ uint32_t *significand_read = significand; /* read pointer into significand */
+ int32_t exponent; /* unbiased exponent */
+ int32_t scientific_exponent; /* the exponent if scientific notation is
+ * used */
+ bool is_zero = false; /* true if the number is zero */
+
+ uint8_t significand_msb; /* the most signifcant significand bits (50-46) */
+ bson_uint128_t
+ significand128; /* temporary storage for significand decoding */
+
+ memset (significand_str, 0, sizeof (significand_str));
+
+ if ((int64_t) dec.high < 0) { /* negative */
+ *(str_out++) = '-';
+ }
+
+ low = (uint32_t) dec.low, midl = (uint32_t) (dec.low >> 32),
+ midh = (uint32_t) dec.high, high = (uint32_t) (dec.high >> 32);
+
+ /* Decode combination field and exponent */
+ combination = (high >> 26) & combination_mask;
+
+ if (JSONCONS_UNLIKELY ((combination >> 3) == 3)) {
+ /* Check for 'special' values */
+ if (combination == combination_infinity) { /* Infinity */
+ if (last-str_out >= static_cast<ptrdiff_t >(bson_decimal128_inf.size()))
+ {
+ std::memcpy(str_out, bson_decimal128_inf.data(), bson_decimal128_inf.size());
+ str_out += bson_decimal128_inf.size();
+ }
+ *str_out = 0;
+ //strcpy_s (str_out, last-str_out, bson_decimal128_inf.c_str());
+ return decimal128_to_chars_result{str_out, std::errc()};
+ } else if (combination == combination_nan) { /* NaN */
+ /* first, not str_out, to erase the sign */
+ str_out = first;
+ if (last-str_out >= static_cast<ptrdiff_t >(bson_decimal128_nan.size()))
+ {
+ std::memcpy(str_out, bson_decimal128_nan.data(), bson_decimal128_nan.size());
+ str_out += bson_decimal128_nan.size();
+ }
+ *str_out = 0;
+ //strcpy_s (first, last-first, bson_decimal128_nan.c_str());
+ /* we don't care about the NaN payload. */
+ return decimal128_to_chars_result{str_out, std::errc()};
+ } else {
+ biased_exponent = (high >> 15) & exponent_mask;
+ significand_msb = 0x8 + ((high >> 14) & 0x1);
+ }
+ } else {
+ significand_msb = (high >> 14) & 0x7;
+ biased_exponent = (high >> 17) & exponent_mask;
+ }
+
+ exponent = biased_exponent - exponent_bias;
+ /* Create string of significand digits */
+
+ /* Convert the 114-bit binary number represented by */
+ /* (high, midh, midl, low) to at most 34 decimal */
+ /* digits through modulo and division. */
+ significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14);
+ significand128.parts[1] = midh;
+ significand128.parts[2] = midl;
+ significand128.parts[3] = low;
+
+ if (significand128.parts[0] == 0 && significand128.parts[1] == 0 &&
+ significand128.parts[2] == 0 && significand128.parts[3] == 0) {
+ is_zero = true;
+ } else if (significand128.parts[0] >= (1 << 17)) {
+ /* The significand is non-canonical or zero.
+ * In order to preserve compatibility with the densely packed decimal
+ * format, the maximum value for the significand of decimal128 is
+ * 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754
+ * standard dictates that the significand is interpreted as zero.
+ */
+ is_zero = true;
+ } else {
+ for (int k = 3; k >= 0; k--) {
+ uint32_t least_digits = 0;
+ detail::bson_uint128_divide1B (
+ significand128, &significand128, &least_digits);
+
+ /* We now have the 9 least significant digits (in base 2). */
+ /* Convert and output to string. */
+ if (!least_digits) {
+ continue;
+ }
+
+ for (int j = 8; j >= 0; j--) {
+ significand[k * 9 + j] = least_digits % 10;
+ least_digits /= 10;
+ }
+ }
+ }
+
+ /* Output format options: */
+ /* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */
+ /* Regular - ddd.ddd */
+
+ if (is_zero) {
+ significand_digits = 1;
+ *significand_read = 0;
+ } else {
+ significand_digits = 36;
+ while (!(*significand_read)) {
+ significand_digits--;
+ significand_read++;
+ }
+ }
+
+ scientific_exponent = significand_digits - 1 + exponent;
+
+ /* The scientific exponent checks are dictated by the string conversion
+ * specification and are somewhat arbitrary cutoffs.
+ *
+ * We must check exponent > 0, because if this is the case, the number
+ * has trailing zeros. However, we *cannot* output these trailing zeros,
+ * because doing so would change the precision of the value, and would
+ * change stored data if the string converted number is round tripped.
+ */
+ if (scientific_exponent < -6 || exponent > 0) {
+ /* Scientific format */
+ *(str_out++) = char(*(significand_read++)) + '0';
+ significand_digits--;
+
+ if (significand_digits) {
+ *(str_out++) = '.';
+ }
+
+ for (std::size_t i = 0; i < significand_digits && (str_out - first) < 36; i++) {
+ *(str_out++) = char(*(significand_read++)) + '0';
+ }
+ /* Exponent */
+ *(str_out++) = 'E';
+
+ std::string s;
+ if (scientific_exponent >= 0) {
+ s.push_back('+');
+ }
+ jsoncons::detail::from_integer(scientific_exponent, s);
+ if (str_out + s.size() < last)
+ {
+ std::memcpy(str_out, s.data(), s.size());
+ }
+ else
+ {
+ return decimal128_to_chars_result{str_out, std::errc::value_too_large};
+ }
+ str_out += s.size();
+ } else {
+ /* Regular format with no decimal place */
+ if (exponent >= 0) {
+ for (std::size_t i = 0; i < significand_digits && (str_out - first) < 36; i++) {
+ *(str_out++) = char(*(significand_read++)) + '0';
+ }
+ } else {
+ int32_t radix_position = significand_digits + exponent;
+
+ if (radix_position > 0) { /* non-zero digits before radix */
+ for (int32_t i = 0;
+ i < radix_position && (str_out < last);
+ i++) {
+ *(str_out++) = char(*(significand_read++)) + '0';
+ }
+ } else { /* leading zero before radix point */
+ *(str_out++) = '0';
+ }
+
+ *(str_out++) = '.';
+ while (radix_position++ < 0) { /* add leading zeros after radix */
+ *(str_out++) = '0';
+ }
+
+ for (std::size_t i = 0;
+ (i < significand_digits - (std::max) (radix_position - 1, 0)) &&
+ (str_out < last);
+ i++) {
+ *(str_out++) = char(*(significand_read++)) + '0';
+ }
+ }
+ }
+ return decimal128_to_chars_result{str_out, std::errc()};
+ }
+
+
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * bson_decimal128_from_string_w_len --
+ *
+ * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to
+ * decimal128. Out of range values are converted to +/-Infinity. Invalid
+ * strings are converted to NaN. @len is the length of the string, or -1
+ * meaning the string is null-terminated.
+ *
+ * If more digits are provided than the available precision allows,
+ * round to the nearest expressable decimal128 with ties going to even will
+ * occur.
+ *
+ * Note: @string must be ASCII only!
+ *
+ * Returns:
+ * true on success, or false on failure. @dec will be NaN if @str was invalid
+ * The &decimal128_t converted from @string at @dec.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ decimal128_from_chars_result decimal128_from_chars(const char* first, const char* last, decimal128_t& dec)
+ {
+ const string_view inf_str = "inf";
+ const string_view infinity_str = "infinity";
+ const string_view nan_str = "nan";
+
+ ptrdiff_t len = last - first;
+
+ bson_uint128_6464_t significand = {0,0};
+
+ const char* str_read = first; /* Read pointer for consuming str. */
+
+ /* Parsing state tracking */
+ bool is_negative = false;
+ bool saw_radix = false;
+ bool includes_sign = false; /* True if the input first contains a sign. */
+ bool found_nonzero = false;
+
+ size_t significant_digits = 0; /* Total number of significant digits
+ * (no leading or trailing zero) */
+ size_t ndigits_read = 0; /* Total number of significand digits read */
+ size_t ndigits = 0; /* Total number of digits (no leading zeros) */
+ size_t radix_position = 0; /* The number of the digits after radix */
+ size_t first_nonzero = 0; /* The index of the first non-zero in *str* */
+
+ uint16_t digits[decimal128_limits::max_digits] = {0};
+ uint16_t ndigits_stored = 0; /* The number of digits in digits */
+ uint16_t *digits_insert = digits; /* Insertion pointer for digits */
+ size_t first_digit = 0; /* The index of the first non-zero digit */
+ size_t last_digit = 0; /* The index of the last digit */
+
+ int32_t exponent = 0;
+ uint64_t significand_high = 0; /* The high 17 digits of the significand */
+ uint64_t significand_low = 0; /* The low 17 digits of the significand */
+ uint16_t biased_exponent = 0; /* The biased exponent */
+
+ dec.high = 0;
+ dec.low = 0;
+
+ if (*str_read == '+' || *str_read == '-') {
+ is_negative = *(str_read++) == '-';
+ includes_sign = true;
+ }
+
+ /* Check for Infinity or NaN */
+ if (!isdigit (*str_read) && *str_read != '.') {
+ if (detail::dec128_istreq (str_read, last, inf_str.data(), inf_str.data()+inf_str.length()) ||
+ detail::dec128_istreq (str_read, last, infinity_str.data(), infinity_str.data()+infinity_str.length()))
+ {
+ dec = is_negative ? decimal128_limits::neg_infinity() : decimal128_limits::infinity();
+ return decimal128_from_chars_result{str_read,std::errc()};
+ } else if (detail::dec128_istreq (str_read, last, nan_str.data(), nan_str.data()+nan_str.length())) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc()};
+ }
+
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ /* Read digits */
+ while (((isdigit (*str_read) || *str_read == '.')) &&
+ (len == -1 || str_read < first + len)) {
+ if (*str_read == '.') {
+ if (saw_radix) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ saw_radix = true;
+ str_read++;
+ continue;
+ }
+
+ if (ndigits_stored < 34) {
+ if (*str_read != '0' || found_nonzero) {
+ if (!found_nonzero) {
+ first_nonzero = ndigits_read;
+ }
+
+ found_nonzero = true;
+ *(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */
+ ndigits_stored++;
+ }
+ }
+
+ if (found_nonzero) {
+ ndigits++;
+ }
+
+ if (saw_radix) {
+ radix_position++;
+ }
+
+ ndigits_read++;
+ str_read++;
+ }
+
+ if (saw_radix && !ndigits_read) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ /* Read exponent if exists */
+ if (*str_read == 'e' || *str_read == 'E') {
+ ++str_read;
+ if (*str_read == '+') {
+ ++str_read;
+ }
+ auto result = jsoncons::detail::to_integer(str_read, last - str_read, exponent);
+ if (result.ec != jsoncons::detail::to_integer_errc())
+ {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+ str_read = result.ptr;
+ }
+
+ if ((len == -1 || str_read < first + len) && *str_read) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ /* Done reading input. */
+ /* Find first non-zero digit in digits */
+ first_digit = 0;
+
+ if (!ndigits_stored) { /* value is zero */
+ first_digit = 0;
+ last_digit = 0;
+ digits[0] = 0;
+ ndigits = 1;
+ ndigits_stored = 1;
+ significant_digits = 0;
+ } else {
+ last_digit = ndigits_stored - 1;
+ significant_digits = ndigits;
+ /* Mark trailing zeros as non-significant */
+ while (first[first_nonzero + significant_digits - 1 + includes_sign +
+ saw_radix] == '0') {
+ significant_digits--;
+ }
+ }
+
+
+ /* Normalization of exponent */
+ /* Correct exponent based on radix position, and shift significand as needed
+ */
+ /* to represent user input */
+
+ /* Overflow prevention */
+ if (exponent <= static_cast<int32_t>(radix_position) && static_cast<int32_t>(radix_position) - exponent > (1 << 14)) {
+ exponent = decimal128_limits::exponent_min;
+ } else {
+ exponent -= static_cast<int32_t>(radix_position);
+ }
+
+ /* Attempt to normalize the exponent */
+ while (exponent > decimal128_limits::exponent_max) {
+ /* Shift exponent to significand and decrease */
+ last_digit++;
+
+ if (last_digit - first_digit > decimal128_limits::max_digits) {
+ /* The exponent is too great to shift into the significand. */
+ if (significant_digits == 0) {
+ /* Value is zero, we are allowed to clamp the exponent. */
+ exponent = decimal128_limits::exponent_max;
+ break;
+ }
+
+ /* Overflow is not permitted, error. */
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ exponent--;
+ }
+
+ while (exponent < decimal128_limits::exponent_min || ndigits_stored < ndigits) {
+ /* Shift last digit */
+ if (last_digit == 0) {
+ /* underflow is not allowed, but zero clamping is */
+ if (significant_digits == 0) {
+ exponent = decimal128_limits::exponent_min;
+ break;
+ }
+
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ if (ndigits_stored < ndigits) {
+ if (first[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 &&
+ significant_digits != 0) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ ndigits--; /* adjust to match digits not stored */
+ } else {
+ if (digits[last_digit] != 0) {
+ /* Inexact rounding is not allowed. */
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+
+ last_digit--; /* adjust to round */
+ }
+
+ if (exponent < decimal128_limits::exponent_max) {
+ exponent++;
+ } else {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+ }
+
+ /* Round */
+ /* We've normalized the exponent, but might still need to round. */
+ if (last_digit - first_digit + 1 < significant_digits) {
+ uint8_t round_digit;
+
+ /* There are non-zero digits after last_digit that need rounding. */
+ /* We round to nearest, ties to even */
+ round_digit =
+ first[first_nonzero + last_digit + includes_sign + saw_radix + 1] -
+ '0';
+
+ if (round_digit != 0) {
+ /* Inexact (non-zero) rounding is not allowed */
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+ }
+
+ /* Encode significand */
+ significand_high = 0, /* The high 17 digits of the significand */
+ significand_low = 0; /* The low 17 digits of the significand */
+
+ if (significant_digits == 0) { /* read a zero */
+ significand_high = 0;
+ significand_low = 0;
+ } else if (last_digit - first_digit < 17) {
+ size_t d_idx = first_digit;
+ significand_low = digits[d_idx++];
+
+ for (; d_idx <= last_digit; d_idx++) {
+ significand_low *= 10;
+ significand_low += digits[d_idx];
+ significand_high = 0;
+ }
+ } else {
+ size_t d_idx = first_digit;
+ significand_high = digits[d_idx++];
+
+ for (; d_idx <= last_digit - 17; d_idx++) {
+ significand_high *= 10;
+ significand_high += digits[d_idx];
+ }
+
+ significand_low = digits[d_idx++];
+
+ for (; d_idx <= last_digit; d_idx++) {
+ significand_low *= 10;
+ significand_low += digits[d_idx];
+ }
+ }
+
+ detail::mul_64x64 (significand_high, 100000000000000000ull, &significand);
+ significand.low += significand_low;
+
+ if (significand.low < significand_low) {
+ significand.high += 1;
+ }
+
+
+ biased_exponent = static_cast<uint16_t>(exponent + static_cast<int32_t>(decimal128_limits::exponent_bias));
+
+ /* Encode combination, exponent, and significand. */
+ if ((significand.high >> 49) & 1) {
+ /* Encode '11' into bits 1 to 3 */
+ dec.high |= (0x3ull << 61);
+ dec.high |= (biased_exponent & 0x3fffull) << 47;
+ dec.high |= significand.high & 0x7fffffffffffull;
+ } else {
+ dec.high |= (biased_exponent & 0x3fffull) << 49;
+ dec.high |= significand.high & 0x1ffffffffffffull;
+ }
+
+ dec.low = significand.low;
+
+ /* Encode sign */
+ if (is_negative) {
+ dec.high |= 0x8000000000000000ull;
+ }
+
+ return decimal128_from_chars_result{str_read,std::errc()};
+ }
+
+} // namespace bson
+} // namespace jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/bson/bson_decimal128.hpp.bak b/include/jsoncons_ext/bson/bson_decimal128.hpp.bak
new file mode 100644
index 0000000..8e27ee1
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_decimal128.hpp.bak
@@ -0,0 +1,816 @@
+#ifndef JSONCONS_BSON_BSON_DECIMAL128_HPP
+#define JSONCONS_BSON_BSON_DECIMAL128_HPP
+
+/*
+ * Copyright 2015 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <system_error>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+namespace jsoncons { namespace bson {
+
+ struct decimal128_to_chars_result
+ {
+ char* ptr;
+ std::errc ec;
+ };
+
+ struct decimal128_from_chars_result
+ {
+ const char* ptr;
+ std::errc ec;
+ };
+
+/**
+ * BSON_DECIMAL128_STRING:
+ *
+ * The length of a decimal128 string (with null terminator).
+ *
+ * 1 for the sign
+ * 35 for digits and radix
+ * 2 for exponent indicator and sign
+ * 4 for exponent digits
+ */
+#define BSON_DECIMAL128_STRING 43
+#define BSON_DECIMAL128_INF "Infinity"
+#define BSON_DECIMAL128_NAN "NaN"
+
+ struct TP1
+ {
+ uint64_t low;
+ uint64_t high;
+
+ constexpr TP1() : low(0), high(0) {}
+ constexpr TP1(uint64_t hi, uint64_t lo) : low(lo), high(hi) {}
+ };
+ struct TP2
+ {
+ uint64_t high;
+ uint64_t low;
+
+ constexpr TP2() : high(0), low(0) {}
+ constexpr TP2(uint64_t hi, uint64_t lo) : high(hi), low(lo) {}
+ };
+
+ typedef typename std::conditional<
+ jsoncons::endian::native == jsoncons::endian::little,
+ TP1,
+ TP2
+ >::type decimal128_t;
+
+ inline
+ bool operator==(const decimal128_t& lhs, const decimal128_t& rhs)
+ {
+ return lhs.high == rhs.high && lhs.low == rhs.low;
+ }
+
+ inline
+ bool operator!=(const decimal128_t& lhs, const decimal128_t& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ struct decimal128_limits
+ {
+ // The length of a decimal128 string (without null terminator).
+ //
+ // 1 for the sign
+ // 35 for digits and radix
+ // 2 for exponent indicator and sign
+ // 4 for exponent digits
+ static constexpr int recommended_buffer_size = 42;
+ static constexpr decimal128_t nan = decimal128_t(0x7c00000000000000ull, 0);
+ static constexpr decimal128_t infinity = decimal128_t(0x7800000000000000ull, 0);
+ static constexpr decimal128_t neg_infinity = decimal128_t(0x7800000000000000ull + 0x8000000000000000ull, 0);
+ static constexpr int exponent_max = 6111;
+ static constexpr int exponent_min = -6176;
+ static constexpr int exponent_bias = 6176;
+ static constexpr int max_digits = 34;
+ };
+
+ /**
+ * bson_uint128_t:
+ *
+ * This struct represents a 128 bit integer.
+ */
+ typedef struct {
+ uint32_t parts[4]; /* 32-bit words stored high to low. */
+ } bson_uint128_t;
+
+ typedef struct {
+ uint64_t high, low;
+ } bson_uint128_6464_t;
+
+ namespace detail {
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * bson_uint128_divide1B --
+ *
+ * This function divides a #bson_uint128_t by 1000000000 (1 billion) and
+ * computes the quotient and remainder.
+ *
+ * The remainder will contain 9 decimal digits for conversion to string.
+ *
+ * @value The #bson_uint128_t operand.
+ * @quotient A pointer to store the #bson_uint128_t quotient.
+ * @rem A pointer to store the #uint64_t remainder.
+ *
+ * Returns:
+ * The quotient at @quotient and the remainder at @rem.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ void bson_uint128_divide1B (bson_uint128_t value, /* IN */
+ bson_uint128_t *quotient, /* OUT */
+ uint32_t *rem) /* OUT */
+ {
+ const uint32_t DIVISOR = 1000 * 1000 * 1000;
+ uint64_t _rem = 0;
+ int i = 0;
+
+ if (!value.parts[0] && !value.parts[1] && !value.parts[2] &&
+ !value.parts[3]) {
+ *quotient = value;
+ *rem = 0;
+ return;
+ }
+
+ for (i = 0; i <= 3; i++) {
+ _rem <<= 32; /* Adjust remainder to match value of next dividend */
+ _rem += value.parts[i]; /* Add the divided to _rem */
+ value.parts[i] = (uint32_t) (_rem / DIVISOR);
+ _rem %= DIVISOR; /* Store the remainder */
+ }
+
+ *quotient = value;
+ *rem = (uint32_t) _rem;
+ }
+
+ /**
+ *-------------------------------------------------------------------------
+ *
+ * mul64x64 --
+ *
+ * This function multiplies two &uint64_t into a &bson_uint128_6464_t.
+ *
+ * Returns:
+ * The product of @left and @right.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ inline
+ void mul_64x64 (uint64_t left, /* IN */
+ uint64_t right, /* IN */
+ bson_uint128_6464_t *product) /* OUT */
+ {
+ uint64_t left_high, left_low, right_high, right_low, product_high,
+ product_mid, product_mid2, product_low;
+ bson_uint128_6464_t rt = {0};
+
+ if (!left && !right) {
+ *product = rt;
+ return;
+ }
+
+ left_high = left >> 32;
+ left_low = (uint32_t) left;
+ right_high = right >> 32;
+ right_low = (uint32_t) right;
+
+ product_high = left_high * right_high;
+ product_mid = left_high * right_low;
+ product_mid2 = left_low * right_high;
+ product_low = left_low * right_low;
+
+ product_high += product_mid >> 32;
+ product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32);
+
+ product_high = product_high + (product_mid >> 32);
+ product_low = (product_mid << 32) + (uint32_t) product_low;
+
+ rt.high = product_high;
+ rt.low = product_low;
+ *product = rt;
+ }
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * dec128_tolower --
+ *
+ * This function converts the ASCII character @c to lowercase. It is locale
+ * insensitive (unlike the stdlib tolower).
+ *
+ * Returns:
+ * The lowercased character.
+ */
+
+ inline
+ char dec128_tolower (char c)
+ {
+ if (isupper (c)) {
+ c += 32;
+ }
+
+ return c;
+ }
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * dec128_istreq --
+ *
+ * This function compares the null-terminated *ASCII* strings @a and @b
+ * for case-insensitive equality.
+ *
+ * Returns:
+ * true if the strings are equal, false otherwise.
+ */
+
+ inline
+ bool dec128_istreq (const char* a, /* IN */
+ const char* b /* IN */)
+ {
+ while (*a != '\0' || *b != '\0') {
+ /* strings are different lengths. */
+ if (*a == '\0' || *b == '\0') {
+ return false;
+ }
+
+ if (dec128_tolower (*a) != dec128_tolower (*b)) {
+ return false;
+ }
+
+ a++;
+ b++;
+ }
+
+ return true;
+ }
+
+ } // namespace detail
+
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * decimal128_to_chars --
+ *
+ * This function converts a BID formatted decimal128 value to string,
+ * accepting a &decimal128_t as @dec. The string is stored at @str.
+ *
+ * @dec : The BID formatted decimal to convert.
+ * @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING
+ *characters.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ void decimal128_to_chars(char* first, char* last, const decimal128_t& dec)
+ {
+ uint32_t COMBINATION_MASK = 0x1f; /* Extract least significant 5 bits */
+ uint32_t EXPONENT_MASK = 0x3fff; /* Extract least significant 14 bits */
+ uint32_t COMBINATION_INFINITY = 30; /* Value of combination field for Inf */
+ uint32_t COMBINATION_NAN = 31; /* Value of combination field for NaN */
+ uint32_t EXPONENT_BIAS = 6176; /* decimal128 exponent bias */
+
+ char* str_out = first; /* output pointer in string */
+ char significand_str[35]; /* decoded significand digits */
+
+
+ /* Note: bits in this routine are referred to starting at 0, */
+ /* from the sign bit, towards the coefficient. */
+ uint32_t high; /* bits 0 - 31 */
+ uint32_t midh; /* bits 32 - 63 */
+ uint32_t midl; /* bits 64 - 95 */
+ uint32_t low; /* bits 96 - 127 */
+ uint32_t combination; /* bits 1 - 5 */
+ uint32_t biased_exponent; /* decoded biased exponent (14 bits) */
+ uint32_t significand_digits = 0; /* the number of significand digits */
+ uint32_t significand[36] = {0}; /* the base-10 digits in the significand */
+ uint32_t *significand_read = significand; /* read pointer into significand */
+ int32_t exponent; /* unbiased exponent */
+ int32_t scientific_exponent; /* the exponent if scientific notation is
+ * used */
+ bool is_zero = false; /* true if the number is zero */
+
+ uint8_t significand_msb; /* the most signifcant significand bits (50-46) */
+ bson_uint128_t
+ significand128; /* temporary storage for significand decoding */
+ size_t i; /* indexing variables */
+ int j, k;
+
+ memset (significand_str, 0, sizeof (significand_str));
+
+ if ((int64_t) dec.high < 0) { /* negative */
+ *(str_out++) = '-';
+ }
+
+ low = (uint32_t) dec.low, midl = (uint32_t) (dec.low >> 32),
+ midh = (uint32_t) dec.high, high = (uint32_t) (dec.high >> 32);
+
+ /* Decode combination field and exponent */
+ combination = (high >> 26) & COMBINATION_MASK;
+
+ if (JSONCONS_UNLIKELY ((combination >> 3) == 3)) {
+ /* Check for 'special' values */
+ if (combination == COMBINATION_INFINITY) { /* Infinity */
+ strcpy (str_out, BSON_DECIMAL128_INF);
+ return;
+ } else if (combination == COMBINATION_NAN) { /* NaN */
+ /* first, not str_out, to erase the sign */
+ strcpy (first, BSON_DECIMAL128_NAN);
+ /* we don't care about the NaN payload. */
+ return;
+ } else {
+ biased_exponent = (high >> 15) & EXPONENT_MASK;
+ significand_msb = 0x8 + ((high >> 14) & 0x1);
+ }
+ } else {
+ significand_msb = (high >> 14) & 0x7;
+ biased_exponent = (high >> 17) & EXPONENT_MASK;
+ }
+
+ exponent = biased_exponent - EXPONENT_BIAS;
+ /* Create string of significand digits */
+
+ /* Convert the 114-bit binary number represented by */
+ /* (high, midh, midl, low) to at most 34 decimal */
+ /* digits through modulo and division. */
+ significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14);
+ significand128.parts[1] = midh;
+ significand128.parts[2] = midl;
+ significand128.parts[3] = low;
+
+ if (significand128.parts[0] == 0 && significand128.parts[1] == 0 &&
+ significand128.parts[2] == 0 && significand128.parts[3] == 0) {
+ is_zero = true;
+ } else if (significand128.parts[0] >= (1 << 17)) {
+ /* The significand is non-canonical or zero.
+ * In order to preserve compatibility with the densely packed decimal
+ * format, the maximum value for the significand of decimal128 is
+ * 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754
+ * standard dictates that the significand is interpreted as zero.
+ */
+ is_zero = true;
+ } else {
+ for (k = 3; k >= 0; k--) {
+ uint32_t least_digits = 0;
+ detail::bson_uint128_divide1B (
+ significand128, &significand128, &least_digits);
+
+ /* We now have the 9 least significant digits (in base 2). */
+ /* Convert and output to string. */
+ if (!least_digits) {
+ continue;
+ }
+
+ for (j = 8; j >= 0; j--) {
+ significand[k * 9 + j] = least_digits % 10;
+ least_digits /= 10;
+ }
+ }
+ }
+
+ /* Output format options: */
+ /* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */
+ /* Regular - ddd.ddd */
+
+ if (is_zero) {
+ significand_digits = 1;
+ *significand_read = 0;
+ } else {
+ significand_digits = 36;
+ while (!(*significand_read)) {
+ significand_digits--;
+ significand_read++;
+ }
+ }
+
+ scientific_exponent = significand_digits - 1 + exponent;
+
+ /* The scientific exponent checks are dictated by the string conversion
+ * specification and are somewhat arbitrary cutoffs.
+ *
+ * We must check exponent > 0, because if this is the case, the number
+ * has trailing zeros. However, we *cannot* output these trailing zeros,
+ * because doing so would change the precision of the value, and would
+ * change stored data if the string converted number is round tripped.
+ */
+ if (scientific_exponent < -6 || exponent > 0) {
+ /* Scientific format */
+ *(str_out++) = *(significand_read++) + '0';
+ significand_digits--;
+
+ if (significand_digits) {
+ *(str_out++) = '.';
+ }
+
+ for (i = 0; i < significand_digits && (str_out - first) < 36; i++) {
+ *(str_out++) = *(significand_read++) + '0';
+ }
+ /* Exponent */
+ *(str_out++) = 'E';
+ snprintf (str_out, 6, "%+d", scientific_exponent);
+ } else {
+ /* Regular format with no decimal place */
+ if (exponent >= 0) {
+ for (i = 0; i < significand_digits && (str_out - first) < 36; i++) {
+ *(str_out++) = *(significand_read++) + '0';
+ }
+ *str_out = '\0';
+ } else {
+ int32_t radix_position = significand_digits + exponent;
+
+ if (radix_position > 0) { /* non-zero digits before radix */
+ for (i = 0;
+ i < radix_position && (str_out < last);
+ i++) {
+ *(str_out++) = *(significand_read++) + '0';
+ }
+ } else { /* leading zero before radix point */
+ *(str_out++) = '0';
+ }
+
+ *(str_out++) = '.';
+ while (radix_position++ < 0) { /* add leading zeros after radix */
+ *(str_out++) = '0';
+ }
+
+ for (i = 0;
+ (i < significand_digits - (std::max) (radix_position - 1, 0)) &&
+ (str_out < last);
+ i++) {
+ *(str_out++) = *(significand_read++) + '0';
+ }
+ *str_out = '\0';
+ }
+ }
+ }
+
+
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * bson_decimal128_from_string_w_len --
+ *
+ * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to
+ * decimal128. Out of range values are converted to +/-Infinity. Invalid
+ * strings are converted to NaN. @len is the length of the string, or -1
+ * meaning the string is null-terminated.
+ *
+ * If more digits are provided than the available precision allows,
+ * round to the nearest expressable decimal128 with ties going to even will
+ * occur.
+ *
+ * Note: @string must be ASCII only!
+ *
+ * Returns:
+ * true on success, or false on failure. @dec will be NaN if @str was invalid
+ * The &decimal128_t converted from @string at @dec.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ bool decimal128_from_chars(const char* first, const char* last, decimal128_t& dec)
+ {
+ int len = last - first;
+
+ bson_uint128_6464_t significand = {0};
+
+ const char* str_read = first; /* Read pointer for consuming str. */
+
+ /* Parsing state tracking */
+ bool is_negative = false;
+ bool saw_radix = false;
+ bool includes_sign = false; /* True if the input first contains a sign. */
+ bool found_nonzero = false;
+
+ size_t significant_digits = 0; /* Total number of significant digits
+ * (no leading or trailing zero) */
+ size_t ndigits_read = 0; /* Total number of significand digits read */
+ size_t ndigits = 0; /* Total number of digits (no leading zeros) */
+ size_t radix_position = 0; /* The number of the digits after radix */
+ size_t first_nonzero = 0; /* The index of the first non-zero in *str* */
+
+ uint16_t digits[decimal128_limits::max_digits] = {0};
+ uint16_t ndigits_stored = 0; /* The number of digits in digits */
+ uint16_t *digits_insert = digits; /* Insertion pointer for digits */
+ size_t first_digit = 0; /* The index of the first non-zero digit */
+ size_t last_digit = 0; /* The index of the last digit */
+
+ int32_t exponent = 0;
+ uint64_t significand_high = 0; /* The high 17 digits of the significand */
+ uint64_t significand_low = 0; /* The low 17 digits of the significand */
+ uint16_t biased_exponent = 0; /* The biased exponent */
+
+ dec.high = 0;
+ dec.low = 0;
+
+ if (*str_read == '+' || *str_read == '-') {
+ is_negative = *(str_read++) == '-';
+ includes_sign = true;
+ }
+
+ /* Check for Infinity or NaN */
+ if (!isdigit (*str_read) && *str_read != '.') {
+ if (detail::dec128_istreq (str_read, "inf") ||
+ detail::dec128_istreq (str_read, "infinity")) {
+ dec = is_negative ? decimal128_limits::neg_infinity : decimal128_limits::infinity;
+ return true;
+ } else if (detail::dec128_istreq (str_read, "nan")) {
+ dec = decimal128_limits::nan;
+ return true;
+ }
+
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+ /* Read digits */
+ while (((isdigit (*str_read) || *str_read == '.')) &&
+ (len == -1 || str_read < first + len)) {
+ if (*str_read == '.') {
+ if (saw_radix) {
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+ saw_radix = true;
+ str_read++;
+ continue;
+ }
+
+ if (ndigits_stored < 34) {
+ if (*str_read != '0' || found_nonzero) {
+ if (!found_nonzero) {
+ first_nonzero = ndigits_read;
+ }
+
+ found_nonzero = true;
+ *(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */
+ ndigits_stored++;
+ }
+ }
+
+ if (found_nonzero) {
+ ndigits++;
+ }
+
+ if (saw_radix) {
+ radix_position++;
+ }
+
+ ndigits_read++;
+ str_read++;
+ }
+
+ if (saw_radix && !ndigits_read) {
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+ /* Read exponent if exists */
+ if (*str_read == 'e' || *str_read == 'E') {
+ int nread = 0;
+ #ifdef _MSC_VER
+ #define SSCANF sscanf_s
+ #else
+ #define SSCANF sscanf
+ #endif
+ int read_exponent = SSCANF (++str_read, "%d%n", &exponent, &nread);
+ str_read += nread;
+
+ if (!read_exponent || nread == 0) {
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+ #undef SSCANF
+ }
+
+ if ((len == -1 || str_read < first + len) && *str_read) {
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+ /* Done reading input. */
+ /* Find first non-zero digit in digits */
+ first_digit = 0;
+
+ if (!ndigits_stored) { /* value is zero */
+ first_digit = 0;
+ last_digit = 0;
+ digits[0] = 0;
+ ndigits = 1;
+ ndigits_stored = 1;
+ significant_digits = 0;
+ } else {
+ last_digit = ndigits_stored - 1;
+ significant_digits = ndigits;
+ /* Mark trailing zeros as non-significant */
+ while (first[first_nonzero + significant_digits - 1 + includes_sign +
+ saw_radix] == '0') {
+ significant_digits--;
+ }
+ }
+
+
+ /* Normalization of exponent */
+ /* Correct exponent based on radix position, and shift significand as needed
+ */
+ /* to represent user input */
+
+ /* Overflow prevention */
+ if (exponent <= radix_position && radix_position - exponent > (1 << 14)) {
+ exponent = decimal128_limits::exponent_min;
+ } else {
+ exponent -= radix_position;
+ }
+
+ /* Attempt to normalize the exponent */
+ while (exponent > decimal128_limits::exponent_max) {
+ /* Shift exponent to significand and decrease */
+ last_digit++;
+
+ if (last_digit - first_digit > decimal128_limits::max_digits) {
+ /* The exponent is too great to shift into the significand. */
+ if (significant_digits == 0) {
+ /* Value is zero, we are allowed to clamp the exponent. */
+ exponent = decimal128_limits::exponent_max;
+ break;
+ }
+
+ /* Overflow is not permitted, error. */
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+ exponent--;
+ }
+
+ while (exponent < decimal128_limits::exponent_min || ndigits_stored < ndigits) {
+ /* Shift last digit */
+ if (last_digit == 0) {
+ /* underflow is not allowed, but zero clamping is */
+ if (significant_digits == 0) {
+ exponent = decimal128_limits::exponent_min;
+ break;
+ }
+
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+ if (ndigits_stored < ndigits) {
+ if (first[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 &&
+ significant_digits != 0) {
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+ ndigits--; /* adjust to match digits not stored */
+ } else {
+ if (digits[last_digit] != 0) {
+ /* Inexact rounding is not allowed. */
+ dec = decimal128_limits::nan;
+ return false;
+ }
+
+
+ last_digit--; /* adjust to round */
+ }
+
+ if (exponent < decimal128_limits::exponent_max) {
+ exponent++;
+ } else {
+ dec = decimal128_limits::nan;
+ return false;
+ }
+ }
+
+ /* Round */
+ /* We've normalized the exponent, but might still need to round. */
+ if (last_digit - first_digit + 1 < significant_digits) {
+ uint8_t round_digit;
+
+ /* There are non-zero digits after last_digit that need rounding. */
+ /* We round to nearest, ties to even */
+ round_digit =
+ first[first_nonzero + last_digit + includes_sign + saw_radix + 1] -
+ '0';
+
+ if (round_digit != 0) {
+ /* Inexact (non-zero) rounding is not allowed */
+ dec = decimal128_limits::nan;
+ return false;
+ }
+ }
+
+ /* Encode significand */
+ significand_high = 0, /* The high 17 digits of the significand */
+ significand_low = 0; /* The low 17 digits of the significand */
+
+ if (significant_digits == 0) { /* read a zero */
+ significand_high = 0;
+ significand_low = 0;
+ } else if (last_digit - first_digit < 17) {
+ size_t d_idx = first_digit;
+ significand_low = digits[d_idx++];
+
+ for (; d_idx <= last_digit; d_idx++) {
+ significand_low *= 10;
+ significand_low += digits[d_idx];
+ significand_high = 0;
+ }
+ } else {
+ size_t d_idx = first_digit;
+ significand_high = digits[d_idx++];
+
+ for (; d_idx <= last_digit - 17; d_idx++) {
+ significand_high *= 10;
+ significand_high += digits[d_idx];
+ }
+
+ significand_low = digits[d_idx++];
+
+ for (; d_idx <= last_digit; d_idx++) {
+ significand_low *= 10;
+ significand_low += digits[d_idx];
+ }
+ }
+
+ detail::mul_64x64 (significand_high, 100000000000000000ull, &significand);
+ significand.low += significand_low;
+
+ if (significand.low < significand_low) {
+ significand.high += 1;
+ }
+
+
+ biased_exponent = (exponent + (int16_t) decimal128_limits::exponent_bias);
+
+ /* Encode combination, exponent, and significand. */
+ if ((significand.high >> 49) & 1) {
+ /* Encode '11' into bits 1 to 3 */
+ dec.high |= (0x3ull << 61);
+ dec.high |= (biased_exponent & 0x3fffull) << 47;
+ dec.high |= significand.high & 0x7fffffffffffull;
+ } else {
+ dec.high |= (biased_exponent & 0x3fffull) << 49;
+ dec.high |= significand.high & 0x1ffffffffffffull;
+ }
+
+ dec.low = significand.low;
+
+ /* Encode sign */
+ if (is_negative) {
+ dec.high |= 0x8000000000000000ull;
+ }
+
+ return true;
+ }
+
+} // namespace bson
+} // namespace jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/bson/bson_encoder.hpp b/include/jsoncons_ext/bson/bson_encoder.hpp
new file mode 100644
index 0000000..4569f06
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_encoder.hpp
@@ -0,0 +1,585 @@
+// 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_BSON_BSON_ENCODER_HPP
+#define JSONCONS_BSON_BSON_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/bson/bson_type.hpp>
+#include <jsoncons_ext/bson/bson_error.hpp>
+#include <jsoncons_ext/bson/bson_options.hpp>
+#include <jsoncons_ext/bson/bson_decimal128.hpp>
+#include <jsoncons_ext/bson/bson_oid.hpp>
+
+namespace jsoncons { namespace bson {
+
+template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>>
+class basic_bson_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
+ {
+ jsoncons::bson::bson_container_type type_;
+ std::size_t offset_;
+ std::size_t name_offset_;
+ std::size_t index_;
+
+ stack_item(jsoncons::bson::bson_container_type type, std::size_t offset) noexcept
+ : type_(type), offset_(offset), name_offset_(0), index_(0)
+ {
+ }
+
+ std::size_t offset() const
+ {
+ return offset_;
+ }
+
+ std::size_t member_offset() const
+ {
+ return name_offset_;
+ }
+
+ void member_offset(std::size_t offset)
+ {
+ name_offset_ = offset;
+ }
+
+ std::size_t next_index()
+ {
+ return index_++;
+ }
+
+ bool is_object() const
+ {
+ return type_ == jsoncons::bson::bson_container_type::document;
+ }
+
+
+ };
+
+ sink_type sink_;
+ const bson_encode_options options_;
+ allocator_type alloc_;
+
+ std::vector<stack_item> stack_;
+ std::vector<uint8_t> buffer_;
+ int nesting_depth_;
+
+ // Noncopyable and nonmoveable
+ basic_bson_encoder(const basic_bson_encoder&) = delete;
+ basic_bson_encoder& operator=(const basic_bson_encoder&) = delete;
+public:
+ explicit basic_bson_encoder(Sink&& sink,
+ const Allocator& alloc = Allocator())
+ : basic_bson_encoder(std::forward<Sink>(sink),
+ bson_encode_options(),
+ alloc)
+ {
+ }
+
+ explicit basic_bson_encoder(Sink&& sink,
+ const bson_encode_options& options,
+ const Allocator& alloc = Allocator())
+ : sink_(std::forward<Sink>(sink)),
+ options_(options),
+ alloc_(alloc),
+ nesting_depth_(0)
+ {
+ }
+
+ ~basic_bson_encoder() noexcept
+ {
+ sink_.flush();
+ }
+
+ void reset()
+ {
+ stack_.clear();
+ buffer_.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
+ {
+ if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
+ {
+ ec = bson_errc::max_nesting_depth_exceeded;
+ return false;
+ }
+ if (buffer_.size() > 0)
+ {
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+ before_value(jsoncons::bson::bson_type::document_type);
+ }
+
+ stack_.emplace_back(jsoncons::bson::bson_container_type::document, buffer_.size());
+ buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
+
+ return true;
+ }
+
+ bool visit_end_object(const ser_context&, std::error_code&) override
+ {
+ JSONCONS_ASSERT(!stack_.empty());
+ --nesting_depth_;
+
+ buffer_.push_back(0x00);
+
+ std::size_t length = buffer_.size() - stack_.back().offset();
+ binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+stack_.back().offset());
+
+ stack_.pop_back();
+ if (stack_.empty())
+ {
+ for (auto c : buffer_)
+ {
+ sink_.push_back(c);
+ }
+ }
+ 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 = bson_errc::max_nesting_depth_exceeded;
+ return false;
+ }
+ if (buffer_.size() > 0)
+ {
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+ before_value(jsoncons::bson::bson_type::array_type);
+ }
+ stack_.emplace_back(jsoncons::bson::bson_container_type::array, buffer_.size());
+ buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
+ return true;
+ }
+
+ bool visit_end_array(const ser_context&, std::error_code&) override
+ {
+ JSONCONS_ASSERT(!stack_.empty());
+ --nesting_depth_;
+
+ buffer_.push_back(0x00);
+
+ std::size_t length = buffer_.size() - stack_.back().offset();
+ binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+stack_.back().offset());
+
+ stack_.pop_back();
+ if (stack_.empty())
+ {
+ for (auto c : buffer_)
+ {
+ sink_.push_back(c);
+ }
+ }
+ return true;
+ }
+
+ bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
+ {
+ stack_.back().member_offset(buffer_.size());
+ buffer_.push_back(0x00); // reserve space for code
+ for (auto c : name)
+ {
+ buffer_.push_back(c);
+ }
+ buffer_.push_back(0x00);
+ return true;
+ }
+
+ bool visit_null(semantic_tag tag, const ser_context&, std::error_code& ec) override
+ {
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+ switch (tag)
+ {
+ case semantic_tag::undefined:
+ before_value(jsoncons::bson::bson_type::undefined_type);
+ break;
+ default:
+ before_value(jsoncons::bson::bson_type::null_type);
+ break;
+ }
+ return true;
+ }
+
+ bool visit_bool(bool val, semantic_tag, const ser_context&, std::error_code& ec) override
+ {
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+ before_value(jsoncons::bson::bson_type::bool_type);
+ if (val)
+ {
+ buffer_.push_back(0x01);
+ }
+ else
+ {
+ buffer_.push_back(0x00);
+ }
+
+ return true;
+ }
+
+ bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) override
+ {
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+
+ switch (tag)
+ {
+ case semantic_tag::float128:
+ {
+ before_value(jsoncons::bson::bson_type::decimal128_type);
+ decimal128_t dec;
+ auto rc = decimal128_from_chars(sv.data(), sv.data()+sv.size(), dec);
+ if (rc.ec != std::errc())
+ {
+ ec = bson_errc::invalid_decimal128_string;
+ return false;
+ }
+ binary::native_to_little(dec.low,std::back_inserter(buffer_));
+ binary::native_to_little(dec.high,std::back_inserter(buffer_));
+ break;
+ }
+ case semantic_tag::id:
+ {
+ before_value(jsoncons::bson::bson_type::object_id_type);
+ oid_t oid(sv);
+ for (auto b : oid)
+ {
+ buffer_.push_back(b);
+ }
+ break;
+ }
+ case semantic_tag::regex:
+ {
+ before_value(jsoncons::bson::bson_type::regex_type);
+ std::size_t first = sv.find_first_of('/');
+ std::size_t last = sv.find_last_of('/');
+ if (first == string_view::npos || last == string_view::npos || first == last)
+ {
+ ec = bson_errc::invalid_regex_string;
+ return false;
+ }
+ string_view regex = sv.substr(first+1,last-1);
+ for (auto c : regex)
+ {
+ buffer_.push_back(c);
+ }
+ buffer_.push_back(0x00);
+ string_view options = sv.substr(last+1);
+ for (auto c : options)
+ {
+ buffer_.push_back(c);
+ }
+ buffer_.push_back(0x00);
+ break;
+ }
+ default:
+ switch (tag)
+ {
+ case semantic_tag::code:
+ before_value(jsoncons::bson::bson_type::javascript_type);
+ break;
+ default:
+ before_value(jsoncons::bson::bson_type::string_type);
+ break;
+ }
+ std::size_t offset = buffer_.size();
+ buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
+ std::size_t string_offset = buffer_.size();
+ auto sink = unicode_traits::validate(sv.data(), sv.size());
+ if (sink.ec != unicode_traits::conv_errc())
+ {
+ ec = bson_errc::invalid_utf8_text_string;
+ return false;
+ }
+ for (auto c : sv)
+ {
+ buffer_.push_back(c);
+ }
+ buffer_.push_back(0x00);
+ std::size_t length = buffer_.size() - string_offset;
+ binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset);
+ break;
+ }
+
+ return true;
+ }
+
+ bool visit_byte_string(const byte_string_view& b,
+ semantic_tag,
+ const ser_context&,
+ std::error_code& ec) override
+ {
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+ before_value(jsoncons::bson::bson_type::binary_type);
+
+ std::size_t offset = buffer_.size();
+ buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
+ std::size_t string_offset = buffer_.size();
+
+ buffer_.push_back(0x80); // default subtype
+
+ for (auto c : b)
+ {
+ buffer_.push_back(c);
+ }
+ std::size_t length = buffer_.size() - string_offset - 1;
+ binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset);
+
+ return true;
+ }
+
+ bool visit_byte_string(const byte_string_view& b,
+ uint64_t ext_tag,
+ const ser_context&,
+ std::error_code& ec) override
+ {
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+ before_value(jsoncons::bson::bson_type::binary_type);
+
+ std::size_t offset = buffer_.size();
+ buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
+ std::size_t string_offset = buffer_.size();
+
+ buffer_.push_back(static_cast<uint8_t>(ext_tag)); // default subtype
+
+ for (auto c : b)
+ {
+ buffer_.push_back(c);
+ }
+ std::size_t length = buffer_.size() - string_offset - 1;
+ binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset);
+
+ return true;
+ }
+
+ bool visit_int64(int64_t val,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code& ec) override
+ {
+ static constexpr int64_t min_value_div_1000 = (std::numeric_limits<int64_t>::min)() / 1000;
+ static constexpr int64_t max_value_div_1000 = (std::numeric_limits<int64_t>::max)() / 1000;
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+
+ switch (tag)
+ {
+ case semantic_tag::epoch_second:
+ if (val < min_value_div_1000)
+ {
+ ec = bson_errc::datetime_too_small;
+ return false;
+ }
+ if (val > max_value_div_1000)
+ {
+ ec = bson_errc::datetime_too_large;
+ return false;
+ }
+ before_value(jsoncons::bson::bson_type::datetime_type);
+ binary::native_to_little(val*millis_in_second,std::back_inserter(buffer_));
+ return true;
+ case semantic_tag::epoch_milli:
+ before_value(jsoncons::bson::bson_type::datetime_type);
+ binary::native_to_little(val,std::back_inserter(buffer_));
+ return true;
+ case semantic_tag::epoch_nano:
+ before_value(jsoncons::bson::bson_type::datetime_type);
+ if (val != 0)
+ {
+ val /= nanos_in_milli;
+ }
+ binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_));
+ return true;
+ default:
+ {
+ if (val >= (std::numeric_limits<int32_t>::lowest)() && val <= (std::numeric_limits<int32_t>::max)())
+ {
+ before_value(jsoncons::bson::bson_type::int32_type);
+ binary::native_to_little(static_cast<uint32_t>(val),std::back_inserter(buffer_));
+ }
+ else
+ {
+ before_value(jsoncons::bson::bson_type::int64_type);
+ binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_));
+ }
+ return true;
+ }
+ }
+ }
+
+ bool visit_uint64(uint64_t val,
+ semantic_tag tag,
+ const ser_context&,
+ std::error_code& ec) override
+ {
+ static constexpr uint64_t max_value_div_1000 = (std::numeric_limits<uint64_t>::max)() / 1000;
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+
+ switch (tag)
+ {
+ case semantic_tag::epoch_second:
+ if (val > max_value_div_1000)
+ {
+ ec = bson_errc::datetime_too_large;
+ return false;
+ }
+ before_value(jsoncons::bson::bson_type::datetime_type);
+ binary::native_to_little(static_cast<int64_t>(val*millis_in_second),std::back_inserter(buffer_));
+ return true;
+ case semantic_tag::epoch_milli:
+ before_value(jsoncons::bson::bson_type::datetime_type);
+ binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_));
+ return true;
+ case semantic_tag::epoch_nano:
+ before_value(jsoncons::bson::bson_type::datetime_type);
+ if (val != 0)
+ {
+ val /= nanos_in_second;
+ }
+ binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_));
+ return true;
+ default:
+ {
+ bool more;
+ if (val <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
+ {
+ before_value(jsoncons::bson::bson_type::int32_type);
+ binary::native_to_little(static_cast<uint32_t>(val),std::back_inserter(buffer_));
+ more = true;
+ }
+ else if (val <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
+ {
+ before_value(jsoncons::bson::bson_type::int64_type);
+ binary::native_to_little(static_cast<uint64_t>(val),std::back_inserter(buffer_));
+ more = true;
+ }
+ else
+ {
+ ec = bson_errc::number_too_large;
+ more = false;
+ }
+ return more;
+ }
+ }
+ }
+
+ bool visit_double(double val,
+ semantic_tag,
+ const ser_context&,
+ std::error_code& ec) override
+ {
+ if (stack_.empty())
+ {
+ ec = bson_errc::expected_bson_document;
+ return false;
+ }
+ before_value(jsoncons::bson::bson_type::double_type);
+ binary::native_to_little(val,std::back_inserter(buffer_));
+ return true;
+ }
+
+ void before_value(uint8_t code)
+ {
+ JSONCONS_ASSERT(!stack_.empty());
+ if (stack_.back().is_object())
+ {
+ buffer_[stack_.back().member_offset()] = code;
+ }
+ else
+ {
+ buffer_.push_back(code);
+ std::string name = std::to_string(stack_.back().next_index());
+ buffer_.insert(buffer_.end(), name.begin(), name.end());
+ buffer_.push_back(0x00);
+ }
+ }
+};
+
+using bson_stream_encoder = basic_bson_encoder<jsoncons::binary_stream_sink>;
+using bson_bytes_encoder = basic_bson_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>;
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+template<class Sink=jsoncons::binary_stream_sink>
+using basic_bson_serializer = basic_bson_encoder<Sink>;
+
+JSONCONS_DEPRECATED_MSG("Instead, use bson_stream_encoder") typedef bson_stream_encoder bson_encoder;
+JSONCONS_DEPRECATED_MSG("Instead, use bson_stream_encoder") typedef bson_stream_encoder bson_serializer;
+JSONCONS_DEPRECATED_MSG("Instead, use bson_bytes_encoder") typedef bson_bytes_encoder bson_buffer_serializer;
+
+#endif
+
+}}
+#endif
diff --git a/include/jsoncons_ext/bson/bson_error.hpp b/include/jsoncons_ext/bson/bson_error.hpp
new file mode 100644
index 0000000..85cf24d
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_error.hpp
@@ -0,0 +1,103 @@
+/// 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_BSON_BSON_ERROR_HPP
+#define JSONCONS_BSON_BSON_ERROR_HPP
+
+#include <system_error>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+namespace jsoncons { namespace bson {
+
+enum class bson_errc
+{
+ success = 0,
+ unexpected_eof = 1,
+ source_error,
+ invalid_utf8_text_string,
+ max_nesting_depth_exceeded,
+ string_length_is_non_positive,
+ length_is_negative,
+ number_too_large,
+ invalid_decimal128_string,
+ datetime_too_small,
+ datetime_too_large,
+ expected_bson_document,
+ invalid_regex_string,
+ size_mismatch,
+ unknown_type
+};
+
+class bson_error_category_impl
+ : public std::error_category
+{
+public:
+ const char* name() const noexcept override
+ {
+ return "jsoncons/bson";
+ }
+ std::string message(int ev) const override
+ {
+ switch (static_cast<bson_errc>(ev))
+ {
+ case bson_errc::unexpected_eof:
+ return "Unexpected end of file";
+ case bson_errc::source_error:
+ return "Source error";
+ case bson_errc::invalid_utf8_text_string:
+ return "Illegal UTF-8 encoding in text string";
+ case bson_errc::max_nesting_depth_exceeded:
+ return "Data item nesting exceeds limit in options";
+ case bson_errc::string_length_is_non_positive:
+ return "Request for the length of a string returned a non-positive result";
+ case bson_errc::length_is_negative:
+ return "Request for the length of a binary returned a negative result";
+ case bson_errc::unknown_type:
+ return "An unknown type was found in the stream";
+ case bson_errc::number_too_large:
+ return "Number too large";
+ case bson_errc::invalid_decimal128_string:
+ return "Invalid decimal128 string";
+ case bson_errc::datetime_too_large:
+ return "datetime too large";
+ case bson_errc::datetime_too_small:
+ return "datetime too small";
+ case bson_errc::expected_bson_document:
+ return "Expected BSON document";
+ case bson_errc::invalid_regex_string:
+ return "Invalid regex string";
+ case bson_errc::size_mismatch:
+ return "Document or array size doesn't match bytes read";
+ default:
+ return "Unknown BSON parser error";
+ }
+ }
+};
+
+inline
+const std::error_category& bson_error_category()
+{
+ static bson_error_category_impl instance;
+ return instance;
+}
+
+inline
+std::error_code make_error_code(bson_errc result)
+{
+ return std::error_code(static_cast<int>(result),bson_error_category());
+}
+
+
+}}
+
+namespace std {
+ template<>
+ struct is_error_code_enum<jsoncons::bson::bson_errc> : public true_type
+ {
+ };
+}
+
+#endif
diff --git a/include/jsoncons_ext/bson/bson_oid.hpp b/include/jsoncons_ext/bson/bson_oid.hpp
new file mode 100644
index 0000000..065d8da
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_oid.hpp
@@ -0,0 +1,245 @@
+#ifndef JSONCONS_BSON_BSON_OID_HPP
+#define JSONCONS_BSON_BSON_OID_HPP
+
+/*
+ * Implements class oid_t and non member function bson_oid_to_string
+ *
+ * Based on the libjson functions bson_oid_to_string
+ * and bson_oid_init_from_string_unsafe , available at
+ * https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-oid.h
+ * and https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-oid.c
+ *
+*/
+
+/*
+ * Copyright 2015 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstdlib>
+#include <cstring>
+#include <ctype.h>
+#include <system_error>
+#include <algorithm>
+#include <string>
+#include <type_traits>
+#include <array>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+namespace jsoncons { namespace bson {
+
+ class oid_t
+ {
+ std::array<uint8_t,12> bytes_;
+ public:
+ using iterator = std::array<uint8_t,12>::iterator;
+ using const_iterator = std::array<uint8_t,12>::const_iterator;
+
+ oid_t(const std::array<uint8_t,12>& bytes)
+ : bytes_(bytes)
+ {
+ }
+ oid_t(uint8_t data[12])
+ {
+ std::memcpy(bytes_.data(),data,12);
+ }
+
+ oid_t(const string_view& str)
+ {
+ for (std::size_t i = 0; i < bytes_.size(); i++)
+ {
+ bytes_[i] = ((parse_hex_char (str[2 * i]) << 4) |
+ (parse_hex_char (str[2 * i + 1])));
+ }
+ }
+
+ const uint8_t* data() const
+ {
+ return bytes_.data();
+ }
+
+ std::size_t size() const
+ {
+ return bytes_.size();
+ }
+
+ iterator begin()
+ {
+ return bytes_.begin();
+ }
+
+ iterator end()
+ {
+ return bytes_.end();
+ }
+
+ const_iterator begin() const
+ {
+ return bytes_.begin();
+ }
+
+ const_iterator end() const
+ {
+ return bytes_.end();
+ }
+
+ private:
+
+ static uint8_t parse_hex_char (char hex)
+ {
+ switch (hex) {
+ case '0':
+ return 0;
+ case '1':
+ return 1;
+ case '2':
+ return 2;
+ case '3':
+ return 3;
+ case '4':
+ return 4;
+ case '5':
+ return 5;
+ case '6':
+ return 6;
+ case '7':
+ return 7;
+ case '8':
+ return 8;
+ case '9':
+ return 9;
+ case 'a':
+ case 'A':
+ return 0xa;
+ case 'b':
+ case 'B':
+ return 0xb;
+ case 'c':
+ case 'C':
+ return 0xc;
+ case 'd':
+ case 'D':
+ return 0xd;
+ case 'e':
+ case 'E':
+ return 0xe;
+ case 'f':
+ case 'F':
+ return 0xf;
+ default:
+ return 0;
+ }
+ }
+ };
+
+ namespace detail {
+
+ inline
+ const uint16_t* get_hex_char_pairs(std::true_type) // big endian
+ {
+ static const uint16_t hex_char_pairs[] = {
+ 12336, 12337, 12338, 12339, 12340, 12341, 12342, 12343, 12344, 12345, 12385,
+ 12386, 12387, 12388, 12389, 12390, 12592, 12593, 12594, 12595, 12596, 12597,
+ 12598, 12599, 12600, 12601, 12641, 12642, 12643, 12644, 12645, 12646, 12848,
+ 12849, 12850, 12851, 12852, 12853, 12854, 12855, 12856, 12857, 12897, 12898,
+ 12899, 12900, 12901, 12902, 13104, 13105, 13106, 13107, 13108, 13109, 13110,
+ 13111, 13112, 13113, 13153, 13154, 13155, 13156, 13157, 13158, 13360, 13361,
+ 13362, 13363, 13364, 13365, 13366, 13367, 13368, 13369, 13409, 13410, 13411,
+ 13412, 13413, 13414, 13616, 13617, 13618, 13619, 13620, 13621, 13622, 13623,
+ 13624, 13625, 13665, 13666, 13667, 13668, 13669, 13670, 13872, 13873, 13874,
+ 13875, 13876, 13877, 13878, 13879, 13880, 13881, 13921, 13922, 13923, 13924,
+ 13925, 13926, 14128, 14129, 14130, 14131, 14132, 14133, 14134, 14135, 14136,
+ 14137, 14177, 14178, 14179, 14180, 14181, 14182, 14384, 14385, 14386, 14387,
+ 14388, 14389, 14390, 14391, 14392, 14393, 14433, 14434, 14435, 14436, 14437,
+ 14438, 14640, 14641, 14642, 14643, 14644, 14645, 14646, 14647, 14648, 14649,
+ 14689, 14690, 14691, 14692, 14693, 14694, 24880, 24881, 24882, 24883, 24884,
+ 24885, 24886, 24887, 24888, 24889, 24929, 24930, 24931, 24932, 24933, 24934,
+ 25136, 25137, 25138, 25139, 25140, 25141, 25142, 25143, 25144, 25145, 25185,
+ 25186, 25187, 25188, 25189, 25190, 25392, 25393, 25394, 25395, 25396, 25397,
+ 25398, 25399, 25400, 25401, 25441, 25442, 25443, 25444, 25445, 25446, 25648,
+ 25649, 25650, 25651, 25652, 25653, 25654, 25655, 25656, 25657, 25697, 25698,
+ 25699, 25700, 25701, 25702, 25904, 25905, 25906, 25907, 25908, 25909, 25910,
+ 25911, 25912, 25913, 25953, 25954, 25955, 25956, 25957, 25958, 26160, 26161,
+ 26162, 26163, 26164, 26165, 26166, 26167, 26168, 26169, 26209, 26210, 26211,
+ 26212, 26213, 26214};
+
+ return hex_char_pairs;
+ }
+
+ inline
+ const uint16_t* get_hex_char_pairs(std::false_type) // little endian
+ {
+ static const uint16_t hex_char_pairs[] = {
+ 12336, 12592, 12848, 13104, 13360, 13616, 13872, 14128, 14384, 14640, 24880,
+ 25136, 25392, 25648, 25904, 26160, 12337, 12593, 12849, 13105, 13361, 13617,
+ 13873, 14129, 14385, 14641, 24881, 25137, 25393, 25649, 25905, 26161, 12338,
+ 12594, 12850, 13106, 13362, 13618, 13874, 14130, 14386, 14642, 24882, 25138,
+ 25394, 25650, 25906, 26162, 12339, 12595, 12851, 13107, 13363, 13619, 13875,
+ 14131, 14387, 14643, 24883, 25139, 25395, 25651, 25907, 26163, 12340, 12596,
+ 12852, 13108, 13364, 13620, 13876, 14132, 14388, 14644, 24884, 25140, 25396,
+ 25652, 25908, 26164, 12341, 12597, 12853, 13109, 13365, 13621, 13877, 14133,
+ 14389, 14645, 24885, 25141, 25397, 25653, 25909, 26165, 12342, 12598, 12854,
+ 13110, 13366, 13622, 13878, 14134, 14390, 14646, 24886, 25142, 25398, 25654,
+ 25910, 26166, 12343, 12599, 12855, 13111, 13367, 13623, 13879, 14135, 14391,
+ 14647, 24887, 25143, 25399, 25655, 25911, 26167, 12344, 12600, 12856, 13112,
+ 13368, 13624, 13880, 14136, 14392, 14648, 24888, 25144, 25400, 25656, 25912,
+ 26168, 12345, 12601, 12857, 13113, 13369, 13625, 13881, 14137, 14393, 14649,
+ 24889, 25145, 25401, 25657, 25913, 26169, 12385, 12641, 12897, 13153, 13409,
+ 13665, 13921, 14177, 14433, 14689, 24929, 25185, 25441, 25697, 25953, 26209,
+ 12386, 12642, 12898, 13154, 13410, 13666, 13922, 14178, 14434, 14690, 24930,
+ 25186, 25442, 25698, 25954, 26210, 12387, 12643, 12899, 13155, 13411, 13667,
+ 13923, 14179, 14435, 14691, 24931, 25187, 25443, 25699, 25955, 26211, 12388,
+ 12644, 12900, 13156, 13412, 13668, 13924, 14180, 14436, 14692, 24932, 25188,
+ 25444, 25700, 25956, 26212, 12389, 12645, 12901, 13157, 13413, 13669, 13925,
+ 14181, 14437, 14693, 24933, 25189, 25445, 25701, 25957, 26213, 12390, 12646,
+ 12902, 13158, 13414, 13670, 13926, 14182, 14438, 14694, 24934, 25190, 25446,
+ 25702, 25958, 26214};
+
+ return hex_char_pairs;
+ }
+
+ inline
+ void init_hex_char_pairs(const oid_t& oid, uint16_t* data)
+ {
+ const uint8_t* bytes = oid.data();
+ const uint16_t* gHexCharPairs = get_hex_char_pairs(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>());
+
+ data[0] = gHexCharPairs[bytes[0]];
+ data[1] = gHexCharPairs[bytes[1]];
+ data[2] = gHexCharPairs[bytes[2]];
+ data[3] = gHexCharPairs[bytes[3]];
+ data[4] = gHexCharPairs[bytes[4]];
+ data[5] = gHexCharPairs[bytes[5]];
+ data[6] = gHexCharPairs[bytes[6]];
+ data[7] = gHexCharPairs[bytes[7]];
+ data[8] = gHexCharPairs[bytes[8]];
+ data[9] = gHexCharPairs[bytes[9]];
+ data[10] = gHexCharPairs[bytes[10]];
+ data[11] = gHexCharPairs[bytes[11]];
+ }
+
+ } // namsepace detail
+
+ template <typename StringT>
+ inline
+ void to_string(const oid_t& oid, StringT& s)
+ {
+ s.resize(24);
+ detail::init_hex_char_pairs(oid, reinterpret_cast<uint16_t*>(&s[0]));
+ }
+
+} // namespace bson
+} // namespace jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/bson/bson_options.hpp b/include/jsoncons_ext/bson/bson_options.hpp
new file mode 100644
index 0000000..0e4620e
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_options.hpp
@@ -0,0 +1,75 @@
+// 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_BSON_BSON_OPTIONS_HPP
+#define JSONCONS_BSON_BSON_OPTIONS_HPP
+
+#include <string>
+#include <limits> // std::numeric_limits
+#include <cwchar>
+#include <jsoncons/json_exception.hpp>
+#include <jsoncons_ext/bson/bson_type.hpp>
+
+namespace jsoncons { namespace bson {
+
+class bson_options;
+
+class bson_options_common
+{
+ friend class bson_options;
+
+ int max_nesting_depth_;
+protected:
+ virtual ~bson_options_common() = default;
+
+ bson_options_common()
+ : max_nesting_depth_(1024)
+ {
+ }
+
+ bson_options_common(const bson_options_common&) = default;
+ bson_options_common& operator=(const bson_options_common&) = default;
+ bson_options_common(bson_options_common&&) = default;
+ bson_options_common& operator=(bson_options_common&&) = default;
+public:
+ int max_nesting_depth() const
+ {
+ return max_nesting_depth_;
+ }
+};
+
+class bson_decode_options : public virtual bson_options_common
+{
+ friend class bson_options;
+public:
+ bson_decode_options()
+ {
+ }
+};
+
+class bson_encode_options : public virtual bson_options_common
+{
+ friend class bson_options;
+public:
+ bson_encode_options()
+ {
+ }
+};
+
+class bson_options final : public bson_decode_options, public bson_encode_options
+{
+public:
+ using bson_options_common::max_nesting_depth;
+
+ bson_options& max_nesting_depth(int value)
+ {
+ this->max_nesting_depth_ = value;
+ return *this;
+ }
+};
+
+}}
+#endif
diff --git a/include/jsoncons_ext/bson/bson_parser.hpp b/include/jsoncons_ext/bson/bson_parser.hpp
new file mode 100644
index 0000000..2dc6e75
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_parser.hpp
@@ -0,0 +1,645 @@
+// 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_BSON_BSON_PARSER_HPP
+#define JSONCONS_BSON_BSON_PARSER_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/bson/bson_type.hpp>
+#include <jsoncons_ext/bson/bson_decimal128.hpp>
+#include <jsoncons_ext/bson/bson_error.hpp>
+#include <jsoncons_ext/bson/bson_options.hpp>
+#include <jsoncons_ext/bson/bson_oid.hpp>
+
+namespace jsoncons { namespace bson {
+
+enum class parse_mode {root,accept,document,array,value};
+
+struct parse_state
+{
+ parse_mode mode;
+ std::size_t length;
+ std::size_t pos;
+ uint8_t type;
+ std::size_t index;
+
+ parse_state(parse_mode mode_, std::size_t length_, std::size_t pos_, uint8_t type_ = 0) noexcept
+ : mode(mode_), length(length_), pos(pos_), type(type_), index(0)
+ {
+ }
+
+ parse_state(const parse_state&) = default;
+ parse_state(parse_state&&) = default;
+ parse_state& operator=(const parse_state&) = default;
+ parse_state& operator=(parse_state&&) = default;
+};
+
+template <class Source,class Allocator=std::allocator<char>>
+class basic_bson_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 parse_state_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<parse_state>;
+
+ Source source_;
+ bson_decode_options options_;
+ bool more_;
+ bool done_;
+ std::vector<uint8_t,byte_allocator_type> bytes_buffer_;
+ std::basic_string<char,std::char_traits<char>,char_allocator_type> text_buffer_;
+ std::vector<parse_state,parse_state_allocator_type> state_stack_;
+public:
+ template <class Sourceable>
+ basic_bson_parser(Sourceable&& source,
+ const bson_decode_options& options = bson_decode_options(),
+ const Allocator alloc = Allocator())
+ : source_(std::forward<Sourceable>(source)),
+ options_(options),
+ more_(true),
+ done_(false),
+ text_buffer_(alloc),
+ state_stack_(alloc)
+ {
+ state_stack_.emplace_back(parse_mode::root,0,0);
+ }
+
+ void restart()
+ {
+ more_ = true;
+ }
+
+ void reset()
+ {
+ more_ = true;
+ done_ = false;
+ bytes_buffer_.clear();
+ text_buffer_.clear();
+ state_stack_.clear();
+ state_stack_.emplace_back(parse_mode::root,0,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 array_expected(json_visitor& visitor, std::error_code& ec)
+ {
+ if (state_stack_.size() == 2 && state_stack_.back().mode == parse_mode::document)
+ {
+ state_stack_.back().mode = parse_mode::array;
+ more_ = visitor.begin_array(semantic_tag::none, *this, ec);
+ }
+ }
+
+ void parse(json_visitor& visitor, std::error_code& ec)
+ {
+ if (JSONCONS_UNLIKELY(source_.is_error()))
+ {
+ ec = bson_errc::source_error;
+ more_ = false;
+ return;
+ }
+
+ while (!done_ && more_)
+ {
+ switch (state_stack_.back().mode)
+ {
+ case parse_mode::root:
+ state_stack_.back().mode = parse_mode::accept;
+ begin_document(visitor, ec);
+ break;
+ case parse_mode::document:
+ {
+ uint8_t type;
+ std::size_t n = source_.read(&type, 1);
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != 1))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ if (type != 0x00)
+ {
+ read_e_name(visitor,jsoncons::bson::bson_container_type::document,ec);
+ state_stack_.back().mode = parse_mode::value;
+ state_stack_.back().type = type;
+ }
+ else
+ {
+ end_document(visitor,ec);
+ }
+ break;
+ }
+ case parse_mode::array:
+ {
+ uint8_t type;
+ std::size_t n = source_.read(&type, 1);
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != 1))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ if (type != 0x00)
+ {
+ read_e_name(visitor,jsoncons::bson::bson_container_type::array,ec);
+ read_value(visitor, type, ec);
+ }
+ else
+ {
+ end_array(visitor,ec);
+ }
+ break;
+ }
+ case parse_mode::value:
+ state_stack_.back().mode = parse_mode::document;
+ read_value(visitor,state_stack_.back().type,ec);
+ break;
+ case parse_mode::accept:
+ {
+ JSONCONS_ASSERT(state_stack_.size() == 1);
+ state_stack_.clear();
+ more_ = false;
+ done_ = true;
+ visitor.flush();
+ break;
+ }
+ }
+ }
+ }
+
+private:
+
+ void begin_document(json_visitor& visitor, std::error_code& ec)
+ {
+ if (JSONCONS_UNLIKELY(static_cast<int>(state_stack_.size()) > options_.max_nesting_depth()))
+ {
+ ec = bson_errc::max_nesting_depth_exceeded;
+ more_ = false;
+ return;
+ }
+
+ uint8_t buf[sizeof(int32_t)];
+ size_t n = source_.read(buf, sizeof(int32_t));
+ if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ auto length = binary::little_to_native<int32_t>(buf, sizeof(buf));
+
+ more_ = visitor.begin_object(semantic_tag::none, *this, ec);
+ state_stack_.emplace_back(parse_mode::document,length,n);
+ }
+
+ void end_document(json_visitor& visitor, std::error_code& ec)
+ {
+ JSONCONS_ASSERT(state_stack_.size() >= 2);
+
+ more_ = visitor.end_object(*this,ec);
+ if (JSONCONS_UNLIKELY(state_stack_.back().pos != state_stack_.back().length))
+ {
+ ec = bson_errc::size_mismatch;
+ more_ = false;
+ return;
+ }
+ std::size_t pos = state_stack_.back().pos;
+ state_stack_.pop_back();
+ state_stack_.back().pos += pos;
+ }
+
+ void begin_array(json_visitor& visitor, std::error_code& ec)
+ {
+ if (JSONCONS_UNLIKELY(static_cast<int>(state_stack_.size()) > options_.max_nesting_depth()))
+ {
+ ec = bson_errc::max_nesting_depth_exceeded;
+ more_ = false;
+ return;
+ }
+ uint8_t buf[sizeof(int32_t)];
+ std::size_t n = source_.read(buf, sizeof(int32_t));
+ if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ auto length = binary::little_to_native<int32_t>(buf, sizeof(buf));
+
+ more_ = visitor.begin_array(semantic_tag::none, *this, ec);
+ if (ec)
+ {
+ return;
+ }
+ state_stack_.emplace_back(parse_mode::array, length, n);
+ }
+
+ void end_array(json_visitor& visitor, std::error_code& ec)
+ {
+ JSONCONS_ASSERT(state_stack_.size() >= 2);
+
+ more_ = visitor.end_array(*this, ec);
+ if (JSONCONS_UNLIKELY(state_stack_.back().pos != state_stack_.back().length))
+ {
+ ec = bson_errc::size_mismatch;
+ more_ = false;
+ return;
+ }
+ std::size_t pos = state_stack_.back().pos;
+ state_stack_.pop_back();
+ state_stack_.back().pos += pos;
+ }
+
+ void read_e_name(json_visitor& visitor, jsoncons::bson::bson_container_type type, std::error_code& ec)
+ {
+ text_buffer_.clear();
+ read_cstring(ec);
+ if (ec)
+ {
+ return;
+ }
+ if (type == jsoncons::bson::bson_container_type::document)
+ {
+ auto result = unicode_traits::validate(text_buffer_.data(),text_buffer_.size());
+ if (JSONCONS_UNLIKELY(result.ec != unicode_traits::conv_errc()))
+ {
+ ec = bson_errc::invalid_utf8_text_string;
+ more_ = false;
+ return;
+ }
+ more_ = visitor.key(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), *this, ec);
+ }
+ }
+
+ void read_value(json_visitor& visitor, uint8_t type, std::error_code& ec)
+ {
+ switch (type)
+ {
+ case jsoncons::bson::bson_type::double_type:
+ {
+ uint8_t buf[sizeof(double)];
+ std::size_t n = source_.read(buf, sizeof(double));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(double)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ double res = binary::little_to_native<double>(buf, sizeof(buf));
+ more_ = visitor.double_value(res, semantic_tag::none, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::symbol_type:
+ case jsoncons::bson::bson_type::min_key_type:
+ case jsoncons::bson::bson_type::max_key_type:
+ case jsoncons::bson::bson_type::string_type:
+ {
+ text_buffer_.clear();
+ read_string(ec);
+ if (ec)
+ {
+ return;
+ }
+ auto result = unicode_traits::validate(text_buffer_.data(), text_buffer_.size());
+ if (JSONCONS_UNLIKELY(result.ec != unicode_traits::conv_errc()))
+ {
+ ec = bson_errc::invalid_utf8_text_string;
+ more_ = false;
+ return;
+ }
+ more_ = visitor.string_value(text_buffer_, semantic_tag::none, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::javascript_type:
+ {
+ text_buffer_.clear();
+ read_string(ec);
+ if (ec)
+ {
+ return;
+ }
+ auto result = unicode_traits::validate(text_buffer_.data(), text_buffer_.size());
+ if (JSONCONS_UNLIKELY(result.ec != unicode_traits::conv_errc()))
+ {
+ ec = bson_errc::invalid_utf8_text_string;
+ more_ = false;
+ return;
+ }
+ more_ = visitor.string_value(text_buffer_, semantic_tag::code, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::regex_type:
+ {
+ text_buffer_.clear();
+ text_buffer_.push_back('/');
+ read_cstring(ec);
+ if (ec)
+ {
+ return;
+ }
+ text_buffer_.push_back('/');
+ read_cstring(ec);
+ if (ec)
+ {
+ return;
+ }
+ more_ = visitor.string_value(text_buffer_, semantic_tag::regex, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::document_type:
+ {
+ begin_document(visitor,ec);
+ break;
+ }
+
+ case jsoncons::bson::bson_type::array_type:
+ {
+ begin_array(visitor,ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::undefined_type:
+ {
+ more_ = visitor.null_value(semantic_tag::undefined, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::null_type:
+ {
+ more_ = visitor.null_value(semantic_tag::none, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::bool_type:
+ {
+ uint8_t c;
+ std::size_t n = source_.read(&c, 1);
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != 1))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ more_ = visitor.bool_value(c != 0, semantic_tag::none, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::int32_type:
+ {
+ uint8_t buf[sizeof(int32_t)];
+ std::size_t n = source_.read(buf, sizeof(int32_t));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ auto val = binary::little_to_native<int32_t>(buf, sizeof(buf));
+ more_ = visitor.int64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::bson::bson_type::timestamp_type:
+ {
+ uint8_t buf[sizeof(uint64_t)];
+ std::size_t n = source_.read(buf, sizeof(uint64_t));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(uint64_t)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ auto val = binary::little_to_native<uint64_t>(buf, sizeof(buf));
+ more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::bson::bson_type::int64_type:
+ {
+ uint8_t buf[sizeof(int64_t)];
+ std::size_t n = source_.read(buf, sizeof(int64_t));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(int64_t)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ auto val = binary::little_to_native<int64_t>(buf, sizeof(buf));
+ more_ = visitor.int64_value(val, semantic_tag::none, *this, ec);
+ break;
+ }
+
+ case jsoncons::bson::bson_type::datetime_type:
+ {
+ uint8_t buf[sizeof(int64_t)];
+ std::size_t n = source_.read(buf, sizeof(int64_t));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(int64_t)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ auto val = binary::little_to_native<int64_t>(buf, sizeof(buf));
+ more_ = visitor.int64_value(val, semantic_tag::epoch_milli, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::binary_type:
+ {
+ uint8_t buf[sizeof(int32_t)];
+ std::size_t n = source_.read(buf, sizeof(int32_t));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ const auto len = binary::little_to_native<int32_t>(buf, sizeof(buf));
+ if (JSONCONS_UNLIKELY(len < 0))
+ {
+ ec = bson_errc::length_is_negative;
+ more_ = false;
+ return;
+ }
+ uint8_t subtype;
+ n = source_.read(&subtype, 1);
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != 1))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ bytes_buffer_.clear();
+ n = source_reader<Source>::read(source_, bytes_buffer_, len);
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != static_cast<std::size_t>(len)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ more_ = visitor.byte_string_value(bytes_buffer_,
+ subtype,
+ *this,
+ ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::decimal128_type:
+ {
+ uint8_t buf[sizeof(uint64_t)*2];
+ std::size_t n = source_.read(buf, sizeof(buf));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(buf)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ decimal128_t dec;
+ dec.low = binary::little_to_native<uint64_t>(buf, sizeof(uint64_t));
+ dec.high = binary::little_to_native<uint64_t>(buf+sizeof(uint64_t), sizeof(uint64_t));
+
+ text_buffer_.clear();
+ text_buffer_.resize(bson::decimal128_limits::buf_size);
+ auto r = bson::decimal128_to_chars(&text_buffer_[0], &text_buffer_[0]+text_buffer_.size(), dec);
+ more_ = visitor.string_value(string_view(text_buffer_.data(),static_cast<std::size_t>(r.ptr-text_buffer_.data())), semantic_tag::float128, *this, ec);
+ break;
+ }
+ case jsoncons::bson::bson_type::object_id_type:
+ {
+ uint8_t buf[12];
+ std::size_t n = source_.read(buf, sizeof(buf));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(buf)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+
+ oid_t oid(buf);
+ to_string(oid, text_buffer_);
+
+ more_ = visitor.string_value(text_buffer_, semantic_tag::id, *this, ec);
+ break;
+ }
+ default:
+ {
+ ec = bson_errc::unknown_type;
+ more_ = false;
+ return;
+ }
+ }
+ }
+
+ void read_cstring(std::error_code& ec)
+ {
+ uint8_t c = 0xff;
+ while (true)
+ {
+ std::size_t n = source_.read(&c, 1);
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != 1))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ if (c == 0)
+ {
+ break;
+ }
+ text_buffer_.push_back(c);
+ }
+ }
+
+ void read_string(std::error_code& ec)
+ {
+ uint8_t buf[sizeof(int32_t)];
+ std::size_t n = source_.read(buf, sizeof(int32_t));
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ auto len = binary::little_to_native<int32_t>(buf, sizeof(buf));
+ if (JSONCONS_UNLIKELY(len < 1))
+ {
+ ec = bson_errc::string_length_is_non_positive;
+ more_ = false;
+ return;
+ }
+
+ std::size_t size = static_cast<std::size_t>(len) - static_cast<std::size_t>(1);
+ n = source_reader<Source>::read(source_, text_buffer_, size);
+ state_stack_.back().pos += n;
+
+ if (JSONCONS_UNLIKELY(n != size))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ uint8_t c;
+ n = source_.read(&c, 1);
+ state_stack_.back().pos += n;
+ if (JSONCONS_UNLIKELY(n != 1))
+ {
+ ec = bson_errc::unexpected_eof;
+ more_ = false;
+ return;
+ }
+ }
+};
+
+}}
+
+#endif
diff --git a/include/jsoncons_ext/bson/bson_reader.hpp b/include/jsoncons_ext/bson/bson_reader.hpp
new file mode 100644
index 0000000..0079cc9
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_reader.hpp
@@ -0,0 +1,92 @@
+// 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_BSON_BSON_READER_HPP
+#define JSONCONS_BSON_BSON_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/bson/bson_type.hpp>
+#include <jsoncons_ext/bson/bson_error.hpp>
+#include <jsoncons_ext/bson/bson_parser.hpp>
+
+namespace jsoncons { namespace bson {
+
+template <class Source,class Allocator=std::allocator<char>>
+class basic_bson_reader
+{
+ basic_bson_parser<Source,Allocator> parser_;
+ json_visitor& visitor_;
+public:
+ template <class Sourceable>
+ basic_bson_reader(Sourceable&& source,
+ json_visitor& visitor,
+ const Allocator alloc)
+ : basic_bson_reader(std::forward<Sourceable>(source),
+ visitor,
+ bson_decode_options(),
+ alloc)
+ {
+ }
+
+ template <class Sourceable>
+ basic_bson_reader(Sourceable&& source,
+ json_visitor& visitor,
+ const bson_decode_options& options = bson_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 bson_stream_reader = basic_bson_reader<jsoncons::binary_stream_source>;
+using bson_bytes_reader = basic_bson_reader<jsoncons::bytes_source>;
+
+#if !defined(JSONCONS_NO_DEPRECATED)
+JSONCONS_DEPRECATED_MSG("Instead, use bson_stream_reader") typedef bson_stream_reader bson_reader;
+JSONCONS_DEPRECATED_MSG("Instead, use bson_bytes_reader") typedef bson_bytes_reader bson_buffer_reader;
+#endif
+
+}}
+
+#endif
diff --git a/include/jsoncons_ext/bson/bson_type.hpp b/include/jsoncons_ext/bson/bson_type.hpp
new file mode 100644
index 0000000..cf12344
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_type.hpp
@@ -0,0 +1,44 @@
+// 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_BSON_BSON_TYPE_HPP
+#define JSONCONS_BSON_BSON_TYPE_HPP
+
+#include <string>
+#include <memory>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+namespace jsoncons { namespace bson {
+
+ namespace bson_type
+ {
+ const uint8_t double_type = 0x01;
+ const uint8_t string_type = 0x02; // UTF-8 string
+ const uint8_t document_type = 0x03;
+ const uint8_t array_type = 0x04;
+ const uint8_t binary_type = 0x05;
+ const uint8_t undefined_type = 0x06; // map to null
+ const uint8_t object_id_type = 0x07;
+ const uint8_t bool_type = 0x08;
+ const uint8_t datetime_type = 0x09;
+ const uint8_t null_type = 0x0a;
+ const uint8_t regex_type = 0x0b;
+ const uint8_t javascript_type = 0x0d;
+ const uint8_t symbol_type = 0x0e; // deprecated, mapped to string
+ const uint8_t javascript_with_scope_type = 0x0f; // unsupported
+ const uint8_t int32_type = 0x10;
+ const uint8_t timestamp_type = 0x11; // MongoDB internal Timestamp, uint64
+ const uint8_t int64_type = 0x12;
+ const uint8_t decimal128_type = 0x13;
+ const uint8_t min_key_type = 0xff;
+ const uint8_t max_key_type = 0x7f;
+ }
+
+ enum class bson_container_type {document, array};
+
+}}
+
+#endif
diff --git a/include/jsoncons_ext/bson/decode_bson.hpp b/include/jsoncons_ext/bson/decode_bson.hpp
new file mode 100644
index 0000000..ad352f6
--- /dev/null
+++ b/include/jsoncons_ext/bson/decode_bson.hpp
@@ -0,0 +1,201 @@
+// 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_BSON_DECODE_BSON_HPP
+#define JSONCONS_BSON_DECODE_BSON_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/bson/bson_reader.hpp>
+#include <jsoncons_ext/bson/bson_cursor.hpp>
+
+namespace jsoncons {
+namespace bson {
+
+ 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_bson(const Source& v,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_bson_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_bson(const Source& v,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ basic_bson_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_bson(std::istream& is,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ bson_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_bson(std::istream& is,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ basic_bson_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_bson(InputIt first, InputIt last,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ jsoncons::json_decoder<T> decoder;
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_bson_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_bson(InputIt first, InputIt last,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ basic_bson_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_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const Source& v,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ json_decoder<T,TempAllocator> decoder(temp_alloc);
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_bson_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_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const Source& v,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ basic_bson_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_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ std::istream& is,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ json_decoder<T,TempAllocator> decoder(temp_alloc);
+ auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
+ basic_bson_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_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ std::istream& is,
+ const bson_decode_options& options = bson_decode_options())
+ {
+ basic_bson_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;
+ }
+
+} // bson
+} // jsoncons
+
+#endif
diff --git a/include/jsoncons_ext/bson/encode_bson.hpp b/include/jsoncons_ext/bson/encode_bson.hpp
new file mode 100644
index 0000000..55f8cf5
--- /dev/null
+++ b/include/jsoncons_ext/bson/encode_bson.hpp
@@ -0,0 +1,144 @@
+// 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_BSON_ENCODE_BSON_HPP
+#define JSONCONS_BSON_ENCODE_BSON_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/bson/bson_encoder.hpp>
+#include <jsoncons_ext/bson/bson_reader.hpp>
+
+namespace jsoncons {
+namespace bson {
+
+ 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_bson(const T& j,
+ Container& v,
+ const bson_encode_options& options = bson_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_bson_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_bson(const T& val,
+ Container& v,
+ const bson_encode_options& options = bson_encode_options())
+ {
+ basic_bson_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_bson(const T& j,
+ std::ostream& os,
+ const bson_encode_options& options = bson_encode_options())
+ {
+ using char_type = typename T::char_type;
+ bson_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_bson(const T& val,
+ std::ostream& os,
+ const bson_encode_options& options = bson_encode_options())
+ {
+ bson_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_rag
+
+ 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_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& j,
+ Container& v,
+ const bson_encode_options& options = bson_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_bson_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_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& val,
+ Container& v,
+ const bson_encode_options& options = bson_encode_options())
+ {
+ basic_bson_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_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& j,
+ std::ostream& os,
+ const bson_encode_options& options = bson_encode_options())
+ {
+ using char_type = typename T::char_type;
+ basic_bson_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_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
+ const T& val,
+ std::ostream& os,
+ const bson_encode_options& options = bson_encode_options())
+ {
+ basic_bson_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));
+ }
+ }
+
+} // bson
+} // jsoncons
+
+#endif