diff --git a/.gitmodules b/.gitmodules index 2cd0d30ba..13ad45ae3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,9 +31,9 @@ [submodule "third_party/capstone"] path = third_party/capstone url = https://github.com/capstone-engine/capstone.git -[submodule "third_party/cpptoml"] - path = third_party/cpptoml - url = https://github.com/skystrife/cpptoml.git +[submodule "third_party/tomlplusplus"] + path = third_party/tomlplusplus + url = https://github.com/marzer/tomlplusplus.git [submodule "third_party/cxxopts"] path = third_party/cxxopts url = https://github.com/jarro2783/cxxopts.git diff --git a/premake5.lua b/premake5.lua index 437b13fe5..39d25db05 100644 --- a/premake5.lua +++ b/premake5.lua @@ -252,7 +252,7 @@ workspace("xenia") include("third_party/dxbc.lua") include("third_party/discord-rpc.lua") include("third_party/cxxopts.lua") - include("third_party/cpptoml.lua") + include("third_party/tomlplusplus.lua") include("third_party/FFmpeg/premake5.lua") include("third_party/fmt.lua") include("third_party/glslang-spirv.lua") diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index d5b861985..0a418d26c 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -16,11 +16,11 @@ #include #include -#include "third_party/cpptoml/include/cpptoml.h" #include "third_party/fmt/include/fmt/chrono.h" #include "third_party/fmt/include/fmt/format.h" #include "third_party/imgui/imgui.h" #include "third_party/stb/stb_image_write.h" +#include "third_party/tomlplusplus/toml.hpp" #include "xenia/base/assert.h" #include "xenia/base/clock.h" #include "xenia/base/cvar.h" @@ -2012,27 +2012,27 @@ void EmulatorWindow::LoadRecentlyLaunchedTitles() { return; } - std::shared_ptr parsed_file; + toml::parse_result parsed_file; try { - cpptoml::parser p(file); - parsed_file = p.parse(); - } catch (cpptoml::parse_exception& exception) { + parsed_file = toml::parse(file); + } catch (toml::parse_error& exception) { XELOGE("Cannot parse file: recent.toml. Error: {}", exception.what()); return; } - if (parsed_file->is_table()) { - for (const auto& [index, entry] : *parsed_file->as_table()) { - if (!entry->is_table()) { + if (parsed_file.is_table()) { + for (const auto& [index, entry] : *parsed_file.as_table()) { + if (!entry.is_table()) { continue; } - const std::shared_ptr entry_table = entry->as_table(); + const toml::table* entry_table = entry.as_table(); - std::string title_name = *entry_table->get_as("title_name"); - std::string path = *entry_table->get_as("path"); + std::string title_name = + entry_table->get_as("title_name")->get(); + std::string path = entry_table->get_as("path")->get(); std::time_t last_run_time = - *entry_table->get_as("last_run_time"); + entry_table->get_as("last_run_time")->get(); std::error_code ec = {}; if (path.empty() || !std::filesystem::exists(path, ec)) { @@ -2063,31 +2063,28 @@ void EmulatorWindow::AddRecentlyLaunchedTitle( recently_launched_titles_.insert(recently_launched_titles_.cbegin(), {title_name, path_to_file, time(nullptr)}); // Serialize to toml - auto toml_table = cpptoml::make_table(); + auto toml_table = toml::table(); uint8_t index = 0; for (const RecentTitleEntry& entry : recently_launched_titles_) { - auto entry_table = cpptoml::make_table(); + auto entry_table = toml::table(); // Fill entry under specific index. std::string str_path = xe::path_to_utf8(entry.path_to_file); - entry_table->insert("title_name", entry.title_name); - entry_table->insert("path", str_path); - entry_table->insert("last_run_time", entry.last_run_time); - entry_table->end(); + entry_table.insert("title_name", entry.title_name); + entry_table.insert("path", str_path); + entry_table.insert("last_run_time", entry.last_run_time); - toml_table->insert(std::to_string(index++), entry_table); + toml_table.insert(std::to_string(index++), entry_table); if (index >= cvars::recent_titles_entry_amount) { break; } } - toml_table->end(); - // Open and write serialized data. std::ofstream file(emulator()->storage_root() / kRecentlyPlayedTitlesFilename, std::ofstream::trunc); - file << *toml_table; + file << toml_table; file.close(); } diff --git a/src/xenia/base/cvar.cc b/src/xenia/base/cvar.cc index c22fecbb6..bc96fd74d 100644 --- a/src/xenia/base/cvar.cc +++ b/src/xenia/base/cvar.cc @@ -101,7 +101,7 @@ void ParseLaunchArguments(int& argc, char**& argv, } } -namespace toml { +namespace toml_internal { std::string EscapeBasicString(const std::string_view view) { std::string result; @@ -202,7 +202,7 @@ std::string EscapeString(const std::string_view view) { if (xe::utf8::find_any_of(view, escape_chars) == std::string_view::npos) { return "'" + std::string(view) + "'"; } else { - return "\"" + toml::EscapeBasicString(view) + "\""; + return "\"" + toml_internal::EscapeBasicString(view) + "\""; } } else { // multi line @@ -210,11 +210,12 @@ std::string EscapeString(const std::string_view view) { xe::utf8::find_first_of(view, u8"'''") == std::string_view::npos) { return "'''\n" + std::string(view) + "'''"; } else { - return u8"\"\"\"\n" + toml::EscapeMultilineBasicString(view) + u8"\"\"\""; + return u8"\"\"\"\n" + toml_internal::EscapeMultilineBasicString(view) + + u8"\"\"\""; } } } -} // namespace toml +} // namespace toml_internal } // namespace cvar diff --git a/src/xenia/base/cvar.h b/src/xenia/base/cvar.h index 5acb8f22c..cf473b788 100644 --- a/src/xenia/base/cvar.h +++ b/src/xenia/base/cvar.h @@ -15,9 +15,9 @@ #include #include -#include "third_party/cpptoml/include/cpptoml.h" #include "third_party/cxxopts/include/cxxopts.hpp" #include "third_party/fmt/include/fmt/format.h" +#include "third_party/tomlplusplus/include/toml++/toml.hpp" #include "xenia/base/assert.h" #include "xenia/base/filesystem.h" #include "xenia/base/platform.h" @@ -29,7 +29,7 @@ namespace cvar { -namespace toml { +namespace toml_internal { std::string EscapeString(const std::string_view str); } @@ -48,8 +48,8 @@ class IConfigVar : virtual public ICommandVar { virtual const std::string& category() const = 0; virtual bool is_transient() const = 0; virtual std::string config_value() const = 0; - virtual void LoadConfigValue(std::shared_ptr result) = 0; - virtual void LoadGameConfigValue(std::shared_ptr result) = 0; + virtual void LoadConfigValue(const toml::node* result) = 0; + virtual void LoadGameConfigValue(const toml::node* result) = 0; virtual void ResetConfigValueToDefault() = 0; }; @@ -87,8 +87,8 @@ class ConfigVar : public CommandVar, virtual public IConfigVar { const std::string& category() const override; bool is_transient() const override; void AddToLaunchOptions(cxxopts::Options* options) override; - void LoadConfigValue(std::shared_ptr result) override; - void LoadGameConfigValue(std::shared_ptr result) override; + void LoadConfigValue(const toml::node* result) override; + void LoadGameConfigValue(const toml::node* result) override; void SetConfigValue(T val); void SetGameConfigValue(T val); // Changes the actual value used to the one specified, and also makes it the @@ -146,24 +146,24 @@ inline void CommandVar::LoadFromLaunchOptions( SetCommandLineValue(value); } template -void ConfigVar::LoadConfigValue(std::shared_ptr result) { - SetConfigValue(*cpptoml::get_impl(result)); +void ConfigVar::LoadConfigValue(const toml::node* result) { + SetConfigValue(result->value().value()); } template <> inline void ConfigVar::LoadConfigValue( - std::shared_ptr result) { + const toml::node* result) { SetConfigValue( - xe::utf8::fix_path_separators(*cpptoml::get_impl(result))); + xe::utf8::fix_path_separators(result->as_string()->value_or(""))); } template -void ConfigVar::LoadGameConfigValue(std::shared_ptr result) { - SetGameConfigValue(*cpptoml::get_impl(result)); +void ConfigVar::LoadGameConfigValue(const toml::node* result) { + SetGameConfigValue(result->value().value()); } template <> inline void ConfigVar::LoadGameConfigValue( - std::shared_ptr result) { + const toml::node* result) { SetGameConfigValue( - xe::utf8::fix_path_separators(*cpptoml::get_impl(result))); + xe::utf8::fix_path_separators(result->as_string()->value_or(""))); } template CommandVar::CommandVar(const char* name, T* default_value, @@ -216,12 +216,12 @@ inline std::string CommandVar::ToString(bool val) { } template <> inline std::string CommandVar::ToString(std::string val) { - return toml::EscapeString(val); + return toml_internal::EscapeString(val); } template <> inline std::string CommandVar::ToString( std::filesystem::path val) { - return toml::EscapeString( + return toml_internal::EscapeString( xe::utf8::fix_path_separators(xe::path_to_utf8(val), '/')); } diff --git a/src/xenia/config.cc b/src/xenia/config.cc index 90d4d6e94..1be355855 100644 --- a/src/xenia/config.cc +++ b/src/xenia/config.cc @@ -17,23 +17,8 @@ #include "xenia/base/string.h" #include "xenia/base/string_buffer.h" -std::shared_ptr ParseFile( - const std::filesystem::path& filename) { - std::ifstream file(filename); - if (!file.is_open()) { - throw cpptoml::parse_exception(xe::path_to_utf8(filename) + - " could not be opened for parsing"); - } - // since cpptoml can't parse files with a UTF-8 BOM we need to skip them - char bom[3]; - file.read(bom, sizeof(bom)); - if (file.fail() || bom[0] != '\xEF' || bom[1] != '\xBB' || bom[2] != '\xBF') { - file.clear(); - file.seekg(0); - } - - cpptoml::parser p(file); - return p.parse(); +toml::parse_result ParseFile(const std::filesystem::path& filename) { + return toml::parse_file(xe::path_to_utf8(filename)); } CmdVar(config, "", "Specifies the target config to load."); @@ -57,14 +42,13 @@ bool sortCvar(cvar::IConfigVar* a, cvar::IConfigVar* b) { return false; } -std::shared_ptr ParseConfig( - const std::filesystem::path& config_path) { +toml::parse_result ParseConfig(const std::filesystem::path& config_path) { try { return ParseFile(config_path); - } catch (cpptoml::parse_exception& e) { + } catch (toml::parse_error& e) { xe::FatalError(fmt::format("Failed to parse config file '{}':\n\n{}", xe::path_to_utf8(config_path), e.what())); - return nullptr; + return toml::parse_result(); } } @@ -107,9 +91,11 @@ void ReadConfig(const std::filesystem::path& file_path, if (!cvar::ConfigVars) { return; } + const auto config = ParseConfig(file_path); PrintConfigToLog(file_path); + // Loading an actual global config file that exists - if there's no // defaults_date in it, it's very old (before updating was added at all, thus // all defaults need to be updated). @@ -119,9 +105,12 @@ void ReadConfig(const std::filesystem::path& file_path, defaults_date_cvar->SetConfigValue(0); for (auto& it : *cvar::ConfigVars) { auto config_var = static_cast(it.second); - auto config_key = config_var->category() + "." + config_var->name(); - if (config->contains_qualified(config_key)) { - config_var->LoadConfigValue(config->get_qualified(config_key)); + toml::path config_key = + toml::path(config_var->category() + "." + config_var->name()); + + const auto config_key_node = config.at_path(config_key); + if (config_key_node) { + config_var->LoadConfigValue(config_key_node.node()); } } uint32_t config_defaults_date = defaults_date_cvar->GetTypedConfigValue(); @@ -139,9 +128,12 @@ void ReadGameConfig(const std::filesystem::path& file_path) { const auto config = ParseConfig(file_path); for (auto& it : *cvar::ConfigVars) { auto config_var = static_cast(it.second); - auto config_key = config_var->category() + "." + config_var->name(); - if (config->contains_qualified(config_key)) { - config_var->LoadGameConfigValue(config->get_qualified(config_key)); + toml::path config_key = + toml::path(config_var->category() + "." + config_var->name()); + + const auto config_key_node = config.at_path(config_key); + if (config_key_node) { + config_var->LoadConfigValue(config_key_node.node()); } } XELOGI("Loaded game config: {}", xe::path_to_utf8(file_path)); diff --git a/src/xenia/config.h b/src/xenia/config.h index 8d7b6269b..907d5ab2c 100644 --- a/src/xenia/config.h +++ b/src/xenia/config.h @@ -11,10 +11,9 @@ #define XENIA_CONFIG_H_ #include -#include "third_party/cpptoml/include/cpptoml.h" +#include "third_party/tomlplusplus/toml.hpp" -std::shared_ptr ParseFile( - const std::filesystem::path& filename); +toml::parse_result ParseFile(const std::filesystem::path& filename); namespace config { void SetupConfig(const std::filesystem::path& config_folder); diff --git a/src/xenia/patcher/patch_db.cc b/src/xenia/patcher/patch_db.cc index 9b61d3672..0d886e3d1 100644 --- a/src/xenia/patcher/patch_db.cc +++ b/src/xenia/patcher/patch_db.cc @@ -57,9 +57,10 @@ void PatchDB::LoadPatches() { XELOGI("PatchDB: Loaded patches for {} titles", loaded_patches_.size()); } -PatchFileEntry PatchDB::ReadPatchFile(const std::filesystem::path& file_path) { +PatchFileEntry PatchDB::ReadPatchFile( + const std::filesystem::path& file_path) const { PatchFileEntry patch_file; - std::shared_ptr patch_toml_fields; + toml::parse_result patch_toml_fields; try { patch_toml_fields = ParseFile(file_path); @@ -69,108 +70,118 @@ PatchFileEntry PatchDB::ReadPatchFile(const std::filesystem::path& file_path) { return patch_file; }; - auto title_name = patch_toml_fields->get_as("title_name"); - auto title_id = patch_toml_fields->get_as("title_id"); + auto title_name = patch_toml_fields.get_as("title_name"); + auto title_id = patch_toml_fields.get_as("title_id"); + auto hashes_node = patch_toml_fields.get("hash"); - patch_file.title_id = strtoul((*title_id).c_str(), NULL, 16); - patch_file.title_name = *title_name; - ReadHashes(patch_file, patch_toml_fields); + patch_file.title_id = strtoul(title_id->get().c_str(), NULL, 16); + patch_file.title_name = title_name->get(); + ReadHashes(patch_file, hashes_node); - auto patch_table = patch_toml_fields->get_table_array("patch"); + auto patch_array = patch_toml_fields.get("patch"); + if (!patch_array->is_array()) { + return patch_file; + } - for (auto patch_table_entry : *patch_table) { - PatchInfoEntry patch = PatchInfoEntry(); - auto patch_name = *patch_table_entry->get_as("name"); - auto patch_desc = *patch_table_entry->get_as("desc"); - auto patch_author = *patch_table_entry->get_as("author"); - auto is_enabled = *patch_table_entry->get_as("is_enabled"); - - patch.id = 0; // Todo(Gliniak): Implement id for future GUI stuff - patch.patch_name = patch_name; - patch.patch_desc = patch_desc; - patch.patch_author = patch_author; - patch.is_enabled = is_enabled; - - // Iterate through all available data sizes - for (const auto& patch_data_type : patch_data_types_size_) { - bool success = - ReadPatchData(patch.patch_data, patch_data_type, patch_table_entry); - - if (!success) { - XELOGE("PatchDB: Cannot read patch {}", patch_name); - break; - } + for (const auto& patch_entry : *patch_array->as_array()) { + if (!patch_entry.is_table()) { + continue; } + + PatchInfoEntry patch = PatchInfoEntry(); + ReadPatchHeader(patch, patch_entry.as_table()); patch_file.patch_info.push_back(patch); } return patch_file; } -bool PatchDB::ReadPatchData( - std::vector& patch_data, - const std::pair data_type, - const std::shared_ptr& patch_table) { - auto patch_data_tarr = patch_table->get_table_array(data_type.first); - if (!patch_data_tarr) { +bool PatchDB::ReadPatchData(std::vector& patch_data, + const std::pair data_type, + const toml::table* patch_fields) const { + auto patch_data_fields = patch_fields->get_as(data_type.first); + if (!patch_data_fields) { return true; } - for (const auto& patch_data_table : *patch_data_tarr) { - uint32_t address = *patch_data_table->get_as("address"); + for (const auto& patch_data_table : *patch_data_fields) { + if (!patch_data_table.is_table()) { + continue; + } + + auto table = patch_data_table.as_table(); + auto address = + static_cast(table->get_as("address")->get()); size_t alloc_size = (size_t)data_type.second.size; switch (data_type.second.type) { case PatchDataType::kBE8: { - uint16_t value = *patch_data_table->get_as("value"); + uint16_t value = + static_cast(table->get_as("value")->get()); patch_data.push_back({address, PatchDataValue(alloc_size, value)}); break; } case PatchDataType::kBE16: { - uint16_t value = *patch_data_table->get_as("value"); + uint16_t value = + static_cast(table->get_as("value")->get()); patch_data.push_back( {address, PatchDataValue(alloc_size, xe::byte_swap(value))}); break; } case PatchDataType::kBE32: { - uint32_t value = *patch_data_table->get_as("value"); + uint32_t value = + static_cast(table->get_as("value")->get()); patch_data.push_back( {address, PatchDataValue(alloc_size, xe::byte_swap(value))}); break; } case PatchDataType::kBE64: { - uint64_t value = *patch_data_table->get_as("value"); + uint64_t value = table->get_as("value")->get(); patch_data.push_back( {address, PatchDataValue(alloc_size, xe::byte_swap(value))}); break; } case PatchDataType::kF64: { - double val = *patch_data_table->get_as("value"); - uint64_t value = *reinterpret_cast(&val); + const auto value_field = table->get("value"); + double value = 0.0; + if (value_field->is_floating_point()) { + value = value_field->as_floating_point()->get(); + } + if (value_field->is_integer()) { + value = static_cast(value_field->as_integer()->get()); + } + patch_data.push_back( {address, PatchDataValue(alloc_size, xe::byte_swap(value))}); break; } case PatchDataType::kF32: { - float value = float(*patch_data_table->get_as("value")); + const auto value_field = table->get("value"); + float value = 0.0f; + if (value_field->is_floating_point()) { + value = static_cast(value_field->as_floating_point()->get()); + } + if (value_field->is_integer()) { + value = static_cast(value_field->as_integer()->get()); + } + patch_data.push_back( {address, PatchDataValue(alloc_size, xe::byte_swap(value))}); break; } case PatchDataType::kString: { - std::string value = *patch_data_table->get_as("value"); + std::string value = table->get_as("value")->get(); patch_data.push_back({address, PatchDataValue(value)}); break; } case PatchDataType::kU16String: { std::u16string value = - xe::to_utf16(*patch_data_table->get_as("value")); + xe::to_utf16(table->get_as("value")->get()); patch_data.push_back({address, PatchDataValue(value)}); break; } case PatchDataType::kByteArray: { std::vector data; - const std::string value = - *patch_data_table->get_as("value"); + const std::string value = table->get_as("value")->get(); bool success = string_util::hex_string_to_array(data, value); if (!success) { @@ -208,16 +219,67 @@ std::vector PatchDB::GetTitlePatches( } void PatchDB::ReadHashes(PatchFileEntry& patch_entry, - std::shared_ptr patch_toml_fields) { - auto title_hashes = patch_toml_fields->get_array_of("hash"); + const toml::node* hashes_node) const { + auto add_hash = [&patch_entry](const toml::node* hash_node) { + if (!hash_node->is_string()) { + return; + } - for (const auto& hash : *title_hashes) { - patch_entry.hashes.push_back(strtoull(hash.c_str(), NULL, 16)); + const auto string_hash = hash_node->as_string()->get(); + if (string_hash.empty()) { + return; + } + + patch_entry.hashes.push_back( + xe::string_util::from_string(string_hash, true)); + }; + + if (hashes_node->is_value()) { + add_hash(hashes_node); } - auto single_hash = patch_toml_fields->get_as("hash"); - if (single_hash) { - patch_entry.hashes.push_back(strtoull((*single_hash).c_str(), NULL, 16)); + if (hashes_node->is_array()) { + for (const auto& hash_entry : *hashes_node->as_array()) { + add_hash(&hash_entry); + } + } +} + +void PatchDB::ReadPatchHeader(PatchInfoEntry& patch_info, + const toml::table* patch_fields) const { + std::string patch_name = {}; + std::string patch_desc = {}; + std::string patch_author = {}; + bool is_enabled = false; + + if (patch_fields->contains("name")) { + patch_name = patch_fields->get_as("name")->get(); + } + if (patch_fields->contains("desc")) { + patch_desc = patch_fields->get_as("desc")->get(); + } + if (patch_fields->contains("author")) { + patch_author = patch_fields->get_as("author")->get(); + } + if (patch_fields->contains("is_enabled")) { + is_enabled = patch_fields->get_as("is_enabled")->get(); + } + + patch_info.id = 0; // Todo(Gliniak): Implement id for future GUI stuff + patch_info.patch_name = patch_name; + patch_info.patch_desc = patch_desc; + patch_info.patch_author = patch_author; + patch_info.is_enabled = is_enabled; + + // Iterate through all available data sizes + for (const auto& patch_data_type : patch_data_types_size_) { + bool success = + ReadPatchData(patch_info.patch_data, patch_data_type, patch_fields); + + if (!success) { + XELOGE("PatchDB: Cannot read patch {}", patch_name); + break; + } } } diff --git a/src/xenia/patcher/patch_db.h b/src/xenia/patcher/patch_db.h index ab3cf03a3..fef737ee8 100644 --- a/src/xenia/patcher/patch_db.h +++ b/src/xenia/patcher/patch_db.h @@ -15,7 +15,7 @@ #include #include -#include "third_party/cpptoml/include/cpptoml.h" +#include "third_party/tomlplusplus/toml.hpp" namespace xe { namespace patcher { @@ -96,10 +96,7 @@ class PatchDB { void LoadPatches(); - PatchFileEntry ReadPatchFile(const std::filesystem::path& file_path); - bool ReadPatchData(std::vector& patch_data, - const std::pair data_type, - const std::shared_ptr& patch_table); + PatchFileEntry ReadPatchFile(const std::filesystem::path& file_path) const; std::vector GetTitlePatches( const uint32_t title_id, const std::optional hash); @@ -107,7 +104,12 @@ class PatchDB { private: void ReadHashes(PatchFileEntry& patch_entry, - std::shared_ptr patch_toml_fields); + const toml::node* patch_toml_fields) const; + void ReadPatchHeader(PatchInfoEntry& patch_info, + const toml::table* patch_fields) const; + bool ReadPatchData(std::vector& patch_data, + const std::pair data_type, + const toml::table* patch_fields) const; inline static const std::regex patch_filename_regex_ = std::regex("^[A-Fa-f0-9]{8}.*\\.patch\\.toml$"); diff --git a/src/xenia/patcher/plugin_loader.cc b/src/xenia/patcher/plugin_loader.cc index bdc792642..3af0b8938 100644 --- a/src/xenia/patcher/plugin_loader.cc +++ b/src/xenia/patcher/plugin_loader.cc @@ -65,7 +65,7 @@ void PluginLoader::LoadTitleConfig(const uint32_t title_id) { return; } - std::shared_ptr plugins_config; + toml::parse_result plugins_config; try { plugins_config = ParseFile(title_plugins_config); @@ -76,64 +76,79 @@ void PluginLoader::LoadTitleConfig(const uint32_t title_id) { } const std::string title_name = - *plugins_config->get_as("title_name"); + plugins_config.get_as("title_name")->get(); - const std::string patch_title_id = - *plugins_config->get_as("title_id"); + const std::string plugin_title_id = + plugins_config.get_as("title_id")->get(); - const auto plugin_tabels = plugins_config->get_table_array("plugin"); - - if (!plugin_tabels) { + if (!plugins_config.contains("plugin")) { XELOGE("Plugins: Cannot find [[plugin]] table in {}", path_to_utf8(title_plugins_config)); return; } - for (auto& plugin : *plugin_tabels) { + const auto plugin_array = plugins_config.get_as("plugin"); + if (!plugin_array) { + return; + } + + for (const auto& plugin_entry : *plugin_array) { PluginInfoEntry entry; - const std::string name = *plugin->get_as("name"); - const std::string file = *plugin->get_as("file"); - const std::string desc = *plugin->get_as("desc"); - const bool is_enabled = *plugin->get_as("is_enabled"); + if (!plugin_entry.is_table()) { + return; + } + entry.title_id = + xe::string_util::from_string(plugin_title_id, true); - if (!plugin->contains("hash")) { - XELOGE("Hash error! skipping plugin {} in: {}", name, + if (plugin_entry.as_table()->contains("name")) { + entry.name = plugin_entry.as_table()->get_as("name")->get(); + } + if (plugin_entry.as_table()->contains("file")) { + entry.file = xe::string_util::trim( + plugin_entry.as_table()->get_as("file")->get()); + } + if (plugin_entry.as_table()->contains("desc")) { + entry.desc = plugin_entry.as_table()->get_as("desc")->get(); + } + if (plugin_entry.as_table()->contains("is_enabled")) { + entry.is_enabled = + plugin_entry.as_table()->get_as("is_enabled")->get(); + } + + if (!plugin_entry.as_table()->contains("hash")) { + XELOGE("Hash error! skipping plugin {} in: {}", entry.name, path_to_utf8(title_plugins_config)); continue; } - entry.hashes = GetHashes(plugin->get("hash")); - entry.name = name; - entry.file = xe::string_util::trim(file); - entry.desc = desc; - entry.title_id = title_id; - entry.is_enabled = is_enabled; + entry.hashes = GetHashes(plugin_entry.as_table()->get("hash")); plugin_configs_.push_back(entry); } } std::vector PluginLoader::GetHashes( - const std::shared_ptr toml_entry) { + const toml::node* toml_entry) const { std::vector hashes; if (!toml_entry) { return hashes; } - if (toml_entry->is_array()) { - const auto arr = toml_entry->as_array(); - - for (cpptoml::array::const_iterator itr = arr->begin(); itr != arr->end(); - ++itr) { - const std::string hash_entry = itr->get()->as()->get(); - hashes.push_back(strtoull(hash_entry.c_str(), NULL, 16)); - } + if (toml_entry->is_value()) { + hashes.push_back(xe::string_util::from_string( + toml_entry->as_string()->get(), true)); } - if (toml_entry->is_value()) { - const std::string hash = toml_entry->as()->get(); - hashes.push_back(strtoull(hash.c_str(), NULL, 16)); + if (toml_entry->is_array()) { + for (const auto& hash_entry : *toml_entry->as_array()) { + if (hash_entry.as_string()->get().empty()) { + continue; + } + + hashes.push_back(xe::string_util::from_string( + hash_entry.as_string()->get(), true)); + } } return hashes; } diff --git a/src/xenia/patcher/plugin_loader.h b/src/xenia/patcher/plugin_loader.h index 2ca1b150c..dd068c629 100644 --- a/src/xenia/patcher/plugin_loader.h +++ b/src/xenia/patcher/plugin_loader.h @@ -10,6 +10,7 @@ #ifndef XENIA_PLUGIN_LOADER_H_ #define XENIA_PLUGIN_LOADER_H_ +#include "third_party/tomlplusplus/toml.hpp" #include "xenia/kernel/kernel_state.h" #include "xenia/memory.h" @@ -41,8 +42,7 @@ class PluginLoader { void CreatePluginDevice(const uint32_t title_id); void LoadTitlePlugin(const PluginInfoEntry& entry); - std::vector GetHashes( - const std::shared_ptr toml_entry); + std::vector GetHashes(const toml::node* toml_entry) const; kernel::KernelState* kernel_state_; std::filesystem::path plugins_root_; diff --git a/third_party/cpptoml b/third_party/cpptoml deleted file mode 160000 index fededad71..000000000 --- a/third_party/cpptoml +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fededad7169e538ca47e11a9ee9251bc361a9a65 diff --git a/third_party/tomlplusplus b/third_party/tomlplusplus new file mode 160000 index 000000000..30172438c --- /dev/null +++ b/third_party/tomlplusplus @@ -0,0 +1 @@ +Subproject commit 30172438cee64926dc41fdd9c11fb3ba5b2ba9de diff --git a/third_party/cpptoml.lua b/third_party/tomlplusplus.lua similarity index 78% rename from third_party/cpptoml.lua rename to third_party/tomlplusplus.lua index 5e7d6d74a..25860b01c 100644 --- a/third_party/cpptoml.lua +++ b/third_party/tomlplusplus.lua @@ -1,5 +1,5 @@ group("third_party") -project("cpptoml") +project("tomlplusplus") uuid("1e86cc51-3f8b-476d-9249-3b200424846b") if os.istarget("android") then -- ndk-build only supports StaticLib and SharedLib. @@ -9,5 +9,5 @@ project("cpptoml") end language("C++") files({ - "cpptoml/include/cpptoml.h", + "tomlplusplus/include/toml++/toml.hpp" })