diff options
| author | Kelly Rauchenberger <fefferburbia@gmail.com> | 2016-12-28 20:41:38 -0500 |
|---|---|---|
| committer | Kelly Rauchenberger <fefferburbia@gmail.com> | 2016-12-28 20:41:38 -0500 |
| commit | 4af7e55733098ca42f75a4ffaca1b0f6bab4dd36 (patch) | |
| tree | 9ca8b51a4c374e8615652def59fa05ff3c7871e2 /vendor | |
| parent | 1f898f3bd66c29672275c2c884b17ba662ced626 (diff) | |
| download | verbly-4af7e55733098ca42f75a4ffaca1b0f6bab4dd36.tar.gz verbly-4af7e55733098ca42f75a4ffaca1b0f6bab4dd36.tar.bz2 verbly-4af7e55733098ca42f75a4ffaca1b0f6bab4dd36.zip | |
Updated to nlohmann/json 2.0.9
Diffstat (limited to 'vendor')
| -rw-r--r-- | vendor/json/json.hpp | 1989 |
1 files changed, 1698 insertions, 291 deletions
| diff --git a/vendor/json/json.hpp b/vendor/json/json.hpp index 4447412..23058be 100644 --- a/vendor/json/json.hpp +++ b/vendor/json/json.hpp | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | __ _____ _____ _____ | 2 | __ _____ _____ _____ |
| 3 | __| | __| | | | JSON for Modern C++ | 3 | __| | __| | | | JSON for Modern C++ |
| 4 | | | |__ | | | | | | version 2.0.7 | 4 | | | |__ | | | | | | version 2.0.9 |
| 5 | |_____|_____|_____|_|___| https://github.com/nlohmann/json | 5 | |_____|_____|_____|_|___| https://github.com/nlohmann/json |
| 6 | 6 | ||
| 7 | Licensed under the MIT License <http://opensource.org/licenses/MIT>. | 7 | Licensed under the MIT License <http://opensource.org/licenses/MIT>. |
| @@ -29,32 +29,32 @@ SOFTWARE. | |||
| 29 | #ifndef NLOHMANN_JSON_HPP | 29 | #ifndef NLOHMANN_JSON_HPP |
| 30 | #define NLOHMANN_JSON_HPP | 30 | #define NLOHMANN_JSON_HPP |
| 31 | 31 | ||
| 32 | #include <algorithm> | 32 | #include <algorithm> // all_of, for_each, transform |
| 33 | #include <array> | 33 | #include <array> // array |
| 34 | #include <cassert> | 34 | #include <cassert> // assert |
| 35 | #include <cctype> | 35 | #include <cctype> // isdigit |
| 36 | #include <ciso646> | 36 | #include <ciso646> // and, not, or |
| 37 | #include <cmath> | 37 | #include <cmath> // isfinite, ldexp, signbit |
| 38 | #include <cstddef> | 38 | #include <cstddef> // nullptr_t, ptrdiff_t, size_t |
| 39 | #include <cstdint> | 39 | #include <cstdint> // int64_t, uint64_t |
| 40 | #include <cstdlib> | 40 | #include <cstdlib> // strtod, strtof, strtold, strtoul |
| 41 | #include <cstring> | 41 | #include <cstring> // strlen |
| 42 | #include <functional> | 42 | #include <functional> // function, hash, less |
| 43 | #include <initializer_list> | 43 | #include <initializer_list> // initializer_list |
| 44 | #include <iomanip> | 44 | #include <iomanip> // setw |
| 45 | #include <iostream> | 45 | #include <iostream> // istream, ostream |
| 46 | #include <iterator> | 46 | #include <iterator> // advance, begin, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator |
| 47 | #include <limits> | 47 | #include <limits> // numeric_limits |
| 48 | #include <locale> | 48 | #include <locale> // locale |
| 49 | #include <map> | 49 | #include <map> // map |
| 50 | #include <memory> | 50 | #include <memory> // addressof, allocator, allocator_traits, unique_ptr |
| 51 | #include <numeric> | 51 | #include <numeric> // accumulate |
| 52 | #include <sstream> | 52 | #include <sstream> // stringstream |
| 53 | #include <stdexcept> | 53 | #include <stdexcept> // domain_error, invalid_argument, out_of_range |
| 54 | #include <string> | 54 | #include <string> // getline, stoi, string, to_string |
| 55 | #include <type_traits> | 55 | #include <type_traits> // add_pointer, enable_if, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_floating_point, is_integral, is_nothrow_move_assignable, std::is_nothrow_move_constructible, std::is_pointer, std::is_reference, std::is_same, remove_const, remove_pointer, remove_reference |
| 56 | #include <utility> | 56 | #include <utility> // declval, forward, make_pair, move, pair, swap |
| 57 | #include <vector> | 57 | #include <vector> // vector |
| 58 | 58 | ||
| 59 | // exclude unsupported compilers | 59 | // exclude unsupported compilers |
| 60 | #if defined(__clang__) | 60 | #if defined(__clang__) |
| @@ -75,6 +75,12 @@ SOFTWARE. | |||
| 75 | #pragma GCC diagnostic ignored "-Wfloat-equal" | 75 | #pragma GCC diagnostic ignored "-Wfloat-equal" |
| 76 | #endif | 76 | #endif |
| 77 | 77 | ||
| 78 | // disable documentation warnings on clang | ||
| 79 | #if defined(__clang__) | ||
| 80 | #pragma GCC diagnostic push | ||
| 81 | #pragma GCC diagnostic ignored "-Wdocumentation" | ||
| 82 | #endif | ||
| 83 | |||
| 78 | // allow for portable deprecation warnings | 84 | // allow for portable deprecation warnings |
| 79 | #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) | 85 | #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) |
| 80 | #define JSON_DEPRECATED __attribute__((deprecated)) | 86 | #define JSON_DEPRECATED __attribute__((deprecated)) |
| @@ -122,26 +128,6 @@ struct has_mapped_type | |||
| 122 | std::is_integral<decltype(detect(std::declval<T>()))>::value; | 128 | std::is_integral<decltype(detect(std::declval<T>()))>::value; |
| 123 | }; | 129 | }; |
| 124 | 130 | ||
| 125 | /*! | ||
| 126 | @brief helper class to create locales with decimal point | ||
| 127 | |||
| 128 | This struct is used a default locale during the JSON serialization. JSON | ||
| 129 | requires the decimal point to be `.`, so this function overloads the | ||
| 130 | `do_decimal_point()` function to return `.`. This function is called by | ||
| 131 | float-to-string conversions to retrieve the decimal separator between integer | ||
| 132 | and fractional parts. | ||
| 133 | |||
| 134 | @sa https://github.com/nlohmann/json/issues/51#issuecomment-86869315 | ||
| 135 | @since version 2.0.0 | ||
| 136 | */ | ||
| 137 | struct DecimalSeparator : std::numpunct<char> | ||
| 138 | { | ||
| 139 | char do_decimal_point() const | ||
| 140 | { | ||
| 141 | return '.'; | ||
| 142 | } | ||
| 143 | }; | ||
| 144 | |||
| 145 | } | 131 | } |
| 146 | 132 | ||
| 147 | /*! | 133 | /*! |
| @@ -242,6 +228,7 @@ class basic_json | |||
| 242 | 228 | ||
| 243 | public: | 229 | public: |
| 244 | // forward declarations | 230 | // forward declarations |
| 231 | template<typename U> class iter_impl; | ||
| 245 | template<typename Base> class json_reverse_iterator; | 232 | template<typename Base> class json_reverse_iterator; |
| 246 | class json_pointer; | 233 | class json_pointer; |
| 247 | 234 | ||
| @@ -276,9 +263,9 @@ class basic_json | |||
| 276 | using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; | 263 | using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; |
| 277 | 264 | ||
| 278 | /// an iterator for a basic_json container | 265 | /// an iterator for a basic_json container |
| 279 | class iterator; | 266 | using iterator = iter_impl<basic_json>; |
| 280 | /// a const iterator for a basic_json container | 267 | /// a const iterator for a basic_json container |
| 281 | class const_iterator; | 268 | using const_iterator = iter_impl<const basic_json>; |
| 282 | /// a reverse iterator for a basic_json container | 269 | /// a reverse iterator for a basic_json container |
| 283 | using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>; | 270 | using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>; |
| 284 | /// a const reverse iterator for a basic_json container | 271 | /// a const reverse iterator for a basic_json container |
| @@ -964,7 +951,7 @@ class basic_json | |||
| 964 | 951 | ||
| 965 | With a parser callback function, the result of parsing a JSON text can be | 952 | With a parser callback function, the result of parsing a JSON text can be |
| 966 | influenced. When passed to @ref parse(std::istream&, const | 953 | influenced. When passed to @ref parse(std::istream&, const |
| 967 | parser_callback_t) or @ref parse(const char*, const parser_callback_t), | 954 | parser_callback_t) or @ref parse(const CharT, const parser_callback_t), |
| 968 | it is called on certain events (passed as @ref parse_event_t via parameter | 955 | it is called on certain events (passed as @ref parse_event_t via parameter |
| 969 | @a event) with a set recursion depth @a depth and context JSON value | 956 | @a event) with a set recursion depth @a depth and context JSON value |
| 970 | @a parsed. The return value of the callback function is a boolean | 957 | @a parsed. The return value of the callback function is a boolean |
| @@ -1007,7 +994,7 @@ class basic_json | |||
| 1007 | skipped completely or replaced by an empty discarded object. | 994 | skipped completely or replaced by an empty discarded object. |
| 1008 | 995 | ||
| 1009 | @sa @ref parse(std::istream&, parser_callback_t) or | 996 | @sa @ref parse(std::istream&, parser_callback_t) or |
| 1010 | @ref parse(const char*, parser_callback_t) for examples | 997 | @ref parse(const CharT, const parser_callback_t) for examples |
| 1011 | 998 | ||
| 1012 | @since version 1.0.0 | 999 | @since version 1.0.0 |
| 1013 | */ | 1000 | */ |
| @@ -2201,8 +2188,7 @@ class basic_json | |||
| 2201 | { | 2188 | { |
| 2202 | std::stringstream ss; | 2189 | std::stringstream ss; |
| 2203 | // fix locale problems | 2190 | // fix locale problems |
| 2204 | const static std::locale loc(std::locale(), new DecimalSeparator); | 2191 | ss.imbue(std::locale::classic()); |
| 2205 | ss.imbue(loc); | ||
| 2206 | 2192 | ||
| 2207 | // 6, 15 or 16 digits of precision allows round-trip IEEE 754 | 2193 | // 6, 15 or 16 digits of precision allows round-trip IEEE 754 |
| 2208 | // string->float->string, string->double->string or string->long | 2194 | // string->float->string, string->double->string or string->long |
| @@ -5054,6 +5040,102 @@ class basic_json | |||
| 5054 | } | 5040 | } |
| 5055 | 5041 | ||
| 5056 | /*! | 5042 | /*! |
| 5043 | @brief add an object to an array | ||
| 5044 | |||
| 5045 | Creates a JSON value from the passed parameters @a args to the end of the | ||
| 5046 | JSON value. If the function is called on a JSON null value, an empty array | ||
| 5047 | is created before appending the value created from @a args. | ||
| 5048 | |||
| 5049 | @param[in] args arguments to forward to a constructor of @ref basic_json | ||
| 5050 | @tparam Args compatible types to create a @ref basic_json object | ||
| 5051 | |||
| 5052 | @throw std::domain_error when called on a type other than JSON array or | ||
| 5053 | null; example: `"cannot use emplace_back() with number"` | ||
| 5054 | |||
| 5055 | @complexity Amortized constant. | ||
| 5056 | |||
| 5057 | @liveexample{The example shows how `push_back()` can be used to add | ||
| 5058 | elements to a JSON array. Note how the `null` value was silently converted | ||
| 5059 | to a JSON array.,emplace_back} | ||
| 5060 | |||
| 5061 | @since version 2.0.8 | ||
| 5062 | */ | ||
| 5063 | template<class... Args> | ||
| 5064 | void emplace_back(Args&& ... args) | ||
| 5065 | { | ||
| 5066 | // emplace_back only works for null objects or arrays | ||
| 5067 | if (not(is_null() or is_array())) | ||
| 5068 | { | ||
| 5069 | throw std::domain_error("cannot use emplace_back() with " + type_name()); | ||
| 5070 | } | ||
| 5071 | |||
| 5072 | // transform null object into an array | ||
| 5073 | if (is_null()) | ||
| 5074 | { | ||
| 5075 | m_type = value_t::array; | ||
| 5076 | m_value = value_t::array; | ||
| 5077 | assert_invariant(); | ||
| 5078 | } | ||
| 5079 | |||
| 5080 | // add element to array (perfect forwarding) | ||
| 5081 | m_value.array->emplace_back(std::forward<Args>(args)...); | ||
| 5082 | } | ||
| 5083 | |||
| 5084 | /*! | ||
| 5085 | @brief add an object to an object if key does not exist | ||
| 5086 | |||
| 5087 | Inserts a new element into a JSON object constructed in-place with the given | ||
| 5088 | @a args if there is no element with the key in the container. If the | ||
| 5089 | function is called on a JSON null value, an empty object is created before | ||
| 5090 | appending the value created from @a args. | ||
| 5091 | |||
| 5092 | @param[in] args arguments to forward to a constructor of @ref basic_json | ||
| 5093 | @tparam Args compatible types to create a @ref basic_json object | ||
| 5094 | |||
| 5095 | @return a pair consisting of an iterator to the inserted element, or the | ||
| 5096 | already-existing element if no insertion happened, and a bool | ||
| 5097 | denoting whether the insertion took place. | ||
| 5098 | |||
| 5099 | @throw std::domain_error when called on a type other than JSON object or | ||
| 5100 | null; example: `"cannot use emplace() with number"` | ||
| 5101 | |||
| 5102 | @complexity Logarithmic in the size of the container, O(log(`size()`)). | ||
| 5103 | |||
| 5104 | @liveexample{The example shows how `emplace()` can be used to add elements | ||
| 5105 | to a JSON object. Note how the `null` value was silently converted to a | ||
| 5106 | JSON object. Further note how no value is added if there was already one | ||
| 5107 | value stored with the same key.,emplace} | ||
| 5108 | |||
| 5109 | @since version 2.0.8 | ||
| 5110 | */ | ||
| 5111 | template<class... Args> | ||
| 5112 | std::pair<iterator, bool> emplace(Args&& ... args) | ||
| 5113 | { | ||
| 5114 | // emplace only works for null objects or arrays | ||
| 5115 | if (not(is_null() or is_object())) | ||
| 5116 | { | ||
| 5117 | throw std::domain_error("cannot use emplace() with " + type_name()); | ||
| 5118 | } | ||
| 5119 | |||
| 5120 | // transform null object into an object | ||
| 5121 | if (is_null()) | ||
| 5122 | { | ||
| 5123 | m_type = value_t::object; | ||
| 5124 | m_value = value_t::object; | ||
| 5125 | assert_invariant(); | ||
| 5126 | } | ||
| 5127 | |||
| 5128 | // add element to array (perfect forwarding) | ||
| 5129 | auto res = m_value.object->emplace(std::forward<Args>(args)...); | ||
| 5130 | // create result iterator and set iterator to the result of emplace | ||
| 5131 | auto it = begin(); | ||
| 5132 | it.m_it.object_iterator = res.first; | ||
| 5133 | |||
| 5134 | // return pair of iterator and boolean | ||
| 5135 | return {it, res.second}; | ||
| 5136 | } | ||
| 5137 | |||
| 5138 | /*! | ||
| 5057 | @brief inserts element | 5139 | @brief inserts element |
| 5058 | 5140 | ||
| 5059 | Inserts element @a val before iterator @a pos. | 5141 | Inserts element @a val before iterator @a pos. |
| @@ -5829,7 +5911,7 @@ class basic_json | |||
| 5829 | o.width(0); | 5911 | o.width(0); |
| 5830 | 5912 | ||
| 5831 | // fix locale problems | 5913 | // fix locale problems |
| 5832 | const auto old_locale = o.imbue(std::locale(std::locale(), new DecimalSeparator)); | 5914 | const auto old_locale = o.imbue(std::locale::classic()); |
| 5833 | // set precision | 5915 | // set precision |
| 5834 | 5916 | ||
| 5835 | // 6, 15 or 16 digits of precision allows round-trip IEEE 754 | 5917 | // 6, 15 or 16 digits of precision allows round-trip IEEE 754 |
| @@ -5928,11 +6010,11 @@ class basic_json | |||
| 5928 | 6010 | ||
| 5929 | @since version 1.0.0 (originally for @ref string_t) | 6011 | @since version 1.0.0 (originally for @ref string_t) |
| 5930 | */ | 6012 | */ |
| 5931 | template<typename CharPT, typename std::enable_if< | 6013 | template<typename CharT, typename std::enable_if< |
| 5932 | std::is_pointer<CharPT>::value and | 6014 | std::is_pointer<CharT>::value and |
| 5933 | std::is_integral<typename std::remove_pointer<CharPT>::type>::value and | 6015 | std::is_integral<typename std::remove_pointer<CharT>::type>::value and |
| 5934 | sizeof(typename std::remove_pointer<CharPT>::type) == 1, int>::type = 0> | 6016 | sizeof(typename std::remove_pointer<CharT>::type) == 1, int>::type = 0> |
| 5935 | static basic_json parse(const CharPT s, | 6017 | static basic_json parse(const CharT s, |
| 5936 | const parser_callback_t cb = nullptr) | 6018 | const parser_callback_t cb = nullptr) |
| 5937 | { | 6019 | { |
| 5938 | return parser(reinterpret_cast<const char*>(s), cb).parse(); | 6020 | return parser(reinterpret_cast<const char*>(s), cb).parse(); |
| @@ -5957,7 +6039,7 @@ class basic_json | |||
| 5957 | @liveexample{The example below demonstrates the `parse()` function with | 6039 | @liveexample{The example below demonstrates the `parse()` function with |
| 5958 | and without callback function.,parse__istream__parser_callback_t} | 6040 | and without callback function.,parse__istream__parser_callback_t} |
| 5959 | 6041 | ||
| 5960 | @sa @ref parse(const char*, const parser_callback_t) for a version | 6042 | @sa @ref parse(const CharT, const parser_callback_t) for a version |
| 5961 | that reads from a string | 6043 | that reads from a string |
| 5962 | 6044 | ||
| 5963 | @since version 1.0.0 | 6045 | @since version 1.0.0 |
| @@ -6142,6 +6224,1435 @@ class basic_json | |||
| 6142 | 6224 | ||
| 6143 | /// @} | 6225 | /// @} |
| 6144 | 6226 | ||
| 6227 | ////////////////////////////////////////// | ||
| 6228 | // binary serialization/deserialization // | ||
| 6229 | ////////////////////////////////////////// | ||
| 6230 | |||
| 6231 | /// @name binary serialization/deserialization support | ||
| 6232 | /// @{ | ||
| 6233 | |||
| 6234 | private: | ||
| 6235 | template<typename T> | ||
| 6236 | static void add_to_vector(std::vector<uint8_t>& vec, size_t bytes, const T number) | ||
| 6237 | { | ||
| 6238 | assert(bytes == 1 or bytes == 2 or bytes == 4 or bytes == 8); | ||
| 6239 | |||
| 6240 | switch (bytes) | ||
| 6241 | { | ||
| 6242 | case 8: | ||
| 6243 | { | ||
| 6244 | vec.push_back(static_cast<uint8_t>((number >> 070) & 0xff)); | ||
| 6245 | vec.push_back(static_cast<uint8_t>((number >> 060) & 0xff)); | ||
| 6246 | vec.push_back(static_cast<uint8_t>((number >> 050) & 0xff)); | ||
| 6247 | vec.push_back(static_cast<uint8_t>((number >> 040) & 0xff)); | ||
| 6248 | // intentional fall-through | ||
| 6249 | } | ||
| 6250 | |||
| 6251 | case 4: | ||
| 6252 | { | ||
| 6253 | vec.push_back(static_cast<uint8_t>((number >> 030) & 0xff)); | ||
| 6254 | vec.push_back(static_cast<uint8_t>((number >> 020) & 0xff)); | ||
| 6255 | // intentional fall-through | ||
| 6256 | } | ||
| 6257 | |||
| 6258 | case 2: | ||
| 6259 | { | ||
| 6260 | vec.push_back(static_cast<uint8_t>((number >> 010) & 0xff)); | ||
| 6261 | // intentional fall-through | ||
| 6262 | } | ||
| 6263 | |||
| 6264 | case 1: | ||
| 6265 | { | ||
| 6266 | vec.push_back(static_cast<uint8_t>(number & 0xff)); | ||
| 6267 | break; | ||
| 6268 | } | ||
| 6269 | } | ||
| 6270 | } | ||
| 6271 | |||
| 6272 | /*! | ||
| 6273 | @brief take sufficient bytes from a vector to fill an integer variable | ||
| 6274 | |||
| 6275 | In the context of binary serialization formats, we need to read several | ||
| 6276 | bytes from a byte vector and combine them to multi-byte integral data | ||
| 6277 | types. | ||
| 6278 | |||
| 6279 | @param[in] vec byte vector to read from | ||
| 6280 | @param[in] current_index the position in the vector after which to read | ||
| 6281 | |||
| 6282 | @return the next sizeof(T) bytes from @a vec, in reverse order as T | ||
| 6283 | |||
| 6284 | @tparam T the integral return type | ||
| 6285 | |||
| 6286 | @throw std::out_of_range if there are less than sizeof(T)+1 bytes in the | ||
| 6287 | vector @a vec to read | ||
| 6288 | |||
| 6289 | In the for loop, the bytes from the vector are copied in reverse order into | ||
| 6290 | the return value. In the figures below, let sizeof(T)=4 and `i` be the loop | ||
| 6291 | variable. | ||
| 6292 | |||
| 6293 | Precondition: | ||
| 6294 | |||
| 6295 | vec: | | | a | b | c | d | T: | | | | | | ||
| 6296 | ^ ^ ^ ^ | ||
| 6297 | current_index i ptr sizeof(T) | ||
| 6298 | |||
| 6299 | Postcondition: | ||
| 6300 | |||
| 6301 | vec: | | | a | b | c | d | T: | d | c | b | a | | ||
| 6302 | ^ ^ ^ | ||
| 6303 | | i ptr | ||
| 6304 | current_index | ||
| 6305 | |||
| 6306 | @sa Code adapted from <http://stackoverflow.com/a/41031865/266378>. | ||
| 6307 | */ | ||
| 6308 | template<typename T> | ||
| 6309 | static T get_from_vector(const std::vector<uint8_t>& vec, const size_t current_index) | ||
| 6310 | { | ||
| 6311 | if (current_index + sizeof(T) + 1 > vec.size()) | ||
| 6312 | { | ||
| 6313 | throw std::out_of_range("cannot read " + std::to_string(sizeof(T)) + " bytes from vector"); | ||
| 6314 | } | ||
| 6315 | |||
| 6316 | T result; | ||
| 6317 | uint8_t* ptr = reinterpret_cast<uint8_t*>(&result); | ||
| 6318 | for (size_t i = 0; i < sizeof(T); ++i) | ||
| 6319 | { | ||
| 6320 | *ptr++ = vec[current_index + sizeof(T) - i]; | ||
| 6321 | } | ||
| 6322 | return result; | ||
| 6323 | } | ||
| 6324 | |||
| 6325 | /*! | ||
| 6326 | @brief create a MessagePack serialization of a given JSON value | ||
| 6327 | |||
| 6328 | This is a straightforward implementation of the MessagePack specification. | ||
| 6329 | |||
| 6330 | @param[in] j JSON value to serialize | ||
| 6331 | @param[in,out] v byte vector to write the serialization to | ||
| 6332 | |||
| 6333 | @sa https://github.com/msgpack/msgpack/blob/master/spec.md | ||
| 6334 | */ | ||
| 6335 | static void to_msgpack_internal(const basic_json& j, std::vector<uint8_t>& v) | ||
| 6336 | { | ||
| 6337 | switch (j.type()) | ||
| 6338 | { | ||
| 6339 | case value_t::null: | ||
| 6340 | { | ||
| 6341 | // nil | ||
| 6342 | v.push_back(0xc0); | ||
| 6343 | break; | ||
| 6344 | } | ||
| 6345 | |||
| 6346 | case value_t::boolean: | ||
| 6347 | { | ||
| 6348 | // true and false | ||
| 6349 | v.push_back(j.m_value.boolean ? 0xc3 : 0xc2); | ||
| 6350 | break; | ||
| 6351 | } | ||
| 6352 | |||
| 6353 | case value_t::number_integer: | ||
| 6354 | { | ||
| 6355 | if (j.m_value.number_integer >= 0) | ||
| 6356 | { | ||
| 6357 | // MessagePack does not differentiate between positive | ||
| 6358 | // signed integers and unsigned integers. Therefore, we used | ||
| 6359 | // the code from the value_t::number_unsigned case here. | ||
| 6360 | if (j.m_value.number_unsigned < 128) | ||
| 6361 | { | ||
| 6362 | // positive fixnum | ||
| 6363 | add_to_vector(v, 1, j.m_value.number_unsigned); | ||
| 6364 | } | ||
| 6365 | else if (j.m_value.number_unsigned <= UINT8_MAX) | ||
| 6366 | { | ||
| 6367 | // uint 8 | ||
| 6368 | v.push_back(0xcc); | ||
| 6369 | add_to_vector(v, 1, j.m_value.number_unsigned); | ||
| 6370 | } | ||
| 6371 | else if (j.m_value.number_unsigned <= UINT16_MAX) | ||
| 6372 | { | ||
| 6373 | // uint 16 | ||
| 6374 | v.push_back(0xcd); | ||
| 6375 | add_to_vector(v, 2, j.m_value.number_unsigned); | ||
| 6376 | } | ||
| 6377 | else if (j.m_value.number_unsigned <= UINT32_MAX) | ||
| 6378 | { | ||
| 6379 | // uint 32 | ||
| 6380 | v.push_back(0xce); | ||
| 6381 | add_to_vector(v, 4, j.m_value.number_unsigned); | ||
| 6382 | } | ||
| 6383 | else if (j.m_value.number_unsigned <= UINT64_MAX) | ||
| 6384 | { | ||
| 6385 | // uint 64 | ||
| 6386 | v.push_back(0xcf); | ||
| 6387 | add_to_vector(v, 8, j.m_value.number_unsigned); | ||
| 6388 | } | ||
| 6389 | } | ||
| 6390 | else | ||
| 6391 | { | ||
| 6392 | if (j.m_value.number_integer >= -32) | ||
| 6393 | { | ||
| 6394 | // negative fixnum | ||
| 6395 | add_to_vector(v, 1, j.m_value.number_integer); | ||
| 6396 | } | ||
| 6397 | else if (j.m_value.number_integer >= INT8_MIN and j.m_value.number_integer <= INT8_MAX) | ||
| 6398 | { | ||
| 6399 | // int 8 | ||
| 6400 | v.push_back(0xd0); | ||
| 6401 | add_to_vector(v, 1, j.m_value.number_integer); | ||
| 6402 | } | ||
| 6403 | else if (j.m_value.number_integer >= INT16_MIN and j.m_value.number_integer <= INT16_MAX) | ||
| 6404 | { | ||
| 6405 | // int 16 | ||
| 6406 | v.push_back(0xd1); | ||
| 6407 | add_to_vector(v, 2, j.m_value.number_integer); | ||
| 6408 | } | ||
| 6409 | else if (j.m_value.number_integer >= INT32_MIN and j.m_value.number_integer <= INT32_MAX) | ||
| 6410 | { | ||
| 6411 | // int 32 | ||
| 6412 | v.push_back(0xd2); | ||
| 6413 | add_to_vector(v, 4, j.m_value.number_integer); | ||
| 6414 | } | ||
| 6415 | else if (j.m_value.number_integer >= INT64_MIN and j.m_value.number_integer <= INT64_MAX) | ||
| 6416 | { | ||
| 6417 | // int 64 | ||
| 6418 | v.push_back(0xd3); | ||
| 6419 | add_to_vector(v, 8, j.m_value.number_integer); | ||
| 6420 | } | ||
| 6421 | } | ||
| 6422 | break; | ||
| 6423 | } | ||
| 6424 | |||
| 6425 | case value_t::number_unsigned: | ||
| 6426 | { | ||
| 6427 | if (j.m_value.number_unsigned < 128) | ||
| 6428 | { | ||
| 6429 | // positive fixnum | ||
| 6430 | add_to_vector(v, 1, j.m_value.number_unsigned); | ||
| 6431 | } | ||
| 6432 | else if (j.m_value.number_unsigned <= UINT8_MAX) | ||
| 6433 | { | ||
| 6434 | // uint 8 | ||
| 6435 | v.push_back(0xcc); | ||
| 6436 | add_to_vector(v, 1, j.m_value.number_unsigned); | ||
| 6437 | } | ||
| 6438 | else if (j.m_value.number_unsigned <= UINT16_MAX) | ||
| 6439 | { | ||
| 6440 | // uint 16 | ||
| 6441 | v.push_back(0xcd); | ||
| 6442 | add_to_vector(v, 2, j.m_value.number_unsigned); | ||
| 6443 | } | ||
| 6444 | else if (j.m_value.number_unsigned <= UINT32_MAX) | ||
| 6445 | { | ||
| 6446 | // uint 32 | ||
| 6447 | v.push_back(0xce); | ||
| 6448 | add_to_vector(v, 4, j.m_value.number_unsigned); | ||
| 6449 | } | ||
| 6450 | else if (j.m_value.number_unsigned <= UINT64_MAX) | ||
| 6451 | { | ||
| 6452 | // uint 64 | ||
| 6453 | v.push_back(0xcf); | ||
| 6454 | add_to_vector(v, 8, j.m_value.number_unsigned); | ||
| 6455 | } | ||
| 6456 | break; | ||
| 6457 | } | ||
| 6458 | |||
| 6459 | case value_t::number_float: | ||
| 6460 | { | ||
| 6461 | // float 64 | ||
| 6462 | v.push_back(0xcb); | ||
| 6463 | const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float)); | ||
| 6464 | for (size_t i = 0; i < 8; ++i) | ||
| 6465 | { | ||
| 6466 | v.push_back(helper[7 - i]); | ||
| 6467 | } | ||
| 6468 | break; | ||
| 6469 | } | ||
| 6470 | |||
| 6471 | case value_t::string: | ||
| 6472 | { | ||
| 6473 | const auto N = j.m_value.string->size(); | ||
| 6474 | if (N <= 31) | ||
| 6475 | { | ||
| 6476 | // fixstr | ||
| 6477 | v.push_back(static_cast<uint8_t>(0xa0 | N)); | ||
| 6478 | } | ||
| 6479 | else if (N <= 255) | ||
| 6480 | { | ||
| 6481 | // str 8 | ||
| 6482 | v.push_back(0xd9); | ||
| 6483 | add_to_vector(v, 1, N); | ||
| 6484 | } | ||
| 6485 | else if (N <= 65535) | ||
| 6486 | { | ||
| 6487 | // str 16 | ||
| 6488 | v.push_back(0xda); | ||
| 6489 | add_to_vector(v, 2, N); | ||
| 6490 | } | ||
| 6491 | else if (N <= 4294967295) | ||
| 6492 | { | ||
| 6493 | // str 32 | ||
| 6494 | v.push_back(0xdb); | ||
| 6495 | add_to_vector(v, 4, N); | ||
| 6496 | } | ||
| 6497 | |||
| 6498 | // append string | ||
| 6499 | std::copy(j.m_value.string->begin(), j.m_value.string->end(), | ||
| 6500 | std::back_inserter(v)); | ||
| 6501 | break; | ||
| 6502 | } | ||
| 6503 | |||
| 6504 | case value_t::array: | ||
| 6505 | { | ||
| 6506 | const auto N = j.m_value.array->size(); | ||
| 6507 | if (N <= 15) | ||
| 6508 | { | ||
| 6509 | // fixarray | ||
| 6510 | v.push_back(static_cast<uint8_t>(0x90 | N)); | ||
| 6511 | } | ||
| 6512 | else if (N <= 0xffff) | ||
| 6513 | { | ||
| 6514 | // array 16 | ||
| 6515 | v.push_back(0xdc); | ||
| 6516 | add_to_vector(v, 2, N); | ||
| 6517 | } | ||
| 6518 | else if (N <= 0xffffffff) | ||
| 6519 | { | ||
| 6520 | // array 32 | ||
| 6521 | v.push_back(0xdd); | ||
| 6522 | add_to_vector(v, 4, N); | ||
| 6523 | } | ||
| 6524 | |||
| 6525 | // append each element | ||
| 6526 | for (const auto& el : *j.m_value.array) | ||
| 6527 | { | ||
| 6528 | to_msgpack_internal(el, v); | ||
| 6529 | } | ||
| 6530 | break; | ||
| 6531 | } | ||
| 6532 | |||
| 6533 | case value_t::object: | ||
| 6534 | { | ||
| 6535 | const auto N = j.m_value.object->size(); | ||
| 6536 | if (N <= 15) | ||
| 6537 | { | ||
| 6538 | // fixmap | ||
| 6539 | v.push_back(static_cast<uint8_t>(0x80 | (N & 0xf))); | ||
| 6540 | } | ||
| 6541 | else if (N <= 65535) | ||
| 6542 | { | ||
| 6543 | // map 16 | ||
| 6544 | v.push_back(0xde); | ||
| 6545 | add_to_vector(v, 2, N); | ||
| 6546 | } | ||
| 6547 | else if (N <= 4294967295) | ||
| 6548 | { | ||
| 6549 | // map 32 | ||
| 6550 | v.push_back(0xdf); | ||
| 6551 | add_to_vector(v, 4, N); | ||
| 6552 | } | ||
| 6553 | |||
| 6554 | // append each element | ||
| 6555 | for (const auto& el : *j.m_value.object) | ||
| 6556 | { | ||
| 6557 | to_msgpack_internal(el.first, v); | ||
| 6558 | to_msgpack_internal(el.second, v); | ||
| 6559 | } | ||
| 6560 | break; | ||
| 6561 | } | ||
| 6562 | |||
| 6563 | default: | ||
| 6564 | { | ||
| 6565 | break; | ||
| 6566 | } | ||
| 6567 | } | ||
| 6568 | } | ||
| 6569 | |||
| 6570 | /*! | ||
| 6571 | @brief create a CBOR serialization of a given JSON value | ||
| 6572 | |||
| 6573 | This is a straightforward implementation of the CBOR specification. | ||
| 6574 | |||
| 6575 | @param[in] j JSON value to serialize | ||
| 6576 | @param[in,out] v byte vector to write the serialization to | ||
| 6577 | |||
| 6578 | @sa https://tools.ietf.org/html/rfc7049 | ||
| 6579 | */ | ||
| 6580 | static void to_cbor_internal(const basic_json& j, std::vector<uint8_t>& v) | ||
| 6581 | { | ||
| 6582 | switch (j.type()) | ||
| 6583 | { | ||
| 6584 | case value_t::null: | ||
| 6585 | { | ||
| 6586 | v.push_back(0xf6); | ||
| 6587 | break; | ||
| 6588 | } | ||
| 6589 | |||
| 6590 | case value_t::boolean: | ||
| 6591 | { | ||
| 6592 | v.push_back(j.m_value.boolean ? 0xf5 : 0xf4); | ||
| 6593 | break; | ||
| 6594 | } | ||
| 6595 | |||
| 6596 | case value_t::number_integer: | ||
| 6597 | { | ||
| 6598 | if (j.m_value.number_integer >= 0) | ||
| 6599 | { | ||
| 6600 | // CBOR does not differentiate between positive signed | ||
| 6601 | // integers and unsigned integers. Therefore, we used the | ||
| 6602 | // code from the value_t::number_unsigned case here. | ||
| 6603 | if (j.m_value.number_integer <= 0x17) | ||
| 6604 | { | ||
| 6605 | add_to_vector(v, 1, j.m_value.number_integer); | ||
| 6606 | } | ||
| 6607 | else if (j.m_value.number_integer <= UINT8_MAX) | ||
| 6608 | { | ||
| 6609 | v.push_back(0x18); | ||
| 6610 | // one-byte uint8_t | ||
| 6611 | add_to_vector(v, 1, j.m_value.number_integer); | ||
| 6612 | } | ||
| 6613 | else if (j.m_value.number_integer <= UINT16_MAX) | ||
| 6614 | { | ||
| 6615 | v.push_back(0x19); | ||
| 6616 | // two-byte uint16_t | ||
| 6617 | add_to_vector(v, 2, j.m_value.number_integer); | ||
| 6618 | } | ||
| 6619 | else if (j.m_value.number_integer <= UINT32_MAX) | ||
| 6620 | { | ||
| 6621 | v.push_back(0x1a); | ||
| 6622 | // four-byte uint32_t | ||
| 6623 | add_to_vector(v, 4, j.m_value.number_integer); | ||
| 6624 | } | ||
| 6625 | else | ||
| 6626 | { | ||
| 6627 | v.push_back(0x1b); | ||
| 6628 | // eight-byte uint64_t | ||
| 6629 | add_to_vector(v, 8, j.m_value.number_integer); | ||
| 6630 | } | ||
| 6631 | } | ||
| 6632 | else | ||
| 6633 | { | ||
| 6634 | // The conversions below encode the sign in the first byte, | ||
| 6635 | // and the value is converted to a positive number. | ||
| 6636 | const auto positive_number = -1 - j.m_value.number_integer; | ||
| 6637 | if (j.m_value.number_integer >= -24) | ||
| 6638 | { | ||
| 6639 | v.push_back(static_cast<uint8_t>(0x20 + positive_number)); | ||
| 6640 | } | ||
| 6641 | else if (positive_number <= UINT8_MAX) | ||
| 6642 | { | ||
| 6643 | // int 8 | ||
| 6644 | v.push_back(0x38); | ||
| 6645 | add_to_vector(v, 1, positive_number); | ||
| 6646 | } | ||
| 6647 | else if (positive_number <= UINT16_MAX) | ||
| 6648 | { | ||
| 6649 | // int 16 | ||
| 6650 | v.push_back(0x39); | ||
| 6651 | add_to_vector(v, 2, positive_number); | ||
| 6652 | } | ||
| 6653 | else if (positive_number <= UINT32_MAX) | ||
| 6654 | { | ||
| 6655 | // int 32 | ||
| 6656 | v.push_back(0x3a); | ||
| 6657 | add_to_vector(v, 4, positive_number); | ||
| 6658 | } | ||
| 6659 | else | ||
| 6660 | { | ||
| 6661 | // int 64 | ||
| 6662 | v.push_back(0x3b); | ||
| 6663 | add_to_vector(v, 8, positive_number); | ||
| 6664 | } | ||
| 6665 | } | ||
| 6666 | break; | ||
| 6667 | } | ||
| 6668 | |||
| 6669 | case value_t::number_unsigned: | ||
| 6670 | { | ||
| 6671 | if (j.m_value.number_unsigned <= 0x17) | ||
| 6672 | { | ||
| 6673 | v.push_back(static_cast<uint8_t>(j.m_value.number_unsigned)); | ||
| 6674 | } | ||
| 6675 | else if (j.m_value.number_unsigned <= 0xff) | ||
| 6676 | { | ||
| 6677 | v.push_back(0x18); | ||
| 6678 | // one-byte uint8_t | ||
| 6679 | add_to_vector(v, 1, j.m_value.number_unsigned); | ||
| 6680 | } | ||
| 6681 | else if (j.m_value.number_unsigned <= 0xffff) | ||
| 6682 | { | ||
| 6683 | v.push_back(0x19); | ||
| 6684 | // two-byte uint16_t | ||
| 6685 | add_to_vector(v, 2, j.m_value.number_unsigned); | ||
| 6686 | } | ||
| 6687 | else if (j.m_value.number_unsigned <= 0xffffffff) | ||
| 6688 | { | ||
| 6689 | v.push_back(0x1a); | ||
| 6690 | // four-byte uint32_t | ||
| 6691 | add_to_vector(v, 4, j.m_value.number_unsigned); | ||
| 6692 | } | ||
| 6693 | else if (j.m_value.number_unsigned <= 0xffffffffffffffff) | ||
| 6694 | { | ||
| 6695 | v.push_back(0x1b); | ||
| 6696 | // eight-byte uint64_t | ||
| 6697 | add_to_vector(v, 8, j.m_value.number_unsigned); | ||
| 6698 | } | ||
| 6699 | break; | ||
| 6700 | } | ||
| 6701 | |||
| 6702 | case value_t::number_float: | ||
| 6703 | { | ||
| 6704 | // Double-Precision Float | ||
| 6705 | v.push_back(0xfb); | ||
| 6706 | const uint8_t* helper = reinterpret_cast<const uint8_t*>(&(j.m_value.number_float)); | ||
| 6707 | for (size_t i = 0; i < 8; ++i) | ||
| 6708 | { | ||
| 6709 | v.push_back(helper[7 - i]); | ||
| 6710 | } | ||
| 6711 | break; | ||
| 6712 | } | ||
| 6713 | |||
| 6714 | case value_t::string: | ||
| 6715 | { | ||
| 6716 | const auto N = j.m_value.string->size(); | ||
| 6717 | if (N <= 0x17) | ||
| 6718 | { | ||
| 6719 | v.push_back(0x60 + N); // 1 byte for string + size | ||
| 6720 | } | ||
| 6721 | else if (N <= 0xff) | ||
| 6722 | { | ||
| 6723 | v.push_back(0x78); // one-byte uint8_t for N | ||
| 6724 | add_to_vector(v, 1, N); | ||
| 6725 | } | ||
| 6726 | else if (N <= 0xffff) | ||
| 6727 | { | ||
| 6728 | v.push_back(0x79); // two-byte uint16_t for N | ||
| 6729 | add_to_vector(v, 2, N); | ||
| 6730 | } | ||
| 6731 | else if (N <= 0xffffffff) | ||
| 6732 | { | ||
| 6733 | v.push_back(0x7a); // four-byte uint32_t for N | ||
| 6734 | add_to_vector(v, 4, N); | ||
| 6735 | } | ||
| 6736 | // LCOV_EXCL_START | ||
| 6737 | else if (N <= 0xffffffffffffffff) | ||
| 6738 | { | ||
| 6739 | v.push_back(0x7b); // eight-byte uint64_t for N | ||
| 6740 | add_to_vector(v, 8, N); | ||
| 6741 | } | ||
| 6742 | // LCOV_EXCL_STOP | ||
| 6743 | |||
| 6744 | // append string | ||
| 6745 | std::copy(j.m_value.string->begin(), j.m_value.string->end(), | ||
| 6746 | std::back_inserter(v)); | ||
| 6747 | break; | ||
| 6748 | } | ||
| 6749 | |||
| 6750 | case value_t::array: | ||
| 6751 | { | ||
| 6752 | const auto N = j.m_value.array->size(); | ||
| 6753 | if (N <= 0x17) | ||
| 6754 | { | ||
| 6755 | v.push_back(0x80 + N); // 1 byte for array + size | ||
| 6756 | } | ||
| 6757 | else if (N <= 0xff) | ||
| 6758 | { | ||
| 6759 | v.push_back(0x98); // one-byte uint8_t for N | ||
| 6760 | add_to_vector(v, 1, N); | ||
| 6761 | } | ||
| 6762 | else if (N <= 0xffff) | ||
| 6763 | { | ||
| 6764 | v.push_back(0x99); // two-byte uint16_t for N | ||
| 6765 | add_to_vector(v, 2, N); | ||
| 6766 | } | ||
| 6767 | else if (N <= 0xffffffff) | ||
| 6768 | { | ||
| 6769 | v.push_back(0x9a); // four-byte uint32_t for N | ||
| 6770 | add_to_vector(v, 4, N); | ||
| 6771 | } | ||
| 6772 | // LCOV_EXCL_START | ||
| 6773 | else if (N <= 0xffffffffffffffff) | ||
| 6774 | { | ||
| 6775 | v.push_back(0x9b); // eight-byte uint64_t for N | ||
| 6776 | add_to_vector(v, 8, N); | ||
| 6777 | } | ||
| 6778 | // LCOV_EXCL_STOP | ||
| 6779 | |||
| 6780 | // append each element | ||
| 6781 | for (const auto& el : *j.m_value.array) | ||
| 6782 | { | ||
| 6783 | to_cbor_internal(el, v); | ||
| 6784 | } | ||
| 6785 | break; | ||
| 6786 | } | ||
| 6787 | |||
| 6788 | case value_t::object: | ||
| 6789 | { | ||
| 6790 | const auto N = j.m_value.object->size(); | ||
| 6791 | if (N <= 0x17) | ||
| 6792 | { | ||
| 6793 | v.push_back(0xa0 + N); // 1 byte for object + size | ||
| 6794 | } | ||
| 6795 | else if (N <= 0xff) | ||
| 6796 | { | ||
| 6797 | v.push_back(0xb8); | ||
| 6798 | add_to_vector(v, 1, N); // one-byte uint8_t for N | ||
| 6799 | } | ||
| 6800 | else if (N <= 0xffff) | ||
| 6801 | { | ||
| 6802 | v.push_back(0xb9); | ||
| 6803 | add_to_vector(v, 2, N); // two-byte uint16_t for N | ||
| 6804 | } | ||
| 6805 | else if (N <= 0xffffffff) | ||
| 6806 | { | ||
| 6807 | v.push_back(0xba); | ||
| 6808 | add_to_vector(v, 4, N); // four-byte uint32_t for N | ||
| 6809 | } | ||
| 6810 | // LCOV_EXCL_START | ||
| 6811 | else if (N <= 0xffffffffffffffff) | ||
| 6812 | { | ||
| 6813 | v.push_back(0xbb); | ||
| 6814 | add_to_vector(v, 8, N); // eight-byte uint64_t for N | ||
| 6815 | } | ||
| 6816 | // LCOV_EXCL_STOP | ||
| 6817 | |||
| 6818 | // append each element | ||
| 6819 | for (const auto& el : *j.m_value.object) | ||
| 6820 | { | ||
| 6821 | to_cbor_internal(el.first, v); | ||
| 6822 | to_cbor_internal(el.second, v); | ||
| 6823 | } | ||
| 6824 | break; | ||
| 6825 | } | ||
| 6826 | |||
| 6827 | default: | ||
| 6828 | { | ||
| 6829 | break; | ||
| 6830 | } | ||
| 6831 | } | ||
| 6832 | } | ||
| 6833 | |||
| 6834 | /*! | ||
| 6835 | @brief create a JSON value from a given MessagePack vector | ||
| 6836 | |||
| 6837 | @param[in] v MessagePack serialization | ||
| 6838 | @param[in] idx byte index to start reading from @a v | ||
| 6839 | |||
| 6840 | @return deserialized JSON value | ||
| 6841 | |||
| 6842 | @throw std::invalid_argument if unsupported features from MessagePack were | ||
| 6843 | used in the given vector @a v or if the input is not valid MessagePack | ||
| 6844 | @throw std::out_of_range if the given vector ends prematurely | ||
| 6845 | |||
| 6846 | @sa https://github.com/msgpack/msgpack/blob/master/spec.md | ||
| 6847 | */ | ||
| 6848 | static basic_json from_msgpack_internal(const std::vector<uint8_t>& v, size_t& idx) | ||
| 6849 | { | ||
| 6850 | // store and increment index | ||
| 6851 | const size_t current_idx = idx++; | ||
| 6852 | |||
| 6853 | if (v[current_idx] <= 0xbf) | ||
| 6854 | { | ||
| 6855 | if (v[current_idx] <= 0x7f) // positive fixint | ||
| 6856 | { | ||
| 6857 | return v[current_idx]; | ||
| 6858 | } | ||
| 6859 | else if (v[current_idx] <= 0x8f) // fixmap | ||
| 6860 | { | ||
| 6861 | basic_json result = value_t::object; | ||
| 6862 | const size_t len = v[current_idx] & 0x0f; | ||
| 6863 | for (size_t i = 0; i < len; ++i) | ||
| 6864 | { | ||
| 6865 | std::string key = from_msgpack_internal(v, idx); | ||
| 6866 | result[key] = from_msgpack_internal(v, idx); | ||
| 6867 | } | ||
| 6868 | return result; | ||
| 6869 | } | ||
| 6870 | else if (v[current_idx] <= 0x9f) // fixarray | ||
| 6871 | { | ||
| 6872 | basic_json result = value_t::array; | ||
| 6873 | const size_t len = v[current_idx] & 0x0f; | ||
| 6874 | for (size_t i = 0; i < len; ++i) | ||
| 6875 | { | ||
| 6876 | result.push_back(from_msgpack_internal(v, idx)); | ||
| 6877 | } | ||
| 6878 | return result; | ||
| 6879 | } | ||
| 6880 | else // fixstr | ||
| 6881 | { | ||
| 6882 | const size_t len = v[current_idx] & 0x1f; | ||
| 6883 | const size_t offset = current_idx + 1; | ||
| 6884 | idx += len; // skip content bytes | ||
| 6885 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 6886 | } | ||
| 6887 | } | ||
| 6888 | else if (v[current_idx] >= 0xe0) // negative fixint | ||
| 6889 | { | ||
| 6890 | return static_cast<int8_t>(v[current_idx]); | ||
| 6891 | } | ||
| 6892 | else | ||
| 6893 | { | ||
| 6894 | switch (v[current_idx]) | ||
| 6895 | { | ||
| 6896 | case 0xc0: // nil | ||
| 6897 | { | ||
| 6898 | return value_t::null; | ||
| 6899 | } | ||
| 6900 | |||
| 6901 | case 0xc2: // false | ||
| 6902 | { | ||
| 6903 | return false; | ||
| 6904 | } | ||
| 6905 | |||
| 6906 | case 0xc3: // true | ||
| 6907 | { | ||
| 6908 | return true; | ||
| 6909 | } | ||
| 6910 | |||
| 6911 | case 0xca: // float 32 | ||
| 6912 | { | ||
| 6913 | // copy bytes in reverse order into the double variable | ||
| 6914 | float res; | ||
| 6915 | for (size_t byte = 0; byte < sizeof(float); ++byte) | ||
| 6916 | { | ||
| 6917 | reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; | ||
| 6918 | } | ||
| 6919 | idx += sizeof(float); // skip content bytes | ||
| 6920 | return res; | ||
| 6921 | } | ||
| 6922 | |||
| 6923 | case 0xcb: // float 64 | ||
| 6924 | { | ||
| 6925 | // copy bytes in reverse order into the double variable | ||
| 6926 | double res; | ||
| 6927 | for (size_t byte = 0; byte < sizeof(double); ++byte) | ||
| 6928 | { | ||
| 6929 | reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; | ||
| 6930 | } | ||
| 6931 | idx += sizeof(double); // skip content bytes | ||
| 6932 | return res; | ||
| 6933 | } | ||
| 6934 | |||
| 6935 | case 0xcc: // uint 8 | ||
| 6936 | { | ||
| 6937 | idx += 1; // skip content byte | ||
| 6938 | return get_from_vector<uint8_t>(v, current_idx); | ||
| 6939 | } | ||
| 6940 | |||
| 6941 | case 0xcd: // uint 16 | ||
| 6942 | { | ||
| 6943 | idx += 2; // skip 2 content bytes | ||
| 6944 | return get_from_vector<uint16_t>(v, current_idx); | ||
| 6945 | } | ||
| 6946 | |||
| 6947 | case 0xce: // uint 32 | ||
| 6948 | { | ||
| 6949 | idx += 4; // skip 4 content bytes | ||
| 6950 | return get_from_vector<uint32_t>(v, current_idx); | ||
| 6951 | } | ||
| 6952 | |||
| 6953 | case 0xcf: // uint 64 | ||
| 6954 | { | ||
| 6955 | idx += 8; // skip 8 content bytes | ||
| 6956 | return get_from_vector<uint64_t>(v, current_idx); | ||
| 6957 | } | ||
| 6958 | |||
| 6959 | case 0xd0: // int 8 | ||
| 6960 | { | ||
| 6961 | idx += 1; // skip content byte | ||
| 6962 | return get_from_vector<int8_t>(v, current_idx); | ||
| 6963 | } | ||
| 6964 | |||
| 6965 | case 0xd1: // int 16 | ||
| 6966 | { | ||
| 6967 | idx += 2; // skip 2 content bytes | ||
| 6968 | return get_from_vector<int16_t>(v, current_idx); | ||
| 6969 | } | ||
| 6970 | |||
| 6971 | case 0xd2: // int 32 | ||
| 6972 | { | ||
| 6973 | idx += 4; // skip 4 content bytes | ||
| 6974 | return get_from_vector<int32_t>(v, current_idx); | ||
| 6975 | } | ||
| 6976 | |||
| 6977 | case 0xd3: // int 64 | ||
| 6978 | { | ||
| 6979 | idx += 8; // skip 8 content bytes | ||
| 6980 | return get_from_vector<int64_t>(v, current_idx); | ||
| 6981 | } | ||
| 6982 | |||
| 6983 | case 0xd9: // str 8 | ||
| 6984 | { | ||
| 6985 | const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); | ||
| 6986 | const size_t offset = current_idx + 2; | ||
| 6987 | idx += len + 1; // skip size byte + content bytes | ||
| 6988 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 6989 | } | ||
| 6990 | |||
| 6991 | case 0xda: // str 16 | ||
| 6992 | { | ||
| 6993 | const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); | ||
| 6994 | const size_t offset = current_idx + 3; | ||
| 6995 | idx += len + 2; // skip 2 size bytes + content bytes | ||
| 6996 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 6997 | } | ||
| 6998 | |||
| 6999 | case 0xdb: // str 32 | ||
| 7000 | { | ||
| 7001 | const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); | ||
| 7002 | const size_t offset = current_idx + 5; | ||
| 7003 | idx += len + 4; // skip 4 size bytes + content bytes | ||
| 7004 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 7005 | } | ||
| 7006 | |||
| 7007 | case 0xdc: // array 16 | ||
| 7008 | { | ||
| 7009 | basic_json result = value_t::array; | ||
| 7010 | const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); | ||
| 7011 | idx += 2; // skip 2 size bytes | ||
| 7012 | for (size_t i = 0; i < len; ++i) | ||
| 7013 | { | ||
| 7014 | result.push_back(from_msgpack_internal(v, idx)); | ||
| 7015 | } | ||
| 7016 | return result; | ||
| 7017 | } | ||
| 7018 | |||
| 7019 | case 0xdd: // array 32 | ||
| 7020 | { | ||
| 7021 | basic_json result = value_t::array; | ||
| 7022 | const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); | ||
| 7023 | idx += 4; // skip 4 size bytes | ||
| 7024 | for (size_t i = 0; i < len; ++i) | ||
| 7025 | { | ||
| 7026 | result.push_back(from_msgpack_internal(v, idx)); | ||
| 7027 | } | ||
| 7028 | return result; | ||
| 7029 | } | ||
| 7030 | |||
| 7031 | case 0xde: // map 16 | ||
| 7032 | { | ||
| 7033 | basic_json result = value_t::object; | ||
| 7034 | const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); | ||
| 7035 | idx += 2; // skip 2 size bytes | ||
| 7036 | for (size_t i = 0; i < len; ++i) | ||
| 7037 | { | ||
| 7038 | std::string key = from_msgpack_internal(v, idx); | ||
| 7039 | result[key] = from_msgpack_internal(v, idx); | ||
| 7040 | } | ||
| 7041 | return result; | ||
| 7042 | } | ||
| 7043 | |||
| 7044 | case 0xdf: // map 32 | ||
| 7045 | { | ||
| 7046 | basic_json result = value_t::object; | ||
| 7047 | const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); | ||
| 7048 | idx += 4; // skip 4 size bytes | ||
| 7049 | for (size_t i = 0; i < len; ++i) | ||
| 7050 | { | ||
| 7051 | std::string key = from_msgpack_internal(v, idx); | ||
| 7052 | result[key] = from_msgpack_internal(v, idx); | ||
| 7053 | } | ||
| 7054 | return result; | ||
| 7055 | } | ||
| 7056 | |||
| 7057 | default: | ||
| 7058 | { | ||
| 7059 | throw std::invalid_argument("error parsing a msgpack @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))); | ||
| 7060 | } | ||
| 7061 | } | ||
| 7062 | } | ||
| 7063 | } | ||
| 7064 | |||
| 7065 | /*! | ||
| 7066 | @brief create a JSON value from a given CBOR vector | ||
| 7067 | |||
| 7068 | @param[in] v CBOR serialization | ||
| 7069 | @param[in] idx byte index to start reading from @a v | ||
| 7070 | |||
| 7071 | @return deserialized JSON value | ||
| 7072 | |||
| 7073 | @throw std::invalid_argument if unsupported features from CBOR were used in | ||
| 7074 | the given vector @a v or if the input is not valid CBOR | ||
| 7075 | @throw std::out_of_range if the given vector ends prematurely | ||
| 7076 | |||
| 7077 | @sa https://tools.ietf.org/html/rfc7049 | ||
| 7078 | */ | ||
| 7079 | static basic_json from_cbor_internal(const std::vector<uint8_t>& v, size_t& idx) | ||
| 7080 | { | ||
| 7081 | // store and increment index | ||
| 7082 | const size_t current_idx = idx++; | ||
| 7083 | |||
| 7084 | switch (v[current_idx]) | ||
| 7085 | { | ||
| 7086 | // Integer 0x00..0x17 (0..23) | ||
| 7087 | case 0x00: | ||
| 7088 | case 0x01: | ||
| 7089 | case 0x02: | ||
| 7090 | case 0x03: | ||
| 7091 | case 0x04: | ||
| 7092 | case 0x05: | ||
| 7093 | case 0x06: | ||
| 7094 | case 0x07: | ||
| 7095 | case 0x08: | ||
| 7096 | case 0x09: | ||
| 7097 | case 0x0a: | ||
| 7098 | case 0x0b: | ||
| 7099 | case 0x0c: | ||
| 7100 | case 0x0d: | ||
| 7101 | case 0x0e: | ||
| 7102 | case 0x0f: | ||
| 7103 | case 0x10: | ||
| 7104 | case 0x11: | ||
| 7105 | case 0x12: | ||
| 7106 | case 0x13: | ||
| 7107 | case 0x14: | ||
| 7108 | case 0x15: | ||
| 7109 | case 0x16: | ||
| 7110 | case 0x17: | ||
| 7111 | { | ||
| 7112 | return v[current_idx]; | ||
| 7113 | } | ||
| 7114 | |||
| 7115 | case 0x18: // Unsigned integer (one-byte uint8_t follows) | ||
| 7116 | { | ||
| 7117 | idx += 1; // skip content byte | ||
| 7118 | return get_from_vector<uint8_t>(v, current_idx); | ||
| 7119 | } | ||
| 7120 | |||
| 7121 | case 0x19: // Unsigned integer (two-byte uint16_t follows) | ||
| 7122 | { | ||
| 7123 | idx += 2; // skip 2 content bytes | ||
| 7124 | return get_from_vector<uint16_t>(v, current_idx); | ||
| 7125 | } | ||
| 7126 | |||
| 7127 | case 0x1a: // Unsigned integer (four-byte uint32_t follows) | ||
| 7128 | { | ||
| 7129 | idx += 4; // skip 4 content bytes | ||
| 7130 | return get_from_vector<uint32_t>(v, current_idx); | ||
| 7131 | } | ||
| 7132 | |||
| 7133 | case 0x1b: // Unsigned integer (eight-byte uint64_t follows) | ||
| 7134 | { | ||
| 7135 | idx += 8; // skip 8 content bytes | ||
| 7136 | return get_from_vector<uint64_t>(v, current_idx); | ||
| 7137 | } | ||
| 7138 | |||
| 7139 | // Negative integer -1-0x00..-1-0x17 (-1..-24) | ||
| 7140 | case 0x20: | ||
| 7141 | case 0x21: | ||
| 7142 | case 0x22: | ||
| 7143 | case 0x23: | ||
| 7144 | case 0x24: | ||
| 7145 | case 0x25: | ||
| 7146 | case 0x26: | ||
| 7147 | case 0x27: | ||
| 7148 | case 0x28: | ||
| 7149 | case 0x29: | ||
| 7150 | case 0x2a: | ||
| 7151 | case 0x2b: | ||
| 7152 | case 0x2c: | ||
| 7153 | case 0x2d: | ||
| 7154 | case 0x2e: | ||
| 7155 | case 0x2f: | ||
| 7156 | case 0x30: | ||
| 7157 | case 0x31: | ||
| 7158 | case 0x32: | ||
| 7159 | case 0x33: | ||
| 7160 | case 0x34: | ||
| 7161 | case 0x35: | ||
| 7162 | case 0x36: | ||
| 7163 | case 0x37: | ||
| 7164 | { | ||
| 7165 | return static_cast<int8_t>(0x20 - 1 - v[current_idx]); | ||
| 7166 | } | ||
| 7167 | |||
| 7168 | case 0x38: // Negative integer (one-byte uint8_t follows) | ||
| 7169 | { | ||
| 7170 | idx += 1; // skip content byte | ||
| 7171 | // must be uint8_t ! | ||
| 7172 | return static_cast<number_integer_t>(-1) - get_from_vector<uint8_t>(v, current_idx); | ||
| 7173 | } | ||
| 7174 | |||
| 7175 | case 0x39: // Negative integer -1-n (two-byte uint16_t follows) | ||
| 7176 | { | ||
| 7177 | idx += 2; // skip 2 content bytes | ||
| 7178 | return static_cast<number_integer_t>(-1) - get_from_vector<uint16_t>(v, current_idx); | ||
| 7179 | } | ||
| 7180 | |||
| 7181 | case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) | ||
| 7182 | { | ||
| 7183 | idx += 4; // skip 4 content bytes | ||
| 7184 | return static_cast<number_integer_t>(-1) - get_from_vector<uint32_t>(v, current_idx); | ||
| 7185 | } | ||
| 7186 | |||
| 7187 | case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) | ||
| 7188 | { | ||
| 7189 | idx += 8; // skip 8 content bytes | ||
| 7190 | return static_cast<number_integer_t>(-1) - static_cast<number_integer_t>(get_from_vector<uint64_t>(v, current_idx)); | ||
| 7191 | } | ||
| 7192 | |||
| 7193 | // UTF-8 string (0x00..0x17 bytes follow) | ||
| 7194 | case 0x60: | ||
| 7195 | case 0x61: | ||
| 7196 | case 0x62: | ||
| 7197 | case 0x63: | ||
| 7198 | case 0x64: | ||
| 7199 | case 0x65: | ||
| 7200 | case 0x66: | ||
| 7201 | case 0x67: | ||
| 7202 | case 0x68: | ||
| 7203 | case 0x69: | ||
| 7204 | case 0x6a: | ||
| 7205 | case 0x6b: | ||
| 7206 | case 0x6c: | ||
| 7207 | case 0x6d: | ||
| 7208 | case 0x6e: | ||
| 7209 | case 0x6f: | ||
| 7210 | case 0x70: | ||
| 7211 | case 0x71: | ||
| 7212 | case 0x72: | ||
| 7213 | case 0x73: | ||
| 7214 | case 0x74: | ||
| 7215 | case 0x75: | ||
| 7216 | case 0x76: | ||
| 7217 | case 0x77: | ||
| 7218 | { | ||
| 7219 | const auto len = static_cast<size_t>(v[current_idx] - 0x60); | ||
| 7220 | const size_t offset = current_idx + 1; | ||
| 7221 | idx += len; // skip content bytes | ||
| 7222 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 7223 | } | ||
| 7224 | |||
| 7225 | case 0x78: // UTF-8 string (one-byte uint8_t for n follows) | ||
| 7226 | { | ||
| 7227 | const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); | ||
| 7228 | const size_t offset = current_idx + 2; | ||
| 7229 | idx += len + 1; // skip size byte + content bytes | ||
| 7230 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 7231 | } | ||
| 7232 | |||
| 7233 | case 0x79: // UTF-8 string (two-byte uint16_t for n follow) | ||
| 7234 | { | ||
| 7235 | const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); | ||
| 7236 | const size_t offset = current_idx + 3; | ||
| 7237 | idx += len + 2; // skip 2 size bytes + content bytes | ||
| 7238 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 7239 | } | ||
| 7240 | |||
| 7241 | case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) | ||
| 7242 | { | ||
| 7243 | const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); | ||
| 7244 | const size_t offset = current_idx + 5; | ||
| 7245 | idx += len + 4; // skip 4 size bytes + content bytes | ||
| 7246 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 7247 | } | ||
| 7248 | |||
| 7249 | case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) | ||
| 7250 | { | ||
| 7251 | const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx)); | ||
| 7252 | const size_t offset = current_idx + 9; | ||
| 7253 | idx += len + 8; // skip 8 size bytes + content bytes | ||
| 7254 | return std::string(reinterpret_cast<const char*>(v.data()) + offset, len); | ||
| 7255 | } | ||
| 7256 | |||
| 7257 | case 0x7f: // UTF-8 string (indefinite length) | ||
| 7258 | { | ||
| 7259 | std::string result; | ||
| 7260 | while (v[idx] != 0xff) | ||
| 7261 | { | ||
| 7262 | string_t s = from_cbor_internal(v, idx); | ||
| 7263 | result += s; | ||
| 7264 | } | ||
| 7265 | // skip break byte (0xFF) | ||
| 7266 | idx += 1; | ||
| 7267 | return result; | ||
| 7268 | } | ||
| 7269 | |||
| 7270 | // array (0x00..0x17 data items follow) | ||
| 7271 | case 0x80: | ||
| 7272 | case 0x81: | ||
| 7273 | case 0x82: | ||
| 7274 | case 0x83: | ||
| 7275 | case 0x84: | ||
| 7276 | case 0x85: | ||
| 7277 | case 0x86: | ||
| 7278 | case 0x87: | ||
| 7279 | case 0x88: | ||
| 7280 | case 0x89: | ||
| 7281 | case 0x8a: | ||
| 7282 | case 0x8b: | ||
| 7283 | case 0x8c: | ||
| 7284 | case 0x8d: | ||
| 7285 | case 0x8e: | ||
| 7286 | case 0x8f: | ||
| 7287 | case 0x90: | ||
| 7288 | case 0x91: | ||
| 7289 | case 0x92: | ||
| 7290 | case 0x93: | ||
| 7291 | case 0x94: | ||
| 7292 | case 0x95: | ||
| 7293 | case 0x96: | ||
| 7294 | case 0x97: | ||
| 7295 | { | ||
| 7296 | basic_json result = value_t::array; | ||
| 7297 | const auto len = static_cast<size_t>(v[current_idx] - 0x80); | ||
| 7298 | for (size_t i = 0; i < len; ++i) | ||
| 7299 | { | ||
| 7300 | result.push_back(from_cbor_internal(v, idx)); | ||
| 7301 | } | ||
| 7302 | return result; | ||
| 7303 | } | ||
| 7304 | |||
| 7305 | case 0x98: // array (one-byte uint8_t for n follows) | ||
| 7306 | { | ||
| 7307 | basic_json result = value_t::array; | ||
| 7308 | const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); | ||
| 7309 | idx += 1; // skip 1 size byte | ||
| 7310 | for (size_t i = 0; i < len; ++i) | ||
| 7311 | { | ||
| 7312 | result.push_back(from_cbor_internal(v, idx)); | ||
| 7313 | } | ||
| 7314 | return result; | ||
| 7315 | } | ||
| 7316 | |||
| 7317 | case 0x99: // array (two-byte uint16_t for n follow) | ||
| 7318 | { | ||
| 7319 | basic_json result = value_t::array; | ||
| 7320 | const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); | ||
| 7321 | idx += 2; // skip 4 size bytes | ||
| 7322 | for (size_t i = 0; i < len; ++i) | ||
| 7323 | { | ||
| 7324 | result.push_back(from_cbor_internal(v, idx)); | ||
| 7325 | } | ||
| 7326 | return result; | ||
| 7327 | } | ||
| 7328 | |||
| 7329 | case 0x9a: // array (four-byte uint32_t for n follow) | ||
| 7330 | { | ||
| 7331 | basic_json result = value_t::array; | ||
| 7332 | const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); | ||
| 7333 | idx += 4; // skip 4 size bytes | ||
| 7334 | for (size_t i = 0; i < len; ++i) | ||
| 7335 | { | ||
| 7336 | result.push_back(from_cbor_internal(v, idx)); | ||
| 7337 | } | ||
| 7338 | return result; | ||
| 7339 | } | ||
| 7340 | |||
| 7341 | case 0x9b: // array (eight-byte uint64_t for n follow) | ||
| 7342 | { | ||
| 7343 | basic_json result = value_t::array; | ||
| 7344 | const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx)); | ||
| 7345 | idx += 8; // skip 8 size bytes | ||
| 7346 | for (size_t i = 0; i < len; ++i) | ||
| 7347 | { | ||
| 7348 | result.push_back(from_cbor_internal(v, idx)); | ||
| 7349 | } | ||
| 7350 | return result; | ||
| 7351 | } | ||
| 7352 | |||
| 7353 | case 0x9f: // array (indefinite length) | ||
| 7354 | { | ||
| 7355 | basic_json result = value_t::array; | ||
| 7356 | while (v[idx] != 0xff) | ||
| 7357 | { | ||
| 7358 | result.push_back(from_cbor_internal(v, idx)); | ||
| 7359 | } | ||
| 7360 | // skip break byte (0xFF) | ||
| 7361 | idx += 1; | ||
| 7362 | return result; | ||
| 7363 | } | ||
| 7364 | |||
| 7365 | // map (0x00..0x17 pairs of data items follow) | ||
| 7366 | case 0xa0: | ||
| 7367 | case 0xa1: | ||
| 7368 | case 0xa2: | ||
| 7369 | case 0xa3: | ||
| 7370 | case 0xa4: | ||
| 7371 | case 0xa5: | ||
| 7372 | case 0xa6: | ||
| 7373 | case 0xa7: | ||
| 7374 | case 0xa8: | ||
| 7375 | case 0xa9: | ||
| 7376 | case 0xaa: | ||
| 7377 | case 0xab: | ||
| 7378 | case 0xac: | ||
| 7379 | case 0xad: | ||
| 7380 | case 0xae: | ||
| 7381 | case 0xaf: | ||
| 7382 | case 0xb0: | ||
| 7383 | case 0xb1: | ||
| 7384 | case 0xb2: | ||
| 7385 | case 0xb3: | ||
| 7386 | case 0xb4: | ||
| 7387 | case 0xb5: | ||
| 7388 | case 0xb6: | ||
| 7389 | case 0xb7: | ||
| 7390 | { | ||
| 7391 | basic_json result = value_t::object; | ||
| 7392 | const auto len = static_cast<size_t>(v[current_idx] - 0xa0); | ||
| 7393 | for (size_t i = 0; i < len; ++i) | ||
| 7394 | { | ||
| 7395 | std::string key = from_cbor_internal(v, idx); | ||
| 7396 | result[key] = from_cbor_internal(v, idx); | ||
| 7397 | } | ||
| 7398 | return result; | ||
| 7399 | } | ||
| 7400 | |||
| 7401 | case 0xb8: // map (one-byte uint8_t for n follows) | ||
| 7402 | { | ||
| 7403 | basic_json result = value_t::object; | ||
| 7404 | const auto len = static_cast<size_t>(get_from_vector<uint8_t>(v, current_idx)); | ||
| 7405 | idx += 1; // skip 1 size byte | ||
| 7406 | for (size_t i = 0; i < len; ++i) | ||
| 7407 | { | ||
| 7408 | std::string key = from_cbor_internal(v, idx); | ||
| 7409 | result[key] = from_cbor_internal(v, idx); | ||
| 7410 | } | ||
| 7411 | return result; | ||
| 7412 | } | ||
| 7413 | |||
| 7414 | case 0xb9: // map (two-byte uint16_t for n follow) | ||
| 7415 | { | ||
| 7416 | basic_json result = value_t::object; | ||
| 7417 | const auto len = static_cast<size_t>(get_from_vector<uint16_t>(v, current_idx)); | ||
| 7418 | idx += 2; // skip 2 size bytes | ||
| 7419 | for (size_t i = 0; i < len; ++i) | ||
| 7420 | { | ||
| 7421 | std::string key = from_cbor_internal(v, idx); | ||
| 7422 | result[key] = from_cbor_internal(v, idx); | ||
| 7423 | } | ||
| 7424 | return result; | ||
| 7425 | } | ||
| 7426 | |||
| 7427 | case 0xba: // map (four-byte uint32_t for n follow) | ||
| 7428 | { | ||
| 7429 | basic_json result = value_t::object; | ||
| 7430 | const auto len = static_cast<size_t>(get_from_vector<uint32_t>(v, current_idx)); | ||
| 7431 | idx += 4; // skip 4 size bytes | ||
| 7432 | for (size_t i = 0; i < len; ++i) | ||
| 7433 | { | ||
| 7434 | std::string key = from_cbor_internal(v, idx); | ||
| 7435 | result[key] = from_cbor_internal(v, idx); | ||
| 7436 | } | ||
| 7437 | return result; | ||
| 7438 | } | ||
| 7439 | |||
| 7440 | case 0xbb: // map (eight-byte uint64_t for n follow) | ||
| 7441 | { | ||
| 7442 | basic_json result = value_t::object; | ||
| 7443 | const auto len = static_cast<size_t>(get_from_vector<uint64_t>(v, current_idx)); | ||
| 7444 | idx += 8; // skip 8 size bytes | ||
| 7445 | for (size_t i = 0; i < len; ++i) | ||
| 7446 | { | ||
| 7447 | std::string key = from_cbor_internal(v, idx); | ||
| 7448 | result[key] = from_cbor_internal(v, idx); | ||
| 7449 | } | ||
| 7450 | return result; | ||
| 7451 | } | ||
| 7452 | |||
| 7453 | case 0xbf: // map (indefinite length) | ||
| 7454 | { | ||
| 7455 | basic_json result = value_t::object; | ||
| 7456 | while (v[idx] != 0xff) | ||
| 7457 | { | ||
| 7458 | std::string key = from_cbor_internal(v, idx); | ||
| 7459 | result[key] = from_cbor_internal(v, idx); | ||
| 7460 | } | ||
| 7461 | // skip break byte (0xFF) | ||
| 7462 | idx += 1; | ||
| 7463 | return result; | ||
| 7464 | } | ||
| 7465 | |||
| 7466 | case 0xf4: // false | ||
| 7467 | { | ||
| 7468 | return false; | ||
| 7469 | } | ||
| 7470 | |||
| 7471 | case 0xf5: // true | ||
| 7472 | { | ||
| 7473 | return true; | ||
| 7474 | } | ||
| 7475 | |||
| 7476 | case 0xf6: // null | ||
| 7477 | { | ||
| 7478 | return value_t::null; | ||
| 7479 | } | ||
| 7480 | |||
| 7481 | case 0xf9: // Half-Precision Float (two-byte IEEE 754) | ||
| 7482 | { | ||
| 7483 | idx += 2; // skip two content bytes | ||
| 7484 | |||
| 7485 | // code from RFC 7049, Appendix D, Figure 3: | ||
| 7486 | // As half-precision floating-point numbers were only added to | ||
| 7487 | // IEEE 754 in 2008, today's programming platforms often still | ||
| 7488 | // only have limited support for them. It is very easy to | ||
| 7489 | // include at least decoding support for them even without such | ||
| 7490 | // support. An example of a small decoder for half-precision | ||
| 7491 | // floating-point numbers in the C language is shown in Fig. 3. | ||
| 7492 | const int half = (v[current_idx + 1] << 8) + v[current_idx + 2]; | ||
| 7493 | const int exp = (half >> 10) & 0x1f; | ||
| 7494 | const int mant = half & 0x3ff; | ||
| 7495 | double val; | ||
| 7496 | if (exp == 0) | ||
| 7497 | { | ||
| 7498 | val = std::ldexp(mant, -24); | ||
| 7499 | } | ||
| 7500 | else if (exp != 31) | ||
| 7501 | { | ||
| 7502 | val = std::ldexp(mant + 1024, exp - 25); | ||
| 7503 | } | ||
| 7504 | else | ||
| 7505 | { | ||
| 7506 | val = mant == 0 ? INFINITY : NAN; | ||
| 7507 | } | ||
| 7508 | return half & 0x8000 ? -val : val; | ||
| 7509 | } | ||
| 7510 | |||
| 7511 | case 0xfa: // Single-Precision Float (four-byte IEEE 754) | ||
| 7512 | { | ||
| 7513 | // copy bytes in reverse order into the float variable | ||
| 7514 | float res; | ||
| 7515 | for (size_t byte = 0; byte < sizeof(float); ++byte) | ||
| 7516 | { | ||
| 7517 | reinterpret_cast<uint8_t*>(&res)[sizeof(float) - byte - 1] = v[current_idx + 1 + byte]; | ||
| 7518 | } | ||
| 7519 | idx += sizeof(float); // skip content bytes | ||
| 7520 | return res; | ||
| 7521 | } | ||
| 7522 | |||
| 7523 | case 0xfb: // Double-Precision Float (eight-byte IEEE 754) | ||
| 7524 | { | ||
| 7525 | // copy bytes in reverse order into the double variable | ||
| 7526 | double res; | ||
| 7527 | for (size_t byte = 0; byte < sizeof(double); ++byte) | ||
| 7528 | { | ||
| 7529 | reinterpret_cast<uint8_t*>(&res)[sizeof(double) - byte - 1] = v[current_idx + 1 + byte]; | ||
| 7530 | } | ||
| 7531 | idx += sizeof(double); // skip content bytes | ||
| 7532 | return res; | ||
| 7533 | } | ||
| 7534 | |||
| 7535 | default: // anything else (0xFF is handled inside the other types) | ||
| 7536 | { | ||
| 7537 | throw std::invalid_argument("error parsing a CBOR @ " + std::to_string(current_idx) + ": " + std::to_string(static_cast<int>(v[current_idx]))); | ||
| 7538 | } | ||
| 7539 | } | ||
| 7540 | } | ||
| 7541 | |||
| 7542 | public: | ||
| 7543 | /*! | ||
| 7544 | @brief create a MessagePack serialization of a given JSON value | ||
| 7545 | |||
| 7546 | Serializes a given JSON value @a j to a byte vector using the MessagePack | ||
| 7547 | serialization format. MessagePack is a binary serialization format which | ||
| 7548 | aims to be more compact than JSON itself, yet more efficient to parse. | ||
| 7549 | |||
| 7550 | @param[in] j JSON value to serialize | ||
| 7551 | @return MessagePack serialization as byte vector | ||
| 7552 | |||
| 7553 | @complexity Linear in the size of the JSON value @a j. | ||
| 7554 | |||
| 7555 | @liveexample{The example shows the serialization of a JSON value to a byte | ||
| 7556 | vector in MessagePack format.,to_msgpack} | ||
| 7557 | |||
| 7558 | @sa http://msgpack.org | ||
| 7559 | @sa @ref from_msgpack(const std::vector<uint8_t>&) for the analogous | ||
| 7560 | deserialization | ||
| 7561 | @sa @ref to_cbor(const basic_json& for the related CBOR format | ||
| 7562 | */ | ||
| 7563 | static std::vector<uint8_t> to_msgpack(const basic_json& j) | ||
| 7564 | { | ||
| 7565 | std::vector<uint8_t> result; | ||
| 7566 | to_msgpack_internal(j, result); | ||
| 7567 | return result; | ||
| 7568 | } | ||
| 7569 | |||
| 7570 | /*! | ||
| 7571 | @brief create a JSON value from a byte vector in MessagePack format | ||
| 7572 | |||
| 7573 | Deserializes a given byte vector @a v to a JSON value using the MessagePack | ||
| 7574 | serialization format. | ||
| 7575 | |||
| 7576 | @param[in] v a byte vector in MessagePack format | ||
| 7577 | @return deserialized JSON value | ||
| 7578 | |||
| 7579 | @throw std::invalid_argument if unsupported features from MessagePack were | ||
| 7580 | used in the given vector @a v or if the input is not valid MessagePack | ||
| 7581 | @throw std::out_of_range if the given vector ends prematurely | ||
| 7582 | |||
| 7583 | @complexity Linear in the size of the byte vector @a v. | ||
| 7584 | |||
| 7585 | @liveexample{The example shows the deserialization of a byte vector in | ||
| 7586 | MessagePack format to a JSON value.,from_msgpack} | ||
| 7587 | |||
| 7588 | @sa http://msgpack.org | ||
| 7589 | @sa @ref to_msgpack(const basic_json&) for the analogous serialization | ||
| 7590 | @sa @ref from_cbor(const std::vector<uint8_t>&) for the related CBOR format | ||
| 7591 | */ | ||
| 7592 | static basic_json from_msgpack(const std::vector<uint8_t>& v) | ||
| 7593 | { | ||
| 7594 | size_t i = 0; | ||
| 7595 | return from_msgpack_internal(v, i); | ||
| 7596 | } | ||
| 7597 | |||
| 7598 | /*! | ||
| 7599 | @brief create a MessagePack serialization of a given JSON value | ||
| 7600 | |||
| 7601 | Serializes a given JSON value @a j to a byte vector using the CBOR (Concise | ||
| 7602 | Binary Object Representation) serialization format. CBOR is a binary | ||
| 7603 | serialization format which aims to be more compact than JSON itself, yet | ||
| 7604 | more efficient to parse. | ||
| 7605 | |||
| 7606 | @param[in] j JSON value to serialize | ||
| 7607 | @return MessagePack serialization as byte vector | ||
| 7608 | |||
| 7609 | @complexity Linear in the size of the JSON value @a j. | ||
| 7610 | |||
| 7611 | @liveexample{The example shows the serialization of a JSON value to a byte | ||
| 7612 | vector in CBOR format.,to_cbor} | ||
| 7613 | |||
| 7614 | @sa http://cbor.io | ||
| 7615 | @sa @ref from_cbor(const std::vector<uint8_t>&) for the analogous | ||
| 7616 | deserialization | ||
| 7617 | @sa @ref to_msgpack(const basic_json& for the related MessagePack format | ||
| 7618 | */ | ||
| 7619 | static std::vector<uint8_t> to_cbor(const basic_json& j) | ||
| 7620 | { | ||
| 7621 | std::vector<uint8_t> result; | ||
| 7622 | to_cbor_internal(j, result); | ||
| 7623 | return result; | ||
| 7624 | } | ||
| 7625 | |||
| 7626 | /*! | ||
| 7627 | @brief create a JSON value from a byte vector in CBOR format | ||
| 7628 | |||
| 7629 | Deserializes a given byte vector @a v to a JSON value using the CBOR | ||
| 7630 | (Concise Binary Object Representation) serialization format. | ||
| 7631 | |||
| 7632 | @param[in] v a byte vector in CBOR format | ||
| 7633 | @return deserialized JSON value | ||
| 7634 | |||
| 7635 | @throw std::invalid_argument if unsupported features from CBOR were used in | ||
| 7636 | the given vector @a v or if the input is not valid MessagePack | ||
| 7637 | @throw std::out_of_range if the given vector ends prematurely | ||
| 7638 | |||
| 7639 | @complexity Linear in the size of the byte vector @a v. | ||
| 7640 | |||
| 7641 | @liveexample{The example shows the deserialization of a byte vector in CBOR | ||
| 7642 | format to a JSON value.,from_cbor} | ||
| 7643 | |||
| 7644 | @sa http://cbor.io | ||
| 7645 | @sa @ref to_cbor(const basic_json&) for the analogous serialization | ||
| 7646 | @sa @ref from_msgpack(const std::vector<uint8_t>&) for the related | ||
| 7647 | MessagePack format | ||
| 7648 | */ | ||
| 7649 | static basic_json from_cbor(const std::vector<uint8_t>& v) | ||
| 7650 | { | ||
| 7651 | size_t i = 0; | ||
| 7652 | return from_cbor_internal(v, i); | ||
| 7653 | } | ||
| 7654 | |||
| 7655 | /// @} | ||
| 6145 | 7656 | ||
| 6146 | private: | 7657 | private: |
| 6147 | /////////////////////////// | 7658 | /////////////////////////// |
| @@ -6694,10 +8205,10 @@ class basic_json | |||
| 6694 | 8205 | ||
| 6695 | public: | 8206 | public: |
| 6696 | /*! | 8207 | /*! |
| 6697 | @brief a const random access iterator for the @ref basic_json class | 8208 | @brief a template for a random access iterator for the @ref basic_json class |
| 6698 | 8209 | ||
| 6699 | This class implements a const iterator for the @ref basic_json class. From | 8210 | This class implements a both iterators (iterator and const_iterator) for the |
| 6700 | this class, the @ref iterator class is derived. | 8211 | @ref basic_json class. |
| 6701 | 8212 | ||
| 6702 | @note An iterator is called *initialized* when a pointer to a JSON value | 8213 | @note An iterator is called *initialized* when a pointer to a JSON value |
| 6703 | has been set (e.g., by a constructor or a copy assignment). If the | 8214 | has been set (e.g., by a constructor or a copy assignment). If the |
| @@ -6710,27 +8221,37 @@ class basic_json | |||
| 6710 | The iterator that can be moved to point (forward and backward) to any | 8221 | The iterator that can be moved to point (forward and backward) to any |
| 6711 | element in constant time. | 8222 | element in constant time. |
| 6712 | 8223 | ||
| 6713 | @since version 1.0.0 | 8224 | @since version 1.0.0, simplified in version 2.0.9 |
| 6714 | */ | 8225 | */ |
| 6715 | class const_iterator : public std::iterator<std::random_access_iterator_tag, const basic_json> | 8226 | template<typename U> |
| 8227 | class iter_impl : public std::iterator<std::random_access_iterator_tag, U> | ||
| 6716 | { | 8228 | { |
| 6717 | /// allow basic_json to access private members | 8229 | /// allow basic_json to access private members |
| 6718 | friend class basic_json; | 8230 | friend class basic_json; |
| 6719 | 8231 | ||
| 8232 | // make sure U is basic_json or const basic_json | ||
| 8233 | static_assert(std::is_same<U, basic_json>::value | ||
| 8234 | or std::is_same<U, const basic_json>::value, | ||
| 8235 | "iter_impl only accepts (const) basic_json"); | ||
| 8236 | |||
| 6720 | public: | 8237 | public: |
| 6721 | /// the type of the values when the iterator is dereferenced | 8238 | /// the type of the values when the iterator is dereferenced |
| 6722 | using value_type = typename basic_json::value_type; | 8239 | using value_type = typename basic_json::value_type; |
| 6723 | /// a type to represent differences between iterators | 8240 | /// a type to represent differences between iterators |
| 6724 | using difference_type = typename basic_json::difference_type; | 8241 | using difference_type = typename basic_json::difference_type; |
| 6725 | /// defines a pointer to the type iterated over (value_type) | 8242 | /// defines a pointer to the type iterated over (value_type) |
| 6726 | using pointer = typename basic_json::const_pointer; | 8243 | using pointer = typename std::conditional<std::is_const<U>::value, |
| 8244 | typename basic_json::const_pointer, | ||
| 8245 | typename basic_json::pointer>::type; | ||
| 6727 | /// defines a reference to the type iterated over (value_type) | 8246 | /// defines a reference to the type iterated over (value_type) |
| 6728 | using reference = typename basic_json::const_reference; | 8247 | using reference = typename std::conditional<std::is_const<U>::value, |
| 8248 | typename basic_json::const_reference, | ||
| 8249 | typename basic_json::reference>::type; | ||
| 6729 | /// the category of the iterator | 8250 | /// the category of the iterator |
| 6730 | using iterator_category = std::bidirectional_iterator_tag; | 8251 | using iterator_category = std::bidirectional_iterator_tag; |
| 6731 | 8252 | ||
| 6732 | /// default constructor | 8253 | /// default constructor |
| 6733 | const_iterator() = default; | 8254 | iter_impl() = default; |
| 6734 | 8255 | ||
| 6735 | /*! | 8256 | /*! |
| 6736 | @brief constructor for a given JSON instance | 8257 | @brief constructor for a given JSON instance |
| @@ -6738,7 +8259,7 @@ class basic_json | |||
| 6738 | @pre object != nullptr | 8259 | @pre object != nullptr |
| 6739 | @post The iterator is initialized; i.e. `m_object != nullptr`. | 8260 | @post The iterator is initialized; i.e. `m_object != nullptr`. |
| 6740 | */ | 8261 | */ |
| 6741 | explicit const_iterator(pointer object) noexcept | 8262 | explicit iter_impl(pointer object) noexcept |
| 6742 | : m_object(object) | 8263 | : m_object(object) |
| 6743 | { | 8264 | { |
| 6744 | assert(m_object != nullptr); | 8265 | assert(m_object != nullptr); |
| @@ -6765,37 +8286,25 @@ class basic_json | |||
| 6765 | } | 8286 | } |
| 6766 | } | 8287 | } |
| 6767 | 8288 | ||
| 6768 | /*! | 8289 | /* |
| 6769 | @brief copy constructor given a non-const iterator | 8290 | Use operator `const_iterator` instead of `const_iterator(const iterator& |
| 6770 | @param[in] other iterator to copy from | 8291 | other) noexcept` to avoid two class definitions for @ref iterator and |
| 6771 | @note It is not checked whether @a other is initialized. | 8292 | @ref const_iterator. |
| 8293 | |||
| 8294 | This function is only called if this class is an @ref iterator. If this | ||
| 8295 | class is a @ref const_iterator this function is not called. | ||
| 6772 | */ | 8296 | */ |
| 6773 | explicit const_iterator(const iterator& other) noexcept | 8297 | operator const_iterator() const |
| 6774 | : m_object(other.m_object) | ||
| 6775 | { | 8298 | { |
| 6776 | if (m_object != nullptr) | 8299 | const_iterator ret; |
| 6777 | { | ||
| 6778 | switch (m_object->m_type) | ||
| 6779 | { | ||
| 6780 | case basic_json::value_t::object: | ||
| 6781 | { | ||
| 6782 | m_it.object_iterator = other.m_it.object_iterator; | ||
| 6783 | break; | ||
| 6784 | } | ||
| 6785 | 8300 | ||
| 6786 | case basic_json::value_t::array: | 8301 | if (m_object) |
| 6787 | { | 8302 | { |
| 6788 | m_it.array_iterator = other.m_it.array_iterator; | 8303 | ret.m_object = m_object; |
| 6789 | break; | 8304 | ret.m_it = m_it; |
| 6790 | } | ||
| 6791 | |||
| 6792 | default: | ||
| 6793 | { | ||
| 6794 | m_it.primitive_iterator = other.m_it.primitive_iterator; | ||
| 6795 | break; | ||
| 6796 | } | ||
| 6797 | } | ||
| 6798 | } | 8305 | } |
| 8306 | |||
| 8307 | return ret; | ||
| 6799 | } | 8308 | } |
| 6800 | 8309 | ||
| 6801 | /*! | 8310 | /*! |
| @@ -6803,7 +8312,7 @@ class basic_json | |||
| 6803 | @param[in] other iterator to copy from | 8312 | @param[in] other iterator to copy from |
| 6804 | @note It is not checked whether @a other is initialized. | 8313 | @note It is not checked whether @a other is initialized. |
| 6805 | */ | 8314 | */ |
| 6806 | const_iterator(const const_iterator& other) noexcept | 8315 | iter_impl(const iter_impl& other) noexcept |
| 6807 | : m_object(other.m_object), m_it(other.m_it) | 8316 | : m_object(other.m_object), m_it(other.m_it) |
| 6808 | {} | 8317 | {} |
| 6809 | 8318 | ||
| @@ -6812,7 +8321,7 @@ class basic_json | |||
| 6812 | @param[in,out] other iterator to copy from | 8321 | @param[in,out] other iterator to copy from |
| 6813 | @note It is not checked whether @a other is initialized. | 8322 | @note It is not checked whether @a other is initialized. |
| 6814 | */ | 8323 | */ |
| 6815 | const_iterator& operator=(const_iterator other) noexcept( | 8324 | iter_impl& operator=(iter_impl other) noexcept( |
| 6816 | std::is_nothrow_move_constructible<pointer>::value and | 8325 | std::is_nothrow_move_constructible<pointer>::value and |
| 6817 | std::is_nothrow_move_assignable<pointer>::value and | 8326 | std::is_nothrow_move_assignable<pointer>::value and |
| 6818 | std::is_nothrow_move_constructible<internal_iterator>::value and | 8327 | std::is_nothrow_move_constructible<internal_iterator>::value and |
| @@ -6974,7 +8483,7 @@ class basic_json | |||
| 6974 | @brief post-increment (it++) | 8483 | @brief post-increment (it++) |
| 6975 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8484 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 6976 | */ | 8485 | */ |
| 6977 | const_iterator operator++(int) | 8486 | iter_impl operator++(int) |
| 6978 | { | 8487 | { |
| 6979 | auto result = *this; | 8488 | auto result = *this; |
| 6980 | ++(*this); | 8489 | ++(*this); |
| @@ -6985,7 +8494,7 @@ class basic_json | |||
| 6985 | @brief pre-increment (++it) | 8494 | @brief pre-increment (++it) |
| 6986 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8495 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 6987 | */ | 8496 | */ |
| 6988 | const_iterator& operator++() | 8497 | iter_impl& operator++() |
| 6989 | { | 8498 | { |
| 6990 | assert(m_object != nullptr); | 8499 | assert(m_object != nullptr); |
| 6991 | 8500 | ||
| @@ -7017,7 +8526,7 @@ class basic_json | |||
| 7017 | @brief post-decrement (it--) | 8526 | @brief post-decrement (it--) |
| 7018 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8527 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7019 | */ | 8528 | */ |
| 7020 | const_iterator operator--(int) | 8529 | iter_impl operator--(int) |
| 7021 | { | 8530 | { |
| 7022 | auto result = *this; | 8531 | auto result = *this; |
| 7023 | --(*this); | 8532 | --(*this); |
| @@ -7028,7 +8537,7 @@ class basic_json | |||
| 7028 | @brief pre-decrement (--it) | 8537 | @brief pre-decrement (--it) |
| 7029 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8538 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7030 | */ | 8539 | */ |
| 7031 | const_iterator& operator--() | 8540 | iter_impl& operator--() |
| 7032 | { | 8541 | { |
| 7033 | assert(m_object != nullptr); | 8542 | assert(m_object != nullptr); |
| 7034 | 8543 | ||
| @@ -7060,7 +8569,7 @@ class basic_json | |||
| 7060 | @brief comparison: equal | 8569 | @brief comparison: equal |
| 7061 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8570 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7062 | */ | 8571 | */ |
| 7063 | bool operator==(const const_iterator& other) const | 8572 | bool operator==(const iter_impl& other) const |
| 7064 | { | 8573 | { |
| 7065 | // if objects are not the same, the comparison is undefined | 8574 | // if objects are not the same, the comparison is undefined |
| 7066 | if (m_object != other.m_object) | 8575 | if (m_object != other.m_object) |
| @@ -7093,7 +8602,7 @@ class basic_json | |||
| 7093 | @brief comparison: not equal | 8602 | @brief comparison: not equal |
| 7094 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8603 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7095 | */ | 8604 | */ |
| 7096 | bool operator!=(const const_iterator& other) const | 8605 | bool operator!=(const iter_impl& other) const |
| 7097 | { | 8606 | { |
| 7098 | return not operator==(other); | 8607 | return not operator==(other); |
| 7099 | } | 8608 | } |
| @@ -7102,7 +8611,7 @@ class basic_json | |||
| 7102 | @brief comparison: smaller | 8611 | @brief comparison: smaller |
| 7103 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8612 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7104 | */ | 8613 | */ |
| 7105 | bool operator<(const const_iterator& other) const | 8614 | bool operator<(const iter_impl& other) const |
| 7106 | { | 8615 | { |
| 7107 | // if objects are not the same, the comparison is undefined | 8616 | // if objects are not the same, the comparison is undefined |
| 7108 | if (m_object != other.m_object) | 8617 | if (m_object != other.m_object) |
| @@ -7135,7 +8644,7 @@ class basic_json | |||
| 7135 | @brief comparison: less than or equal | 8644 | @brief comparison: less than or equal |
| 7136 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8645 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7137 | */ | 8646 | */ |
| 7138 | bool operator<=(const const_iterator& other) const | 8647 | bool operator<=(const iter_impl& other) const |
| 7139 | { | 8648 | { |
| 7140 | return not other.operator < (*this); | 8649 | return not other.operator < (*this); |
| 7141 | } | 8650 | } |
| @@ -7144,7 +8653,7 @@ class basic_json | |||
| 7144 | @brief comparison: greater than | 8653 | @brief comparison: greater than |
| 7145 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8654 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7146 | */ | 8655 | */ |
| 7147 | bool operator>(const const_iterator& other) const | 8656 | bool operator>(const iter_impl& other) const |
| 7148 | { | 8657 | { |
| 7149 | return not operator<=(other); | 8658 | return not operator<=(other); |
| 7150 | } | 8659 | } |
| @@ -7153,7 +8662,7 @@ class basic_json | |||
| 7153 | @brief comparison: greater than or equal | 8662 | @brief comparison: greater than or equal |
| 7154 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8663 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7155 | */ | 8664 | */ |
| 7156 | bool operator>=(const const_iterator& other) const | 8665 | bool operator>=(const iter_impl& other) const |
| 7157 | { | 8666 | { |
| 7158 | return not operator<(other); | 8667 | return not operator<(other); |
| 7159 | } | 8668 | } |
| @@ -7162,7 +8671,7 @@ class basic_json | |||
| 7162 | @brief add to iterator | 8671 | @brief add to iterator |
| 7163 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8672 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7164 | */ | 8673 | */ |
| 7165 | const_iterator& operator+=(difference_type i) | 8674 | iter_impl& operator+=(difference_type i) |
| 7166 | { | 8675 | { |
| 7167 | assert(m_object != nullptr); | 8676 | assert(m_object != nullptr); |
| 7168 | 8677 | ||
| @@ -7193,7 +8702,7 @@ class basic_json | |||
| 7193 | @brief subtract from iterator | 8702 | @brief subtract from iterator |
| 7194 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8703 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7195 | */ | 8704 | */ |
| 7196 | const_iterator& operator-=(difference_type i) | 8705 | iter_impl& operator-=(difference_type i) |
| 7197 | { | 8706 | { |
| 7198 | return operator+=(-i); | 8707 | return operator+=(-i); |
| 7199 | } | 8708 | } |
| @@ -7202,7 +8711,7 @@ class basic_json | |||
| 7202 | @brief add to iterator | 8711 | @brief add to iterator |
| 7203 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8712 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7204 | */ | 8713 | */ |
| 7205 | const_iterator operator+(difference_type i) | 8714 | iter_impl operator+(difference_type i) |
| 7206 | { | 8715 | { |
| 7207 | auto result = *this; | 8716 | auto result = *this; |
| 7208 | result += i; | 8717 | result += i; |
| @@ -7213,7 +8722,7 @@ class basic_json | |||
| 7213 | @brief subtract from iterator | 8722 | @brief subtract from iterator |
| 7214 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8723 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7215 | */ | 8724 | */ |
| 7216 | const_iterator operator-(difference_type i) | 8725 | iter_impl operator-(difference_type i) |
| 7217 | { | 8726 | { |
| 7218 | auto result = *this; | 8727 | auto result = *this; |
| 7219 | result -= i; | 8728 | result -= i; |
| @@ -7224,7 +8733,7 @@ class basic_json | |||
| 7224 | @brief return difference | 8733 | @brief return difference |
| 7225 | @pre The iterator is initialized; i.e. `m_object != nullptr`. | 8734 | @pre The iterator is initialized; i.e. `m_object != nullptr`. |
| 7226 | */ | 8735 | */ |
| 7227 | difference_type operator-(const const_iterator& other) const | 8736 | difference_type operator-(const iter_impl& other) const |
| 7228 | { | 8737 | { |
| 7229 | assert(m_object != nullptr); | 8738 | assert(m_object != nullptr); |
| 7230 | 8739 | ||
| @@ -7321,141 +8830,6 @@ class basic_json | |||
| 7321 | }; | 8830 | }; |
| 7322 | 8831 | ||
| 7323 | /*! | 8832 | /*! |
| 7324 | @brief a mutable random access iterator for the @ref basic_json class | ||
| 7325 | |||
| 7326 | @requirement The class satisfies the following concept requirements: | ||
| 7327 | - [RandomAccessIterator](http://en.cppreference.com/w/cpp/concept/RandomAccessIterator): | ||
| 7328 | The iterator that can be moved to point (forward and backward) to any | ||
| 7329 | element in constant time. | ||
| 7330 | - [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): | ||
| 7331 | It is possible to write to the pointed-to element. | ||
| 7332 | |||
| 7333 | @since version 1.0.0 | ||
| 7334 | */ | ||
| 7335 | class iterator : public const_iterator | ||
| 7336 | { | ||
| 7337 | public: | ||
| 7338 | using base_iterator = const_iterator; | ||
| 7339 | using pointer = typename basic_json::pointer; | ||
| 7340 | using reference = typename basic_json::reference; | ||
| 7341 | |||
| 7342 | /// default constructor | ||
| 7343 | iterator() = default; | ||
| 7344 | |||
| 7345 | /// constructor for a given JSON instance | ||
| 7346 | explicit iterator(pointer object) noexcept | ||
| 7347 | : base_iterator(object) | ||
| 7348 | {} | ||
| 7349 | |||
| 7350 | /// copy constructor | ||
| 7351 | iterator(const iterator& other) noexcept | ||
| 7352 | : base_iterator(other) | ||
| 7353 | {} | ||
| 7354 | |||
| 7355 | /// copy assignment | ||
| 7356 | iterator& operator=(iterator other) noexcept( | ||
| 7357 | std::is_nothrow_move_constructible<pointer>::value and | ||
| 7358 | std::is_nothrow_move_assignable<pointer>::value and | ||
| 7359 | std::is_nothrow_move_constructible<internal_iterator>::value and | ||
| 7360 | std::is_nothrow_move_assignable<internal_iterator>::value | ||
| 7361 | ) | ||
| 7362 | { | ||
| 7363 | base_iterator::operator=(other); | ||
| 7364 | return *this; | ||
| 7365 | } | ||
| 7366 | |||
| 7367 | /// return a reference to the value pointed to by the iterator | ||
| 7368 | reference operator*() const | ||
| 7369 | { | ||
| 7370 | return const_cast<reference>(base_iterator::operator*()); | ||
| 7371 | } | ||
| 7372 | |||
| 7373 | /// dereference the iterator | ||
| 7374 | pointer operator->() const | ||
| 7375 | { | ||
| 7376 | return const_cast<pointer>(base_iterator::operator->()); | ||
| 7377 | } | ||
| 7378 | |||
| 7379 | /// post-increment (it++) | ||
| 7380 | iterator operator++(int) | ||
| 7381 | { | ||
| 7382 | iterator result = *this; | ||
| 7383 | base_iterator::operator++(); | ||
| 7384 | return result; | ||
| 7385 | } | ||
| 7386 | |||
| 7387 | /// pre-increment (++it) | ||
| 7388 | iterator& operator++() | ||
| 7389 | { | ||
| 7390 | base_iterator::operator++(); | ||
| 7391 | return *this; | ||
| 7392 | } | ||
| 7393 | |||
| 7394 | /// post-decrement (it--) | ||
| 7395 | iterator operator--(int) | ||
| 7396 | { | ||
| 7397 | iterator result = *this; | ||
| 7398 | base_iterator::operator--(); | ||
| 7399 | return result; | ||
| 7400 | } | ||
| 7401 | |||
| 7402 | /// pre-decrement (--it) | ||
| 7403 | iterator& operator--() | ||
| 7404 | { | ||
| 7405 | base_iterator::operator--(); | ||
| 7406 | return *this; | ||
| 7407 | } | ||
| 7408 | |||
| 7409 | /// add to iterator | ||
| 7410 | iterator& operator+=(difference_type i) | ||
| 7411 | { | ||
| 7412 | base_iterator::operator+=(i); | ||
| 7413 | return *this; | ||
| 7414 | } | ||
| 7415 | |||
| 7416 | /// subtract from iterator | ||
| 7417 | iterator& operator-=(difference_type i) | ||
| 7418 | { | ||
| 7419 | base_iterator::operator-=(i); | ||
| 7420 | return *this; | ||
| 7421 | } | ||
| 7422 | |||
| 7423 | /// add to iterator | ||
| 7424 | iterator operator+(difference_type i) | ||
| 7425 | { | ||
| 7426 | auto result = *this; | ||
| 7427 | result += i; | ||
| 7428 | return result; | ||
| 7429 | } | ||
| 7430 | |||
| 7431 | /// subtract from iterator | ||
| 7432 | iterator operator-(difference_type i) | ||
| 7433 | { | ||
| 7434 | auto result = *this; | ||
| 7435 | result -= i; | ||
| 7436 | return result; | ||
| 7437 | } | ||
| 7438 | |||
| 7439 | /// return difference | ||
| 7440 | difference_type operator-(const iterator& other) const | ||
| 7441 | { | ||
| 7442 | return base_iterator::operator-(other); | ||
| 7443 | } | ||
| 7444 | |||
| 7445 | /// access to successor | ||
| 7446 | reference operator[](difference_type n) const | ||
| 7447 | { | ||
| 7448 | return const_cast<reference>(base_iterator::operator[](n)); | ||
| 7449 | } | ||
| 7450 | |||
| 7451 | /// return the value of an iterator | ||
| 7452 | reference value() const | ||
| 7453 | { | ||
| 7454 | return const_cast<reference>(base_iterator::value()); | ||
| 7455 | } | ||
| 7456 | }; | ||
| 7457 | |||
| 7458 | /*! | ||
| 7459 | @brief a template for a reverse iterator class | 8833 | @brief a template for a reverse iterator class |
| 7460 | 8834 | ||
| 7461 | @tparam Base the base iterator type to reverse. Valid types are @ref | 8835 | @tparam Base the base iterator type to reverse. Valid types are @ref |
| @@ -7618,6 +8992,12 @@ class basic_json | |||
| 7618 | explicit lexer(std::istream& s) | 8992 | explicit lexer(std::istream& s) |
| 7619 | : m_stream(&s), m_line_buffer() | 8993 | : m_stream(&s), m_line_buffer() |
| 7620 | { | 8994 | { |
| 8995 | // immediately abort if stream is erroneous | ||
| 8996 | if (s.fail()) | ||
| 8997 | { | ||
| 8998 | throw std::invalid_argument("stream error: " + std::string(strerror(errno))); | ||
| 8999 | } | ||
| 9000 | |||
| 7621 | // fill buffer | 9001 | // fill buffer |
| 7622 | fill_line_buffer(); | 9002 | fill_line_buffer(); |
| 7623 | 9003 | ||
| @@ -8740,8 +10120,22 @@ basic_json_parser_66: | |||
| 8740 | */ | 10120 | */ |
| 8741 | void fill_line_buffer(size_t n = 0) | 10121 | void fill_line_buffer(size_t n = 0) |
| 8742 | { | 10122 | { |
| 10123 | // if line buffer is used, m_content points to its data | ||
| 10124 | assert(m_line_buffer.empty() | ||
| 10125 | or m_content == reinterpret_cast<const lexer_char_t*>(m_line_buffer.data())); | ||
| 10126 | |||
| 10127 | // if line buffer is used, m_limit is set past the end of its data | ||
| 10128 | assert(m_line_buffer.empty() | ||
| 10129 | or m_limit == m_content + m_line_buffer.size()); | ||
| 10130 | |||
| 10131 | // pointer relationships | ||
| 10132 | assert(m_content <= m_start); | ||
| 10133 | assert(m_start <= m_cursor); | ||
| 10134 | assert(m_cursor <= m_limit); | ||
| 10135 | assert(m_marker == nullptr or m_marker <= m_limit); | ||
| 10136 | |||
| 8743 | // number of processed characters (p) | 10137 | // number of processed characters (p) |
| 8744 | const auto offset_start = m_start - m_content; | 10138 | const size_t num_processed_chars = static_cast<size_t>(m_start - m_content); |
| 8745 | // offset for m_marker wrt. to m_start | 10139 | // offset for m_marker wrt. to m_start |
| 8746 | const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start; | 10140 | const auto offset_marker = (m_marker == nullptr) ? 0 : m_marker - m_start; |
| 8747 | // number of unprocessed characters (u) | 10141 | // number of unprocessed characters (u) |
| @@ -8750,35 +10144,34 @@ basic_json_parser_66: | |||
| 8750 | // no stream is used or end of file is reached | 10144 | // no stream is used or end of file is reached |
| 8751 | if (m_stream == nullptr or m_stream->eof()) | 10145 | if (m_stream == nullptr or m_stream->eof()) |
| 8752 | { | 10146 | { |
| 8753 | // skip this part if we are already using the line buffer | 10147 | // m_start may or may not be pointing into m_line_buffer at |
| 8754 | if (m_start != reinterpret_cast<const lexer_char_t*>(m_line_buffer.data())) | 10148 | // this point. We trust the standand library to do the right |
| 8755 | { | 10149 | // thing. See http://stackoverflow.com/q/28142011/266378 |
| 8756 | // copy unprocessed characters to line buffer | 10150 | m_line_buffer.assign(m_start, m_limit); |
| 8757 | m_line_buffer.clear(); | ||
| 8758 | for (m_cursor = m_start; m_cursor != m_limit; ++m_cursor) | ||
| 8759 | { | ||
| 8760 | m_line_buffer.append(1, static_cast<const char>(*m_cursor)); | ||
| 8761 | } | ||
| 8762 | } | ||
| 8763 | 10151 | ||
| 8764 | // append n characters to make sure that there is sufficient | 10152 | // append n characters to make sure that there is sufficient |
| 8765 | // space between m_cursor and m_limit | 10153 | // space between m_cursor and m_limit |
| 8766 | m_line_buffer.append(1, '\x00'); | 10154 | m_line_buffer.append(1, '\x00'); |
| 8767 | m_line_buffer.append(n - 1, '\x01'); | 10155 | if (n > 0) |
| 10156 | { | ||
| 10157 | m_line_buffer.append(n - 1, '\x01'); | ||
| 10158 | } | ||
| 8768 | } | 10159 | } |
| 8769 | else | 10160 | else |
| 8770 | { | 10161 | { |
| 8771 | // delete processed characters from line buffer | 10162 | // delete processed characters from line buffer |
| 8772 | m_line_buffer.erase(0, static_cast<size_t>(offset_start)); | 10163 | m_line_buffer.erase(0, num_processed_chars); |
| 8773 | // read next line from input stream | 10164 | // read next line from input stream |
| 8774 | std::string line; | 10165 | m_line_buffer_tmp.clear(); |
| 8775 | std::getline(*m_stream, line, '\n'); | 10166 | std::getline(*m_stream, m_line_buffer_tmp, '\n'); |
| 10167 | |||
| 8776 | // add line with newline symbol to the line buffer | 10168 | // add line with newline symbol to the line buffer |
| 8777 | m_line_buffer += line + "\n"; | 10169 | m_line_buffer += m_line_buffer_tmp; |
| 10170 | m_line_buffer.push_back('\n'); | ||
| 8778 | } | 10171 | } |
| 8779 | 10172 | ||
| 8780 | // set pointers | 10173 | // set pointers |
| 8781 | m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.c_str()); | 10174 | m_content = reinterpret_cast<const lexer_char_t*>(m_line_buffer.data()); |
| 8782 | assert(m_content != nullptr); | 10175 | assert(m_content != nullptr); |
| 8783 | m_start = m_content; | 10176 | m_start = m_content; |
| 8784 | m_marker = m_start + offset_marker; | 10177 | m_marker = m_start + offset_marker; |
| @@ -8861,9 +10254,20 @@ basic_json_parser_66: | |||
| 8861 | // iterate the result between the quotes | 10254 | // iterate the result between the quotes |
| 8862 | for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) | 10255 | for (const lexer_char_t* i = m_start + 1; i < m_cursor - 1; ++i) |
| 8863 | { | 10256 | { |
| 8864 | // process escaped characters | 10257 | // find next escape character |
| 8865 | if (*i == '\\') | 10258 | auto e = std::find(i, m_cursor - 1, '\\'); |
| 10259 | if (e != i) | ||
| 10260 | { | ||
| 10261 | // see https://github.com/nlohmann/json/issues/365#issuecomment-262874705 | ||
| 10262 | for (auto k = i; k < e; k++) | ||
| 10263 | { | ||
| 10264 | result.push_back(static_cast<typename string_t::value_type>(*k)); | ||
| 10265 | } | ||
| 10266 | i = e - 1; // -1 because of ++i | ||
| 10267 | } | ||
| 10268 | else | ||
| 8866 | { | 10269 | { |
| 10270 | // processing escaped character | ||
| 8867 | // read next character | 10271 | // read next character |
| 8868 | ++i; | 10272 | ++i; |
| 8869 | 10273 | ||
| @@ -8950,12 +10354,6 @@ basic_json_parser_66: | |||
| 8950 | } | 10354 | } |
| 8951 | } | 10355 | } |
| 8952 | } | 10356 | } |
| 8953 | else | ||
| 8954 | { | ||
| 8955 | // all other characters are just copied to the end of the | ||
| 8956 | // string | ||
| 8957 | result.append(1, static_cast<typename string_t::value_type>(*i)); | ||
| 8958 | } | ||
| 8959 | } | 10357 | } |
| 8960 | 10358 | ||
| 8961 | return result; | 10359 | return result; |
| @@ -8969,8 +10367,6 @@ basic_json_parser_66: | |||
| 8969 | supplied via the first parameter. Set this to @a | 10367 | supplied via the first parameter. Set this to @a |
| 8970 | static_cast<number_float_t*>(nullptr). | 10368 | static_cast<number_float_t*>(nullptr). |
| 8971 | 10369 | ||
| 8972 | @param[in] type the @ref number_float_t in use | ||
| 8973 | |||
| 8974 | @param[in,out] endptr recieves a pointer to the first character after | 10370 | @param[in,out] endptr recieves a pointer to the first character after |
| 8975 | the number | 10371 | the number |
| 8976 | 10372 | ||
| @@ -8989,8 +10385,6 @@ basic_json_parser_66: | |||
| 8989 | supplied via the first parameter. Set this to @a | 10385 | supplied via the first parameter. Set this to @a |
| 8990 | static_cast<number_float_t*>(nullptr). | 10386 | static_cast<number_float_t*>(nullptr). |
| 8991 | 10387 | ||
| 8992 | @param[in] type the @ref number_float_t in use | ||
| 8993 | |||
| 8994 | @param[in,out] endptr recieves a pointer to the first character after | 10388 | @param[in,out] endptr recieves a pointer to the first character after |
| 8995 | the number | 10389 | the number |
| 8996 | 10390 | ||
| @@ -9009,8 +10403,6 @@ basic_json_parser_66: | |||
| 9009 | supplied via the first parameter. Set this to @a | 10403 | supplied via the first parameter. Set this to @a |
| 9010 | static_cast<number_float_t*>(nullptr). | 10404 | static_cast<number_float_t*>(nullptr). |
| 9011 | 10405 | ||
| 9012 | @param[in] type the @ref number_float_t in use | ||
| 9013 | |||
| 9014 | @param[in,out] endptr recieves a pointer to the first character after | 10406 | @param[in,out] endptr recieves a pointer to the first character after |
| 9015 | the number | 10407 | the number |
| 9016 | 10408 | ||
| @@ -9091,19 +10483,19 @@ basic_json_parser_66: | |||
| 9091 | // skip if definitely not an integer | 10483 | // skip if definitely not an integer |
| 9092 | if (type != value_t::number_float) | 10484 | if (type != value_t::number_float) |
| 9093 | { | 10485 | { |
| 9094 | // multiply last value by ten and add the new digit | 10486 | auto digit = static_cast<number_unsigned_t>(*curptr - '0'); |
| 9095 | auto temp = value * 10 + *curptr - '0'; | ||
| 9096 | 10487 | ||
| 9097 | // test for overflow | 10488 | // overflow if value * 10 + digit > max, move terms around |
| 9098 | if (temp < value || temp > max) | 10489 | // to avoid overflow in intermediate values |
| 10490 | if (value > (max - digit) / 10) | ||
| 9099 | { | 10491 | { |
| 9100 | // overflow | 10492 | // overflow |
| 9101 | type = value_t::number_float; | 10493 | type = value_t::number_float; |
| 9102 | } | 10494 | } |
| 9103 | else | 10495 | else |
| 9104 | { | 10496 | { |
| 9105 | // no overflow - save it | 10497 | // no overflow |
| 9106 | value = temp; | 10498 | value = value * 10 + digit; |
| 9107 | } | 10499 | } |
| 9108 | } | 10500 | } |
| 9109 | } | 10501 | } |
| @@ -9115,7 +10507,22 @@ basic_json_parser_66: | |||
| 9115 | } | 10507 | } |
| 9116 | else if (type == value_t::number_integer) | 10508 | else if (type == value_t::number_integer) |
| 9117 | { | 10509 | { |
| 9118 | result.m_value.number_integer = -static_cast<number_integer_t>(value); | 10510 | // invariant: if we parsed a '-', the absolute value is between |
| 10511 | // 0 (we allow -0) and max == -INT64_MIN | ||
| 10512 | assert(value >= 0); | ||
| 10513 | assert(value <= max); | ||
| 10514 | |||
| 10515 | if (value == max) | ||
| 10516 | { | ||
| 10517 | // we cannot simply negate value (== max == -INT64_MIN), | ||
| 10518 | // see https://github.com/nlohmann/json/issues/389 | ||
| 10519 | result.m_value.number_integer = static_cast<number_integer_t>(INT64_MIN); | ||
| 10520 | } | ||
| 10521 | else | ||
| 10522 | { | ||
| 10523 | // all other values can be negated safely | ||
| 10524 | result.m_value.number_integer = -static_cast<number_integer_t>(value); | ||
| 10525 | } | ||
| 9119 | } | 10526 | } |
| 9120 | else | 10527 | else |
| 9121 | { | 10528 | { |
| @@ -9139,6 +10546,8 @@ basic_json_parser_66: | |||
| 9139 | std::istream* m_stream = nullptr; | 10546 | std::istream* m_stream = nullptr; |
| 9140 | /// line buffer buffer for m_stream | 10547 | /// line buffer buffer for m_stream |
| 9141 | string_t m_line_buffer {}; | 10548 | string_t m_line_buffer {}; |
| 10549 | /// used for filling m_line_buffer | ||
| 10550 | string_t m_line_buffer_tmp {}; | ||
| 9142 | /// the buffer pointer | 10551 | /// the buffer pointer |
| 9143 | const lexer_char_t* m_content = nullptr; | 10552 | const lexer_char_t* m_content = nullptr; |
| 9144 | /// pointer to the beginning of the current symbol | 10553 | /// pointer to the beginning of the current symbol |
| @@ -9164,7 +10573,7 @@ basic_json_parser_66: | |||
| 9164 | /// a parser reading from a string literal | 10573 | /// a parser reading from a string literal |
| 9165 | parser(const char* buff, const parser_callback_t cb = nullptr) | 10574 | parser(const char* buff, const parser_callback_t cb = nullptr) |
| 9166 | : callback(cb), | 10575 | : callback(cb), |
| 9167 | m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), strlen(buff)) | 10576 | m_lexer(reinterpret_cast<const typename lexer::lexer_char_t*>(buff), std::strlen(buff)) |
| 9168 | {} | 10577 | {} |
| 9169 | 10578 | ||
| 9170 | /// a parser reading from an input stream | 10579 | /// a parser reading from an input stream |
| @@ -9896,13 +11305,11 @@ basic_json_parser_66: | |||
| 9896 | /*! | 11305 | /*! |
| 9897 | @brief replace all occurrences of a substring by another string | 11306 | @brief replace all occurrences of a substring by another string |
| 9898 | 11307 | ||
| 9899 | @param[in,out] s the string to manipulate | 11308 | @param[in,out] s the string to manipulate; changed so that all |
| 11309 | occurrences of @a f are replaced with @a t | ||
| 9900 | @param[in] f the substring to replace with @a t | 11310 | @param[in] f the substring to replace with @a t |
| 9901 | @param[in] t the string to replace @a f | 11311 | @param[in] t the string to replace @a f |
| 9902 | 11312 | ||
| 9903 | @return The string @a s where all occurrences of @a f are replaced | ||
| 9904 | with @a t. | ||
| 9905 | |||
| 9906 | @pre The search string @a f must not be empty. | 11313 | @pre The search string @a f must not be empty. |
| 9907 | 11314 | ||
| 9908 | @since version 2.0.0 | 11315 | @since version 2.0.0 |
