From acc372c836fb4ebde1b4c8ec5f2da53a26981990 Mon Sep 17 00:00:00 2001 From: Maschell Date: Sat, 16 Dec 2023 12:44:20 +0100 Subject: [PATCH] Simplify the StorageAPI --- Dockerfile | 2 +- source/hooks.cpp | 9 +- source/main.cpp | 14 ++ source/plugin/PluginContainer.h | 34 +++- source/utils/storage/StorageItem.cpp | 4 +- source/utils/storage/StorageItem.h | 4 +- source/utils/storage/StorageItemRoot.h | 7 +- source/utils/storage/StorageSubItem.cpp | 45 ++--- source/utils/storage/StorageSubItem.h | 14 +- source/utils/storage/StorageUtils.cpp | 244 +++++++++++++++--------- source/utils/storage/StorageUtils.h | 11 +- source/utils/utils.cpp | 7 +- 12 files changed, 254 insertions(+), 141 deletions(-) diff --git a/Dockerfile b/Dockerfile index f791b48..dea9e42 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM ghcr.io/wiiu-env/devkitppc:20230621 COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:0.3.2-dev-20231203-2e5832b /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:0.8.0-dev-20231216-104fdc3 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:0.8.0-dev-20231221-ca17105 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/libwupsbackend:20230621 /artifacts $DEVKITPRO diff --git a/source/hooks.cpp b/source/hooks.cpp index 49d0f8b..7e664b2 100644 --- a/source/hooks.cpp +++ b/source/hooks.cpp @@ -89,21 +89,22 @@ void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type) } wups_loader_init_storage_args_t_ args{}; args.version = WUPS_STORAGE_CUR_API_VERSION; - args.open_storage_ptr = &StorageUtils::API::OpenStorage; - args.close_storage_ptr = &StorageUtils::API::CloseStorage; + args.root_item = plugin.getStorageRootItem(); + args.save_function_ptr = &StorageUtils::API::SaveStorage; + args.force_reload_function_ptr = &StorageUtils::API::ForceReloadStorage; + args.wipe_storage_function_ptr = &StorageUtils::API::WipeStorage; args.delete_item_function_ptr = &StorageUtils::API::DeleteItem; args.create_sub_item_function_ptr = &StorageUtils::API::CreateSubItem; args.get_sub_item_function_ptr = &StorageUtils::API::GetSubItem; args.store_item_function_ptr = &StorageUtils::API::StoreItem; args.get_item_function_ptr = &StorageUtils::API::GetItem; args.get_item_size_function_ptr = &StorageUtils::API::GetItemSize; - args.plugin_id = plugin.getMetaInformation().getStorageId().c_str(); // clang-format off auto res = ((WUPSStorageError(*)(wups_loader_init_storage_args_t_))((uint32_t *) func_ptr))(args); // clang-format on if (res != WUPS_STORAGE_ERROR_SUCCESS) { // TODO: More error handling? Notification? - DEBUG_FUNCTION_LINE_ERR("WUPS_LOADER_HOOK_INIT_STORAGE failed for plugin %s: %s", plugin.getMetaInformation().getName().c_str(), WUPS_GetStorageStatusStr(res)); + DEBUG_FUNCTION_LINE_ERR("WUPS_LOADER_HOOK_INIT_STORAGE failed for plugin %s: %s", plugin.getMetaInformation().getName().c_str(), WUPSStorageAPI_GetStatusStr(res)); } break; } diff --git a/source/main.cpp b/source/main.cpp index fabf56a..bec20b3 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -135,6 +135,14 @@ WUMS_APPLICATION_STARTS() { DEBUG_FUNCTION_LINE("Restore function patches of currently loaded plugins."); PluginManagement::RestoreFunctionPatches(gLoadedPlugins); + + for (auto &plugin : gLoadedPlugins) { + WUPSStorageError err = plugin->CloseStorage(); + if (err != WUPS_STORAGE_ERROR_SUCCESS) { + DEBUG_FUNCTION_LINE_ERR("Failed to close storage for plugin: %s", plugin->getMetaInformation().getName().c_str()); + } + } + DEBUG_FUNCTION_LINE("Unload existing plugins."); gLoadedPlugins.clear(); for (auto &cur : gTrampData) { @@ -170,6 +178,12 @@ WUMS_APPLICATION_STARTS() { } if (initNeeded) { + for (auto &plugin : gLoadedPlugins) { + WUPSStorageError err = plugin->OpenStorage(); + if (err != WUPS_STORAGE_ERROR_SUCCESS) { + DEBUG_FUNCTION_LINE_ERR("Failed to open storage for plugin: %s. (%s)", plugin->getMetaInformation().getName().c_str(), WUPSStorageAPI_GetStatusStr(err)); + } + } PluginManagement::callInitHooks(gLoadedPlugins); } diff --git a/source/plugin/PluginContainer.h b/source/plugin/PluginContainer.h index 71c7f4a..5a325fc 100644 --- a/source/plugin/PluginContainer.h +++ b/source/plugin/PluginContainer.h @@ -21,6 +21,7 @@ #include "PluginData.h" #include "PluginInformation.h" #include "PluginMetaInformation.h" +#include "utils/storage/StorageUtils.h" #include #include #include @@ -45,7 +46,7 @@ public: return mPluginData; } - uint32_t getHandle() const { + [[nodiscard]] uint32_t getHandle() const { return (uint32_t) this; } @@ -57,9 +58,40 @@ public: mPluginConfigData = pluginConfigData; } + WUPSStorageError OpenStorage() { + if (getMetaInformation().getWUPSVersion() < WUPSVersion(0, 8, 0)) { + return WUPS_STORAGE_ERROR_SUCCESS; + } + auto &storageId = getMetaInformation().getStorageId(); + if (storageId.empty()) { + return WUPS_STORAGE_ERROR_SUCCESS; + } + auto res = StorageUtils::API::Internal::OpenStorage(storageId, storageRootItem); + if (res != WUPS_STORAGE_ERROR_SUCCESS) { + storageRootItem = nullptr; + } + return res; + } + + WUPSStorageError CloseStorage() { + if (getMetaInformation().getWUPSVersion() < WUPSVersion(0, 8, 0)) { + return WUPS_STORAGE_ERROR_SUCCESS; + } + if (storageRootItem == nullptr) { + return WUPS_STORAGE_ERROR_SUCCESS; + } + return StorageUtils::API::Internal::CloseStorage(storageRootItem); + } + + [[nodiscard]] wups_storage_root_item getStorageRootItem() const { + return storageRootItem; + } + private: const std::unique_ptr mMetaInformation; const std::unique_ptr mPluginInformation; const std::shared_ptr mPluginData; + std::optional mPluginConfigData; + wups_storage_root_item storageRootItem = nullptr; }; diff --git a/source/utils/storage/StorageItem.cpp b/source/utils/storage/StorageItem.cpp index 4ba2856..0a9d07e 100644 --- a/source/utils/storage/StorageItem.cpp +++ b/source/utils/storage/StorageItem.cpp @@ -83,7 +83,7 @@ bool StorageItem::getValue(int32_t &result) const { return false; } -bool StorageItem::getValue(std::vector &result) { +bool StorageItem::getValue(std::vector &result) const { if (mType == StorageItemType::Binary) { result = std::get>(mData); return true; @@ -174,7 +174,7 @@ bool StorageItem::attemptBinaryConversion() { } free(dec); } else { - DEBUG_FUNCTION_LINE_ERR("Malloc failed for string->binary parsing"); + DEBUG_FUNCTION_LINE_WARN("Malloc failed for string->binary parsing"); return false; } } diff --git a/source/utils/storage/StorageItem.h b/source/utils/storage/StorageItem.h index ea4f8d3..bfe55bf 100644 --- a/source/utils/storage/StorageItem.h +++ b/source/utils/storage/StorageItem.h @@ -19,7 +19,7 @@ enum class StorageItemType { None, class StorageItem { public: - explicit StorageItem(std::string key) : mData(std::monostate{}), mType(StorageItemType::None), mKey(std::move(key)) { + explicit StorageItem(std::string_view key) : mData(std::monostate{}), mType(StorageItemType::None), mKey(key) { } [[nodiscard]] uint32_t getHandle() const { @@ -63,7 +63,7 @@ public: bool getValue(std::string &result) const; - bool getValue(std::vector &result); + bool getValue(std::vector &result) const; [[nodiscard]] StorageItemType getType() const { return mType; diff --git a/source/utils/storage/StorageItemRoot.h b/source/utils/storage/StorageItemRoot.h index 78f74c7..e0271d9 100644 --- a/source/utils/storage/StorageItemRoot.h +++ b/source/utils/storage/StorageItemRoot.h @@ -12,13 +12,18 @@ class StorageItemRoot : public StorageSubItem { public: - explicit StorageItemRoot(const std::string &plugin_name) : StorageSubItem(plugin_name), mPluginName(plugin_name) { + explicit StorageItemRoot(std::string_view plugin_name) : StorageSubItem(plugin_name), mPluginName(plugin_name) { } [[nodiscard]] const std::string &getPluginId() const { return mPluginName; } + void wipe() { + mSubCategories.clear(); + mItems.clear(); + } + private: std::string mPluginName; }; diff --git a/source/utils/storage/StorageSubItem.cpp b/source/utils/storage/StorageSubItem.cpp index f86b03d..98c1f61 100644 --- a/source/utils/storage/StorageSubItem.cpp +++ b/source/utils/storage/StorageSubItem.cpp @@ -1,16 +1,16 @@ #include "StorageSubItem.h" -StorageSubItem *StorageSubItem::getSubItem(wups_storage_item item) const { +StorageSubItem *StorageSubItem::getSubItem(wups_storage_item item) { // Try to find the sub-item based on item handle. - for (const auto &cur : mSubCategories) { - if (cur->getHandle() == (uint32_t) item) { - return cur.get(); + for (auto &cur : mSubCategories) { + if (cur.getHandle() == (uint32_t) item) { + return &cur; } } // If not found in current category, recursively search in sub-categories. - for (const auto &cur : mSubCategories) { - auto res = cur->getSubItem(item); + for (auto &cur : mSubCategories) { + auto res = cur.getSubItem(item); if (res) { return res; } @@ -22,8 +22,8 @@ StorageSubItem *StorageSubItem::getSubItem(wups_storage_item item) const { const StorageSubItem *StorageSubItem::getSubItem(const char *key) const { // Try to find the sub-item based on key. for (const auto &cur : mSubCategories) { - if (cur->getKey() == key) { - return cur.get(); + if (cur.getKey() == key) { + return &cur; } } @@ -31,7 +31,7 @@ const StorageSubItem *StorageSubItem::getSubItem(const char *key) const { } bool StorageSubItem::deleteItem(const char *key) { - if (remove_first_if(mSubCategories, [key](auto &cur) { return cur->getKey() == key; })) { + if (remove_first_if(mSubCategories, [key](auto &cur) { return cur.getKey() == key; })) { return true; } @@ -45,20 +45,17 @@ bool StorageSubItem::deleteItem(const char *key) { StorageItem *StorageSubItem::createItem(const char *key, StorageSubItem::StorageSubItemError &error) { for (const auto &cur : mSubCategories) { - if (cur->getKey() == key) { + if (cur.getKey() == key) { error = STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE; return nullptr; } } - auto res = make_unique_nothrow(key); - if (!res) { - error = STORAGE_SUB_ITEM_ERROR_MALLOC_FAILED; - return nullptr; + auto result = mItems.insert({key, StorageItem(key)}); + if (result.second) { + return &result.first->second; } - auto *result = res.get(); - mItems[key] = std::move(res); - return result; + return nullptr; } StorageSubItem *StorageSubItem::createSubItem(const char *key, StorageSubItem::StorageSubItemError &error) { @@ -68,26 +65,20 @@ StorageSubItem *StorageSubItem::createSubItem(const char *key, StorageSubItem::S return nullptr; } for (const auto &cur : mSubCategories) { - if (cur->getKey() == key) { + if (cur.getKey() == key) { error = STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE; return nullptr; } } - auto res = make_unique_nothrow(key); - if (!res) { - error = STORAGE_SUB_ITEM_ERROR_MALLOC_FAILED; - return nullptr; - } - auto *result = res.get(); - mSubCategories.push_front(std::move(res)); - return result; + mSubCategories.emplace_front(key); + return &mSubCategories.front(); } StorageItem *StorageSubItem::getItem(const char *name) { auto resItr = mItems.find(name); if (resItr != mItems.end()) { - return resItr->second.get(); + return &resItr->second; } return nullptr; } diff --git a/source/utils/storage/StorageSubItem.h b/source/utils/storage/StorageSubItem.h index 8feca09..a385123 100644 --- a/source/utils/storage/StorageSubItem.h +++ b/source/utils/storage/StorageSubItem.h @@ -17,10 +17,10 @@ public: STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE = 2, }; - explicit StorageSubItem(const std::string &key) : StorageItem(key) { + explicit StorageSubItem(std::string_view key) : StorageItem(key) { } - StorageSubItem *getSubItem(wups_storage_item item) const; + StorageSubItem *getSubItem(wups_storage_item item); const StorageSubItem *getSubItem(const char *key) const; @@ -32,15 +32,15 @@ public: StorageItem *getItem(const char *name); - [[nodiscard]] const std::forward_list> &getSubItems() const { + [[nodiscard]] const std::forward_list &getSubItems() const { return mSubCategories; } - [[nodiscard]] const std::map> &getItems() const { + [[nodiscard]] const std::map &getItems() const { return mItems; } -private: - std::forward_list> mSubCategories; - std::map> mItems; +protected: + std::forward_list mSubCategories; + std::map mItems; }; diff --git a/source/utils/storage/StorageUtils.cpp b/source/utils/storage/StorageUtils.cpp index 54f89d6..ee8c667 100644 --- a/source/utils/storage/StorageUtils.cpp +++ b/source/utils/storage/StorageUtils.cpp @@ -43,7 +43,6 @@ namespace StorageUtils { } } } else { - auto res = item.createItem(it.key().c_str(), subItemError); if (!res) { @@ -73,7 +72,7 @@ namespace StorageUtils { return true; } - static std::unique_ptr deserializeFromJson(const nlohmann::json &json, const std::string &key) { + static std::unique_ptr deserializeFromJson(const nlohmann::json &json, std::string_view key) { if (json.empty() || !json.is_object()) { return nullptr; } @@ -90,49 +89,49 @@ namespace StorageUtils { nlohmann::json json = nlohmann::json::object(); for (const auto &curSubItem : baseItem.getSubItems()) { - json[curSubItem->getKey()] = serializeToJson(*curSubItem); + json[curSubItem.getKey()] = serializeToJson(curSubItem); } for (const auto &[key, value] : baseItem.getItems()) { - switch ((StorageItemType) value->getType()) { + switch ((StorageItemType) value.getType()) { case StorageItemType::String: { std::string res; - if (value->getValue(res)) { + if (value.getValue(res)) { json[key] = res; } break; } case StorageItemType::Boolean: { bool res; - if (value->getValue(res)) { + if (value.getValue(res)) { json[key] = res; } break; } case StorageItemType::S64: { int64_t res; - if (value->getValue(res)) { + if (value.getValue(res)) { json[key] = res; } break; } case StorageItemType::U64: { uint64_t res; - if (value->getValue(res)) { + if (value.getValue(res)) { json[key] = res; } break; } case StorageItemType::Double: { double res; - if (value->getValue(res)) { + if (value.getValue(res)) { json[key] = res; } break; } case StorageItemType::Binary: { std::vector tmp; - if (value->getValue(tmp)) { + if (value.getValue(tmp)) { auto *enc = b64_encode(tmp.data(), tmp.size()); if (enc) { json[key] = enc; @@ -152,7 +151,7 @@ namespace StorageUtils { return json; } - static StorageSubItem *getRootItem(wups_storage_root_item root) { + static StorageItemRoot *getRootItem(wups_storage_root_item root) { for (const auto &cur : gStorage) { if (cur->getHandle() == (uint32_t) root) { return cur.get(); @@ -173,40 +172,100 @@ namespace StorageUtils { return nullptr; } + WUPSStorageError LoadFromFile(std::string_view plugin_id, nlohmann::json &outJson) { + std::string filePath = getPluginPath() + "/config/" + plugin_id.data() + ".json"; + CFile file(filePath, CFile::ReadOnly); + if (!file.isOpen() || file.size() == 0) { + return WUPS_STORAGE_ERROR_IO_ERROR; + } + auto *json_data = (uint8_t *) memalign(0x40, ROUNDUP(file.size() + 1, 0x40)); + if (!json_data) { + return WUPS_STORAGE_ERROR_MALLOC_FAILED; + } + WUPSStorageError result = WUPS_STORAGE_ERROR_SUCCESS; + uint64_t readRes = file.read(json_data, file.size()); + if (readRes == file.size()) { + json_data[file.size()] = '\0'; + outJson = nlohmann::json::parse(json_data, nullptr, false); + } else { + result = WUPS_STORAGE_ERROR_IO_ERROR; + } + file.close(); + free(json_data); + return result; + } - static WUPSStorageError WriteStorageToSD(const char *plugin_id) { + WUPSStorageError LoadFromFile(std::string_view plugin_id, StorageItemRoot &rootItem) { + nlohmann::json j; + WUPSStorageError err; + + if ((err = LoadFromFile(plugin_id, j)) != WUPS_STORAGE_ERROR_SUCCESS) { + return err; + } + + std::unique_ptr storage; + if (j.empty() || !j.is_object() || !j.contains("storageitems") || j["storageitems"].empty() || !j["storageitems"].is_object()) { + storage = make_unique_nothrow(plugin_id); + } else { + storage = StorageUtils::Helper::deserializeFromJson(j["storageitems"], plugin_id); + if (!storage) { + storage = make_unique_nothrow(plugin_id); + } + } + rootItem = *storage; + return WUPS_STORAGE_ERROR_SUCCESS; + } + + static WUPSStorageError WriteStorageToSD(wups_storage_root_item root, bool forceSave) { std::shared_ptr rootItem; for (const auto &cur : gStorage) { - if (cur->getPluginId() == plugin_id) { + if (cur->getHandle() == (uint32_t) root) { rootItem = cur; break; } } if (!rootItem) { - return WUPS_STORAGE_ERROR_NOT_FOUND; + return WUPS_STORAGE_ERROR_INTERNAL_NOT_INITIALIZED; } std::string folderPath = getPluginPath() + "/config/"; std::string filePath = folderPath + rootItem->getPluginId() + ".json"; - FSUtils::CreateSubfolder(folderPath); + nlohmann::json j; + j["storageitems"] = serializeToJson(*rootItem); + + if (!forceSave) { + nlohmann::json jsonFromFile; + if (Helper::LoadFromFile(rootItem->getPluginId(), jsonFromFile) == WUPS_STORAGE_ERROR_SUCCESS) { + if (j == jsonFromFile) { + DEBUG_FUNCTION_LINE_VERBOSE("Storage has no changes, avoid saving \"%s.json\"", rootItem->getPluginId().c_str()); + return WUPS_STORAGE_ERROR_SUCCESS; + } + } else { + DEBUG_FUNCTION_LINE_WARN("Failed to load \"%s.json\"", rootItem->getPluginId().c_str()); + } + DEBUG_FUNCTION_LINE_VERBOSE("Saving \"%s.json\"...", rootItem->getPluginId().c_str()); + } else { + DEBUG_FUNCTION_LINE_VERBOSE("Force saving \"%s.json\"...", rootItem->getPluginId().c_str()); + } + + if (!FSUtils::CreateSubfolder(folderPath)) { + return WUPS_STORAGE_ERROR_IO_ERROR; + } CFile file(filePath, CFile::WriteOnly); if (!file.isOpen()) { DEBUG_FUNCTION_LINE_ERR("Cannot create file %s", filePath.c_str()); - return WUPS_STORAGE_ERROR_SUCCESS; + return WUPS_STORAGE_ERROR_IO_ERROR; } - nlohmann::json j; - j["storageitems"] = serializeToJson(*rootItem); - std::string jsonString = j.dump(4, ' ', false, nlohmann::json::error_handler_t::ignore); auto writeResult = file.write((const uint8_t *) jsonString.c_str(), jsonString.size()); file.close(); if (writeResult != (int32_t) jsonString.size()) { - return WUPS_STORAGE_ERROR_SUCCESS; + return WUPS_STORAGE_ERROR_IO_ERROR; } return WUPS_STORAGE_ERROR_SUCCESS; } @@ -252,14 +311,13 @@ namespace StorageUtils { if (item->getValue(result)) { return WUPS_STORAGE_ERROR_SUCCESS; } - DEBUG_FUNCTION_LINE_ERR("GetValue failed? %s", key); return WUPS_STORAGE_ERROR_UNEXPECTED_DATA_TYPE; } return WUPS_STORAGE_ERROR_NOT_FOUND; } template - WUPSStorageError GetItemGeneric(wups_storage_root_item root, wups_storage_item parent, const char *key, T *result) { + WUPSStorageError GetItemGeneric(wups_storage_root_item root, wups_storage_item parent, const char *key, T *result, uint32_t *outSize) { if (!result) { return WUPS_STORAGE_ERROR_INVALID_ARGS; } @@ -267,6 +325,9 @@ namespace StorageUtils { auto res = GetItemEx(root, parent, key, tmp); if (res == WUPS_STORAGE_ERROR_SUCCESS) { *result = tmp; + if (outSize) { + *outSize = sizeof(T); + } } return res; } @@ -330,78 +391,72 @@ namespace StorageUtils { } // namespace Helper namespace API { - WUPSStorageError OpenStorage(const char *plugin_id, wups_storage_root_item *item) { + namespace Internal { + WUPSStorageError OpenStorage(std::string_view plugin_id, wups_storage_root_item &outItem) { + std::unique_ptr root = make_unique_nothrow(plugin_id); + if (!root) { + return WUPS_STORAGE_ERROR_MALLOC_FAILED; + } + + WUPSStorageError err; + if ((err = Helper::LoadFromFile(plugin_id, *root)) != WUPS_STORAGE_ERROR_SUCCESS) { + return err; + } + + outItem = (wups_storage_root_item) root->getHandle(); + { + std::lock_guard lock(gStorageMutex); + gStorage.push_front(std::move(root)); + } + + return WUPS_STORAGE_ERROR_SUCCESS; + } + + WUPSStorageError CloseStorage(wups_storage_root_item root) { + std::lock_guard lock(gStorageMutex); + + auto res = StorageUtils::Helper::WriteStorageToSD(root, false); + // TODO: handle write error? + + if (!remove_locked_first_if(gStorageMutex, gStorage, [root](auto &cur) { return cur->getHandle() == (uint32_t) root; })) { + DEBUG_FUNCTION_LINE_WARN("Failed to close storage: Not opened (\"%08X\")", root); + return WUPS_STORAGE_ERROR_NOT_FOUND; + } + return res; + } + } // namespace Internal + + WUPSStorageError SaveStorage(wups_storage_root_item root, bool force) { std::lock_guard lock(gStorageMutex); - // Check if we already have a storage with the given plugin id - for (const auto &cur : gStorage) { - if (cur->getPluginId() == plugin_id) { - *item = (wups_storage_root_item) cur->getHandle(); - return WUPS_STORAGE_ERROR_ALREADY_OPENED; - } - } - - - std::string filePath = getPluginPath() + "/config/" + plugin_id + ".json"; - nlohmann::json j; - { - CFile file(filePath, CFile::ReadOnly); - if (file.isOpen() && file.size() > 0) { - auto *json_data = (uint8_t *) memalign(0x40, ROUNDUP(file.size() + 1, 0x40)); - if (!json_data) { - DEBUG_FUNCTION_LINE_WARN("Failed to create StorageItem: Malloc failed"); - return WUPS_STORAGE_ERROR_MALLOC_FAILED; - } - - file.read(json_data, file.size()); - - json_data[file.size()] = '\0'; - - file.close(); - j = nlohmann::json::parse(json_data, nullptr, false); - free(json_data); - - if (j == nlohmann::detail::value_t::discarded || j.empty() || !j.is_object()) { - std::string errorMessage = string_format("Corrupted plugin storage detected: \"%s\". You have to reconfigure the plugin.", plugin_id); - DEBUG_FUNCTION_LINE_ERR("%s", errorMessage.c_str()); - remove(filePath.c_str()); - - DisplayErrorNotificationMessage(errorMessage, 10.0f); - } - } - } - - - std::unique_ptr storage; - if (j.empty() || !j.is_object() || !j.contains("storageitems") || j["storageitems"].empty() || !j["storageitems"].is_object()) { - storage = make_unique_nothrow(plugin_id); - } else { - storage = StorageUtils::Helper::deserializeFromJson(j["storageitems"], plugin_id); - if (!storage) { - storage = make_unique_nothrow(plugin_id); - } - } - - if (!storage) { - return WUPS_STORAGE_ERROR_MALLOC_FAILED; - } - - *item = (wups_storage_root_item) storage->getHandle(); - gStorage.push_front(std::move(storage)); - - return WUPS_STORAGE_ERROR_SUCCESS; + return StorageUtils::Helper::WriteStorageToSD(root, force); } - WUPSStorageError CloseStorage(const char *plugin_id) { + WUPSStorageError ForceReloadStorage(wups_storage_root_item root) { std::lock_guard lock(gStorageMutex); - auto res = StorageUtils::Helper::WriteStorageToSD(plugin_id); - // TODO: handle write error? + auto rootItem = Helper::getRootItem(root); + if (!rootItem) { + return WUPS_STORAGE_ERROR_INTERNAL_NOT_INITIALIZED; + } - if (!remove_locked_first_if(gStorageMutex, gStorage, [plugin_id](auto &cur) { return cur->getPluginId() == plugin_id; })) { - DEBUG_FUNCTION_LINE_WARN("Failed to close storage: Not opened (\"%s\")", plugin_id); + WUPSStorageError result; + if ((result = Helper::LoadFromFile(rootItem->getPluginId(), *rootItem)) != WUPS_STORAGE_ERROR_SUCCESS) { + return result; + } + return result; + } + + WUPSStorageError WipeStorage(wups_storage_root_item root) { + std::lock_guard lock(gStorageMutex); + + auto rootItem = Helper::getRootItem(root); + if (!rootItem) { return WUPS_STORAGE_ERROR_NOT_FOUND; } - return res; + + rootItem->wipe(); + + return WUPS_STORAGE_ERROR_SUCCESS; } WUPSStorageError CreateSubItem(wups_storage_root_item root, wups_storage_item parent, const char *key, wups_storage_item *outItem) { @@ -554,6 +609,9 @@ namespace StorageUtils { WUPSStorageError GetItem(wups_storage_root_item root, wups_storage_item parent, const char *key, WUPSStorageItemType itemType, void *data, uint32_t maxSize, uint32_t *outSize) { std::lock_guard lock(gStorageMutex); + if (outSize) { + *outSize = 0; + } switch ((WUPSStorageItemTypes) itemType) { case WUPS_STORAGE_ITEM_STRING: { if (!data || maxSize == 0) { @@ -571,43 +629,43 @@ namespace StorageUtils { if (!data || maxSize != sizeof(bool)) { return WUPS_STORAGE_ERROR_INVALID_ARGS; } - return StorageUtils::Helper::GetItemGeneric(root, parent, key, (bool *) data); + return StorageUtils::Helper::GetItemGeneric(root, parent, key, (bool *) data, outSize); } case WUPS_STORAGE_ITEM_S32: { if (!data || maxSize != sizeof(int32_t)) { return WUPS_STORAGE_ERROR_INVALID_ARGS; } - return StorageUtils::Helper::GetItemGeneric(root, parent, key, (int32_t *) data); + return StorageUtils::Helper::GetItemGeneric(root, parent, key, (int32_t *) data, outSize); } case WUPS_STORAGE_ITEM_S64: { if (!data || maxSize != sizeof(int64_t)) { return WUPS_STORAGE_ERROR_INVALID_ARGS; } - return StorageUtils::Helper::GetItemGeneric(root, parent, key, (int64_t *) data); + return StorageUtils::Helper::GetItemGeneric(root, parent, key, (int64_t *) data, outSize); } case WUPS_STORAGE_ITEM_U32: { if (!data || maxSize != sizeof(uint32_t)) { return WUPS_STORAGE_ERROR_INVALID_ARGS; } - return StorageUtils::Helper::GetItemGeneric(root, parent, key, (uint32_t *) data); + return StorageUtils::Helper::GetItemGeneric(root, parent, key, (uint32_t *) data, outSize); } case WUPS_STORAGE_ITEM_U64: { if (!data || maxSize != sizeof(uint64_t)) { return WUPS_STORAGE_ERROR_INVALID_ARGS; } - return StorageUtils::Helper::GetItemGeneric(root, parent, key, (uint64_t *) data); + return StorageUtils::Helper::GetItemGeneric(root, parent, key, (uint64_t *) data, outSize); } case WUPS_STORAGE_ITEM_FLOAT: { if (!data || maxSize != sizeof(float)) { return WUPS_STORAGE_ERROR_INVALID_ARGS; } - return StorageUtils::Helper::GetItemGeneric(root, parent, key, (float *) data); + return StorageUtils::Helper::GetItemGeneric(root, parent, key, (float *) data, outSize); } case WUPS_STORAGE_ITEM_DOUBLE: { if (!data || maxSize != sizeof(double)) { return WUPS_STORAGE_ERROR_INVALID_ARGS; } - return StorageUtils::Helper::GetItemGeneric(root, parent, key, (double *) data); + return StorageUtils::Helper::GetItemGeneric(root, parent, key, (double *) data, outSize); } } return WUPS_STORAGE_ERROR_NOT_FOUND; diff --git a/source/utils/storage/StorageUtils.h b/source/utils/storage/StorageUtils.h index 3ef5071..be9f8a2 100644 --- a/source/utils/storage/StorageUtils.h +++ b/source/utils/storage/StorageUtils.h @@ -3,8 +3,15 @@ #include namespace StorageUtils::API { - WUPSStorageError OpenStorage(const char *plugin_id, wups_storage_root_item *item); - WUPSStorageError CloseStorage(const char *plugin_id); + namespace Internal { + WUPSStorageError OpenStorage(std::string_view plugin_id, wups_storage_root_item &outItem); + WUPSStorageError CloseStorage(wups_storage_root_item item); + } // namespace Internal + + WUPSStorageError SaveStorage(wups_storage_root_item root, bool force); + WUPSStorageError ForceReloadStorage(wups_storage_root_item root); + WUPSStorageError WipeStorage(wups_storage_root_item root); + WUPSStorageError DeleteItem(wups_storage_root_item root, wups_storage_item parent, const char *key); WUPSStorageError CreateSubItem(wups_storage_root_item root, wups_storage_item parent, const char *key, wups_storage_item *outItem); WUPSStorageError GetSubItem(wups_storage_root_item root, wups_storage_item parent, const char *key, wups_storage_item *outItem); diff --git a/source/utils/utils.cpp b/source/utils/utils.cpp index c1c7059..49070c9 100644 --- a/source/utils/utils.cpp +++ b/source/utils/utils.cpp @@ -5,7 +5,11 @@ #include #include +static std::string sPluginPath; std::string getPluginPath() { + if (!sPluginPath.empty()) { + return sPluginPath; + } char environmentPath[0x100]; memset(environmentPath, 0, sizeof(environmentPath)); @@ -18,7 +22,8 @@ std::string getPluginPath() { IOS_Close(handle); } - return std::string(environmentPath).append("/plugins"); + sPluginPath = std::string(environmentPath).append("/plugins"); + return sPluginPath; } // https://gist.github.com/ccbrown/9722406