/* * This file is part of EasyRPG Player. * * EasyRPG Player is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * EasyRPG Player is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with EasyRPG Player. If not, see . */ #include "json_helper.h" #ifdef HAVE_NLOHMANN_JSON #include "output.h" #include #include #include #include #include "string_view.h" namespace { std::string GetValueAsString(const json& json_obj) { if (json_obj.is_null()) { return "null"; } if (json_obj.is_string()) { return json_obj.get(); } if (json_obj.is_number_integer()) { return std::to_string(json_obj.get()); } if (json_obj.is_number_float()) { return std::to_string(json_obj.get()); } if (json_obj.is_boolean()) { return json_obj.get() ? "true" : "false"; } return json_obj.dump(); } } // namespace namespace Json_Helper { std::optional Parse(std::string_view json_data) { json json_obj = json::parse(json_data, nullptr, false); if (json_obj.is_discarded()) { return {}; } return json_obj; } bool CheckJsonPointer(std::string_view json_path) { if (json_path.empty()) { Output::Warning("JSON: Empty json pointer at: {}", json_path); return false; } if (json_path.front() != '/') { Output::Warning("JSON: Json pointer must start with /: {}", json_path); return false; } return true; } std::string GetValue(json& json_obj, std::string_view json_path) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); if (!json_obj.contains(ptr)) { return {}; } const json& value = json_obj[ptr]; auto val = GetValueAsString(value); return val; } std::string SetValue(json& json_obj, std::string_view json_path, std::string_view value) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); json obj_value = json::parse(value, nullptr, false); if (obj_value.is_discarded()) { // If parsing fails, treat it as a string value json_obj[ptr] = std::string(value); } else { json_obj[ptr] = obj_value; } return json_obj.dump(); } size_t GetLength(const json& json_obj, std::string_view json_path) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); if (!json_obj.contains(ptr)) { return 0; } const json& value = json_obj[ptr]; if (!value.is_array() && !value.is_object()) { return 0; } return value.size(); } std::vector GetKeys(const json& json_obj, std::string_view json_path) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); if (!json_obj.contains(ptr)) { return {}; } const json& value = json_obj[ptr]; std::vector keys; if (value.is_object()) { for (const auto& item : value.items()) { keys.push_back(item.key()); } } else if (value.is_array()) { for (size_t i = 0; i < value.size(); ++i) { keys.push_back(std::to_string(i)); } } return keys; } std::string GetType(const json& json_obj, std::string_view json_path) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); if (!json_obj.contains(ptr)) { return {}; } const json& value = json_obj[ptr]; if (value.is_object()) return std::string("object"); if (value.is_array()) return std::string("array"); if (value.is_string()) return std::string("string"); if (value.is_number()) return std::string("number"); if (value.is_boolean()) return std::string("boolean"); if (value.is_null()) return std::string("null"); return std::string("unknown"); } std::string GetPath(const json& json_obj, const json& search_value) { std::function find_path; find_path = [&find_path](const json& obj, const json& target, const std::string& current_path) -> std::string { if (obj == target) { return current_path; } if (obj.is_object()) { for (const auto& item : obj.items()) { auto path = find_path(item.value(), target, current_path + "/" + item.key()); if (!path.empty()) return path; } } else if (obj.is_array()) { for (size_t i = 0; i < obj.size(); ++i) { auto path = find_path(obj[i], target, current_path + "/" + std::to_string(i)); if (!path.empty()) return path; } } return {}; }; return find_path(json_obj, search_value, ""); } std::string PrettyPrint(const json& json_obj, int indent) { return json_obj.dump(std::max(0, indent)); } std::string RemoveValue(json& json_obj, std::string_view json_path) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); if (!json_obj.contains(ptr)) { return {}; } // Get parent path and key/index to remove auto parent_ptr = ptr.parent_pointer(); json& parent = json_obj[parent_ptr]; json_path.remove_prefix(parent_ptr.to_string().size() + 1); if (parent.is_object()) { parent.erase(std::string(json_path)); } else if (parent.is_array()) { // Check if key is a valid positive number unsigned index; auto ec = std::from_chars(json_path.data(), json_path.data() + json_path.size(), index).ec; if (ec == std::errc()) { if (index < parent.size()) { parent.erase(index); } } else { Output::Warning("JSON: Invalid array index at: {}", json_path); return {}; } } return json_obj.dump(); } std::string PushValue(json& json_obj, std::string_view json_path, std::string_view value) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); if (!json_obj.contains(ptr)) { return {}; } json& array = json_obj[ptr]; if (!array.is_array()) { Output::Warning("JSON: Path does not point to an array: {}", json_path); return {}; } json obj_value = json::parse(value, nullptr, false); if (obj_value.is_discarded()) { // If parsing fails, treat it as a string value array.push_back(std::string(value)); } else { array.push_back(obj_value); } return json_obj.dump(); } std::tuple PopValue(json& json_obj, std::string_view json_path) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); if (!json_obj.contains(ptr)) { return {}; } json& array = json_obj[ptr]; if (!array.is_array() || array.empty()) { Output::Warning("JSON: Path does not point to a non-empty array: {}", json_path); return {}; } json popped = array.back(); array.erase(array.size() - 1); return {json_obj.dump(), GetValueAsString(popped)}; } bool Contains(const json& json_obj, std::string_view json_path) { std::string path_str = std::string(json_path); json::json_pointer ptr(path_str); return json_obj.contains(ptr); } } // namespace Json_Helper #endif // HAVE_NLOHMANN_JSON