1c5f01b2fSopenharmony_ci// __ _____ _____ _____ 2c5f01b2fSopenharmony_ci// __| | __| | | | JSON for Modern C++ 3c5f01b2fSopenharmony_ci// | | |__ | | | | | | version 3.11.2 4c5f01b2fSopenharmony_ci// |_____|_____|_____|_|___| https://github.com/nlohmann/json 5c5f01b2fSopenharmony_ci// 6c5f01b2fSopenharmony_ci// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de> 7c5f01b2fSopenharmony_ci// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me> 8c5f01b2fSopenharmony_ci// SPDX-License-Identifier: MIT 9c5f01b2fSopenharmony_ci 10c5f01b2fSopenharmony_ci#pragma once 11c5f01b2fSopenharmony_ci 12c5f01b2fSopenharmony_ci#include <algorithm> // reverse, remove, fill, find, none_of 13c5f01b2fSopenharmony_ci#include <array> // array 14c5f01b2fSopenharmony_ci#include <clocale> // localeconv, lconv 15c5f01b2fSopenharmony_ci#include <cmath> // labs, isfinite, isnan, signbit 16c5f01b2fSopenharmony_ci#include <cstddef> // size_t, ptrdiff_t 17c5f01b2fSopenharmony_ci#include <cstdint> // uint8_t 18c5f01b2fSopenharmony_ci#include <cstdio> // snprintf 19c5f01b2fSopenharmony_ci#include <limits> // numeric_limits 20c5f01b2fSopenharmony_ci#include <string> // string, char_traits 21c5f01b2fSopenharmony_ci#include <iomanip> // setfill, setw 22c5f01b2fSopenharmony_ci#include <type_traits> // is_same 23c5f01b2fSopenharmony_ci#include <utility> // move 24c5f01b2fSopenharmony_ci 25c5f01b2fSopenharmony_ci#include <nlohmann/detail/conversions/to_chars.hpp> 26c5f01b2fSopenharmony_ci#include <nlohmann/detail/exceptions.hpp> 27c5f01b2fSopenharmony_ci#include <nlohmann/detail/macro_scope.hpp> 28c5f01b2fSopenharmony_ci#include <nlohmann/detail/meta/cpp_future.hpp> 29c5f01b2fSopenharmony_ci#include <nlohmann/detail/output/binary_writer.hpp> 30c5f01b2fSopenharmony_ci#include <nlohmann/detail/output/output_adapters.hpp> 31c5f01b2fSopenharmony_ci#include <nlohmann/detail/string_concat.hpp> 32c5f01b2fSopenharmony_ci#include <nlohmann/detail/value_t.hpp> 33c5f01b2fSopenharmony_ci 34c5f01b2fSopenharmony_ciNLOHMANN_JSON_NAMESPACE_BEGIN 35c5f01b2fSopenharmony_cinamespace detail 36c5f01b2fSopenharmony_ci{ 37c5f01b2fSopenharmony_ci 38c5f01b2fSopenharmony_ci/////////////////// 39c5f01b2fSopenharmony_ci// serialization // 40c5f01b2fSopenharmony_ci/////////////////// 41c5f01b2fSopenharmony_ci 42c5f01b2fSopenharmony_ci/// how to treat decoding errors 43c5f01b2fSopenharmony_cienum class error_handler_t 44c5f01b2fSopenharmony_ci{ 45c5f01b2fSopenharmony_ci strict, ///< throw a type_error exception in case of invalid UTF-8 46c5f01b2fSopenharmony_ci replace, ///< replace invalid UTF-8 sequences with U+FFFD 47c5f01b2fSopenharmony_ci ignore ///< ignore invalid UTF-8 sequences 48c5f01b2fSopenharmony_ci}; 49c5f01b2fSopenharmony_ci 50c5f01b2fSopenharmony_citemplate<typename BasicJsonType> 51c5f01b2fSopenharmony_ciclass serializer 52c5f01b2fSopenharmony_ci{ 53c5f01b2fSopenharmony_ci using string_t = typename BasicJsonType::string_t; 54c5f01b2fSopenharmony_ci using number_float_t = typename BasicJsonType::number_float_t; 55c5f01b2fSopenharmony_ci using number_integer_t = typename BasicJsonType::number_integer_t; 56c5f01b2fSopenharmony_ci using number_unsigned_t = typename BasicJsonType::number_unsigned_t; 57c5f01b2fSopenharmony_ci using binary_char_t = typename BasicJsonType::binary_t::value_type; 58c5f01b2fSopenharmony_ci static constexpr std::uint8_t UTF8_ACCEPT = 0; 59c5f01b2fSopenharmony_ci static constexpr std::uint8_t UTF8_REJECT = 1; 60c5f01b2fSopenharmony_ci 61c5f01b2fSopenharmony_ci public: 62c5f01b2fSopenharmony_ci /*! 63c5f01b2fSopenharmony_ci @param[in] s output stream to serialize to 64c5f01b2fSopenharmony_ci @param[in] ichar indentation character to use 65c5f01b2fSopenharmony_ci @param[in] error_handler_ how to react on decoding errors 66c5f01b2fSopenharmony_ci */ 67c5f01b2fSopenharmony_ci serializer(output_adapter_t<char> s, const char ichar, 68c5f01b2fSopenharmony_ci error_handler_t error_handler_ = error_handler_t::strict) 69c5f01b2fSopenharmony_ci : o(std::move(s)) 70c5f01b2fSopenharmony_ci , loc(std::localeconv()) 71c5f01b2fSopenharmony_ci , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep))) 72c5f01b2fSopenharmony_ci , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point))) 73c5f01b2fSopenharmony_ci , indent_char(ichar) 74c5f01b2fSopenharmony_ci , indent_string(512, indent_char) 75c5f01b2fSopenharmony_ci , error_handler(error_handler_) 76c5f01b2fSopenharmony_ci {} 77c5f01b2fSopenharmony_ci 78c5f01b2fSopenharmony_ci // delete because of pointer members 79c5f01b2fSopenharmony_ci serializer(const serializer&) = delete; 80c5f01b2fSopenharmony_ci serializer& operator=(const serializer&) = delete; 81c5f01b2fSopenharmony_ci serializer(serializer&&) = delete; 82c5f01b2fSopenharmony_ci serializer& operator=(serializer&&) = delete; 83c5f01b2fSopenharmony_ci ~serializer() = default; 84c5f01b2fSopenharmony_ci 85c5f01b2fSopenharmony_ci /*! 86c5f01b2fSopenharmony_ci @brief internal implementation of the serialization function 87c5f01b2fSopenharmony_ci 88c5f01b2fSopenharmony_ci This function is called by the public member function dump and organizes 89c5f01b2fSopenharmony_ci the serialization internally. The indentation level is propagated as 90c5f01b2fSopenharmony_ci additional parameter. In case of arrays and objects, the function is 91c5f01b2fSopenharmony_ci called recursively. 92c5f01b2fSopenharmony_ci 93c5f01b2fSopenharmony_ci - strings and object keys are escaped using `escape_string()` 94c5f01b2fSopenharmony_ci - integer numbers are converted implicitly via `operator<<` 95c5f01b2fSopenharmony_ci - floating-point numbers are converted to a string using `"%g"` format 96c5f01b2fSopenharmony_ci - binary values are serialized as objects containing the subtype and the 97c5f01b2fSopenharmony_ci byte array 98c5f01b2fSopenharmony_ci 99c5f01b2fSopenharmony_ci @param[in] val value to serialize 100c5f01b2fSopenharmony_ci @param[in] pretty_print whether the output shall be pretty-printed 101c5f01b2fSopenharmony_ci @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters 102c5f01b2fSopenharmony_ci in the output are escaped with `\uXXXX` sequences, and the result consists 103c5f01b2fSopenharmony_ci of ASCII characters only. 104c5f01b2fSopenharmony_ci @param[in] indent_step the indent level 105c5f01b2fSopenharmony_ci @param[in] current_indent the current indent level (only used internally) 106c5f01b2fSopenharmony_ci */ 107c5f01b2fSopenharmony_ci void dump(const BasicJsonType& val, 108c5f01b2fSopenharmony_ci const bool pretty_print, 109c5f01b2fSopenharmony_ci const bool ensure_ascii, 110c5f01b2fSopenharmony_ci const unsigned int indent_step, 111c5f01b2fSopenharmony_ci const unsigned int current_indent = 0) 112c5f01b2fSopenharmony_ci { 113c5f01b2fSopenharmony_ci switch (val.m_type) 114c5f01b2fSopenharmony_ci { 115c5f01b2fSopenharmony_ci case value_t::object: 116c5f01b2fSopenharmony_ci { 117c5f01b2fSopenharmony_ci if (val.m_value.object->empty()) 118c5f01b2fSopenharmony_ci { 119c5f01b2fSopenharmony_ci o->write_characters("{}", 2); 120c5f01b2fSopenharmony_ci return; 121c5f01b2fSopenharmony_ci } 122c5f01b2fSopenharmony_ci 123c5f01b2fSopenharmony_ci if (pretty_print) 124c5f01b2fSopenharmony_ci { 125c5f01b2fSopenharmony_ci o->write_characters("{\n", 2); 126c5f01b2fSopenharmony_ci 127c5f01b2fSopenharmony_ci // variable to hold indentation for recursive calls 128c5f01b2fSopenharmony_ci const auto new_indent = current_indent + indent_step; 129c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) 130c5f01b2fSopenharmony_ci { 131c5f01b2fSopenharmony_ci indent_string.resize(indent_string.size() * 2, ' '); 132c5f01b2fSopenharmony_ci } 133c5f01b2fSopenharmony_ci 134c5f01b2fSopenharmony_ci // first n-1 elements 135c5f01b2fSopenharmony_ci auto i = val.m_value.object->cbegin(); 136c5f01b2fSopenharmony_ci for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) 137c5f01b2fSopenharmony_ci { 138c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), new_indent); 139c5f01b2fSopenharmony_ci o->write_character('\"'); 140c5f01b2fSopenharmony_ci dump_escaped(i->first, ensure_ascii); 141c5f01b2fSopenharmony_ci o->write_characters("\": ", 3); 142c5f01b2fSopenharmony_ci dump(i->second, true, ensure_ascii, indent_step, new_indent); 143c5f01b2fSopenharmony_ci o->write_characters(",\n", 2); 144c5f01b2fSopenharmony_ci } 145c5f01b2fSopenharmony_ci 146c5f01b2fSopenharmony_ci // last element 147c5f01b2fSopenharmony_ci JSON_ASSERT(i != val.m_value.object->cend()); 148c5f01b2fSopenharmony_ci JSON_ASSERT(std::next(i) == val.m_value.object->cend()); 149c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), new_indent); 150c5f01b2fSopenharmony_ci o->write_character('\"'); 151c5f01b2fSopenharmony_ci dump_escaped(i->first, ensure_ascii); 152c5f01b2fSopenharmony_ci o->write_characters("\": ", 3); 153c5f01b2fSopenharmony_ci dump(i->second, true, ensure_ascii, indent_step, new_indent); 154c5f01b2fSopenharmony_ci 155c5f01b2fSopenharmony_ci o->write_character('\n'); 156c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), current_indent); 157c5f01b2fSopenharmony_ci o->write_character('}'); 158c5f01b2fSopenharmony_ci } 159c5f01b2fSopenharmony_ci else 160c5f01b2fSopenharmony_ci { 161c5f01b2fSopenharmony_ci o->write_character('{'); 162c5f01b2fSopenharmony_ci 163c5f01b2fSopenharmony_ci // first n-1 elements 164c5f01b2fSopenharmony_ci auto i = val.m_value.object->cbegin(); 165c5f01b2fSopenharmony_ci for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) 166c5f01b2fSopenharmony_ci { 167c5f01b2fSopenharmony_ci o->write_character('\"'); 168c5f01b2fSopenharmony_ci dump_escaped(i->first, ensure_ascii); 169c5f01b2fSopenharmony_ci o->write_characters("\":", 2); 170c5f01b2fSopenharmony_ci dump(i->second, false, ensure_ascii, indent_step, current_indent); 171c5f01b2fSopenharmony_ci o->write_character(','); 172c5f01b2fSopenharmony_ci } 173c5f01b2fSopenharmony_ci 174c5f01b2fSopenharmony_ci // last element 175c5f01b2fSopenharmony_ci JSON_ASSERT(i != val.m_value.object->cend()); 176c5f01b2fSopenharmony_ci JSON_ASSERT(std::next(i) == val.m_value.object->cend()); 177c5f01b2fSopenharmony_ci o->write_character('\"'); 178c5f01b2fSopenharmony_ci dump_escaped(i->first, ensure_ascii); 179c5f01b2fSopenharmony_ci o->write_characters("\":", 2); 180c5f01b2fSopenharmony_ci dump(i->second, false, ensure_ascii, indent_step, current_indent); 181c5f01b2fSopenharmony_ci 182c5f01b2fSopenharmony_ci o->write_character('}'); 183c5f01b2fSopenharmony_ci } 184c5f01b2fSopenharmony_ci 185c5f01b2fSopenharmony_ci return; 186c5f01b2fSopenharmony_ci } 187c5f01b2fSopenharmony_ci 188c5f01b2fSopenharmony_ci case value_t::array: 189c5f01b2fSopenharmony_ci { 190c5f01b2fSopenharmony_ci if (val.m_value.array->empty()) 191c5f01b2fSopenharmony_ci { 192c5f01b2fSopenharmony_ci o->write_characters("[]", 2); 193c5f01b2fSopenharmony_ci return; 194c5f01b2fSopenharmony_ci } 195c5f01b2fSopenharmony_ci 196c5f01b2fSopenharmony_ci if (pretty_print) 197c5f01b2fSopenharmony_ci { 198c5f01b2fSopenharmony_ci o->write_characters("[\n", 2); 199c5f01b2fSopenharmony_ci 200c5f01b2fSopenharmony_ci // variable to hold indentation for recursive calls 201c5f01b2fSopenharmony_ci const auto new_indent = current_indent + indent_step; 202c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) 203c5f01b2fSopenharmony_ci { 204c5f01b2fSopenharmony_ci indent_string.resize(indent_string.size() * 2, ' '); 205c5f01b2fSopenharmony_ci } 206c5f01b2fSopenharmony_ci 207c5f01b2fSopenharmony_ci // first n-1 elements 208c5f01b2fSopenharmony_ci for (auto i = val.m_value.array->cbegin(); 209c5f01b2fSopenharmony_ci i != val.m_value.array->cend() - 1; ++i) 210c5f01b2fSopenharmony_ci { 211c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), new_indent); 212c5f01b2fSopenharmony_ci dump(*i, true, ensure_ascii, indent_step, new_indent); 213c5f01b2fSopenharmony_ci o->write_characters(",\n", 2); 214c5f01b2fSopenharmony_ci } 215c5f01b2fSopenharmony_ci 216c5f01b2fSopenharmony_ci // last element 217c5f01b2fSopenharmony_ci JSON_ASSERT(!val.m_value.array->empty()); 218c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), new_indent); 219c5f01b2fSopenharmony_ci dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); 220c5f01b2fSopenharmony_ci 221c5f01b2fSopenharmony_ci o->write_character('\n'); 222c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), current_indent); 223c5f01b2fSopenharmony_ci o->write_character(']'); 224c5f01b2fSopenharmony_ci } 225c5f01b2fSopenharmony_ci else 226c5f01b2fSopenharmony_ci { 227c5f01b2fSopenharmony_ci o->write_character('['); 228c5f01b2fSopenharmony_ci 229c5f01b2fSopenharmony_ci // first n-1 elements 230c5f01b2fSopenharmony_ci for (auto i = val.m_value.array->cbegin(); 231c5f01b2fSopenharmony_ci i != val.m_value.array->cend() - 1; ++i) 232c5f01b2fSopenharmony_ci { 233c5f01b2fSopenharmony_ci dump(*i, false, ensure_ascii, indent_step, current_indent); 234c5f01b2fSopenharmony_ci o->write_character(','); 235c5f01b2fSopenharmony_ci } 236c5f01b2fSopenharmony_ci 237c5f01b2fSopenharmony_ci // last element 238c5f01b2fSopenharmony_ci JSON_ASSERT(!val.m_value.array->empty()); 239c5f01b2fSopenharmony_ci dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); 240c5f01b2fSopenharmony_ci 241c5f01b2fSopenharmony_ci o->write_character(']'); 242c5f01b2fSopenharmony_ci } 243c5f01b2fSopenharmony_ci 244c5f01b2fSopenharmony_ci return; 245c5f01b2fSopenharmony_ci } 246c5f01b2fSopenharmony_ci 247c5f01b2fSopenharmony_ci case value_t::string: 248c5f01b2fSopenharmony_ci { 249c5f01b2fSopenharmony_ci o->write_character('\"'); 250c5f01b2fSopenharmony_ci dump_escaped(*val.m_value.string, ensure_ascii); 251c5f01b2fSopenharmony_ci o->write_character('\"'); 252c5f01b2fSopenharmony_ci return; 253c5f01b2fSopenharmony_ci } 254c5f01b2fSopenharmony_ci 255c5f01b2fSopenharmony_ci case value_t::binary: 256c5f01b2fSopenharmony_ci { 257c5f01b2fSopenharmony_ci if (pretty_print) 258c5f01b2fSopenharmony_ci { 259c5f01b2fSopenharmony_ci o->write_characters("{\n", 2); 260c5f01b2fSopenharmony_ci 261c5f01b2fSopenharmony_ci // variable to hold indentation for recursive calls 262c5f01b2fSopenharmony_ci const auto new_indent = current_indent + indent_step; 263c5f01b2fSopenharmony_ci if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) 264c5f01b2fSopenharmony_ci { 265c5f01b2fSopenharmony_ci indent_string.resize(indent_string.size() * 2, ' '); 266c5f01b2fSopenharmony_ci } 267c5f01b2fSopenharmony_ci 268c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), new_indent); 269c5f01b2fSopenharmony_ci 270c5f01b2fSopenharmony_ci o->write_characters("\"bytes\": [", 10); 271c5f01b2fSopenharmony_ci 272c5f01b2fSopenharmony_ci if (!val.m_value.binary->empty()) 273c5f01b2fSopenharmony_ci { 274c5f01b2fSopenharmony_ci for (auto i = val.m_value.binary->cbegin(); 275c5f01b2fSopenharmony_ci i != val.m_value.binary->cend() - 1; ++i) 276c5f01b2fSopenharmony_ci { 277c5f01b2fSopenharmony_ci dump_integer(*i); 278c5f01b2fSopenharmony_ci o->write_characters(", ", 2); 279c5f01b2fSopenharmony_ci } 280c5f01b2fSopenharmony_ci dump_integer(val.m_value.binary->back()); 281c5f01b2fSopenharmony_ci } 282c5f01b2fSopenharmony_ci 283c5f01b2fSopenharmony_ci o->write_characters("],\n", 3); 284c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), new_indent); 285c5f01b2fSopenharmony_ci 286c5f01b2fSopenharmony_ci o->write_characters("\"subtype\": ", 11); 287c5f01b2fSopenharmony_ci if (val.m_value.binary->has_subtype()) 288c5f01b2fSopenharmony_ci { 289c5f01b2fSopenharmony_ci dump_integer(val.m_value.binary->subtype()); 290c5f01b2fSopenharmony_ci } 291c5f01b2fSopenharmony_ci else 292c5f01b2fSopenharmony_ci { 293c5f01b2fSopenharmony_ci o->write_characters("null", 4); 294c5f01b2fSopenharmony_ci } 295c5f01b2fSopenharmony_ci o->write_character('\n'); 296c5f01b2fSopenharmony_ci o->write_characters(indent_string.c_str(), current_indent); 297c5f01b2fSopenharmony_ci o->write_character('}'); 298c5f01b2fSopenharmony_ci } 299c5f01b2fSopenharmony_ci else 300c5f01b2fSopenharmony_ci { 301c5f01b2fSopenharmony_ci o->write_characters("{\"bytes\":[", 10); 302c5f01b2fSopenharmony_ci 303c5f01b2fSopenharmony_ci if (!val.m_value.binary->empty()) 304c5f01b2fSopenharmony_ci { 305c5f01b2fSopenharmony_ci for (auto i = val.m_value.binary->cbegin(); 306c5f01b2fSopenharmony_ci i != val.m_value.binary->cend() - 1; ++i) 307c5f01b2fSopenharmony_ci { 308c5f01b2fSopenharmony_ci dump_integer(*i); 309c5f01b2fSopenharmony_ci o->write_character(','); 310c5f01b2fSopenharmony_ci } 311c5f01b2fSopenharmony_ci dump_integer(val.m_value.binary->back()); 312c5f01b2fSopenharmony_ci } 313c5f01b2fSopenharmony_ci 314c5f01b2fSopenharmony_ci o->write_characters("],\"subtype\":", 12); 315c5f01b2fSopenharmony_ci if (val.m_value.binary->has_subtype()) 316c5f01b2fSopenharmony_ci { 317c5f01b2fSopenharmony_ci dump_integer(val.m_value.binary->subtype()); 318c5f01b2fSopenharmony_ci o->write_character('}'); 319c5f01b2fSopenharmony_ci } 320c5f01b2fSopenharmony_ci else 321c5f01b2fSopenharmony_ci { 322c5f01b2fSopenharmony_ci o->write_characters("null}", 5); 323c5f01b2fSopenharmony_ci } 324c5f01b2fSopenharmony_ci } 325c5f01b2fSopenharmony_ci return; 326c5f01b2fSopenharmony_ci } 327c5f01b2fSopenharmony_ci 328c5f01b2fSopenharmony_ci case value_t::boolean: 329c5f01b2fSopenharmony_ci { 330c5f01b2fSopenharmony_ci if (val.m_value.boolean) 331c5f01b2fSopenharmony_ci { 332c5f01b2fSopenharmony_ci o->write_characters("true", 4); 333c5f01b2fSopenharmony_ci } 334c5f01b2fSopenharmony_ci else 335c5f01b2fSopenharmony_ci { 336c5f01b2fSopenharmony_ci o->write_characters("false", 5); 337c5f01b2fSopenharmony_ci } 338c5f01b2fSopenharmony_ci return; 339c5f01b2fSopenharmony_ci } 340c5f01b2fSopenharmony_ci 341c5f01b2fSopenharmony_ci case value_t::number_integer: 342c5f01b2fSopenharmony_ci { 343c5f01b2fSopenharmony_ci dump_integer(val.m_value.number_integer); 344c5f01b2fSopenharmony_ci return; 345c5f01b2fSopenharmony_ci } 346c5f01b2fSopenharmony_ci 347c5f01b2fSopenharmony_ci case value_t::number_unsigned: 348c5f01b2fSopenharmony_ci { 349c5f01b2fSopenharmony_ci dump_integer(val.m_value.number_unsigned); 350c5f01b2fSopenharmony_ci return; 351c5f01b2fSopenharmony_ci } 352c5f01b2fSopenharmony_ci 353c5f01b2fSopenharmony_ci case value_t::number_float: 354c5f01b2fSopenharmony_ci { 355c5f01b2fSopenharmony_ci dump_float(val.m_value.number_float); 356c5f01b2fSopenharmony_ci return; 357c5f01b2fSopenharmony_ci } 358c5f01b2fSopenharmony_ci 359c5f01b2fSopenharmony_ci case value_t::discarded: 360c5f01b2fSopenharmony_ci { 361c5f01b2fSopenharmony_ci o->write_characters("<discarded>", 11); 362c5f01b2fSopenharmony_ci return; 363c5f01b2fSopenharmony_ci } 364c5f01b2fSopenharmony_ci 365c5f01b2fSopenharmony_ci case value_t::null: 366c5f01b2fSopenharmony_ci { 367c5f01b2fSopenharmony_ci o->write_characters("null", 4); 368c5f01b2fSopenharmony_ci return; 369c5f01b2fSopenharmony_ci } 370c5f01b2fSopenharmony_ci 371c5f01b2fSopenharmony_ci default: // LCOV_EXCL_LINE 372c5f01b2fSopenharmony_ci JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE 373c5f01b2fSopenharmony_ci } 374c5f01b2fSopenharmony_ci } 375c5f01b2fSopenharmony_ci 376c5f01b2fSopenharmony_ci JSON_PRIVATE_UNLESS_TESTED: 377c5f01b2fSopenharmony_ci /*! 378c5f01b2fSopenharmony_ci @brief dump escaped string 379c5f01b2fSopenharmony_ci 380c5f01b2fSopenharmony_ci Escape a string by replacing certain special characters by a sequence of an 381c5f01b2fSopenharmony_ci escape character (backslash) and another character and other control 382c5f01b2fSopenharmony_ci characters by a sequence of "\u" followed by a four-digit hex 383c5f01b2fSopenharmony_ci representation. The escaped string is written to output stream @a o. 384c5f01b2fSopenharmony_ci 385c5f01b2fSopenharmony_ci @param[in] s the string to escape 386c5f01b2fSopenharmony_ci @param[in] ensure_ascii whether to escape non-ASCII characters with 387c5f01b2fSopenharmony_ci \uXXXX sequences 388c5f01b2fSopenharmony_ci 389c5f01b2fSopenharmony_ci @complexity Linear in the length of string @a s. 390c5f01b2fSopenharmony_ci */ 391c5f01b2fSopenharmony_ci void dump_escaped(const string_t& s, const bool ensure_ascii) 392c5f01b2fSopenharmony_ci { 393c5f01b2fSopenharmony_ci std::uint32_t codepoint{}; 394c5f01b2fSopenharmony_ci std::uint8_t state = UTF8_ACCEPT; 395c5f01b2fSopenharmony_ci std::size_t bytes = 0; // number of bytes written to string_buffer 396c5f01b2fSopenharmony_ci 397c5f01b2fSopenharmony_ci // number of bytes written at the point of the last valid byte 398c5f01b2fSopenharmony_ci std::size_t bytes_after_last_accept = 0; 399c5f01b2fSopenharmony_ci std::size_t undumped_chars = 0; 400c5f01b2fSopenharmony_ci 401c5f01b2fSopenharmony_ci for (std::size_t i = 0; i < s.size(); ++i) 402c5f01b2fSopenharmony_ci { 403c5f01b2fSopenharmony_ci const auto byte = static_cast<std::uint8_t>(s[i]); 404c5f01b2fSopenharmony_ci 405c5f01b2fSopenharmony_ci switch (decode(state, codepoint, byte)) 406c5f01b2fSopenharmony_ci { 407c5f01b2fSopenharmony_ci case UTF8_ACCEPT: // decode found a new code point 408c5f01b2fSopenharmony_ci { 409c5f01b2fSopenharmony_ci switch (codepoint) 410c5f01b2fSopenharmony_ci { 411c5f01b2fSopenharmony_ci case 0x08: // backspace 412c5f01b2fSopenharmony_ci { 413c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 414c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'b'; 415c5f01b2fSopenharmony_ci break; 416c5f01b2fSopenharmony_ci } 417c5f01b2fSopenharmony_ci 418c5f01b2fSopenharmony_ci case 0x09: // horizontal tab 419c5f01b2fSopenharmony_ci { 420c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 421c5f01b2fSopenharmony_ci string_buffer[bytes++] = 't'; 422c5f01b2fSopenharmony_ci break; 423c5f01b2fSopenharmony_ci } 424c5f01b2fSopenharmony_ci 425c5f01b2fSopenharmony_ci case 0x0A: // newline 426c5f01b2fSopenharmony_ci { 427c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 428c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'n'; 429c5f01b2fSopenharmony_ci break; 430c5f01b2fSopenharmony_ci } 431c5f01b2fSopenharmony_ci 432c5f01b2fSopenharmony_ci case 0x0C: // formfeed 433c5f01b2fSopenharmony_ci { 434c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 435c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'f'; 436c5f01b2fSopenharmony_ci break; 437c5f01b2fSopenharmony_ci } 438c5f01b2fSopenharmony_ci 439c5f01b2fSopenharmony_ci case 0x0D: // carriage return 440c5f01b2fSopenharmony_ci { 441c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 442c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'r'; 443c5f01b2fSopenharmony_ci break; 444c5f01b2fSopenharmony_ci } 445c5f01b2fSopenharmony_ci 446c5f01b2fSopenharmony_ci case 0x22: // quotation mark 447c5f01b2fSopenharmony_ci { 448c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 449c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\"'; 450c5f01b2fSopenharmony_ci break; 451c5f01b2fSopenharmony_ci } 452c5f01b2fSopenharmony_ci 453c5f01b2fSopenharmony_ci case 0x5C: // reverse solidus 454c5f01b2fSopenharmony_ci { 455c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 456c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 457c5f01b2fSopenharmony_ci break; 458c5f01b2fSopenharmony_ci } 459c5f01b2fSopenharmony_ci 460c5f01b2fSopenharmony_ci default: 461c5f01b2fSopenharmony_ci { 462c5f01b2fSopenharmony_ci // escape control characters (0x00..0x1F) or, if 463c5f01b2fSopenharmony_ci // ensure_ascii parameter is used, non-ASCII characters 464c5f01b2fSopenharmony_ci if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) 465c5f01b2fSopenharmony_ci { 466c5f01b2fSopenharmony_ci if (codepoint <= 0xFFFF) 467c5f01b2fSopenharmony_ci { 468c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) 469c5f01b2fSopenharmony_ci static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", 470c5f01b2fSopenharmony_ci static_cast<std::uint16_t>(codepoint))); 471c5f01b2fSopenharmony_ci bytes += 6; 472c5f01b2fSopenharmony_ci } 473c5f01b2fSopenharmony_ci else 474c5f01b2fSopenharmony_ci { 475c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) 476c5f01b2fSopenharmony_ci static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", 477c5f01b2fSopenharmony_ci static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)), 478c5f01b2fSopenharmony_ci static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)))); 479c5f01b2fSopenharmony_ci bytes += 12; 480c5f01b2fSopenharmony_ci } 481c5f01b2fSopenharmony_ci } 482c5f01b2fSopenharmony_ci else 483c5f01b2fSopenharmony_ci { 484c5f01b2fSopenharmony_ci // copy byte to buffer (all previous bytes 485c5f01b2fSopenharmony_ci // been copied have in default case above) 486c5f01b2fSopenharmony_ci string_buffer[bytes++] = s[i]; 487c5f01b2fSopenharmony_ci } 488c5f01b2fSopenharmony_ci break; 489c5f01b2fSopenharmony_ci } 490c5f01b2fSopenharmony_ci } 491c5f01b2fSopenharmony_ci 492c5f01b2fSopenharmony_ci // write buffer and reset index; there must be 13 bytes 493c5f01b2fSopenharmony_ci // left, as this is the maximal number of bytes to be 494c5f01b2fSopenharmony_ci // written ("\uxxxx\uxxxx\0") for one code point 495c5f01b2fSopenharmony_ci if (string_buffer.size() - bytes < 13) 496c5f01b2fSopenharmony_ci { 497c5f01b2fSopenharmony_ci o->write_characters(string_buffer.data(), bytes); 498c5f01b2fSopenharmony_ci bytes = 0; 499c5f01b2fSopenharmony_ci } 500c5f01b2fSopenharmony_ci 501c5f01b2fSopenharmony_ci // remember the byte position of this accept 502c5f01b2fSopenharmony_ci bytes_after_last_accept = bytes; 503c5f01b2fSopenharmony_ci undumped_chars = 0; 504c5f01b2fSopenharmony_ci break; 505c5f01b2fSopenharmony_ci } 506c5f01b2fSopenharmony_ci 507c5f01b2fSopenharmony_ci case UTF8_REJECT: // decode found invalid UTF-8 byte 508c5f01b2fSopenharmony_ci { 509c5f01b2fSopenharmony_ci switch (error_handler) 510c5f01b2fSopenharmony_ci { 511c5f01b2fSopenharmony_ci case error_handler_t::strict: 512c5f01b2fSopenharmony_ci { 513c5f01b2fSopenharmony_ci JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr)); 514c5f01b2fSopenharmony_ci } 515c5f01b2fSopenharmony_ci 516c5f01b2fSopenharmony_ci case error_handler_t::ignore: 517c5f01b2fSopenharmony_ci case error_handler_t::replace: 518c5f01b2fSopenharmony_ci { 519c5f01b2fSopenharmony_ci // in case we saw this character the first time, we 520c5f01b2fSopenharmony_ci // would like to read it again, because the byte 521c5f01b2fSopenharmony_ci // may be OK for itself, but just not OK for the 522c5f01b2fSopenharmony_ci // previous sequence 523c5f01b2fSopenharmony_ci if (undumped_chars > 0) 524c5f01b2fSopenharmony_ci { 525c5f01b2fSopenharmony_ci --i; 526c5f01b2fSopenharmony_ci } 527c5f01b2fSopenharmony_ci 528c5f01b2fSopenharmony_ci // reset length buffer to the last accepted index; 529c5f01b2fSopenharmony_ci // thus removing/ignoring the invalid characters 530c5f01b2fSopenharmony_ci bytes = bytes_after_last_accept; 531c5f01b2fSopenharmony_ci 532c5f01b2fSopenharmony_ci if (error_handler == error_handler_t::replace) 533c5f01b2fSopenharmony_ci { 534c5f01b2fSopenharmony_ci // add a replacement character 535c5f01b2fSopenharmony_ci if (ensure_ascii) 536c5f01b2fSopenharmony_ci { 537c5f01b2fSopenharmony_ci string_buffer[bytes++] = '\\'; 538c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'u'; 539c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'f'; 540c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'f'; 541c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'f'; 542c5f01b2fSopenharmony_ci string_buffer[bytes++] = 'd'; 543c5f01b2fSopenharmony_ci } 544c5f01b2fSopenharmony_ci else 545c5f01b2fSopenharmony_ci { 546c5f01b2fSopenharmony_ci string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF'); 547c5f01b2fSopenharmony_ci string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF'); 548c5f01b2fSopenharmony_ci string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD'); 549c5f01b2fSopenharmony_ci } 550c5f01b2fSopenharmony_ci 551c5f01b2fSopenharmony_ci // write buffer and reset index; there must be 13 bytes 552c5f01b2fSopenharmony_ci // left, as this is the maximal number of bytes to be 553c5f01b2fSopenharmony_ci // written ("\uxxxx\uxxxx\0") for one code point 554c5f01b2fSopenharmony_ci if (string_buffer.size() - bytes < 13) 555c5f01b2fSopenharmony_ci { 556c5f01b2fSopenharmony_ci o->write_characters(string_buffer.data(), bytes); 557c5f01b2fSopenharmony_ci bytes = 0; 558c5f01b2fSopenharmony_ci } 559c5f01b2fSopenharmony_ci 560c5f01b2fSopenharmony_ci bytes_after_last_accept = bytes; 561c5f01b2fSopenharmony_ci } 562c5f01b2fSopenharmony_ci 563c5f01b2fSopenharmony_ci undumped_chars = 0; 564c5f01b2fSopenharmony_ci 565c5f01b2fSopenharmony_ci // continue processing the string 566c5f01b2fSopenharmony_ci state = UTF8_ACCEPT; 567c5f01b2fSopenharmony_ci break; 568c5f01b2fSopenharmony_ci } 569c5f01b2fSopenharmony_ci 570c5f01b2fSopenharmony_ci default: // LCOV_EXCL_LINE 571c5f01b2fSopenharmony_ci JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE 572c5f01b2fSopenharmony_ci } 573c5f01b2fSopenharmony_ci break; 574c5f01b2fSopenharmony_ci } 575c5f01b2fSopenharmony_ci 576c5f01b2fSopenharmony_ci default: // decode found yet incomplete multi-byte code point 577c5f01b2fSopenharmony_ci { 578c5f01b2fSopenharmony_ci if (!ensure_ascii) 579c5f01b2fSopenharmony_ci { 580c5f01b2fSopenharmony_ci // code point will not be escaped - copy byte to buffer 581c5f01b2fSopenharmony_ci string_buffer[bytes++] = s[i]; 582c5f01b2fSopenharmony_ci } 583c5f01b2fSopenharmony_ci ++undumped_chars; 584c5f01b2fSopenharmony_ci break; 585c5f01b2fSopenharmony_ci } 586c5f01b2fSopenharmony_ci } 587c5f01b2fSopenharmony_ci } 588c5f01b2fSopenharmony_ci 589c5f01b2fSopenharmony_ci // we finished processing the string 590c5f01b2fSopenharmony_ci if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) 591c5f01b2fSopenharmony_ci { 592c5f01b2fSopenharmony_ci // write buffer 593c5f01b2fSopenharmony_ci if (bytes > 0) 594c5f01b2fSopenharmony_ci { 595c5f01b2fSopenharmony_ci o->write_characters(string_buffer.data(), bytes); 596c5f01b2fSopenharmony_ci } 597c5f01b2fSopenharmony_ci } 598c5f01b2fSopenharmony_ci else 599c5f01b2fSopenharmony_ci { 600c5f01b2fSopenharmony_ci // we finish reading, but do not accept: string was incomplete 601c5f01b2fSopenharmony_ci switch (error_handler) 602c5f01b2fSopenharmony_ci { 603c5f01b2fSopenharmony_ci case error_handler_t::strict: 604c5f01b2fSopenharmony_ci { 605c5f01b2fSopenharmony_ci JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr)); 606c5f01b2fSopenharmony_ci } 607c5f01b2fSopenharmony_ci 608c5f01b2fSopenharmony_ci case error_handler_t::ignore: 609c5f01b2fSopenharmony_ci { 610c5f01b2fSopenharmony_ci // write all accepted bytes 611c5f01b2fSopenharmony_ci o->write_characters(string_buffer.data(), bytes_after_last_accept); 612c5f01b2fSopenharmony_ci break; 613c5f01b2fSopenharmony_ci } 614c5f01b2fSopenharmony_ci 615c5f01b2fSopenharmony_ci case error_handler_t::replace: 616c5f01b2fSopenharmony_ci { 617c5f01b2fSopenharmony_ci // write all accepted bytes 618c5f01b2fSopenharmony_ci o->write_characters(string_buffer.data(), bytes_after_last_accept); 619c5f01b2fSopenharmony_ci // add a replacement character 620c5f01b2fSopenharmony_ci if (ensure_ascii) 621c5f01b2fSopenharmony_ci { 622c5f01b2fSopenharmony_ci o->write_characters("\\ufffd", 6); 623c5f01b2fSopenharmony_ci } 624c5f01b2fSopenharmony_ci else 625c5f01b2fSopenharmony_ci { 626c5f01b2fSopenharmony_ci o->write_characters("\xEF\xBF\xBD", 3); 627c5f01b2fSopenharmony_ci } 628c5f01b2fSopenharmony_ci break; 629c5f01b2fSopenharmony_ci } 630c5f01b2fSopenharmony_ci 631c5f01b2fSopenharmony_ci default: // LCOV_EXCL_LINE 632c5f01b2fSopenharmony_ci JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE 633c5f01b2fSopenharmony_ci } 634c5f01b2fSopenharmony_ci } 635c5f01b2fSopenharmony_ci } 636c5f01b2fSopenharmony_ci 637c5f01b2fSopenharmony_ci private: 638c5f01b2fSopenharmony_ci /*! 639c5f01b2fSopenharmony_ci @brief count digits 640c5f01b2fSopenharmony_ci 641c5f01b2fSopenharmony_ci Count the number of decimal (base 10) digits for an input unsigned integer. 642c5f01b2fSopenharmony_ci 643c5f01b2fSopenharmony_ci @param[in] x unsigned integer number to count its digits 644c5f01b2fSopenharmony_ci @return number of decimal digits 645c5f01b2fSopenharmony_ci */ 646c5f01b2fSopenharmony_ci inline unsigned int count_digits(number_unsigned_t x) noexcept 647c5f01b2fSopenharmony_ci { 648c5f01b2fSopenharmony_ci unsigned int n_digits = 1; 649c5f01b2fSopenharmony_ci for (;;) 650c5f01b2fSopenharmony_ci { 651c5f01b2fSopenharmony_ci if (x < 10) 652c5f01b2fSopenharmony_ci { 653c5f01b2fSopenharmony_ci return n_digits; 654c5f01b2fSopenharmony_ci } 655c5f01b2fSopenharmony_ci if (x < 100) 656c5f01b2fSopenharmony_ci { 657c5f01b2fSopenharmony_ci return n_digits + 1; 658c5f01b2fSopenharmony_ci } 659c5f01b2fSopenharmony_ci if (x < 1000) 660c5f01b2fSopenharmony_ci { 661c5f01b2fSopenharmony_ci return n_digits + 2; 662c5f01b2fSopenharmony_ci } 663c5f01b2fSopenharmony_ci if (x < 10000) 664c5f01b2fSopenharmony_ci { 665c5f01b2fSopenharmony_ci return n_digits + 3; 666c5f01b2fSopenharmony_ci } 667c5f01b2fSopenharmony_ci x = x / 10000u; 668c5f01b2fSopenharmony_ci n_digits += 4; 669c5f01b2fSopenharmony_ci } 670c5f01b2fSopenharmony_ci } 671c5f01b2fSopenharmony_ci 672c5f01b2fSopenharmony_ci /*! 673c5f01b2fSopenharmony_ci * @brief convert a byte to a uppercase hex representation 674c5f01b2fSopenharmony_ci * @param[in] byte byte to represent 675c5f01b2fSopenharmony_ci * @return representation ("00".."FF") 676c5f01b2fSopenharmony_ci */ 677c5f01b2fSopenharmony_ci static std::string hex_bytes(std::uint8_t byte) 678c5f01b2fSopenharmony_ci { 679c5f01b2fSopenharmony_ci std::string result = "FF"; 680c5f01b2fSopenharmony_ci constexpr const char* nibble_to_hex = "0123456789ABCDEF"; 681c5f01b2fSopenharmony_ci result[0] = nibble_to_hex[byte / 16]; 682c5f01b2fSopenharmony_ci result[1] = nibble_to_hex[byte % 16]; 683c5f01b2fSopenharmony_ci return result; 684c5f01b2fSopenharmony_ci } 685c5f01b2fSopenharmony_ci 686c5f01b2fSopenharmony_ci // templates to avoid warnings about useless casts 687c5f01b2fSopenharmony_ci template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0> 688c5f01b2fSopenharmony_ci bool is_negative_number(NumberType x) 689c5f01b2fSopenharmony_ci { 690c5f01b2fSopenharmony_ci return x < 0; 691c5f01b2fSopenharmony_ci } 692c5f01b2fSopenharmony_ci 693c5f01b2fSopenharmony_ci template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 > 694c5f01b2fSopenharmony_ci bool is_negative_number(NumberType /*unused*/) 695c5f01b2fSopenharmony_ci { 696c5f01b2fSopenharmony_ci return false; 697c5f01b2fSopenharmony_ci } 698c5f01b2fSopenharmony_ci 699c5f01b2fSopenharmony_ci /*! 700c5f01b2fSopenharmony_ci @brief dump an integer 701c5f01b2fSopenharmony_ci 702c5f01b2fSopenharmony_ci Dump a given integer to output stream @a o. Works internally with 703c5f01b2fSopenharmony_ci @a number_buffer. 704c5f01b2fSopenharmony_ci 705c5f01b2fSopenharmony_ci @param[in] x integer number (signed or unsigned) to dump 706c5f01b2fSopenharmony_ci @tparam NumberType either @a number_integer_t or @a number_unsigned_t 707c5f01b2fSopenharmony_ci */ 708c5f01b2fSopenharmony_ci template < typename NumberType, detail::enable_if_t < 709c5f01b2fSopenharmony_ci std::is_integral<NumberType>::value || 710c5f01b2fSopenharmony_ci std::is_same<NumberType, number_unsigned_t>::value || 711c5f01b2fSopenharmony_ci std::is_same<NumberType, number_integer_t>::value || 712c5f01b2fSopenharmony_ci std::is_same<NumberType, binary_char_t>::value, 713c5f01b2fSopenharmony_ci int > = 0 > 714c5f01b2fSopenharmony_ci void dump_integer(NumberType x) 715c5f01b2fSopenharmony_ci { 716c5f01b2fSopenharmony_ci static constexpr std::array<std::array<char, 2>, 100> digits_to_99 717c5f01b2fSopenharmony_ci { 718c5f01b2fSopenharmony_ci { 719c5f01b2fSopenharmony_ci {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, 720c5f01b2fSopenharmony_ci {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, 721c5f01b2fSopenharmony_ci {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, 722c5f01b2fSopenharmony_ci {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, 723c5f01b2fSopenharmony_ci {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, 724c5f01b2fSopenharmony_ci {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, 725c5f01b2fSopenharmony_ci {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, 726c5f01b2fSopenharmony_ci {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, 727c5f01b2fSopenharmony_ci {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, 728c5f01b2fSopenharmony_ci {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, 729c5f01b2fSopenharmony_ci } 730c5f01b2fSopenharmony_ci }; 731c5f01b2fSopenharmony_ci 732c5f01b2fSopenharmony_ci // special case for "0" 733c5f01b2fSopenharmony_ci if (x == 0) 734c5f01b2fSopenharmony_ci { 735c5f01b2fSopenharmony_ci o->write_character('0'); 736c5f01b2fSopenharmony_ci return; 737c5f01b2fSopenharmony_ci } 738c5f01b2fSopenharmony_ci 739c5f01b2fSopenharmony_ci // use a pointer to fill the buffer 740c5f01b2fSopenharmony_ci auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) 741c5f01b2fSopenharmony_ci 742c5f01b2fSopenharmony_ci number_unsigned_t abs_value; 743c5f01b2fSopenharmony_ci 744c5f01b2fSopenharmony_ci unsigned int n_chars{}; 745c5f01b2fSopenharmony_ci 746c5f01b2fSopenharmony_ci if (is_negative_number(x)) 747c5f01b2fSopenharmony_ci { 748c5f01b2fSopenharmony_ci *buffer_ptr = '-'; 749c5f01b2fSopenharmony_ci abs_value = remove_sign(static_cast<number_integer_t>(x)); 750c5f01b2fSopenharmony_ci 751c5f01b2fSopenharmony_ci // account one more byte for the minus sign 752c5f01b2fSopenharmony_ci n_chars = 1 + count_digits(abs_value); 753c5f01b2fSopenharmony_ci } 754c5f01b2fSopenharmony_ci else 755c5f01b2fSopenharmony_ci { 756c5f01b2fSopenharmony_ci abs_value = static_cast<number_unsigned_t>(x); 757c5f01b2fSopenharmony_ci n_chars = count_digits(abs_value); 758c5f01b2fSopenharmony_ci } 759c5f01b2fSopenharmony_ci 760c5f01b2fSopenharmony_ci // spare 1 byte for '\0' 761c5f01b2fSopenharmony_ci JSON_ASSERT(n_chars < number_buffer.size() - 1); 762c5f01b2fSopenharmony_ci 763c5f01b2fSopenharmony_ci // jump to the end to generate the string from backward, 764c5f01b2fSopenharmony_ci // so we later avoid reversing the result 765c5f01b2fSopenharmony_ci buffer_ptr += n_chars; 766c5f01b2fSopenharmony_ci 767c5f01b2fSopenharmony_ci // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu 768c5f01b2fSopenharmony_ci // See: https://www.youtube.com/watch?v=o4-CwDo2zpg 769c5f01b2fSopenharmony_ci while (abs_value >= 100) 770c5f01b2fSopenharmony_ci { 771c5f01b2fSopenharmony_ci const auto digits_index = static_cast<unsigned>((abs_value % 100)); 772c5f01b2fSopenharmony_ci abs_value /= 100; 773c5f01b2fSopenharmony_ci *(--buffer_ptr) = digits_to_99[digits_index][1]; 774c5f01b2fSopenharmony_ci *(--buffer_ptr) = digits_to_99[digits_index][0]; 775c5f01b2fSopenharmony_ci } 776c5f01b2fSopenharmony_ci 777c5f01b2fSopenharmony_ci if (abs_value >= 10) 778c5f01b2fSopenharmony_ci { 779c5f01b2fSopenharmony_ci const auto digits_index = static_cast<unsigned>(abs_value); 780c5f01b2fSopenharmony_ci *(--buffer_ptr) = digits_to_99[digits_index][1]; 781c5f01b2fSopenharmony_ci *(--buffer_ptr) = digits_to_99[digits_index][0]; 782c5f01b2fSopenharmony_ci } 783c5f01b2fSopenharmony_ci else 784c5f01b2fSopenharmony_ci { 785c5f01b2fSopenharmony_ci *(--buffer_ptr) = static_cast<char>('0' + abs_value); 786c5f01b2fSopenharmony_ci } 787c5f01b2fSopenharmony_ci 788c5f01b2fSopenharmony_ci o->write_characters(number_buffer.data(), n_chars); 789c5f01b2fSopenharmony_ci } 790c5f01b2fSopenharmony_ci 791c5f01b2fSopenharmony_ci /*! 792c5f01b2fSopenharmony_ci @brief dump a floating-point number 793c5f01b2fSopenharmony_ci 794c5f01b2fSopenharmony_ci Dump a given floating-point number to output stream @a o. Works internally 795c5f01b2fSopenharmony_ci with @a number_buffer. 796c5f01b2fSopenharmony_ci 797c5f01b2fSopenharmony_ci @param[in] x floating-point number to dump 798c5f01b2fSopenharmony_ci */ 799c5f01b2fSopenharmony_ci void dump_float(number_float_t x) 800c5f01b2fSopenharmony_ci { 801c5f01b2fSopenharmony_ci // NaN / inf 802c5f01b2fSopenharmony_ci if (!std::isfinite(x)) 803c5f01b2fSopenharmony_ci { 804c5f01b2fSopenharmony_ci o->write_characters("null", 4); 805c5f01b2fSopenharmony_ci return; 806c5f01b2fSopenharmony_ci } 807c5f01b2fSopenharmony_ci 808c5f01b2fSopenharmony_ci // If number_float_t is an IEEE-754 single or double precision number, 809c5f01b2fSopenharmony_ci // use the Grisu2 algorithm to produce short numbers which are 810c5f01b2fSopenharmony_ci // guaranteed to round-trip, using strtof and strtod, resp. 811c5f01b2fSopenharmony_ci // 812c5f01b2fSopenharmony_ci // NB: The test below works if <long double> == <double>. 813c5f01b2fSopenharmony_ci static constexpr bool is_ieee_single_or_double 814c5f01b2fSopenharmony_ci = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) || 815c5f01b2fSopenharmony_ci (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024); 816c5f01b2fSopenharmony_ci 817c5f01b2fSopenharmony_ci dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>()); 818c5f01b2fSopenharmony_ci } 819c5f01b2fSopenharmony_ci 820c5f01b2fSopenharmony_ci void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) 821c5f01b2fSopenharmony_ci { 822c5f01b2fSopenharmony_ci auto* begin = number_buffer.data(); 823c5f01b2fSopenharmony_ci auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); 824c5f01b2fSopenharmony_ci 825c5f01b2fSopenharmony_ci o->write_characters(begin, static_cast<size_t>(end - begin)); 826c5f01b2fSopenharmony_ci } 827c5f01b2fSopenharmony_ci 828c5f01b2fSopenharmony_ci void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) 829c5f01b2fSopenharmony_ci { 830c5f01b2fSopenharmony_ci // get number of digits for a float -> text -> float round-trip 831c5f01b2fSopenharmony_ci static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10; 832c5f01b2fSopenharmony_ci 833c5f01b2fSopenharmony_ci // the actual conversion 834c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) 835c5f01b2fSopenharmony_ci std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); 836c5f01b2fSopenharmony_ci 837c5f01b2fSopenharmony_ci // negative value indicates an error 838c5f01b2fSopenharmony_ci JSON_ASSERT(len > 0); 839c5f01b2fSopenharmony_ci // check if buffer was large enough 840c5f01b2fSopenharmony_ci JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size()); 841c5f01b2fSopenharmony_ci 842c5f01b2fSopenharmony_ci // erase thousands separator 843c5f01b2fSopenharmony_ci if (thousands_sep != '\0') 844c5f01b2fSopenharmony_ci { 845c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 846c5f01b2fSopenharmony_ci const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); 847c5f01b2fSopenharmony_ci std::fill(end, number_buffer.end(), '\0'); 848c5f01b2fSopenharmony_ci JSON_ASSERT((end - number_buffer.begin()) <= len); 849c5f01b2fSopenharmony_ci len = (end - number_buffer.begin()); 850c5f01b2fSopenharmony_ci } 851c5f01b2fSopenharmony_ci 852c5f01b2fSopenharmony_ci // convert decimal point to '.' 853c5f01b2fSopenharmony_ci if (decimal_point != '\0' && decimal_point != '.') 854c5f01b2fSopenharmony_ci { 855c5f01b2fSopenharmony_ci // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081 856c5f01b2fSopenharmony_ci const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); 857c5f01b2fSopenharmony_ci if (dec_pos != number_buffer.end()) 858c5f01b2fSopenharmony_ci { 859c5f01b2fSopenharmony_ci *dec_pos = '.'; 860c5f01b2fSopenharmony_ci } 861c5f01b2fSopenharmony_ci } 862c5f01b2fSopenharmony_ci 863c5f01b2fSopenharmony_ci o->write_characters(number_buffer.data(), static_cast<std::size_t>(len)); 864c5f01b2fSopenharmony_ci 865c5f01b2fSopenharmony_ci // determine if we need to append ".0" 866c5f01b2fSopenharmony_ci const bool value_is_int_like = 867c5f01b2fSopenharmony_ci std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, 868c5f01b2fSopenharmony_ci [](char c) 869c5f01b2fSopenharmony_ci { 870c5f01b2fSopenharmony_ci return c == '.' || c == 'e'; 871c5f01b2fSopenharmony_ci }); 872c5f01b2fSopenharmony_ci 873c5f01b2fSopenharmony_ci if (value_is_int_like) 874c5f01b2fSopenharmony_ci { 875c5f01b2fSopenharmony_ci o->write_characters(".0", 2); 876c5f01b2fSopenharmony_ci } 877c5f01b2fSopenharmony_ci } 878c5f01b2fSopenharmony_ci 879c5f01b2fSopenharmony_ci /*! 880c5f01b2fSopenharmony_ci @brief check whether a string is UTF-8 encoded 881c5f01b2fSopenharmony_ci 882c5f01b2fSopenharmony_ci The function checks each byte of a string whether it is UTF-8 encoded. The 883c5f01b2fSopenharmony_ci result of the check is stored in the @a state parameter. The function must 884c5f01b2fSopenharmony_ci be called initially with state 0 (accept). State 1 means the string must 885c5f01b2fSopenharmony_ci be rejected, because the current byte is not allowed. If the string is 886c5f01b2fSopenharmony_ci completely processed, but the state is non-zero, the string ended 887c5f01b2fSopenharmony_ci prematurely; that is, the last byte indicated more bytes should have 888c5f01b2fSopenharmony_ci followed. 889c5f01b2fSopenharmony_ci 890c5f01b2fSopenharmony_ci @param[in,out] state the state of the decoding 891c5f01b2fSopenharmony_ci @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) 892c5f01b2fSopenharmony_ci @param[in] byte next byte to decode 893c5f01b2fSopenharmony_ci @return new state 894c5f01b2fSopenharmony_ci 895c5f01b2fSopenharmony_ci @note The function has been edited: a std::array is used. 896c5f01b2fSopenharmony_ci 897c5f01b2fSopenharmony_ci @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> 898c5f01b2fSopenharmony_ci @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ 899c5f01b2fSopenharmony_ci */ 900c5f01b2fSopenharmony_ci static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept 901c5f01b2fSopenharmony_ci { 902c5f01b2fSopenharmony_ci static const std::array<std::uint8_t, 400> utf8d = 903c5f01b2fSopenharmony_ci { 904c5f01b2fSopenharmony_ci { 905c5f01b2fSopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F 906c5f01b2fSopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F 907c5f01b2fSopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F 908c5f01b2fSopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F 909c5f01b2fSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F 910c5f01b2fSopenharmony_ci 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF 911c5f01b2fSopenharmony_ci 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF 912c5f01b2fSopenharmony_ci 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF 913c5f01b2fSopenharmony_ci 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF 914c5f01b2fSopenharmony_ci 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 915c5f01b2fSopenharmony_ci 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 916c5f01b2fSopenharmony_ci 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 917c5f01b2fSopenharmony_ci 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 918c5f01b2fSopenharmony_ci 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 919c5f01b2fSopenharmony_ci } 920c5f01b2fSopenharmony_ci }; 921c5f01b2fSopenharmony_ci 922c5f01b2fSopenharmony_ci JSON_ASSERT(byte < utf8d.size()); 923c5f01b2fSopenharmony_ci const std::uint8_t type = utf8d[byte]; 924c5f01b2fSopenharmony_ci 925c5f01b2fSopenharmony_ci codep = (state != UTF8_ACCEPT) 926c5f01b2fSopenharmony_ci ? (byte & 0x3fu) | (codep << 6u) 927c5f01b2fSopenharmony_ci : (0xFFu >> type) & (byte); 928c5f01b2fSopenharmony_ci 929c5f01b2fSopenharmony_ci std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type); 930c5f01b2fSopenharmony_ci JSON_ASSERT(index < 400); 931c5f01b2fSopenharmony_ci state = utf8d[index]; 932c5f01b2fSopenharmony_ci return state; 933c5f01b2fSopenharmony_ci } 934c5f01b2fSopenharmony_ci 935c5f01b2fSopenharmony_ci /* 936c5f01b2fSopenharmony_ci * Overload to make the compiler happy while it is instantiating 937c5f01b2fSopenharmony_ci * dump_integer for number_unsigned_t. 938c5f01b2fSopenharmony_ci * Must never be called. 939c5f01b2fSopenharmony_ci */ 940c5f01b2fSopenharmony_ci number_unsigned_t remove_sign(number_unsigned_t x) 941c5f01b2fSopenharmony_ci { 942c5f01b2fSopenharmony_ci JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE 943c5f01b2fSopenharmony_ci return x; // LCOV_EXCL_LINE 944c5f01b2fSopenharmony_ci } 945c5f01b2fSopenharmony_ci 946c5f01b2fSopenharmony_ci /* 947c5f01b2fSopenharmony_ci * Helper function for dump_integer 948c5f01b2fSopenharmony_ci * 949c5f01b2fSopenharmony_ci * This function takes a negative signed integer and returns its absolute 950c5f01b2fSopenharmony_ci * value as unsigned integer. The plus/minus shuffling is necessary as we can 951c5f01b2fSopenharmony_ci * not directly remove the sign of an arbitrary signed integer as the 952c5f01b2fSopenharmony_ci * absolute values of INT_MIN and INT_MAX are usually not the same. See 953c5f01b2fSopenharmony_ci * #1708 for details. 954c5f01b2fSopenharmony_ci */ 955c5f01b2fSopenharmony_ci inline number_unsigned_t remove_sign(number_integer_t x) noexcept 956c5f01b2fSopenharmony_ci { 957c5f01b2fSopenharmony_ci JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression) 958c5f01b2fSopenharmony_ci return static_cast<number_unsigned_t>(-(x + 1)) + 1; 959c5f01b2fSopenharmony_ci } 960c5f01b2fSopenharmony_ci 961c5f01b2fSopenharmony_ci private: 962c5f01b2fSopenharmony_ci /// the output of the serializer 963c5f01b2fSopenharmony_ci output_adapter_t<char> o = nullptr; 964c5f01b2fSopenharmony_ci 965c5f01b2fSopenharmony_ci /// a (hopefully) large enough character buffer 966c5f01b2fSopenharmony_ci std::array<char, 64> number_buffer{{}}; 967c5f01b2fSopenharmony_ci 968c5f01b2fSopenharmony_ci /// the locale 969c5f01b2fSopenharmony_ci const std::lconv* loc = nullptr; 970c5f01b2fSopenharmony_ci /// the locale's thousand separator character 971c5f01b2fSopenharmony_ci const char thousands_sep = '\0'; 972c5f01b2fSopenharmony_ci /// the locale's decimal point character 973c5f01b2fSopenharmony_ci const char decimal_point = '\0'; 974c5f01b2fSopenharmony_ci 975c5f01b2fSopenharmony_ci /// string buffer 976c5f01b2fSopenharmony_ci std::array<char, 512> string_buffer{{}}; 977c5f01b2fSopenharmony_ci 978c5f01b2fSopenharmony_ci /// the indentation character 979c5f01b2fSopenharmony_ci const char indent_char; 980c5f01b2fSopenharmony_ci /// the indentation string 981c5f01b2fSopenharmony_ci string_t indent_string; 982c5f01b2fSopenharmony_ci 983c5f01b2fSopenharmony_ci /// error_handler how to react on decoding errors 984c5f01b2fSopenharmony_ci const error_handler_t error_handler; 985c5f01b2fSopenharmony_ci}; 986c5f01b2fSopenharmony_ci 987c5f01b2fSopenharmony_ci} // namespace detail 988c5f01b2fSopenharmony_ciNLOHMANN_JSON_NAMESPACE_END 989