// __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ // | | |__ | | | | | | version 3.12.0 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2013-2026 Niels Lohmann // SPDX-License-Identifier: MIT #pragma once #include // size_t #include // uint64_t #include // numeric_limits #include // string, to_string #include #include #include NLOHMANN_JSON_NAMESPACE_BEGIN namespace detail { namespace view { /// what resolving a JSON pointer does where it cannot continue enum class pointer_mode { unchecked, ///< as const basic_json::operator[]: a discarded view where basic_json's behavior is undefined checked, ///< as basic_json::at(): out_of_range.401/403 value, ///< as basic_json::value(): no out_of_range exceptions (the default value is used) contains, ///< as basic_json::contains(): no exceptions at all }; /// the outcome of reading an array index: detail::parse_array_index(), shared with json_pointer using index_status = detail::array_index_status; /// reads an array index like json_pointer::array_index (RFC 6901, Sect. 4), /// but reports errors instead of throwing them template index_status array_index(const StringType& s, std::size_t& idx) noexcept { return detail::parse_array_index(s, idx); } /// throws the exception json_pointer::array_index throws for this status template [[noreturn]] NLOHMANN_VIEW_NOINLINE void throw_array_index_error(index_status status, const StringType& s) { switch (status) { case index_status::leading_zero: throw_parse_error(exception_id::pointer_index_leading_zero, concat("array index '", s, "' must not begin with '0'")); case index_status::not_a_number: throw_parse_error(exception_id::pointer_index_not_a_number, concat("array index '", s, "' is not a number")); case index_status::exceeds_size_type: throw_out_of_range(exception_id::value_out_of_range, concat("array index ", s, " exceeds size_type")); // LCOV_EXCL_LINE case index_status::unresolved: case index_status::ok: default: throw_out_of_range(exception_id::pointer_unresolved, concat("unresolved reference token '", s, "'")); } } /*! @brief resolve the reference tokens of a JSON pointer, starting at a view The exceptions are those basic_json throws for the same pointer; where basic_json's behavior is undefined (a missing key or an index out of range with const operator[]), the result is a discarded view. */ template View resolve_pointer(View cur, const Tokens& tokens, pointer_mode mode) { using string_view_t = typename View::string_view_t; const bool throwing = mode == pointer_mode::unchecked || mode == pointer_mode::checked; for (const auto& token : tokens) { if (cur.is_object()) { const auto it = cur.find(string_view_t(token.data(), token.size())); if (it == cur.end()) { if (mode == pointer_mode::checked) { throw_key_not_found(token); } return View(); } cur = *it; } else if (cur.is_array()) { if (token.size() == 1 && token[0] == '-') { if (throwing) { throw_array_index_past_end(cur.size()); } return View(); } std::size_t idx = 0; const index_status status = array_index(token, idx); if (status != index_status::ok) { const bool parse_error = status == index_status::leading_zero || status == index_status::not_a_number; if (throwing || (mode == pointer_mode::value && parse_error)) { throw_array_index_error(status, token); } return View(); } if (idx >= cur.size()) { if (mode == pointer_mode::checked) { throw_array_index_out_of_range(idx); } return View(); } cur = cur[idx]; } else { if (throwing) { throw_out_of_range(exception_id::pointer_unresolved, concat("unresolved reference token '", token, "'")); } return View(); } } return cur; } } // namespace view } // namespace detail NLOHMANN_JSON_NAMESPACE_END