mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-25 14:16:53 +01:00
Simplify the StorageAPI
This commit is contained in:
parent
921b5ce157
commit
acc372c836
@ -1,7 +1,7 @@
|
|||||||
FROM ghcr.io/wiiu-env/devkitppc:20230621
|
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/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/libfunctionpatcher:20230621 /artifacts $DEVKITPRO
|
||||||
COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO
|
COPY --from=ghcr.io/wiiu-env/libmappedmemory:20230621 /artifacts $DEVKITPRO
|
||||||
COPY --from=ghcr.io/wiiu-env/libwupsbackend:20230621 /artifacts $DEVKITPRO
|
COPY --from=ghcr.io/wiiu-env/libwupsbackend:20230621 /artifacts $DEVKITPRO
|
||||||
|
@ -89,21 +89,22 @@ void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type)
|
|||||||
}
|
}
|
||||||
wups_loader_init_storage_args_t_ args{};
|
wups_loader_init_storage_args_t_ args{};
|
||||||
args.version = WUPS_STORAGE_CUR_API_VERSION;
|
args.version = WUPS_STORAGE_CUR_API_VERSION;
|
||||||
args.open_storage_ptr = &StorageUtils::API::OpenStorage;
|
args.root_item = plugin.getStorageRootItem();
|
||||||
args.close_storage_ptr = &StorageUtils::API::CloseStorage;
|
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.delete_item_function_ptr = &StorageUtils::API::DeleteItem;
|
||||||
args.create_sub_item_function_ptr = &StorageUtils::API::CreateSubItem;
|
args.create_sub_item_function_ptr = &StorageUtils::API::CreateSubItem;
|
||||||
args.get_sub_item_function_ptr = &StorageUtils::API::GetSubItem;
|
args.get_sub_item_function_ptr = &StorageUtils::API::GetSubItem;
|
||||||
args.store_item_function_ptr = &StorageUtils::API::StoreItem;
|
args.store_item_function_ptr = &StorageUtils::API::StoreItem;
|
||||||
args.get_item_function_ptr = &StorageUtils::API::GetItem;
|
args.get_item_function_ptr = &StorageUtils::API::GetItem;
|
||||||
args.get_item_size_function_ptr = &StorageUtils::API::GetItemSize;
|
args.get_item_size_function_ptr = &StorageUtils::API::GetItemSize;
|
||||||
args.plugin_id = plugin.getMetaInformation().getStorageId().c_str();
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
auto res = ((WUPSStorageError(*)(wups_loader_init_storage_args_t_))((uint32_t *) func_ptr))(args);
|
auto res = ((WUPSStorageError(*)(wups_loader_init_storage_args_t_))((uint32_t *) func_ptr))(args);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
if (res != WUPS_STORAGE_ERROR_SUCCESS) {
|
if (res != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
// TODO: More error handling? Notification?
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -135,6 +135,14 @@ WUMS_APPLICATION_STARTS() {
|
|||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Restore function patches of currently loaded plugins.");
|
DEBUG_FUNCTION_LINE("Restore function patches of currently loaded plugins.");
|
||||||
PluginManagement::RestoreFunctionPatches(gLoadedPlugins);
|
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.");
|
DEBUG_FUNCTION_LINE("Unload existing plugins.");
|
||||||
gLoadedPlugins.clear();
|
gLoadedPlugins.clear();
|
||||||
for (auto &cur : gTrampData) {
|
for (auto &cur : gTrampData) {
|
||||||
@ -170,6 +178,12 @@ WUMS_APPLICATION_STARTS() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (initNeeded) {
|
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);
|
PluginManagement::callInitHooks(gLoadedPlugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "PluginData.h"
|
#include "PluginData.h"
|
||||||
#include "PluginInformation.h"
|
#include "PluginInformation.h"
|
||||||
#include "PluginMetaInformation.h"
|
#include "PluginMetaInformation.h"
|
||||||
|
#include "utils/storage/StorageUtils.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <wups/config_api.h>
|
#include <wups/config_api.h>
|
||||||
@ -45,7 +46,7 @@ public:
|
|||||||
return mPluginData;
|
return mPluginData;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getHandle() const {
|
[[nodiscard]] uint32_t getHandle() const {
|
||||||
return (uint32_t) this;
|
return (uint32_t) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,9 +58,40 @@ public:
|
|||||||
mPluginConfigData = pluginConfigData;
|
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:
|
private:
|
||||||
const std::unique_ptr<PluginMetaInformation> mMetaInformation;
|
const std::unique_ptr<PluginMetaInformation> mMetaInformation;
|
||||||
const std::unique_ptr<PluginInformation> mPluginInformation;
|
const std::unique_ptr<PluginInformation> mPluginInformation;
|
||||||
const std::shared_ptr<PluginData> mPluginData;
|
const std::shared_ptr<PluginData> mPluginData;
|
||||||
|
|
||||||
std::optional<PluginConfigData> mPluginConfigData;
|
std::optional<PluginConfigData> mPluginConfigData;
|
||||||
|
wups_storage_root_item storageRootItem = nullptr;
|
||||||
};
|
};
|
||||||
|
@ -83,7 +83,7 @@ bool StorageItem::getValue(int32_t &result) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StorageItem::getValue(std::vector<uint8_t> &result) {
|
bool StorageItem::getValue(std::vector<uint8_t> &result) const {
|
||||||
if (mType == StorageItemType::Binary) {
|
if (mType == StorageItemType::Binary) {
|
||||||
result = std::get<std::vector<uint8_t>>(mData);
|
result = std::get<std::vector<uint8_t>>(mData);
|
||||||
return true;
|
return true;
|
||||||
@ -174,7 +174,7 @@ bool StorageItem::attemptBinaryConversion() {
|
|||||||
}
|
}
|
||||||
free(dec);
|
free(dec);
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Malloc failed for string->binary parsing");
|
DEBUG_FUNCTION_LINE_WARN("Malloc failed for string->binary parsing");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ enum class StorageItemType { None,
|
|||||||
|
|
||||||
class StorageItem {
|
class StorageItem {
|
||||||
public:
|
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 {
|
[[nodiscard]] uint32_t getHandle() const {
|
||||||
@ -63,7 +63,7 @@ public:
|
|||||||
|
|
||||||
bool getValue(std::string &result) const;
|
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 {
|
[[nodiscard]] StorageItemType getType() const {
|
||||||
return mType;
|
return mType;
|
||||||
|
@ -12,13 +12,18 @@
|
|||||||
|
|
||||||
class StorageItemRoot : public StorageSubItem {
|
class StorageItemRoot : public StorageSubItem {
|
||||||
public:
|
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 {
|
[[nodiscard]] const std::string &getPluginId() const {
|
||||||
return mPluginName;
|
return mPluginName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wipe() {
|
||||||
|
mSubCategories.clear();
|
||||||
|
mItems.clear();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mPluginName;
|
std::string mPluginName;
|
||||||
};
|
};
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
#include "StorageSubItem.h"
|
#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.
|
// Try to find the sub-item based on item handle.
|
||||||
for (const auto &cur : mSubCategories) {
|
for (auto &cur : mSubCategories) {
|
||||||
if (cur->getHandle() == (uint32_t) item) {
|
if (cur.getHandle() == (uint32_t) item) {
|
||||||
return cur.get();
|
return &cur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not found in current category, recursively search in sub-categories.
|
// If not found in current category, recursively search in sub-categories.
|
||||||
for (const auto &cur : mSubCategories) {
|
for (auto &cur : mSubCategories) {
|
||||||
auto res = cur->getSubItem(item);
|
auto res = cur.getSubItem(item);
|
||||||
if (res) {
|
if (res) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -22,8 +22,8 @@ StorageSubItem *StorageSubItem::getSubItem(wups_storage_item item) const {
|
|||||||
const StorageSubItem *StorageSubItem::getSubItem(const char *key) const {
|
const StorageSubItem *StorageSubItem::getSubItem(const char *key) const {
|
||||||
// Try to find the sub-item based on key.
|
// Try to find the sub-item based on key.
|
||||||
for (const auto &cur : mSubCategories) {
|
for (const auto &cur : mSubCategories) {
|
||||||
if (cur->getKey() == key) {
|
if (cur.getKey() == key) {
|
||||||
return cur.get();
|
return &cur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ const StorageSubItem *StorageSubItem::getSubItem(const char *key) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool StorageSubItem::deleteItem(const char *key) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,20 +45,17 @@ bool StorageSubItem::deleteItem(const char *key) {
|
|||||||
|
|
||||||
StorageItem *StorageSubItem::createItem(const char *key, StorageSubItem::StorageSubItemError &error) {
|
StorageItem *StorageSubItem::createItem(const char *key, StorageSubItem::StorageSubItemError &error) {
|
||||||
for (const auto &cur : mSubCategories) {
|
for (const auto &cur : mSubCategories) {
|
||||||
if (cur->getKey() == key) {
|
if (cur.getKey() == key) {
|
||||||
error = STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE;
|
error = STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = make_unique_nothrow<StorageItem>(key);
|
auto result = mItems.insert({key, StorageItem(key)});
|
||||||
if (!res) {
|
if (result.second) {
|
||||||
error = STORAGE_SUB_ITEM_ERROR_MALLOC_FAILED;
|
return &result.first->second;
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
auto *result = res.get();
|
return nullptr;
|
||||||
mItems[key] = std::move(res);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageSubItem *StorageSubItem::createSubItem(const char *key, StorageSubItem::StorageSubItemError &error) {
|
StorageSubItem *StorageSubItem::createSubItem(const char *key, StorageSubItem::StorageSubItemError &error) {
|
||||||
@ -68,26 +65,20 @@ StorageSubItem *StorageSubItem::createSubItem(const char *key, StorageSubItem::S
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
for (const auto &cur : mSubCategories) {
|
for (const auto &cur : mSubCategories) {
|
||||||
if (cur->getKey() == key) {
|
if (cur.getKey() == key) {
|
||||||
error = STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE;
|
error = STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto res = make_unique_nothrow<StorageSubItem>(key);
|
mSubCategories.emplace_front(key);
|
||||||
if (!res) {
|
return &mSubCategories.front();
|
||||||
error = STORAGE_SUB_ITEM_ERROR_MALLOC_FAILED;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
auto *result = res.get();
|
|
||||||
mSubCategories.push_front(std::move(res));
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageItem *StorageSubItem::getItem(const char *name) {
|
StorageItem *StorageSubItem::getItem(const char *name) {
|
||||||
auto resItr = mItems.find(name);
|
auto resItr = mItems.find(name);
|
||||||
if (resItr != mItems.end()) {
|
if (resItr != mItems.end()) {
|
||||||
return resItr->second.get();
|
return &resItr->second;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@ public:
|
|||||||
STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE = 2,
|
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;
|
const StorageSubItem *getSubItem(const char *key) const;
|
||||||
|
|
||||||
@ -32,15 +32,15 @@ public:
|
|||||||
|
|
||||||
StorageItem *getItem(const char *name);
|
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;
|
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;
|
return mItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
std::forward_list<std::unique_ptr<StorageSubItem>> mSubCategories;
|
std::forward_list<StorageSubItem> mSubCategories;
|
||||||
std::map<std::string, std::unique_ptr<StorageItem>> mItems;
|
std::map<std::string, StorageItem> mItems;
|
||||||
};
|
};
|
||||||
|
@ -43,7 +43,6 @@ namespace StorageUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
auto res = item.createItem(it.key().c_str(), subItemError);
|
auto res = item.createItem(it.key().c_str(), subItemError);
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
@ -73,7 +72,7 @@ namespace StorageUtils {
|
|||||||
return true;
|
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()) {
|
if (json.empty() || !json.is_object()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -90,49 +89,49 @@ namespace StorageUtils {
|
|||||||
nlohmann::json json = nlohmann::json::object();
|
nlohmann::json json = nlohmann::json::object();
|
||||||
|
|
||||||
for (const auto &curSubItem : baseItem.getSubItems()) {
|
for (const auto &curSubItem : baseItem.getSubItems()) {
|
||||||
json[curSubItem->getKey()] = serializeToJson(*curSubItem);
|
json[curSubItem.getKey()] = serializeToJson(curSubItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &[key, value] : baseItem.getItems()) {
|
for (const auto &[key, value] : baseItem.getItems()) {
|
||||||
switch ((StorageItemType) value->getType()) {
|
switch ((StorageItemType) value.getType()) {
|
||||||
case StorageItemType::String: {
|
case StorageItemType::String: {
|
||||||
std::string res;
|
std::string res;
|
||||||
if (value->getValue(res)) {
|
if (value.getValue(res)) {
|
||||||
json[key] = res;
|
json[key] = res;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case StorageItemType::Boolean: {
|
case StorageItemType::Boolean: {
|
||||||
bool res;
|
bool res;
|
||||||
if (value->getValue(res)) {
|
if (value.getValue(res)) {
|
||||||
json[key] = res;
|
json[key] = res;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case StorageItemType::S64: {
|
case StorageItemType::S64: {
|
||||||
int64_t res;
|
int64_t res;
|
||||||
if (value->getValue(res)) {
|
if (value.getValue(res)) {
|
||||||
json[key] = res;
|
json[key] = res;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case StorageItemType::U64: {
|
case StorageItemType::U64: {
|
||||||
uint64_t res;
|
uint64_t res;
|
||||||
if (value->getValue(res)) {
|
if (value.getValue(res)) {
|
||||||
json[key] = res;
|
json[key] = res;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case StorageItemType::Double: {
|
case StorageItemType::Double: {
|
||||||
double res;
|
double res;
|
||||||
if (value->getValue(res)) {
|
if (value.getValue(res)) {
|
||||||
json[key] = res;
|
json[key] = res;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case StorageItemType::Binary: {
|
case StorageItemType::Binary: {
|
||||||
std::vector<uint8_t> tmp;
|
std::vector<uint8_t> tmp;
|
||||||
if (value->getValue(tmp)) {
|
if (value.getValue(tmp)) {
|
||||||
auto *enc = b64_encode(tmp.data(), tmp.size());
|
auto *enc = b64_encode(tmp.data(), tmp.size());
|
||||||
if (enc) {
|
if (enc) {
|
||||||
json[key] = enc;
|
json[key] = enc;
|
||||||
@ -152,7 +151,7 @@ namespace StorageUtils {
|
|||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
static StorageSubItem *getRootItem(wups_storage_root_item root) {
|
static StorageItemRoot *getRootItem(wups_storage_root_item root) {
|
||||||
for (const auto &cur : gStorage) {
|
for (const auto &cur : gStorage) {
|
||||||
if (cur->getHandle() == (uint32_t) root) {
|
if (cur->getHandle() == (uint32_t) root) {
|
||||||
return cur.get();
|
return cur.get();
|
||||||
@ -173,40 +172,100 @@ namespace StorageUtils {
|
|||||||
return nullptr;
|
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;
|
std::shared_ptr<StorageItemRoot> rootItem;
|
||||||
for (const auto &cur : gStorage) {
|
for (const auto &cur : gStorage) {
|
||||||
if (cur->getPluginId() == plugin_id) {
|
if (cur->getHandle() == (uint32_t) root) {
|
||||||
rootItem = cur;
|
rootItem = cur;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!rootItem) {
|
if (!rootItem) {
|
||||||
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
return WUPS_STORAGE_ERROR_INTERNAL_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string folderPath = getPluginPath() + "/config/";
|
std::string folderPath = getPluginPath() + "/config/";
|
||||||
std::string filePath = folderPath + rootItem->getPluginId() + ".json";
|
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);
|
CFile file(filePath, CFile::WriteOnly);
|
||||||
if (!file.isOpen()) {
|
if (!file.isOpen()) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Cannot create file %s", filePath.c_str());
|
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);
|
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());
|
auto writeResult = file.write((const uint8_t *) jsonString.c_str(), jsonString.size());
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
if (writeResult != (int32_t) jsonString.size()) {
|
if (writeResult != (int32_t) jsonString.size()) {
|
||||||
return WUPS_STORAGE_ERROR_SUCCESS;
|
return WUPS_STORAGE_ERROR_IO_ERROR;
|
||||||
}
|
}
|
||||||
return WUPS_STORAGE_ERROR_SUCCESS;
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -252,14 +311,13 @@ namespace StorageUtils {
|
|||||||
if (item->getValue(result)) {
|
if (item->getValue(result)) {
|
||||||
return WUPS_STORAGE_ERROR_SUCCESS;
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE_ERR("GetValue failed? %s", key);
|
|
||||||
return WUPS_STORAGE_ERROR_UNEXPECTED_DATA_TYPE;
|
return WUPS_STORAGE_ERROR_UNEXPECTED_DATA_TYPE;
|
||||||
}
|
}
|
||||||
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
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) {
|
if (!result) {
|
||||||
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
}
|
}
|
||||||
@ -267,6 +325,9 @@ namespace StorageUtils {
|
|||||||
auto res = GetItemEx<T>(root, parent, key, tmp);
|
auto res = GetItemEx<T>(root, parent, key, tmp);
|
||||||
if (res == WUPS_STORAGE_ERROR_SUCCESS) {
|
if (res == WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
*result = tmp;
|
*result = tmp;
|
||||||
|
if (outSize) {
|
||||||
|
*outSize = sizeof(T);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -330,79 +391,73 @@ namespace StorageUtils {
|
|||||||
} // namespace Helper
|
} // namespace Helper
|
||||||
|
|
||||||
namespace API {
|
namespace API {
|
||||||
WUPSStorageError OpenStorage(const char *plugin_id, wups_storage_root_item *item) {
|
namespace Internal {
|
||||||
std::lock_guard lock(gStorageMutex);
|
WUPSStorageError OpenStorage(std::string_view plugin_id, wups_storage_root_item &outItem) {
|
||||||
// Check if we already have a storage with the given plugin id
|
std::unique_ptr<StorageItemRoot> root = make_unique_nothrow<StorageItemRoot>(plugin_id);
|
||||||
for (const auto &cur : gStorage) {
|
if (!root) {
|
||||||
if (cur->getPluginId() == plugin_id) {
|
return WUPS_STORAGE_ERROR_MALLOC_FAILED;
|
||||||
*item = (wups_storage_root_item) cur->getHandle();
|
|
||||||
return WUPS_STORAGE_ERROR_ALREADY_OPENED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WUPSStorageError err;
|
||||||
|
if ((err = Helper::LoadFromFile(plugin_id, *root)) != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
std::string filePath = getPluginPath() + "/config/" + plugin_id + ".json";
|
outItem = (wups_storage_root_item) root->getHandle();
|
||||||
nlohmann::json j;
|
|
||||||
{
|
{
|
||||||
CFile file(filePath, CFile::ReadOnly);
|
std::lock_guard lock(gStorageMutex);
|
||||||
if (file.isOpen() && file.size() > 0) {
|
gStorage.push_front(std::move(root));
|
||||||
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 WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
WUPSStorageError CloseStorage(const char *plugin_id) {
|
WUPSStorageError CloseStorage(wups_storage_root_item root) {
|
||||||
std::lock_guard lock(gStorageMutex);
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
|
||||||
auto res = StorageUtils::Helper::WriteStorageToSD(plugin_id);
|
auto res = StorageUtils::Helper::WriteStorageToSD(root, false);
|
||||||
// TODO: handle write error?
|
// TODO: handle write error?
|
||||||
|
|
||||||
if (!remove_locked_first_if(gStorageMutex, gStorage, [plugin_id](auto &cur) { return cur->getPluginId() == plugin_id; })) {
|
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 (\"%s\")", plugin_id);
|
DEBUG_FUNCTION_LINE_WARN("Failed to close storage: Not opened (\"%08X\")", root);
|
||||||
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
} // namespace Internal
|
||||||
|
|
||||||
|
WUPSStorageError SaveStorage(wups_storage_root_item root, bool force) {
|
||||||
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
return StorageUtils::Helper::WriteStorageToSD(root, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPSStorageError ForceReloadStorage(wups_storage_root_item root) {
|
||||||
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
|
||||||
|
auto rootItem = Helper::getRootItem(root);
|
||||||
|
if (!rootItem) {
|
||||||
|
return WUPS_STORAGE_ERROR_INTERNAL_NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
WUPSStorageError CreateSubItem(wups_storage_root_item root, wups_storage_item parent, const char *key, wups_storage_item *outItem) {
|
||||||
if (!outItem) {
|
if (!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) {
|
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);
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
if (outSize) {
|
||||||
|
*outSize = 0;
|
||||||
|
}
|
||||||
switch ((WUPSStorageItemTypes) itemType) {
|
switch ((WUPSStorageItemTypes) itemType) {
|
||||||
case WUPS_STORAGE_ITEM_STRING: {
|
case WUPS_STORAGE_ITEM_STRING: {
|
||||||
if (!data || maxSize == 0) {
|
if (!data || maxSize == 0) {
|
||||||
@ -571,43 +629,43 @@ namespace StorageUtils {
|
|||||||
if (!data || maxSize != sizeof(bool)) {
|
if (!data || maxSize != sizeof(bool)) {
|
||||||
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
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: {
|
case WUPS_STORAGE_ITEM_S32: {
|
||||||
if (!data || maxSize != sizeof(int32_t)) {
|
if (!data || maxSize != sizeof(int32_t)) {
|
||||||
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
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: {
|
case WUPS_STORAGE_ITEM_S64: {
|
||||||
if (!data || maxSize != sizeof(int64_t)) {
|
if (!data || maxSize != sizeof(int64_t)) {
|
||||||
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
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: {
|
case WUPS_STORAGE_ITEM_U32: {
|
||||||
if (!data || maxSize != sizeof(uint32_t)) {
|
if (!data || maxSize != sizeof(uint32_t)) {
|
||||||
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
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: {
|
case WUPS_STORAGE_ITEM_U64: {
|
||||||
if (!data || maxSize != sizeof(uint64_t)) {
|
if (!data || maxSize != sizeof(uint64_t)) {
|
||||||
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
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: {
|
case WUPS_STORAGE_ITEM_FLOAT: {
|
||||||
if (!data || maxSize != sizeof(float)) {
|
if (!data || maxSize != sizeof(float)) {
|
||||||
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
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: {
|
case WUPS_STORAGE_ITEM_DOUBLE: {
|
||||||
if (!data || maxSize != sizeof(double)) {
|
if (!data || maxSize != sizeof(double)) {
|
||||||
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
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;
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
@ -3,8 +3,15 @@
|
|||||||
#include <wups/storage.h>
|
#include <wups/storage.h>
|
||||||
|
|
||||||
namespace StorageUtils::API {
|
namespace StorageUtils::API {
|
||||||
WUPSStorageError OpenStorage(const char *plugin_id, wups_storage_root_item *item);
|
namespace Internal {
|
||||||
WUPSStorageError CloseStorage(const char *plugin_id);
|
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 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 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);
|
WUPSStorageError GetSubItem(wups_storage_root_item root, wups_storage_item parent, const char *key, wups_storage_item *outItem);
|
||||||
|
@ -5,7 +5,11 @@
|
|||||||
#include <coreinit/ios.h>
|
#include <coreinit/ios.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
static std::string sPluginPath;
|
||||||
std::string getPluginPath() {
|
std::string getPluginPath() {
|
||||||
|
if (!sPluginPath.empty()) {
|
||||||
|
return sPluginPath;
|
||||||
|
}
|
||||||
char environmentPath[0x100];
|
char environmentPath[0x100];
|
||||||
memset(environmentPath, 0, sizeof(environmentPath));
|
memset(environmentPath, 0, sizeof(environmentPath));
|
||||||
|
|
||||||
@ -18,7 +22,8 @@ std::string getPluginPath() {
|
|||||||
|
|
||||||
IOS_Close(handle);
|
IOS_Close(handle);
|
||||||
}
|
}
|
||||||
return std::string(environmentPath).append("/plugins");
|
sPluginPath = std::string(environmentPath).append("/plugins");
|
||||||
|
return sPluginPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://gist.github.com/ccbrown/9722406
|
// https://gist.github.com/ccbrown/9722406
|
||||||
|
Loading…
Reference in New Issue
Block a user