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/json | |
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/json')
-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 |