Simplify the StorageAPI

This commit is contained in:
Maschell 2023-12-16 12:44:20 +01:00
parent 921b5ce157
commit acc372c836
12 changed files with 254 additions and 141 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -21,6 +21,7 @@
#include "PluginData.h"
#include "PluginInformation.h"
#include "PluginMetaInformation.h"
#include "utils/storage/StorageUtils.h"
#include <memory>
#include <utility>
#include <wups/config_api.h>
@ -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<PluginMetaInformation> mMetaInformation;
const std::unique_ptr<PluginInformation> mPluginInformation;
const std::shared_ptr<PluginData> mPluginData;
std::optional<PluginConfigData> mPluginConfigData;
wups_storage_root_item storageRootItem = nullptr;
};

View File

@ -83,7 +83,7 @@ bool StorageItem::getValue(int32_t &result) const {
return false;
}
bool StorageItem::getValue(std::vector<uint8_t> &result) {
bool StorageItem::getValue(std::vector<uint8_t> &result) const {
if (mType == StorageItemType::Binary) {
result = std::get<std::vector<uint8_t>>(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;
}
}

View File

@ -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<uint8_t> &result);
bool getValue(std::vector<uint8_t> &result) const;
[[nodiscard]] StorageItemType getType() const {
return mType;

View File

@ -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;
};

View File

@ -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<StorageItem>(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<StorageSubItem>(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;
}

View File

@ -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<std::unique_ptr<StorageSubItem>> &getSubItems() const {
[[nodiscard]] const std::forward_list<StorageSubItem> &getSubItems() const {
return mSubCategories;
}
[[nodiscard]] const std::map<std::string, std::unique_ptr<StorageItem>> &getItems() const {
[[nodiscard]] const std::map<std::string, StorageItem> &getItems() const {
return mItems;
}
private:
std::forward_list<std::unique_ptr<StorageSubItem>> mSubCategories;
std::map<std::string, std::unique_ptr<StorageItem>> mItems;
protected:
std::forward_list<StorageSubItem> mSubCategories;
std::map<std::string, StorageItem> mItems;
};

View File

@ -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<StorageItemRoot> deserializeFromJson(const nlohmann::json &json, const std::string &key) {
static std::unique_ptr<StorageItemRoot> 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<uint8_t> 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<StorageItemRoot> storage;
if (j.empty() || !j.is_object() || !j.contains("storageitems") || j["storageitems"].empty() || !j["storageitems"].is_object()) {
storage = make_unique_nothrow<StorageItemRoot>(plugin_id);
} else {
storage = StorageUtils::Helper::deserializeFromJson(j["storageitems"], plugin_id);
if (!storage) {
storage = make_unique_nothrow<StorageItemRoot>(plugin_id);
}
}
rootItem = *storage;
return WUPS_STORAGE_ERROR_SUCCESS;
}
static WUPSStorageError WriteStorageToSD(wups_storage_root_item root, bool forceSave) {
std::shared_ptr<StorageItemRoot> 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<typename T>
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<T>(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<StorageItemRoot> root = make_unique_nothrow<StorageItemRoot>(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<StorageItemRoot> storage;
if (j.empty() || !j.is_object() || !j.contains("storageitems") || j["storageitems"].empty() || !j["storageitems"].is_object()) {
storage = make_unique_nothrow<StorageItemRoot>(plugin_id);
} else {
storage = StorageUtils::Helper::deserializeFromJson(j["storageitems"], plugin_id);
if (!storage) {
storage = make_unique_nothrow<StorageItemRoot>(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<bool>(root, parent, key, (bool *) data);
return StorageUtils::Helper::GetItemGeneric<bool>(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<int32_t>(root, parent, key, (int32_t *) data);
return StorageUtils::Helper::GetItemGeneric<int32_t>(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<int64_t>(root, parent, key, (int64_t *) data);
return StorageUtils::Helper::GetItemGeneric<int64_t>(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<uint32_t>(root, parent, key, (uint32_t *) data);
return StorageUtils::Helper::GetItemGeneric<uint32_t>(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<uint64_t>(root, parent, key, (uint64_t *) data);
return StorageUtils::Helper::GetItemGeneric<uint64_t>(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<float>(root, parent, key, (float *) data);
return StorageUtils::Helper::GetItemGeneric<float>(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<double>(root, parent, key, (double *) data);
return StorageUtils::Helper::GetItemGeneric<double>(root, parent, key, (double *) data, outSize);
}
}
return WUPS_STORAGE_ERROR_NOT_FOUND;

View File

@ -3,8 +3,15 @@
#include <wups/storage.h>
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);

View File

@ -5,7 +5,11 @@
#include <coreinit/ios.h>
#include <string>
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