From: <sv...@op...> - 2025-04-18 09:05:47
|
Author: manx Date: Fri Apr 18 11:05:17 2025 New Revision: 23134 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=23134 Log: [Var] nlohmann-json: Update to v3.12.0 (2025-04-11). Added: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/string_utils.hpp (contents, props changed) Modified: trunk/OpenMPT/include/nlohmann-json/LICENSE.MIT trunk/OpenMPT/include/nlohmann-json/OpenMPT.txt trunk/OpenMPT/include/nlohmann-json/include/nlohmann/adl_serializer.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/byte_container_with_subtype.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/abi_macros.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/from_json.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/to_chars.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/exceptions.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/hash.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/binary_reader.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/input_adapters.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/json_sax.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/lexer.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/parser.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/position_t.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/iterators/internal_iterator.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/iterators/iter_impl.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/iterators/iteration_proxy.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/iterators/iterator_traits.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/iterators/json_reverse_iterator.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/iterators/primitive_iterator.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/json_custom_base_class.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/json_pointer.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/json_ref.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/macro_scope.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/macro_unscope.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/call_std/begin.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/call_std/end.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/cpp_future.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/detected.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/identity_tag.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/is_sax.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/std_fs.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/type_traits.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/meta/void_t.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/output/binary_writer.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/output/output_adapters.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/output/serializer.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/string_concat.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/string_escape.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/value_t.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/json.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/json_fwd.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/ordered_map.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/thirdparty/hedley/hedley.hpp trunk/OpenMPT/include/nlohmann-json/include/nlohmann/thirdparty/hedley/hedley_undef.hpp Modified: trunk/OpenMPT/include/nlohmann-json/LICENSE.MIT ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/LICENSE.MIT Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/LICENSE.MIT Fri Apr 18 11:05:17 2025 (r23134) @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2013-2022 Niels Lohmann +Copyright (c) 2013-2025 Niels Lohmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal Modified: trunk/OpenMPT/include/nlohmann-json/OpenMPT.txt ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/OpenMPT.txt Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/OpenMPT.txt Fri Apr 18 11:05:17 2025 (r23134) @@ -1 +1 @@ -https://github.com/nlohmann/json version 3.11.3 (2023-11-28) +https://github.com/nlohmann/json version 3.12.0 (2025-01-11) Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/adl_serializer.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/adl_serializer.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/adl_serializer.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/byte_container_with_subtype.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/byte_container_with_subtype.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/byte_container_with_subtype.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/abi_macros.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/abi_macros.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/abi_macros.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once @@ -12,20 +12,24 @@ #ifndef JSON_SKIP_LIBRARY_VERSION_CHECK #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) - #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0 #warning "Already included a different version of the library!" #endif #endif #endif #define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) -#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum) #ifndef JSON_DIAGNOSTICS #define JSON_DIAGNOSTICS 0 #endif +#ifndef JSON_DIAGNOSTIC_POSITIONS + #define JSON_DIAGNOSTIC_POSITIONS 0 +#endif + #ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 #endif @@ -36,6 +40,12 @@ #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS #endif +#if JSON_DIAGNOSTIC_POSITIONS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS +#endif + #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp #else @@ -47,14 +57,15 @@ #endif // Construct the namespace ABI tags component -#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b -#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ - NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) #define NLOHMANN_JSON_ABI_TAGS \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \ NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ - NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS) // Construct the namespace version component #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/from_json.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/from_json.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/from_json.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once @@ -13,6 +13,9 @@ #include <forward_list> // forward_list #include <iterator> // inserter, front_inserter, end #include <map> // map +#ifdef JSON_HAS_CPP_17 + #include <optional> // optional +#endif #include <string> // string #include <tuple> // tuple, make_tuple #include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible @@ -43,6 +46,24 @@ n = nullptr; } +#ifdef JSON_HAS_CPP_17 +#ifndef JSON_USE_IMPLICIT_CONVERSIONS +template<typename BasicJsonType, typename T> +void from_json(const BasicJsonType& j, std::optional<T>& opt) +{ + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt.emplace(j.template get<T>()); + } +} + +#endif // JSON_USE_IMPLICIT_CONVERSIONS +#endif // JSON_HAS_CPP_17 + // overloads for basic_json template parameters template < typename BasicJsonType, typename ArithmeticType, enable_if_t < std::is_arithmetic<ArithmeticType>::value&& @@ -190,6 +211,54 @@ } } +template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2> +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get<T>(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + arr[i1][i2] = j.at(i1).at(i2).template get<T>(); + } + } +} + +template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3> +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get<T>(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + for (std::size_t i3 = 0; i3 < N3; ++i3) + { + arr[i1][i2][i3] = j.at(i1).at(i2).at(i3).template get<T>(); + } + } + } +} + +template<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3, std::size_t N4> +auto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3][N4]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get<T>(), void()) +{ + for (std::size_t i1 = 0; i1 < N1; ++i1) + { + for (std::size_t i2 = 0; i2 < N2; ++i2) + { + for (std::size_t i3 = 0; i3 < N3; ++i3) + { + for (std::size_t i4 = 0; i4 < N4; ++i4) + { + arr[i1][i2][i3][i4] = j.at(i1).at(i2).at(i3).at(i4).template get<T>(); + } + } + } + } +} + template<typename BasicJsonType> inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) { @@ -275,7 +344,7 @@ template < typename BasicJsonType, typename T, std::size_t... Idx > std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j, - identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/) + identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/) { return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } }; } @@ -379,6 +448,12 @@ return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...); } +template<typename BasicJsonType> +std::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/) +{ + return {}; +} + template < typename BasicJsonType, class A1, class A2 > std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/) { @@ -464,7 +539,12 @@ { JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j)); } - p = *j.template get_ptr<const typename BasicJsonType::string_t*>(); + const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); +#ifdef JSON_HAS_CPP_20 + p = std_fs::path(std::u8string_view(reinterpret_cast<const char8_t*>(s.data()), s.size())); +#else + p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20 +#endif } #endif Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/to_chars.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/to_chars.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/to_chars.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,10 +1,10 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/> -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once @@ -239,10 +239,10 @@ // v- m- v m+ v+ const bool lower_boundary_is_closer = F == 0 && E > 1; - const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_plus = diyfp((2 * v.f) + 1, v.e - 1); const diyfp m_minus = lower_boundary_is_closer - ? diyfp(4 * v.f - 1, v.e - 2) // (B) - : diyfp(2 * v.f - 1, v.e - 1); // (A) + ? diyfp((4 * v.f) - 1, v.e - 2) // (B) + : diyfp((2 * v.f) - 1, v.e - 1); // (A) // Determine the normalized w+ = m+. const diyfp w_plus = diyfp::normalize(m_plus); @@ -472,7 +472,7 @@ JSON_ASSERT(e >= -1500); JSON_ASSERT(e <= 1500); const int f = kAlpha - e - 1; - const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0); + const int k = ((f * 78913) / (1 << 18)) + static_cast<int>(f > 0); const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; JSON_ASSERT(index >= 0); @@ -950,15 +950,15 @@ } else if (k < 100) { - *buf++ = static_cast<char>('0' + k / 10); + *buf++ = static_cast<char>('0' + (k / 10)); k %= 10; *buf++ = static_cast<char>('0' + k); } else { - *buf++ = static_cast<char>('0' + k / 100); + *buf++ = static_cast<char>('0' + (k / 100)); k %= 100; - *buf++ = static_cast<char>('0' + k / 10); + *buf++ = static_cast<char>('0' + (k / 10)); k %= 10; *buf++ = static_cast<char>('0' + k); } Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,13 +1,18 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once +#include <nlohmann/detail/macro_scope.hpp> // JSON_HAS_CPP_17 +#ifdef JSON_HAS_CPP_17 + #include <optional> // optional +#endif + #include <algorithm> // copy #include <iterator> // begin, end #include <string> // string @@ -18,7 +23,6 @@ #include <vector> // vector #include <nlohmann/detail/iterators/iteration_proxy.hpp> -#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/std_fs.hpp> #include <nlohmann/detail/meta/type_traits.hpp> @@ -260,6 +264,22 @@ // to_json // ///////////// +#ifdef JSON_HAS_CPP_17 +template<typename BasicJsonType, typename T, + enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0> +void to_json(BasicJsonType& j, const std::optional<T>& opt) +{ + if (opt.has_value()) + { + j = *opt; + } + else + { + j = nullptr; + } +} +#endif + template<typename BasicJsonType, typename T, enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0> inline void to_json(BasicJsonType& j, T b) noexcept @@ -320,7 +340,8 @@ inline void to_json(BasicJsonType& j, EnumType e) noexcept { using underlying_type = typename std::underlying_type<EnumType>::type; - external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e)); + static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer; + external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e)); } #endif // JSON_DISABLE_ENUM_SERIALIZATION @@ -405,6 +426,13 @@ j = { std::get<Idx>(t)... }; } +template<typename BasicJsonType, typename Tuple> +inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/) +{ + using array_t = typename BasicJsonType::array_t; + j = array_t(); +} + template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0> inline void to_json(BasicJsonType& j, const T& t) { @@ -415,7 +443,12 @@ template<typename BasicJsonType> inline void to_json(BasicJsonType& j, const std_fs::path& p) { - j = p.string(); +#ifdef JSON_HAS_CPP_20 + const std::u8string s = p.u8string(); + j = std::string(s.begin(), s.end()); +#else + j = p.u8string(); // returns std::string in C++17 +#endif } #endif Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/exceptions.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/exceptions.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/exceptions.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once @@ -25,6 +25,18 @@ #include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/string_concat.hpp> +// With -Wweak-vtables, Clang will complain about the exception classes as they +// have no out-of-line virtual method definitions and their vtable will be +// emitted in every translation unit. This issue cannot be fixed with a +// header-only library as there is no implementation file to move these +// functions to. As a result, we suppress this warning here to avoid client +// code to stumble over this. See https://github.com/nlohmann/json/issues/4087 +// for a discussion. +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wweak-vtables" +#endif + NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { @@ -119,16 +131,34 @@ { return concat(a, '/', detail::escape(b)); }); - return concat('(', str, ") "); + + return concat('(', str, ") ", get_byte_positions(leaf_element)); #else - static_cast<void>(leaf_element); - return ""; + return get_byte_positions(leaf_element); #endif } private: /// an exception object as storage for error messages std::runtime_error m; +#if JSON_DIAGNOSTIC_POSITIONS + template<typename BasicJsonType> + static std::string get_byte_positions(const BasicJsonType* leaf_element) + { + if ((leaf_element->start_pos() != std::string::npos) && (leaf_element->end_pos() != std::string::npos)) + { + return concat("(bytes ", std::to_string(leaf_element->start_pos()), "-", std::to_string(leaf_element->end_pos()), ") "); + } + return ""; + } +#else + template<typename BasicJsonType> + static std::string get_byte_positions(const BasicJsonType* leaf_element) + { + static_cast<void>(leaf_element); + return ""; + } +#endif }; /// @brief exception indicating a parse error @@ -255,3 +285,7 @@ } // namespace detail NLOHMANN_JSON_NAMESPACE_END + +#if defined(__clang__) + #pragma clang diagnostic pop +#endif Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/hash.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/hash.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/hash.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/binary_reader.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/binary_reader.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/binary_reader.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once @@ -20,6 +20,9 @@ #include <string> // char_traits, string #include <utility> // make_pair, move #include <vector> // vector +#ifdef __cpp_lib_byteswap + #include <bit> //byteswap +#endif #include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/input/input_adapters.hpp> @@ -62,7 +65,7 @@ /*! @brief deserialization of CBOR, MessagePack, and UBJSON values */ -template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>> +template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType, InputAdapterType>> class binary_reader { using number_integer_t = typename BasicJsonType::number_integer_t; @@ -169,7 +172,7 @@ std::int32_t document_size{}; get_number<std::int32_t, true>(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { return false; } @@ -325,6 +328,12 @@ return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value); } + case 0x11: // uint64 + { + std::uint64_t value{}; + return get_number<std::uint64_t, true>(input_format_t::bson, value) && sax->number_unsigned(value); + } + default: // anything else not supported (yet) { std::array<char, 3> cr{{}}; @@ -391,7 +400,7 @@ std::int32_t document_size{}; get_number<std::int32_t, true>(input_format_t::bson, document_size); - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { return false; } @@ -651,7 +660,7 @@ } case 0x9F: // array (indefinite length) - return get_cbor_array(static_cast<std::size_t>(-1), tag_handler); + return get_cbor_array(detail::unknown_size(), tag_handler); // map (0x00..0x17 pairs of data items follow) case 0xA0: @@ -705,7 +714,7 @@ } case 0xBF: // map (indefinite length) - return get_cbor_object(static_cast<std::size_t>(-1), tag_handler); + return get_cbor_object(detail::unknown_size(), tag_handler); case 0xC6: // tagged item case 0xC7: @@ -1093,7 +1102,7 @@ } /*! - @param[in] len the length of the array or static_cast<std::size_t>(-1) for an + @param[in] len the length of the array or detail::unknown_size() for an array of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether array creation completed @@ -1106,7 +1115,7 @@ return false; } - if (len != static_cast<std::size_t>(-1)) + if (len != detail::unknown_size()) { for (std::size_t i = 0; i < len; ++i) { @@ -1131,7 +1140,7 @@ } /*! - @param[in] len the length of the object or static_cast<std::size_t>(-1) for an + @param[in] len the length of the object or detail::unknown_size() for an object of indefinite size @param[in] tag_handler how CBOR tags should be treated @return whether object creation completed @@ -1147,7 +1156,7 @@ if (len != 0) { string_t key; - if (len != static_cast<std::size_t>(-1)) + if (len != detail::unknown_size()) { for (std::size_t i = 0; i < len; ++i) { @@ -2310,6 +2319,16 @@ case 'Z': // null return sax->null(); + case 'B': // byte + { + if (input_format != input_format_t::bjdata) + { + break; + } + std::uint8_t number{}; + return get_number(input_format, number) && sax->number_unsigned(number); + } + case 'U': { std::uint8_t number{}; @@ -2510,7 +2529,7 @@ return false; } - if (size_and_type.second == 'C') + if (size_and_type.second == 'C' || size_and_type.second == 'B') { size_and_type.second = 'U'; } @@ -2532,6 +2551,13 @@ return (sax->end_array() && sax->end_object()); } + // If BJData type marker is 'B' decode as binary + if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B') + { + binary_t result; + return get_binary(input_format, size_and_type.first, result) && sax->binary(result); + } + if (size_and_type.first != npos) { if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) @@ -2565,7 +2591,7 @@ } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size()))) { return false; } @@ -2643,7 +2669,7 @@ } else { - if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1)))) + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size()))) { return false; } @@ -2755,6 +2781,29 @@ } /*! + @brief get_to read into a primitive type + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns false instead + + @return bool, whether the read was successful + */ + template<class T> + bool get_to(T& dest, const input_format_t format, const char* context) + { + auto new_chars_read = ia.get_elements(&dest); + chars_read += new_chars_read; + if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T))) + { + // in case of failure, advance position by 1 to report failing location + ++chars_read; + sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr)); + return false; + } + return true; + } + + /*! @return character read from the input after ignoring all 'N' entries */ char_int_type get_ignore_noop() @@ -2768,6 +2817,28 @@ return current; } + template<class NumberType> + static void byte_swap(NumberType& number) + { + constexpr std::size_t sz = sizeof(number); +#ifdef __cpp_lib_byteswap + if constexpr (sz == 1) + { + return; + } + if constexpr(std::is_integral_v<NumberType>) + { + number = std::byteswap(number); + return; + } +#endif + auto* ptr = reinterpret_cast<std::uint8_t*>(&number); + for (std::size_t i = 0; i < sz / 2; ++i) + { + std::swap(ptr[i], ptr[sz - i - 1]); + } + } + /* @brief read a number from the input @@ -2786,29 +2857,16 @@ template<typename NumberType, bool InputIsLittleEndian = false> bool get_number(const input_format_t format, NumberType& result) { - // step 1: read input into array with system's byte order - std::array<std::uint8_t, sizeof(NumberType)> vec{}; - for (std::size_t i = 0; i < sizeof(NumberType); ++i) - { - get(); - if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) - { - return false; - } + // read in the original format - // reverse byte order prior to conversion if necessary - if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) - { - vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current); - } - else - { - vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE - } + if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number"))) + { + return false; + } + if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata)) + { + byte_swap(result); } - - // step 2: convert array into number of type T and return - std::memcpy(&result, vec.data(), sizeof(NumberType)); return true; } @@ -2947,7 +3005,7 @@ } private: - static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast<std::size_t>(-1); + static JSON_INLINE_VARIABLE constexpr std::size_t npos = detail::unknown_size(); /// input adapter InputAdapterType ia; @@ -2973,6 +3031,7 @@ #define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \ make_array<bjd_type>( \ + bjd_type{'B', "byte"}, \ bjd_type{'C', "char"}, \ bjd_type{'D', "double"}, \ bjd_type{'I', "int16"}, \ Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/input_adapters.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/input_adapters.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/input_adapters.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once @@ -23,6 +23,7 @@ #include <istream> // istream #endif // JSON_NO_IO +#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/iterators/iterator_traits.hpp> #include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/meta/type_traits.hpp> @@ -67,6 +68,13 @@ return std::fgetc(m_file); } + // returns the number of characters successfully read + template<class T> + std::size_t get_elements(T* dest, std::size_t count = 1) + { + return fread(dest, 1, sizeof(T) * count, m_file); + } + private: /// the file pointer to read from std::FILE* m_file; @@ -126,6 +134,17 @@ return res; } + template<class T> + std::size_t get_elements(T* dest, std::size_t count = 1) + { + auto res = static_cast<std::size_t>(sb->sgetn(reinterpret_cast<char*>(dest), static_cast<std::streamsize>(count * sizeof(T)))); + if (JSON_HEDLEY_UNLIKELY(res < count * sizeof(T))) + { + is->clear(is->rdstate() | std::ios::eofbit); + } + return res; + } + private: /// the associated input stream std::istream* is = nullptr; @@ -157,6 +176,26 @@ return char_traits<char_type>::eof(); } + // for general iterators, we cannot really do something better than falling back to processing the range one-by-one + template<class T> + std::size_t get_elements(T* dest, std::size_t count = 1) + { + auto* ptr = reinterpret_cast<char*>(dest); + for (std::size_t read_index = 0; read_index < count * sizeof(T); ++read_index) + { + if (JSON_HEDLEY_LIKELY(current != end)) + { + ptr[read_index] = static_cast<char>(*current); + std::advance(current, 1); + } + else + { + return read_index; + } + } + return count * sizeof(T); + } + private: IteratorType current; IteratorType end; @@ -320,6 +359,13 @@ return utf8_bytes[utf8_bytes_index++]; } + // parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here + template<class T> + std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1) + { + JSON_THROW(parse_error::create(112, 1, "wide string type cannot be interpreted as binary data", nullptr)); + } + private: BaseInputAdapter base_adapter; @@ -416,10 +462,17 @@ return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container); } +// specialization for std::string +using string_input_adapter_type = decltype(input_adapter(std::declval<std::string>())); + #ifndef JSON_NO_IO // Special cases with fast paths inline file_input_adapter input_adapter(std::FILE* file) { + if (file == nullptr) + { + JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } return file_input_adapter(file); } @@ -446,9 +499,13 @@ int >::type = 0 > contiguous_bytes_input_adapter input_adapter(CharT b) { + if (b == nullptr) + { + JSON_THROW(parse_error::create(101, 0, "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr)); + } auto length = std::strlen(reinterpret_cast<const char*>(b)); const auto* ptr = reinterpret_cast<const char*>(b); - return input_adapter(ptr, ptr + length); + return input_adapter(ptr, ptr + length); // cppcheck-suppress[nullPointerArithmeticRedundantCheck] } template<typename T, std::size_t N> Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/json_sax.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/json_sax.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/json_sax.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,22 +1,23 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once #include <cstddef> #include <string> // string +#include <type_traits> // enable_if_t #include <utility> // move #include <vector> // vector #include <nlohmann/detail/exceptions.hpp> +#include <nlohmann/detail/input/lexer.hpp> #include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/string_concat.hpp> - NLOHMANN_JSON_NAMESPACE_BEGIN /*! @@ -144,6 +145,11 @@ namespace detail { +constexpr std::size_t unknown_size() +{ + return (std::numeric_limits<std::size_t>::max)(); +} + /*! @brief SAX implementation to create a JSON value from SAX events @@ -157,7 +163,7 @@ @tparam BasicJsonType the JSON type */ -template<typename BasicJsonType> +template<typename BasicJsonType, typename InputAdapterType> class json_sax_dom_parser { public: @@ -166,14 +172,15 @@ using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; using binary_t = typename BasicJsonType::binary_t; + using lexer_t = lexer<BasicJsonType, InputAdapterType>; /*! @param[in,out] r reference to a JSON value that is manipulated while parsing @param[in] allow_exceptions_ whether parse errors yield exceptions */ - explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) - : root(r), allow_exceptions(allow_exceptions_) + explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true, lexer_t* lexer_ = nullptr) + : root(r), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_) {} // make class move-only @@ -229,7 +236,18 @@ { ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the object here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the object, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); } @@ -252,6 +270,14 @@ JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(ref_stack.back()->is_object()); +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing brace, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + ref_stack.back()->set_parents(); ref_stack.pop_back(); return true; @@ -261,7 +287,16 @@ { ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the array here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); } @@ -274,6 +309,14 @@ JSON_ASSERT(!ref_stack.empty()); JSON_ASSERT(ref_stack.back()->is_array()); +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing bracket, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + ref_stack.back()->set_parents(); ref_stack.pop_back(); return true; @@ -298,6 +341,75 @@ } private: + +#if JSON_DIAGNOSTIC_POSITIONS + void handle_diagnostic_positions_for_json_value(BasicJsonType& v) + { + if (m_lexer_ref) + { + // Lexer has read past the current field value, so set the end position to the current position. + // The start position will be set below based on the length of the string representation + // of the value. + v.end_position = m_lexer_ref->get_position(); + + switch (v.type()) + { + case value_t::boolean: + { + // 4 and 5 are the string length of "true" and "false" + v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5); + break; + } + + case value_t::null: + { + // 4 is the string length of "null" + v.start_position = v.end_position - 4; + break; + } + + case value_t::string: + { + // include the length of the quotes, which is 2 + v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + break; + } + + // As we handle the start and end positions for values created during parsing, + // we do not expect the following value type to be called. Regardless, set the positions + // in case this is created manually or through a different constructor. Exclude from lcov + // since the exact condition of this switch is esoteric. + // LCOV_EXCL_START + case value_t::discarded: + { + v.end_position = std::string::npos; + v.start_position = v.end_position; + break; + } + // LCOV_EXCL_STOP + case value_t::binary: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + { + v.start_position = v.end_position - m_lexer_ref->get_string().size(); + break; + } + case value_t::object: + case value_t::array: + { + // object and array are handled in start_object() and start_array() handlers + // skip setting the values here. + break; + } + default: // LCOV_EXCL_LINE + // Handle all possible types discretely, default handler should never be reached. + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE + } + } + } +#endif + /*! @invariant If the ref stack is empty, then the passed value will be the new root. @@ -311,6 +423,11 @@ if (ref_stack.empty()) { root = BasicJsonType(std::forward<Value>(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(root); +#endif + return &root; } @@ -319,12 +436,22 @@ if (ref_stack.back()->is_array()) { ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(ref_stack.back()->m_data.m_value.array->back()); +#endif + return &(ref_stack.back()->m_data.m_value.array->back()); } JSON_ASSERT(ref_stack.back()->is_object()); JSON_ASSERT(object_element); *object_element = BasicJsonType(std::forward<Value>(v)); + +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(*object_element); +#endif + return object_element; } @@ -338,9 +465,11 @@ bool errored = false; /// whether to throw exceptions in case of errors const bool allow_exceptions = true; + /// the lexer reference to obtain the current position + lexer_t* m_lexer_ref = nullptr; }; -template<typename BasicJsonType> +template<typename BasicJsonType, typename InputAdapterType> class json_sax_dom_callback_parser { public: @@ -351,11 +480,13 @@ using binary_t = typename BasicJsonType::binary_t; using parser_callback_t = typename BasicJsonType::parser_callback_t; using parse_event_t = typename BasicJsonType::parse_event_t; + using lexer_t = lexer<BasicJsonType, InputAdapterType>; json_sax_dom_callback_parser(BasicJsonType& r, - const parser_callback_t cb, - const bool allow_exceptions_ = true) - : root(r), callback(cb), allow_exceptions(allow_exceptions_) + parser_callback_t cb, + const bool allow_exceptions_ = true, + lexer_t* lexer_ = nullptr) + : root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_) { keep_stack.push_back(true); } @@ -418,12 +549,26 @@ auto val = handle_value(BasicJsonType::value_t::object, true); ref_stack.push_back(val.second); - // check object limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) + if (ref_stack.back()) { - JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); - } +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the object here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the object, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + // check object limit + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back())); + } + } return true; } @@ -452,9 +597,23 @@ { // discard object *ref_stack.back() = discarded; + +#if JSON_DIAGNOSTIC_POSITIONS + // Set start/end positions for discarded object. + handle_diagnostic_positions_for_json_value(*ref_stack.back()); +#endif } else { + +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing brace, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + ref_stack.back()->set_parents(); } } @@ -488,10 +647,25 @@ auto val = handle_value(BasicJsonType::value_t::array, true); ref_stack.push_back(val.second); - // check array limit - if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size())) + if (ref_stack.back()) { - JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + +#if JSON_DIAGNOSTIC_POSITIONS + // Manually set the start position of the array here. + // Ensure this is after the call to handle_value to ensure correct start position. + if (m_lexer_ref) + { + // Lexer has read the first character of the array, so + // subtract 1 from the position to get the correct start position. + ref_stack.back()->start_position = m_lexer_ref->get_position() - 1; + } +#endif + + // check array limit + if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back())); + } } return true; @@ -506,12 +680,26 @@ keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); if (keep) { + +#if JSON_DIAGNOSTIC_POSITIONS + if (m_lexer_ref) + { + // Lexer's position is past the closing bracket, so set that as the end position. + ref_stack.back()->end_position = m_lexer_ref->get_position(); + } +#endif + ref_stack.back()->set_parents(); } else { // discard array *ref_stack.back() = discarded; + +#if JSON_DIAGNOSTIC_POSITIONS + // Set start/end positions for discarded array. + handle_diagnostic_positions_for_json_value(*ref_stack.back()); +#endif } } @@ -548,6 +736,71 @@ } private: + +#if JSON_DIAGNOSTIC_POSITIONS + void handle_diagnostic_positions_for_json_value(BasicJsonType& v) + { + if (m_lexer_ref) + { + // Lexer has read past the current field value, so set the end position to the current position. + // The start position will be set below based on the length of the string representation + // of the value. + v.end_position = m_lexer_ref->get_position(); + + switch (v.type()) + { + case value_t::boolean: + { + // 4 and 5 are the string length of "true" and "false" + v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5); + break; + } + + case value_t::null: + { + // 4 is the string length of "null" + v.start_position = v.end_position - 4; + break; + } + + case value_t::string: + { + // include the length of the quotes, which is 2 + v.start_position = v.end_position - v.m_data.m_value.string->size() - 2; + break; + } + + case value_t::discarded: + { + v.end_position = std::string::npos; + v.start_position = v.end_position; + break; + } + + case value_t::binary: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + { + v.start_position = v.end_position - m_lexer_ref->get_string().size(); + break; + } + + case value_t::object: + case value_t::array: + { + // object and array are handled in start_object() and start_array() handlers + // skip setting the values here. + break; + } + default: // LCOV_EXCL_LINE + // Handle all possible types discretely, default handler should never be reached. + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE + } + } + } +#endif + /*! @param[in] v value to add to the JSON value we build during parsing @param[in] skip_callback whether we should skip calling the callback @@ -578,6 +831,10 @@ // create value auto value = BasicJsonType(std::forward<Value>(v)); +#if JSON_DIAGNOSTIC_POSITIONS + handle_diagnostic_positions_for_json_value(value); +#endif + // check callback const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value); @@ -632,9 +889,9 @@ /// stack to model hierarchy of values std::vector<BasicJsonType*> ref_stack {}; /// stack to manage which values to keep - std::vector<bool> keep_stack {}; + std::vector<bool> keep_stack {}; // NOLINT(readability-redundant-member-init) /// stack to manage which object keys to keep - std::vector<bool> key_keep_stack {}; + std::vector<bool> key_keep_stack {}; // NOLINT(readability-redundant-member-init) /// helper to hold the reference for the next object element BasicJsonType* object_element = nullptr; /// whether a syntax error occurred @@ -645,6 +902,8 @@ const bool allow_exceptions = true; /// a discarded value for the callback BasicJsonType discarded = BasicJsonType::value_t::discarded; + /// the lexer reference to obtain the current position + lexer_t* m_lexer_ref = nullptr; }; template<typename BasicJsonType> @@ -692,7 +951,7 @@ return true; } - bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) + bool start_object(std::size_t /*unused*/ = detail::unknown_size()) { return true; } @@ -707,7 +966,7 @@ return true; } - bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1)) + bool start_array(std::size_t /*unused*/ = detail::unknown_size()) { return true; } Modified: trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/lexer.hpp ============================================================================== --- trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/lexer.hpp Fri Apr 18 11:04:13 2025 (r23133) +++ trunk/OpenMPT/include/nlohmann-json/include/nlohmann/detail/input/lexer.hpp Fri Apr 18 11:05:17 2025 (r23134) @@ -1,9 +1,9 @@ // __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ -// | | |__ | | | | | | version 3.11.3 +// | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // -// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> +// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me> // SPDX-License-Identifier: MIT #pragma once @@ -967,7 +967,7 @@ locale's decimal point is used instead of `.` to work with the locale-dependent converters. */ - token_type scan_number() // lgtm [cpp/use-of-goto] + token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipu... [truncated message content] |