From eec6de6b73e3c3ff48cde490fe88d6f3781d625d Mon Sep 17 00:00:00 2001 From: Mauro Junior <45118493+jetrotal@users.noreply.github.com> Date: Fri, 3 May 2024 01:15:02 -0300 Subject: [PATCH 1/6] New Command 2055 - Process JSON Code --- CMakeLists.txt | 2 + src/game_interpreter.cpp | 46 ++++++++++- src/game_interpreter.h | 1 + src/json_helper.cpp | 159 +++++++++++++++++++++++++++++++++++++++ src/json_helper.h | 11 +++ 5 files changed, 217 insertions(+), 2 deletions(-) create mode 100644 src/json_helper.cpp create mode 100644 src/json_helper.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ddbc0b3106..48b917b7a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,6 +239,8 @@ add_library(${PROJECT_NAME} OBJECT src/input_source.h src/instrumentation.cpp src/instrumentation.h + src/json_helper.cpp + src/json_helper.h src/keys.h src/main_data.cpp src/main_data.h diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 0dc5ba3ec1..609179c3cf 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -46,6 +46,7 @@ #include "game_screen.h" #include "game_interpreter_control_variables.h" #include "game_windows.h" +#include "json_helper.h" #include "maniac_patch.h" #include "spriteset_map.h" #include "sprite_character.h" @@ -789,9 +790,11 @@ bool Game_Interpreter::ExecuteCommand(lcf::rpg::EventCommand const& com) { return CommandManiacCallCommand(com); case Cmd::EasyRpg_SetInterpreterFlag: return CommandEasyRpgSetInterpreterFlag(com); - case static_cast(2056): //EasyRPG_CloneMapEvent + case Cmd::EasyRpg_ProcessJson: + return CommandEasyRpgProcessJson(com); + case Cmd::EasyRpg_CloneMapEvent: return CommandEasyRpgCloneMapEvent(com); - case static_cast(2057): //EasyRPG_DestroyMapEvent + case Cmd::EasyRpg_DestroyMapEvent: return CommandEasyRpgDestroyMapEvent(com); default: return true; @@ -5062,6 +5065,45 @@ bool Game_Interpreter::CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand c return true; } +bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& com) { + if (!Player::IsPatchManiac()) { + return true; + } + + int operation = ValueOrVariable(com.parameters[0], com.parameters[1]); + int sourceVarId = ValueOrVariable(com.parameters[2], com.parameters[3]); + int targetVarId = ValueOrVariable(com.parameters[4], com.parameters[5]); + + std::string jsonPath = ToString(CommandStringOrVariable(com, 6, 7)); + std::string jsonData = ToString(Main_Data::game_strings->Get(sourceVarId)); + + int assignVarId = 0; + std::string result; + std::string newValue; + + switch (operation) { + case 0: // Get operation: Extract a value from JSON data + result = Json_Helper::GetValue(jsonData, jsonPath); + assignVarId = targetVarId; + break; + + case 1: // Set operation: Update JSON data with a new value + newValue = ToString(Main_Data::game_strings->Get(targetVarId)); + result = Json_Helper::SetValue(jsonData, jsonPath, newValue); + assignVarId = sourceVarId; + break; + + default: + Output::Warning("Process JSON - Invalid Operation: {}", operation); + result = "<>"; + break; + } + + if (result != "<>") Main_Data::game_strings->Asg({ assignVarId }, result); + + return true; +} + bool Game_Interpreter::CommandEasyRpgCloneMapEvent(lcf::rpg::EventCommand const& com) { if (!Player::HasEasyRpgExtensions()) { return true; diff --git a/src/game_interpreter.h b/src/game_interpreter.h index 7149d59ca2..4956ebb44d 100644 --- a/src/game_interpreter.h +++ b/src/game_interpreter.h @@ -298,6 +298,7 @@ class Game_Interpreter : public Game_BaseInterpreterContext bool CommandManiacControlStrings(lcf::rpg::EventCommand const& com); bool CommandManiacCallCommand(lcf::rpg::EventCommand const& com); bool CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand const& com); + bool CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& com); bool CommandEasyRpgCloneMapEvent(lcf::rpg::EventCommand const& com); bool CommandEasyRpgDestroyMapEvent(lcf::rpg::EventCommand const& com); diff --git a/src/json_helper.cpp b/src/json_helper.cpp new file mode 100644 index 0000000000..83d139f4a7 --- /dev/null +++ b/src/json_helper.cpp @@ -0,0 +1,159 @@ +#include "json_helper.h" +#include "external/picojson.h" +#include "output.h" +#include + +namespace Json_Helper { + const std::string kInvalidOutput = "<>"; + + std::vector SplitPath(const std::string& jsonPath) { + std::istringstream iss(jsonPath); + std::vector pathParts; + std::string part; + while (std::getline(iss, part, '.')) { + pathParts.push_back(part); + } + return pathParts; + } + + picojson::value* GetValuePointer(picojson::value& jsonValue, const std::vector& pathParts, bool allowCreation) { + picojson::value* currentValue = &jsonValue; + + for (const auto& part : pathParts) { + std::string arrayName; + int arrayIndex = -1; + bool inArray = false; + + for (char c : part) { + if (!inArray) { + if (c == '[') { + inArray = true; + arrayIndex = 0; + } + else { + arrayName += c; + } + } + else { + if (c == ']') { + break; + } + else { + arrayIndex = arrayIndex * 10 + (c - '0'); + } + } + } + + if (inArray) { + if (!currentValue->is()) { + if (allowCreation) { + *currentValue = picojson::value(picojson::object()); + } + else { + Output::Warning("JSON_ERROR - Invalid JSON type for array: {}", arrayName); + return nullptr; + } + } + + auto& obj = currentValue->get(); + auto arrayIt = obj.find(arrayName); + + if (arrayIt == obj.end()) { + if (allowCreation) { + obj.emplace(arrayName, picojson::value(picojson::array())); + arrayIt = obj.find(arrayName); + } + else { + Output::Warning("JSON_ERROR - Array not found: {}", arrayName); + return nullptr; + } + } + + auto& arr = arrayIt->second.get(); + + if (arrayIndex >= static_cast(arr.size())) { + if (allowCreation) { + arr.resize(arrayIndex + 1); + } + else { + Output::Warning("JSON_ERROR - Array index out of bounds: {}", part); + return nullptr; + } + } + + currentValue = &arr[arrayIndex]; + } + else { + if (!currentValue->is()) { + if (allowCreation) { + *currentValue = picojson::value(picojson::object()); + } + else { + Output::Warning("JSON_ERROR - Invalid JSON type for path: {}", part); + return nullptr; + } + } + + auto& obj = currentValue->get(); + auto objIt = obj.find(arrayName); + + if (objIt == obj.end()) { + if (allowCreation) { + obj.emplace(arrayName, picojson::value(picojson::object())); + objIt = obj.find(arrayName); + } + else { + Output::Warning("JSON_ERROR - Object key not found: {}", part); + return nullptr; + } + } + + currentValue = &objIt->second; + } + } + + return currentValue; + } + + std::string GetValue(const std::string& jsonData, const std::string& jsonPath) { + picojson::value jsonValue; + std::string err = picojson::parse(jsonValue, jsonData); + + if (!err.empty()) { + Output::Warning("JSON_ERROR - JSON parsing error: {}", err); + return kInvalidOutput; + } + + auto pathParts = SplitPath(jsonPath); + auto valuePtr = GetValuePointer(jsonValue, pathParts, false); + + if (valuePtr == nullptr || !valuePtr->is()) { + Output::Warning("JSON_ERROR - Value not found or not a string"); + return kInvalidOutput; + } + + return valuePtr->get(); + } + + std::string SetValue(const std::string& jsonData, const std::string& jsonPath, const std::string& value) { + picojson::value jsonValue; + std::string err = picojson::parse(jsonValue, jsonData); + + if (!err.empty()) { + Output::Warning("JSON_ERROR - JSON parsing error: {}", err); + return kInvalidOutput; + } + + auto pathParts = SplitPath(jsonPath); + auto valuePtr = GetValuePointer(jsonValue, pathParts, true); + + if (valuePtr == nullptr) { + Output::Warning("JSON_ERROR - Unable to create value"); + return kInvalidOutput; + } + + *valuePtr = picojson::value(value); + + return picojson::value(jsonValue).serialize(); + } +} diff --git a/src/json_helper.h b/src/json_helper.h new file mode 100644 index 0000000000..1e846a94c0 --- /dev/null +++ b/src/json_helper.h @@ -0,0 +1,11 @@ +#ifndef JSON_HELPER_H +#define JSON_HELPER_H + +#include + +namespace Json_Helper { + std::string GetValue(const std::string& jsonData, const std::string& jsonPath); + std::string SetValue(const std::string& jsonData, const std::string& jsonPath, const std::string& value); +} + +#endif // JSON_HELPER_H From 391a7e324698957cbbde983d95b20784d5f212a7 Mon Sep 17 00:00:00 2001 From: Mauro Junior <45118493+jetrotal@users.noreply.github.com> Date: Sat, 18 May 2024 21:48:26 -0300 Subject: [PATCH 2/6] use nlohmann's JSON Library instead of picoJSON. also Update Makefile.am --- Makefile.am | 2 + src/json_helper.cpp | 219 ++++++++++++++++++-------------------------- 2 files changed, 91 insertions(+), 130 deletions(-) diff --git a/Makefile.am b/Makefile.am index 28b8b8e006..7ee65f6792 100644 --- a/Makefile.am +++ b/Makefile.am @@ -217,6 +217,8 @@ libeasyrpg_player_a_SOURCES = \ src/input_source.h \ src/instrumentation.cpp \ src/instrumentation.h \ + src/json_helper.cpp \ + src/json_helper.h \ src/keys.h \ src/main_data.cpp \ src/main_data.h \ diff --git a/src/json_helper.cpp b/src/json_helper.cpp index 83d139f4a7..5c4d01311f 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -1,159 +1,118 @@ #include "json_helper.h" -#include "external/picojson.h" #include "output.h" -#include +#include namespace Json_Helper { - const std::string kInvalidOutput = "<>"; - - std::vector SplitPath(const std::string& jsonPath) { - std::istringstream iss(jsonPath); - std::vector pathParts; - std::string part; - while (std::getline(iss, part, '.')) { - pathParts.push_back(part); - } - return pathParts; - } - - picojson::value* GetValuePointer(picojson::value& jsonValue, const std::vector& pathParts, bool allowCreation) { - picojson::value* currentValue = &jsonValue; - - for (const auto& part : pathParts) { - std::string arrayName; - int arrayIndex = -1; - bool inArray = false; - - for (char c : part) { - if (!inArray) { - if (c == '[') { - inArray = true; - arrayIndex = 0; - } - else { - arrayName += c; + std::string invalid_str = "<>"; + std::string GetValue(const std::string& jsonData, const std::string& jsonPath) { + try { + nlohmann::json jsonObj = nlohmann::json::parse(jsonData); + nlohmann::json* currentObj = &jsonObj; + + std::string mutableJsonPath = jsonPath; + size_t pos = 0; + std::string token; + while ((pos = mutableJsonPath.find('.')) != std::string::npos) { + token = mutableJsonPath.substr(0, pos); + if (token.back() == ']') { + size_t bracketPos = token.find('['); + std::string arrayName = token.substr(0, bracketPos); + int index = std::stoi(token.substr(bracketPos + 1, token.length() - bracketPos - 2)); + if (currentObj->find(arrayName) == currentObj->end() || !(*currentObj)[arrayName].is_array() || index >= (*currentObj)[arrayName].size()) { + Output::Warning("JSON_ERROR - Invalid path: {}", jsonPath); + return invalid_str; } + currentObj = &((*currentObj)[arrayName][index]); } else { - if (c == ']') { - break; - } - else { - arrayIndex = arrayIndex * 10 + (c - '0'); + if (currentObj->find(token) == currentObj->end()) { + Output::Warning("JSON_ERROR - Invalid path: {}", jsonPath); + return invalid_str; } + currentObj = &((*currentObj)[token]); } + mutableJsonPath.erase(0, pos + 1); } - if (inArray) { - if (!currentValue->is()) { - if (allowCreation) { - *currentValue = picojson::value(picojson::object()); - } - else { - Output::Warning("JSON_ERROR - Invalid JSON type for array: {}", arrayName); - return nullptr; + if (!mutableJsonPath.empty()) { + if (mutableJsonPath.back() == ']') { + size_t bracketPos = mutableJsonPath.find('['); + std::string arrayName = mutableJsonPath.substr(0, bracketPos); + int index = std::stoi(mutableJsonPath.substr(bracketPos + 1, mutableJsonPath.length() - bracketPos - 2)); + if (currentObj->find(arrayName) == currentObj->end() || !(*currentObj)[arrayName].is_array() || index >= (*currentObj)[arrayName].size()) { + Output::Warning("JSON_ERROR - Invalid path: {}", jsonPath); + return invalid_str; } + currentObj = &((*currentObj)[arrayName][index]); } - - auto& obj = currentValue->get(); - auto arrayIt = obj.find(arrayName); - - if (arrayIt == obj.end()) { - if (allowCreation) { - obj.emplace(arrayName, picojson::value(picojson::array())); - arrayIt = obj.find(arrayName); - } - else { - Output::Warning("JSON_ERROR - Array not found: {}", arrayName); - return nullptr; - } - } - - auto& arr = arrayIt->second.get(); - - if (arrayIndex >= static_cast(arr.size())) { - if (allowCreation) { - arr.resize(arrayIndex + 1); - } - else { - Output::Warning("JSON_ERROR - Array index out of bounds: {}", part); - return nullptr; + else { + if (currentObj->find(mutableJsonPath) == currentObj->end()) { + Output::Warning("JSON_ERROR - Invalid path: {}", jsonPath); + return invalid_str; } + currentObj = &((*currentObj)[mutableJsonPath]); } + } - currentValue = &arr[arrayIndex]; + if (currentObj->is_string()) { + return currentObj->get(); + } + else if (currentObj->is_number_integer()) { + return std::to_string(currentObj->get()); + } + else if (currentObj->is_number_float()) { + return std::to_string(currentObj->get()); + } + else if (currentObj->is_boolean()) { + return currentObj->get() ? "true" : "false"; } else { - if (!currentValue->is()) { - if (allowCreation) { - *currentValue = picojson::value(picojson::object()); - } - else { - Output::Warning("JSON_ERROR - Invalid JSON type for path: {}", part); - return nullptr; - } - } - - auto& obj = currentValue->get(); - auto objIt = obj.find(arrayName); - - if (objIt == obj.end()) { - if (allowCreation) { - obj.emplace(arrayName, picojson::value(picojson::object())); - objIt = obj.find(arrayName); - } - else { - Output::Warning("JSON_ERROR - Object key not found: {}", part); - return nullptr; - } - } - - currentValue = &objIt->second; + return currentObj->dump(); } } - - return currentValue; - } - - std::string GetValue(const std::string& jsonData, const std::string& jsonPath) { - picojson::value jsonValue; - std::string err = picojson::parse(jsonValue, jsonData); - - if (!err.empty()) { - Output::Warning("JSON_ERROR - JSON parsing error: {}", err); - return kInvalidOutput; - } - - auto pathParts = SplitPath(jsonPath); - auto valuePtr = GetValuePointer(jsonValue, pathParts, false); - - if (valuePtr == nullptr || !valuePtr->is()) { - Output::Warning("JSON_ERROR - Value not found or not a string"); - return kInvalidOutput; + catch (const std::exception& e) { + Output::Warning("JSON_ERROR - {}", e.what()); + return invalid_str; } - - return valuePtr->get(); } std::string SetValue(const std::string& jsonData, const std::string& jsonPath, const std::string& value) { - picojson::value jsonValue; - std::string err = picojson::parse(jsonValue, jsonData); - - if (!err.empty()) { - Output::Warning("JSON_ERROR - JSON parsing error: {}", err); - return kInvalidOutput; - } + try { + nlohmann::json jsonObj = nlohmann::json::parse(jsonData); + nlohmann::json* currentObj = &jsonObj; + + std::string mutableJsonPath = jsonPath; + size_t pos = 0; + std::string token; + while ((pos = mutableJsonPath.find('.')) != std::string::npos) { + token = mutableJsonPath.substr(0, pos); + if (token.back() == ']') { + size_t bracketPos = token.find('['); + std::string arrayName = token.substr(0, bracketPos); + int index = std::stoi(token.substr(bracketPos + 1, token.length() - bracketPos - 2)); + currentObj = &((*currentObj)[arrayName][index]); + } + else { + currentObj = &((*currentObj)[token]); + } + mutableJsonPath.erase(0, pos + 1); + } - auto pathParts = SplitPath(jsonPath); - auto valuePtr = GetValuePointer(jsonValue, pathParts, true); + if (mutableJsonPath.back() == ']') { + size_t bracketPos = mutableJsonPath.find('['); + std::string arrayName = mutableJsonPath.substr(0, bracketPos); + int index = std::stoi(mutableJsonPath.substr(bracketPos + 1, mutableJsonPath.length() - bracketPos - 2)); + (*currentObj)[arrayName][index] = value; + } + else { + (*currentObj)[mutableJsonPath] = value; + } - if (valuePtr == nullptr) { - Output::Warning("JSON_ERROR - Unable to create value"); - return kInvalidOutput; + return jsonObj.dump(); + } + catch (const std::exception& e) { + Output::Warning("JSON_ERROR - {}", e.what()); + return jsonData; } - - *valuePtr = picojson::value(value); - - return picojson::value(jsonValue).serialize(); } } From 03a8a3eb13e45b7d6f643e62fd9afd66c7699ba6 Mon Sep 17 00:00:00 2001 From: Mauro Junior <45118493+jetrotal@users.noreply.github.com> Date: Sun, 19 May 2024 21:25:06 -0300 Subject: [PATCH 3/6] Syntax Refactor + target_var_type Param It's a bit faster and now you can tell if the target output is Switch, Variable, or StringVar. Update game_message.cpp --- src/game_interpreter.cpp | 75 ++++++++++----- src/json_helper.cpp | 198 +++++++++++++++++++++++---------------- src/json_helper.h | 5 +- 3 files changed, 171 insertions(+), 107 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 609179c3cf..e8b1733ce0 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -5071,35 +5071,66 @@ bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& c } int operation = ValueOrVariable(com.parameters[0], com.parameters[1]); - int sourceVarId = ValueOrVariable(com.parameters[2], com.parameters[3]); - int targetVarId = ValueOrVariable(com.parameters[4], com.parameters[5]); + int source_var_id = ValueOrVariable(com.parameters[2], com.parameters[3]); + int target_var_type = ValueOrVariable(com.parameters[4], com.parameters[5]); + int target_var_id = ValueOrVariable(com.parameters[6], com.parameters[7]); + std::string json_path = ToString(CommandStringOrVariable(com, 8, 9)); + std::string json_data = ToString(Main_Data::game_strings->Get(source_var_id)); - std::string jsonPath = ToString(CommandStringOrVariable(com, 6, 7)); - std::string jsonData = ToString(Main_Data::game_strings->Get(sourceVarId)); - - int assignVarId = 0; std::string result; - std::string newValue; - switch (operation) { - case 0: // Get operation: Extract a value from JSON data - result = Json_Helper::GetValue(jsonData, jsonPath); - assignVarId = targetVarId; - break; + if (operation == 0) { // Get operation: Extract a value from JSON data + result = Json_Helper::GetValue(json_data, json_path); - case 1: // Set operation: Update JSON data with a new value - newValue = ToString(Main_Data::game_strings->Get(targetVarId)); - result = Json_Helper::SetValue(jsonData, jsonPath, newValue); - assignVarId = sourceVarId; - break; + if (result != "<>") { + int output_value = 0; - default: - Output::Warning("Process JSON - Invalid Operation: {}", operation); - result = "<>"; - break; + std::istringstream iss(result); + int temp; + if (iss >> temp) { + output_value = temp; + } + else { + output_value = 0; + } + + switch (target_var_type) { + case 0: // Switch + Main_Data::game_switches->Set({ target_var_id }, output_value); + break; + case 1: // Variable + Main_Data::game_variables->Set({ target_var_id }, output_value); + break; + default: // String + Main_Data::game_strings->Asg({ target_var_id }, result); + break; + } + } } + else if (operation == 1) { // Set operation: Update JSON data with a new value + std::string new_value; + + switch (target_var_type) { + case 0: // Switch + new_value = std::to_string(Main_Data::game_switches->Get(target_var_id)); + break; + case 1: // Variable + new_value = std::to_string(Main_Data::game_variables->Get(target_var_id)); + break; + default: // String + new_value = ToString(Main_Data::game_strings->Get(target_var_id)); + break; + } + + result = Json_Helper::SetValue(json_data, json_path, new_value); - if (result != "<>") Main_Data::game_strings->Asg({ assignVarId }, result); + if (result != "<>") { + Main_Data::game_strings->Asg({ source_var_id }, result); + } + } + else { + Output::Warning("Process JSON - Invalid Operation: {}", operation); + } return true; } diff --git a/src/json_helper.cpp b/src/json_helper.cpp index 5c4d01311f..86f23a758a 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -1,118 +1,150 @@ #include "json_helper.h" #include "output.h" -#include +#include +#include namespace Json_Helper { - std::string invalid_str = "<>"; - std::string GetValue(const std::string& jsonData, const std::string& jsonPath) { - try { - nlohmann::json jsonObj = nlohmann::json::parse(jsonData); - nlohmann::json* currentObj = &jsonObj; - - std::string mutableJsonPath = jsonPath; - size_t pos = 0; - std::string token; - while ((pos = mutableJsonPath.find('.')) != std::string::npos) { - token = mutableJsonPath.substr(0, pos); - if (token.back() == ']') { - size_t bracketPos = token.find('['); - std::string arrayName = token.substr(0, bracketPos); - int index = std::stoi(token.substr(bracketPos + 1, token.length() - bracketPos - 2)); - if (currentObj->find(arrayName) == currentObj->end() || !(*currentObj)[arrayName].is_array() || index >= (*currentObj)[arrayName].size()) { - Output::Warning("JSON_ERROR - Invalid path: {}", jsonPath); - return invalid_str; + + const std::string k_invalid_str = "<>"; + + std::unordered_map json_cache; + + nlohmann::json* GetObjectAtPath(nlohmann::json& json_obj, std::string_view json_path, bool allow_path_creation = false) { + nlohmann::json* current_obj = &json_obj; + + std::stringstream path_stream(json_path.data()); + std::string token; + + while (std::getline(path_stream, token, '.')) { + if (token.back() == ']') { + size_t bracket_pos = token.find('['); + std::string array_name = token.substr(0, bracket_pos); + int index = std::stoi(token.substr(bracket_pos + 1, token.length() - bracket_pos - 2)); + + if (!current_obj->contains(array_name)) { + if (allow_path_creation) { + (*current_obj)[array_name] = nlohmann::json::array(); } - currentObj = &((*currentObj)[arrayName][index]); - } - else { - if (currentObj->find(token) == currentObj->end()) { - Output::Warning("JSON_ERROR - Invalid path: {}", jsonPath); - return invalid_str; + else { + return nullptr; } - currentObj = &((*currentObj)[token]); } - mutableJsonPath.erase(0, pos + 1); - } - if (!mutableJsonPath.empty()) { - if (mutableJsonPath.back() == ']') { - size_t bracketPos = mutableJsonPath.find('['); - std::string arrayName = mutableJsonPath.substr(0, bracketPos); - int index = std::stoi(mutableJsonPath.substr(bracketPos + 1, mutableJsonPath.length() - bracketPos - 2)); - if (currentObj->find(arrayName) == currentObj->end() || !(*currentObj)[arrayName].is_array() || index >= (*currentObj)[arrayName].size()) { - Output::Warning("JSON_ERROR - Invalid path: {}", jsonPath); - return invalid_str; + nlohmann::json& array_obj = (*current_obj)[array_name]; + + if (index >= array_obj.size()) { + if (allow_path_creation) { + array_obj.get_ref().resize(index + 1); } - currentObj = &((*currentObj)[arrayName][index]); - } - else { - if (currentObj->find(mutableJsonPath) == currentObj->end()) { - Output::Warning("JSON_ERROR - Invalid path: {}", jsonPath); - return invalid_str; + else { + return nullptr; } - currentObj = &((*currentObj)[mutableJsonPath]); } - } - if (currentObj->is_string()) { - return currentObj->get(); + current_obj = &(array_obj[index]); } - else if (currentObj->is_number_integer()) { - return std::to_string(currentObj->get()); - } - else if (currentObj->is_number_float()) { - return std::to_string(currentObj->get()); + else { + if (!current_obj->contains(token)) { + if (allow_path_creation) { + (*current_obj)[token] = nlohmann::json::object(); + } + else { + return nullptr; + } + } + + current_obj = &((*current_obj)[token]); } - else if (currentObj->is_boolean()) { - return currentObj->get() ? "true" : "false"; + } + + return current_obj; + } + + std::string GetValueAsString(const nlohmann::json& json_obj) { + std::string result; + + if (json_obj.is_string()) { + result = json_obj.get(); + } + else if (json_obj.is_number_integer()) { + result = std::to_string(json_obj.get()); + } + else if (json_obj.is_number_float()) { + result = std::to_string(json_obj.get()); + } + else if (json_obj.is_boolean()) { + result = json_obj.get() ? "true" : "false"; + } + else { + result = json_obj.dump(); + } + + return result; + } + + std::string GetValue(std::string_view json_data, std::string_view json_path) { + try { + nlohmann::json json_obj; + auto it = json_cache.find(json_data.data()); + + if (it != json_cache.end()) { + json_obj = it->second; } else { - return currentObj->dump(); + json_obj = nlohmann::json::parse(json_data); + json_cache[json_data.data()] = json_obj; + } + + nlohmann::json* current_obj = GetObjectAtPath(json_obj, json_path); + + if (current_obj == nullptr) { + Output::Warning("JSON_ERROR - Invalid path: {}", json_path); + return k_invalid_str; } + + return GetValueAsString(*current_obj); } catch (const std::exception& e) { Output::Warning("JSON_ERROR - {}", e.what()); - return invalid_str; + return k_invalid_str; } } - std::string SetValue(const std::string& jsonData, const std::string& jsonPath, const std::string& value) { + std::string SetValue(std::string_view json_data, std::string_view json_path, std::string_view value) { try { - nlohmann::json jsonObj = nlohmann::json::parse(jsonData); - nlohmann::json* currentObj = &jsonObj; - - std::string mutableJsonPath = jsonPath; - size_t pos = 0; - std::string token; - while ((pos = mutableJsonPath.find('.')) != std::string::npos) { - token = mutableJsonPath.substr(0, pos); - if (token.back() == ']') { - size_t bracketPos = token.find('['); - std::string arrayName = token.substr(0, bracketPos); - int index = std::stoi(token.substr(bracketPos + 1, token.length() - bracketPos - 2)); - currentObj = &((*currentObj)[arrayName][index]); - } - else { - currentObj = &((*currentObj)[token]); - } - mutableJsonPath.erase(0, pos + 1); - } + nlohmann::json json_obj; + auto it = json_cache.find(json_data.data()); - if (mutableJsonPath.back() == ']') { - size_t bracketPos = mutableJsonPath.find('['); - std::string arrayName = mutableJsonPath.substr(0, bracketPos); - int index = std::stoi(mutableJsonPath.substr(bracketPos + 1, mutableJsonPath.length() - bracketPos - 2)); - (*currentObj)[arrayName][index] = value; + if (it != json_cache.end()) { + json_obj = it->second; } else { - (*currentObj)[mutableJsonPath] = value; + json_obj = nlohmann::json::parse(json_data); + json_cache[json_data.data()] = json_obj; } - return jsonObj.dump(); + nlohmann::json* current_obj = GetObjectAtPath(json_obj, json_path, true); + + if (current_obj == nullptr) { + Output::Warning("JSON_ERROR - Invalid path: {}", json_path); + return std::string(json_data); + } + + // Parse the value string and set the appropriate JSON type + try { + *current_obj = nlohmann::json::parse(value); + } + catch (const nlohmann::json::parse_error&) { + // If parsing fails, treat it as a string value + *current_obj = value; + } + + return json_obj.dump(); } catch (const std::exception& e) { Output::Warning("JSON_ERROR - {}", e.what()); - return jsonData; + return std::string(json_data); } } + } diff --git a/src/json_helper.h b/src/json_helper.h index 1e846a94c0..d614fc55cd 100644 --- a/src/json_helper.h +++ b/src/json_helper.h @@ -2,10 +2,11 @@ #define JSON_HELPER_H #include +#include namespace Json_Helper { - std::string GetValue(const std::string& jsonData, const std::string& jsonPath); - std::string SetValue(const std::string& jsonData, const std::string& jsonPath, const std::string& value); + std::string GetValue(std::string_view json_data, std::string_view json_path); + std::string SetValue(std::string_view json_data, std::string_view json_path, std::string_view value); } #endif // JSON_HELPER_H From d75c939c385ffd718ee82d1407227f06681cfef0 Mon Sep 17 00:00:00 2001 From: Mauro Junior <45118493+jetrotal@users.noreply.github.com> Date: Tue, 21 May 2024 21:35:19 -0300 Subject: [PATCH 4/6] Process JSON Code: License + Dependency Check --- src/game_interpreter.cpp | 9 ++++++++- src/json_helper.cpp | 22 ++++++++++++++++++++++ src/json_helper.h | 22 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index e8b1733ce0..1544e5df94 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -5058,7 +5058,6 @@ bool Game_Interpreter::CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand c Player::game_config.patch_key_patch.Set(flag_value); if (flag_name == "rpg2k3-cmds" || flag_name == "rpg2k3-commands") Player::game_config.patch_rpg2k3_commands.Set(flag_value); - if (flag_name == "rpg2k-battle") lcf::Data::system.easyrpg_use_rpg2k_battle_system = flag_value; @@ -5066,7 +5065,13 @@ bool Game_Interpreter::CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand c } bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& com) { +#ifndef HAVE_NLOHMANN_JSON + Output::Warning("CommandProcessJson: JSON not supported on this platform"); + return true; +#else + if (!Player::IsPatchManiac()) { + Output::Warning("CommandProcessJson: This command needs Maniac Patch support"); return true; } @@ -5133,6 +5138,8 @@ bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& c } return true; + +#endif // !HAVE_NLOHMANN_JSON } bool Game_Interpreter::CommandEasyRpgCloneMapEvent(lcf::rpg::EventCommand const& com) { diff --git a/src/json_helper.cpp b/src/json_helper.cpp index 86f23a758a..1548fb15a3 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -1,4 +1,24 @@ +/* + * 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 @@ -148,3 +168,5 @@ namespace Json_Helper { } } + +#endif // HAVE_NLOHMANN_JSON diff --git a/src/json_helper.h b/src/json_helper.h index d614fc55cd..5a07aa9022 100644 --- a/src/json_helper.h +++ b/src/json_helper.h @@ -1,6 +1,27 @@ +/* + * 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 . + */ + #ifndef JSON_HELPER_H #define JSON_HELPER_H +#include "system.h" + +#ifdef HAVE_NLOHMANN_JSON + #include #include @@ -9,4 +30,5 @@ namespace Json_Helper { std::string SetValue(std::string_view json_data, std::string_view json_path, std::string_view value); } +#endif // HAVE_NLOHMANN_JSON #endif // JSON_HELPER_H From 4280490f754a058a9031d0f5046b64eb860ac583 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Thu, 21 Nov 2024 22:24:30 +0100 Subject: [PATCH 5/6] ProcessJson: Refactor, add sanity checks, use json pointer for read/write --- src/game_interpreter.cpp | 54 ++++++------- src/json_helper.cpp | 162 +++++++++++++-------------------------- src/json_helper.h | 6 +- 3 files changed, 83 insertions(+), 139 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 1544e5df94..ed54c39cfe 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -5065,50 +5065,47 @@ bool Game_Interpreter::CommandEasyRpgSetInterpreterFlag(lcf::rpg::EventCommand c } bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& com) { + if (!Player::HasEasyRpgExtensions()) { + return true; + } + #ifndef HAVE_NLOHMANN_JSON - Output::Warning("CommandProcessJson: JSON not supported on this platform"); + Output::Warning("CommandEasyRpgProcessJson: JSON not supported on this platform"); return true; #else - if (!Player::IsPatchManiac()) { - Output::Warning("CommandProcessJson: This command needs Maniac Patch support"); - return true; - } - int operation = ValueOrVariable(com.parameters[0], com.parameters[1]); int source_var_id = ValueOrVariable(com.parameters[2], com.parameters[3]); int target_var_type = ValueOrVariable(com.parameters[4], com.parameters[5]); int target_var_id = ValueOrVariable(com.parameters[6], com.parameters[7]); + std::string json_path = ToString(CommandStringOrVariable(com, 8, 9)); std::string json_data = ToString(Main_Data::game_strings->Get(source_var_id)); - std::string result; + if (target_var_type == 2 && !Player::IsPatchManiac()) { + Output::Warning("CommandEasyRpgProcessJson: String operations require Maniac Patch support"); + return true; + } + + std::optional result; if (operation == 0) { // Get operation: Extract a value from JSON data result = Json_Helper::GetValue(json_data, json_path); - if (result != "<>") { - int output_value = 0; - - std::istringstream iss(result); - int temp; - if (iss >> temp) { - output_value = temp; - } - else { - output_value = 0; - } - + if (result) { switch (target_var_type) { case 0: // Switch - Main_Data::game_switches->Set({ target_var_id }, output_value); + Main_Data::game_switches->Set(target_var_id, atoi(result->c_str()) != 0); break; case 1: // Variable - Main_Data::game_variables->Set({ target_var_id }, output_value); + Main_Data::game_variables->Set(target_var_id, atoi(result->c_str())); break; - default: // String - Main_Data::game_strings->Asg({ target_var_id }, result); + case 2: // String + Main_Data::game_strings->Asg({ target_var_id }, *result); break; + default: + Output::Warning("CommandEasyRpgProcessJson: Unsupported target_var_type {}", operation); + return true; } } } @@ -5122,19 +5119,22 @@ bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& c case 1: // Variable new_value = std::to_string(Main_Data::game_variables->Get(target_var_id)); break; - default: // String + case 2: // String new_value = ToString(Main_Data::game_strings->Get(target_var_id)); break; + default: + Output::Warning("CommandEasyRpgProcessJson: Unsupported target_var_type {}", operation); + return true; } result = Json_Helper::SetValue(json_data, json_path, new_value); - if (result != "<>") { - Main_Data::game_strings->Asg({ source_var_id }, result); + if (result) { + Main_Data::game_strings->Asg({ source_var_id }, *result); } } else { - Output::Warning("Process JSON - Invalid Operation: {}", operation); + Output::Warning("CommandEasyRpgProcessJson: Invalid Operation {}", operation); } return true; diff --git a/src/json_helper.cpp b/src/json_helper.cpp index 1548fb15a3..c0f26db2c8 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -20,67 +20,15 @@ #ifdef HAVE_NLOHMANN_JSON #include "output.h" +#include #include #include +#include "string_view.h" -namespace Json_Helper { - - const std::string k_invalid_str = "<>"; - - std::unordered_map json_cache; - - nlohmann::json* GetObjectAtPath(nlohmann::json& json_obj, std::string_view json_path, bool allow_path_creation = false) { - nlohmann::json* current_obj = &json_obj; - - std::stringstream path_stream(json_path.data()); - std::string token; - - while (std::getline(path_stream, token, '.')) { - if (token.back() == ']') { - size_t bracket_pos = token.find('['); - std::string array_name = token.substr(0, bracket_pos); - int index = std::stoi(token.substr(bracket_pos + 1, token.length() - bracket_pos - 2)); - - if (!current_obj->contains(array_name)) { - if (allow_path_creation) { - (*current_obj)[array_name] = nlohmann::json::array(); - } - else { - return nullptr; - } - } - - nlohmann::json& array_obj = (*current_obj)[array_name]; - - if (index >= array_obj.size()) { - if (allow_path_creation) { - array_obj.get_ref().resize(index + 1); - } - else { - return nullptr; - } - } - - current_obj = &(array_obj[index]); - } - else { - if (!current_obj->contains(token)) { - if (allow_path_creation) { - (*current_obj)[token] = nlohmann::json::object(); - } - else { - return nullptr; - } - } - - current_obj = &((*current_obj)[token]); - } - } +using json = nlohmann::json; - return current_obj; - } - - std::string GetValueAsString(const nlohmann::json& json_obj) { +namespace { + std::string GetValueAsString(const json& json_obj) { std::string result; if (json_obj.is_string()) { @@ -101,72 +49,66 @@ namespace Json_Helper { return result; } +} - std::string GetValue(std::string_view json_data, std::string_view json_path) { - try { - nlohmann::json json_obj; - auto it = json_cache.find(json_data.data()); +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 {}; + } - if (it != json_cache.end()) { - json_obj = it->second; - } - else { - json_obj = nlohmann::json::parse(json_data); - json_cache[json_data.data()] = json_obj; - } + return json_obj; + } - nlohmann::json* current_obj = GetObjectAtPath(json_obj, json_path); + std::optional GetValue(std::string_view json_data, std::string_view json_path) { + auto json_obj = Parse(json_data); + + if (!json_obj) { + Output::Warning("JSON: Parse error for {}", json_data); + return {}; + } - if (current_obj == nullptr) { - Output::Warning("JSON_ERROR - Invalid path: {}", json_path); - return k_invalid_str; - } + json::json_pointer ptr((std::string(json_path))); - return GetValueAsString(*current_obj); + if (ptr.empty()) { + Output::Warning("JSON: Bad json pointer {}", json_path); + return {}; } - catch (const std::exception& e) { - Output::Warning("JSON_ERROR - {}", e.what()); - return k_invalid_str; + + if (!json_obj->contains(ptr)) { + return ""; } + + return GetValueAsString((*json_obj)[ptr]); } std::string SetValue(std::string_view json_data, std::string_view json_path, std::string_view value) { - try { - nlohmann::json json_obj; - auto it = json_cache.find(json_data.data()); - - if (it != json_cache.end()) { - json_obj = it->second; - } - else { - json_obj = nlohmann::json::parse(json_data); - json_cache[json_data.data()] = json_obj; - } - - nlohmann::json* current_obj = GetObjectAtPath(json_obj, json_path, true); - - if (current_obj == nullptr) { - Output::Warning("JSON_ERROR - Invalid path: {}", json_path); - return std::string(json_data); - } - - // Parse the value string and set the appropriate JSON type - try { - *current_obj = nlohmann::json::parse(value); - } - catch (const nlohmann::json::parse_error&) { - // If parsing fails, treat it as a string value - *current_obj = value; - } - - return json_obj.dump(); + auto json_obj = Parse(json_data); + + if (!json_obj) { + Output::Warning("JSON Parse error for {}", json_data); + return std::string(json_data); + } + + json::json_pointer ptr((std::string(json_path))); + + if (ptr.empty()) { + Output::Warning("JSON: Bad json pointer {}", json_path); + return {}; } - catch (const std::exception& e) { - Output::Warning("JSON_ERROR - {}", e.what()); - return std::string(json_data); + + 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(); + } } #endif // HAVE_NLOHMANN_JSON diff --git a/src/json_helper.h b/src/json_helper.h index 5a07aa9022..75a5e775b3 100644 --- a/src/json_helper.h +++ b/src/json_helper.h @@ -22,11 +22,13 @@ #ifdef HAVE_NLOHMANN_JSON -#include +#include +#include #include namespace Json_Helper { - std::string GetValue(std::string_view json_data, std::string_view json_path); + std::optional Parse(std::string_view json_data); + std::optional GetValue(std::string_view json_data, std::string_view json_path); std::string SetValue(std::string_view json_data, std::string_view json_path, std::string_view value); } From 842c2a422fc900ebac8a0773962ccc8ee95b3a60 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Thu, 21 Nov 2024 22:37:42 +0100 Subject: [PATCH 6/6] ProcessJson: Cache parsed JSON to make accessing significantly faster The cache is invalidated when the string is set --- src/game_interpreter.cpp | 11 ++++++++--- src/game_strings.cpp | 23 +++++++++++++++++++++++ src/game_strings.h | 28 ++++++++++++++++++++++++++-- src/json_helper.cpp | 28 +++++++--------------------- src/json_helper.h | 4 ++-- 5 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index ed54c39cfe..d903697b8f 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -5080,7 +5080,12 @@ bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& c int target_var_id = ValueOrVariable(com.parameters[6], com.parameters[7]); std::string json_path = ToString(CommandStringOrVariable(com, 8, 9)); - std::string json_data = ToString(Main_Data::game_strings->Get(source_var_id)); + auto* json_data = Main_Data::game_strings->ParseJson(source_var_id); + + if (!json_data) { + Output::Warning("JSON Parse error for {}", Main_Data::game_strings->Get(source_var_id)); + return true; + } if (target_var_type == 2 && !Player::IsPatchManiac()) { Output::Warning("CommandEasyRpgProcessJson: String operations require Maniac Patch support"); @@ -5090,7 +5095,7 @@ bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& c std::optional result; if (operation == 0) { // Get operation: Extract a value from JSON data - result = Json_Helper::GetValue(json_data, json_path); + result = Json_Helper::GetValue(*json_data, json_path); if (result) { switch (target_var_type) { @@ -5127,7 +5132,7 @@ bool Game_Interpreter::CommandEasyRpgProcessJson(lcf::rpg::EventCommand const& c return true; } - result = Json_Helper::SetValue(json_data, json_path, new_value); + result = Json_Helper::SetValue(*json_data, json_path, new_value); if (result) { Main_Data::game_strings->Asg({ source_var_id }, *result); diff --git a/src/game_strings.cpp b/src/game_strings.cpp index c16d988a33..0dfb4319ac 100644 --- a/src/game_strings.cpp +++ b/src/game_strings.cpp @@ -28,11 +28,34 @@ #include "player.h" #include "utils.h" +#ifdef HAVE_NLOHMANN_JSON +#include "json_helper.h" +#endif + void Game_Strings::WarnGet(int id) const { Output::Debug("Invalid read strvar[{}]!", id); --_warnings; } +#ifdef HAVE_NLOHMANN_JSON +nlohmann::json* Game_Strings::ParseJson(int id) { + auto it = _json_cache.find(id); + if (it != _json_cache.end()) { + return &(it->second); + } + + auto str = ToString(Get(id)); + auto res = Json_Helper::Parse(str); + + if (!res) { + return nullptr; + } else { + _json_cache[id] = *res; + return &_json_cache[id]; + } +} +#endif + StringView Game_Strings::Asg(Str_Params params, StringView string) { Set(params, string); return Get(params.string_id); diff --git a/src/game_strings.h b/src/game_strings.h index d630bc8ab5..dbee88cb3c 100644 --- a/src/game_strings.h +++ b/src/game_strings.h @@ -15,7 +15,8 @@ * along with EasyRPG Player. If not, see . */ - // Headers +// Headers +#include "system.h" #include #include #include @@ -27,6 +28,10 @@ #include "player.h" #include "string_view.h" +#ifdef HAVE_NLOHMANN_JSON +#include +#endif + /** * Game_Strings class. */ @@ -59,6 +64,10 @@ class Game_Strings { StringView GetWithMode(StringView str_data, int mode, int arg, const Game_Variables& variables) const; StringView GetWithModeAndPos(StringView str_data, int mode, int arg, int* pos, const Game_Variables& variables); +#ifdef HAVE_NLOHMANN_JSON + nlohmann::json* ParseJson(int id); +#endif + StringView Asg(Str_Params params, StringView string); StringView Cat(Str_Params params, StringView string); int ToNum(Str_Params params, int var_id, Game_Variables& variables); @@ -85,8 +94,11 @@ class Game_Strings { Strings_t _strings; mutable int _warnings = max_warnings; -}; +#ifdef HAVE_NLOHMANN_JSON + std::unordered_map _json_cache; +#endif +}; inline void Game_Strings::Set(Str_Params params, StringView string) { if (params.string_id <= 0) { @@ -108,10 +120,18 @@ inline void Game_Strings::Set(Str_Params params, StringView string) { } else { it->second = ins_string; } + +#ifdef HAVE_NLOHMANN_JSON + _json_cache.erase(params.string_id); +#endif } inline void Game_Strings::SetData(Strings_t s) { _strings = std::move(s); + +#ifdef HAVE_NLOHMANN_JSON + _json_cache.clear(); +#endif } inline void Game_Strings::SetData(const std::vector& s) { @@ -122,6 +142,10 @@ inline void Game_Strings::SetData(const std::vector& s) { } ++i; } + +#ifdef HAVE_NLOHMANN_JSON + _json_cache.clear(); +#endif } inline const Game_Strings::Strings_t& Game_Strings::GetData() const { diff --git a/src/json_helper.cpp b/src/json_helper.cpp index c0f26db2c8..7205f361a1 100644 --- a/src/json_helper.cpp +++ b/src/json_helper.cpp @@ -61,14 +61,7 @@ namespace Json_Helper { return json_obj; } - std::optional GetValue(std::string_view json_data, std::string_view json_path) { - auto json_obj = Parse(json_data); - - if (!json_obj) { - Output::Warning("JSON: Parse error for {}", json_data); - return {}; - } - + std::optional GetValue(nlohmann::json& json_obj, std::string_view json_path) { json::json_pointer ptr((std::string(json_path))); if (ptr.empty()) { @@ -76,21 +69,14 @@ namespace Json_Helper { return {}; } - if (!json_obj->contains(ptr)) { + if (!json_obj.contains(ptr)) { return ""; } - return GetValueAsString((*json_obj)[ptr]); + return GetValueAsString(json_obj[ptr]); } - std::string SetValue(std::string_view json_data, std::string_view json_path, std::string_view value) { - auto json_obj = Parse(json_data); - - if (!json_obj) { - Output::Warning("JSON Parse error for {}", json_data); - return std::string(json_data); - } - + std::string SetValue(nlohmann::json& json_obj, std::string_view json_path, std::string_view value) { json::json_pointer ptr((std::string(json_path))); if (ptr.empty()) { @@ -102,12 +88,12 @@ namespace Json_Helper { if (obj_value.is_discarded()) { // If parsing fails, treat it as a string value - (*json_obj)[ptr] = std::string(value); + json_obj[ptr] = std::string(value); } else { - (*json_obj)[ptr] = obj_value; + json_obj[ptr] = obj_value; } - return (*json_obj).dump(); + return json_obj.dump(); } } diff --git a/src/json_helper.h b/src/json_helper.h index 75a5e775b3..f9cd117e12 100644 --- a/src/json_helper.h +++ b/src/json_helper.h @@ -28,8 +28,8 @@ namespace Json_Helper { std::optional Parse(std::string_view json_data); - std::optional GetValue(std::string_view json_data, std::string_view json_path); - std::string SetValue(std::string_view json_data, std::string_view json_path, std::string_view value); + std::optional GetValue(nlohmann::json& json_obj, std::string_view json_path); + std::string SetValue(nlohmann::json& json_obj, std::string_view json_path, std::string_view value); } #endif // HAVE_NLOHMANN_JSON