mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-22 12:49:17 +01:00
Implementation of new StorageAPI
This commit is contained in:
parent
fb2ea68627
commit
ed13894dc3
3
Makefile
3
Makefile
@ -28,7 +28,8 @@ SOURCES := source \
|
|||||||
source/elfio \
|
source/elfio \
|
||||||
source/patcher \
|
source/patcher \
|
||||||
source/plugin \
|
source/plugin \
|
||||||
source/utils
|
source/utils \
|
||||||
|
source/utils/storage
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := source
|
INCLUDES := source
|
||||||
|
|
||||||
|
@ -181,6 +181,7 @@ bool PluginManagement::DoFunctionPatches(const std::vector<std::unique_ptr<Plugi
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PluginManagement::callInitHooks(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
void PluginManagement::callInitHooks(const std::vector<std::unique_ptr<PluginContainer>> &plugins) {
|
||||||
|
CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE_DEPRECATED);
|
||||||
CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE);
|
CallHook(plugins, WUPS_LOADER_HOOK_INIT_STORAGE);
|
||||||
CallHook(plugins, WUPS_LOADER_HOOK_INIT_PLUGIN);
|
CallHook(plugins, WUPS_LOADER_HOOK_INIT_PLUGIN);
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks");
|
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks");
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#include "plugin/PluginContainer.h"
|
#include "plugin/PluginContainer.h"
|
||||||
#include "utils/StorageUtilsDeprecated.h"
|
#include "utils/StorageUtilsDeprecated.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include "utils/storage/StorageUtils.h"
|
||||||
|
#include <wups/storage.h>
|
||||||
|
|
||||||
static const char **hook_names = (const char *[]){
|
static const char **hook_names = (const char *[]){
|
||||||
"WUPS_LOADER_HOOK_INIT_WUT_MALLOC",
|
"WUPS_LOADER_HOOK_INIT_WUT_MALLOC",
|
||||||
@ -21,7 +23,7 @@ static const char **hook_names = (const char *[]){
|
|||||||
"WUPS_LOADER_HOOK_GET_CONFIG",
|
"WUPS_LOADER_HOOK_GET_CONFIG",
|
||||||
"WUPS_LOADER_HOOK_CONFIG_CLOSED",
|
"WUPS_LOADER_HOOK_CONFIG_CLOSED",
|
||||||
|
|
||||||
"WUPS_LOADER_HOOK_INIT_STORAGE",
|
"WUPS_LOADER_HOOK_INIT_STORAGE_DEPRECATED",
|
||||||
|
|
||||||
"WUPS_LOADER_HOOK_INIT_PLUGIN",
|
"WUPS_LOADER_HOOK_INIT_PLUGIN",
|
||||||
"WUPS_LOADER_HOOK_DEINIT_PLUGIN",
|
"WUPS_LOADER_HOOK_DEINIT_PLUGIN",
|
||||||
@ -29,7 +31,8 @@ static const char **hook_names = (const char *[]){
|
|||||||
"WUPS_LOADER_HOOK_RELEASE_FOREGROUND",
|
"WUPS_LOADER_HOOK_RELEASE_FOREGROUND",
|
||||||
"WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND",
|
"WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND",
|
||||||
"WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT",
|
"WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT",
|
||||||
"WUPS_LOADER_HOOK_APPLICATION_ENDS"};
|
"WUPS_LOADER_HOOK_APPLICATION_ENDS",
|
||||||
|
"WUPS_LOADER_HOOK_INIT_STORAGE"};
|
||||||
|
|
||||||
void CallHook(const std::vector<std::unique_ptr<PluginContainer>> &plugins, wups_loader_hook_type_t hook_type) {
|
void CallHook(const std::vector<std::unique_ptr<PluginContainer>> &plugins, wups_loader_hook_type_t hook_type) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d]", hook_names[hook_type], hook_type);
|
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s [%d]", hook_names[hook_type], hook_type);
|
||||||
@ -70,20 +73,38 @@ void CallHook(const PluginContainer &plugin, wups_loader_hook_type_t hook_type)
|
|||||||
((void(*)())((uint32_t *) func_ptr))();
|
((void(*)())((uint32_t *) func_ptr))();
|
||||||
// clang-format on
|
// clang-format on
|
||||||
break;
|
break;
|
||||||
case WUPS_LOADER_HOOK_INIT_STORAGE: {
|
case WUPS_LOADER_HOOK_INIT_STORAGE:
|
||||||
|
case WUPS_LOADER_HOOK_INIT_STORAGE_DEPRECATED: {
|
||||||
if (plugin.getMetaInformation().getWUPSVersion() < WUPSVersion(0, 7, 2)) {
|
if (plugin.getMetaInformation().getWUPSVersion() < WUPSVersion(0, 7, 2)) {
|
||||||
WUPSStorageDeprecated::wups_loader_init_storage_args_t args;
|
WUPSStorageDeprecated::wups_loader_init_storage_args_t_ args{};
|
||||||
args.open_storage_ptr = &WUPSStorageDeprecated::StorageUtils::OpenStorage;
|
args.open_storage_ptr = &WUPSStorageDeprecated::StorageUtils::OpenStorage;
|
||||||
args.close_storage_ptr = &WUPSStorageDeprecated::StorageUtils::CloseStorage;
|
args.close_storage_ptr = &WUPSStorageDeprecated::StorageUtils::CloseStorage;
|
||||||
args.plugin_id = plugin.getMetaInformation().getStorageId().c_str();
|
args.plugin_id = plugin.getMetaInformation().getStorageId().c_str();
|
||||||
// clang-format off
|
// clang-format off
|
||||||
((void(*)(WUPSStorageDeprecated::wups_loader_init_storage_args_t))((uint32_t *) func_ptr))(args);
|
|
||||||
|
((void(*)(WUPSStorageDeprecated::wups_loader_init_storage_args_t_))((uint32_t *) func_ptr))(args);
|
||||||
// clang-format on
|
// clang-format on
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
DEBUG_FUNCTION_LINE_ERR("WUPS_LOADER_HOOK_INIT_STORAGE hook for WUPSVersion 0.7.2 or higher not implemented");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
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.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_INVALID_VERSION) {
|
||||||
|
// TODO: More error handling? Notification?
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("WUPS_LOADER_HOOK_INIT_STORAGE failed for plugin %s: WUPS_STORAGE_ERROR_INVALID_VERSION", plugin.getMetaInformation().getName().c_str());
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
DEBUG_FUNCTION_LINE_ERR("######################################");
|
DEBUG_FUNCTION_LINE_ERR("######################################");
|
||||||
|
@ -105,6 +105,8 @@ std::unique_ptr<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(
|
|||||||
} else if (key == "wups") {
|
} else if (key == "wups") {
|
||||||
if (value == "0.7.1") {
|
if (value == "0.7.1") {
|
||||||
pluginInfo->setWUPSVersion(0, 7, 1);
|
pluginInfo->setWUPSVersion(0, 7, 1);
|
||||||
|
} else if (value == "0.7.2") {
|
||||||
|
pluginInfo->setWUPSVersion(0, 7, 2);
|
||||||
} else {
|
} else {
|
||||||
error = PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION;
|
error = PLUGIN_PARSE_ERROR_INCOMPATIBLE_VERSION;
|
||||||
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
|
DEBUG_FUNCTION_LINE_ERR("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
|
||||||
|
127
source/utils/base64.cpp
Normal file
127
source/utils/base64.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#include "base64.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
|
|
||||||
|
size_t b64_encoded_size(size_t inlen) {
|
||||||
|
size_t ret;
|
||||||
|
|
||||||
|
ret = inlen;
|
||||||
|
if (inlen % 3 != 0)
|
||||||
|
ret += 3 - (inlen % 3);
|
||||||
|
ret /= 3;
|
||||||
|
ret *= 4;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *b64_encode(const uint8_t *in, size_t len) {
|
||||||
|
char *out;
|
||||||
|
size_t elen;
|
||||||
|
size_t i;
|
||||||
|
size_t j;
|
||||||
|
size_t v;
|
||||||
|
|
||||||
|
if (in == NULL || len == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
elen = b64_encoded_size(len);
|
||||||
|
out = (char *) malloc(elen + 1);
|
||||||
|
out[elen] = '\0';
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < len; i += 3, j += 4) {
|
||||||
|
v = in[i];
|
||||||
|
v = i + 1 < len ? v << 8 | in[i + 1] : v << 8;
|
||||||
|
v = i + 2 < len ? v << 8 | in[i + 2] : v << 8;
|
||||||
|
|
||||||
|
out[j] = b64chars[(v >> 18) & 0x3F];
|
||||||
|
out[j + 1] = b64chars[(v >> 12) & 0x3F];
|
||||||
|
if (i + 1 < len) {
|
||||||
|
out[j + 2] = b64chars[(v >> 6) & 0x3F];
|
||||||
|
} else {
|
||||||
|
out[j + 2] = '=';
|
||||||
|
}
|
||||||
|
if (i + 2 < len) {
|
||||||
|
out[j + 3] = b64chars[v & 0x3F];
|
||||||
|
} else {
|
||||||
|
out[j + 3] = '=';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t b64_decoded_size(const char *in) {
|
||||||
|
size_t len;
|
||||||
|
size_t ret;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (in == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = strlen(in);
|
||||||
|
ret = len / 4 * 3;
|
||||||
|
|
||||||
|
for (i = len; i-- > 0;) {
|
||||||
|
if (in[i] == '=') {
|
||||||
|
ret--;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int b64invs[] = {
|
||||||
|
62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3,
|
||||||
|
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||||
|
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};
|
||||||
|
|
||||||
|
static int b64_isvalidchar(char c) {
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return 1;
|
||||||
|
if (c >= 'A' && c <= 'Z')
|
||||||
|
return 1;
|
||||||
|
if (c >= 'a' && c <= 'z')
|
||||||
|
return 1;
|
||||||
|
if (c == '+' || c == '/' || c == '=')
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int b64_decode(const char *in, uint8_t *out, size_t outlen) {
|
||||||
|
size_t len;
|
||||||
|
size_t i;
|
||||||
|
size_t j;
|
||||||
|
int v;
|
||||||
|
|
||||||
|
if (in == NULL || out == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = strlen(in);
|
||||||
|
if (outlen < b64_decoded_size(in) || len % 4 != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (!b64_isvalidchar(in[i])) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < len; i += 4, j += 3) {
|
||||||
|
v = b64invs[in[i] - 43];
|
||||||
|
v = (v << 6) | b64invs[in[i + 1] - 43];
|
||||||
|
v = in[i + 2] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 2] - 43];
|
||||||
|
v = in[i + 3] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 3] - 43];
|
||||||
|
|
||||||
|
out[j] = (v >> 16) & 0xFF;
|
||||||
|
if (in[i + 2] != '=')
|
||||||
|
out[j + 1] = (v >> 8) & 0xFF;
|
||||||
|
if (in[i + 3] != '=')
|
||||||
|
out[j + 2] = v & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
20
source/utils/base64.h
Normal file
20
source/utils/base64.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// based on https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t b64_encoded_size(size_t inlen);
|
||||||
|
char *b64_encode(const uint8_t *in, size_t len);
|
||||||
|
|
||||||
|
size_t b64_decoded_size(const char *in);
|
||||||
|
int b64_decode(const char *in, uint8_t *out, size_t outlen);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -39,6 +39,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
|
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
|
||||||
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS)
|
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS)
|
||||||
|
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##INFO ## ", "", FMT, ##ARGS)
|
||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
|
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
|
||||||
|
|
||||||
@ -54,6 +55,7 @@ extern "C" {
|
|||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
||||||
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
|
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
|
||||||
|
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
|
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
|
||||||
|
|
||||||
|
184
source/utils/storage/StorageItem.cpp
Normal file
184
source/utils/storage/StorageItem.cpp
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
#include "StorageItem.h"
|
||||||
|
|
||||||
|
void StorageItem::setValue(const std::string &value) {
|
||||||
|
mData = value;
|
||||||
|
mType = StorageItemType::String;
|
||||||
|
mBinaryConversionDone = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(bool value) {
|
||||||
|
mData = value;
|
||||||
|
mType = StorageItemType::Boolean;
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(int32_t value) {
|
||||||
|
mData = (int64_t) value;
|
||||||
|
mType = StorageItemType::S64;
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(int64_t value) {
|
||||||
|
mData = value;
|
||||||
|
mType = StorageItemType::S64;
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(uint64_t value) {
|
||||||
|
mData = value;
|
||||||
|
mType = StorageItemType::U64;
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(uint32_t value) {
|
||||||
|
mData = (uint64_t) value;
|
||||||
|
mType = StorageItemType::U64;
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(float value) {
|
||||||
|
mData = (double) value;
|
||||||
|
mType = StorageItemType::Double;
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(double value) {
|
||||||
|
mData = value;
|
||||||
|
mType = StorageItemType::Double;
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(const std::vector<uint8_t> &data) {
|
||||||
|
mData = data;
|
||||||
|
mType = StorageItemType::Binary;
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageItem::setValue(const uint8_t *data, size_t size) {
|
||||||
|
setValue(std::vector<uint8_t>(data, data + size));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(bool &result) const {
|
||||||
|
if (mType == StorageItemType::Boolean) {
|
||||||
|
result = std::get<bool>(mData);
|
||||||
|
return true;
|
||||||
|
} else if (mType == StorageItemType::S64) {
|
||||||
|
result = !!(std::get<int64_t>(mData));
|
||||||
|
return true;
|
||||||
|
} else if (mType == StorageItemType::U64) {
|
||||||
|
result = !!(std::get<uint64_t>(mData));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(int32_t &result) const {
|
||||||
|
if (mType == StorageItemType::S64) {
|
||||||
|
result = (int32_t) std::get<int64_t>(mData);
|
||||||
|
return true;
|
||||||
|
} else if (mType == StorageItemType::U64) {
|
||||||
|
result = (int32_t) std::get<uint64_t>(mData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(std::vector<uint8_t> &result) {
|
||||||
|
if (mType == StorageItemType::Binary) {
|
||||||
|
result = std::get<std::vector<uint8_t>>(mData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(std::string &result) const {
|
||||||
|
if (mType == StorageItemType::String) {
|
||||||
|
result = std::get<std::string>(mData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(double &result) const {
|
||||||
|
if (mType == StorageItemType::Double) {
|
||||||
|
result = std::get<double>(mData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(float &result) const {
|
||||||
|
if (mType == StorageItemType::Double) {
|
||||||
|
result = (float) std::get<double>(mData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(uint64_t &result) const {
|
||||||
|
if (mType == StorageItemType::U64) {
|
||||||
|
result = std::get<uint64_t>(mData);
|
||||||
|
return true;
|
||||||
|
} else if (mType == StorageItemType::S64) {
|
||||||
|
result = (uint64_t) std::get<int64_t>(mData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(uint32_t &result) const {
|
||||||
|
if (mType == StorageItemType::U64) {
|
||||||
|
result = (uint32_t) std::get<uint64_t>(mData);
|
||||||
|
return true;
|
||||||
|
} else if (mType == StorageItemType::S64) {
|
||||||
|
result = (uint32_t) std::get<int64_t>(mData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getValue(int64_t &result) const {
|
||||||
|
if (mType == StorageItemType::S64) {
|
||||||
|
result = std::get<int64_t>(mData);
|
||||||
|
return true;
|
||||||
|
} else if (mType == StorageItemType::U64) {
|
||||||
|
result = (int64_t) std::get<uint64_t>(mData);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::getItemSize(uint32_t &outSize) const {
|
||||||
|
if (mType == StorageItemType::String) {
|
||||||
|
outSize = (std::get<std::string>(mData).length() + 1);
|
||||||
|
return true;
|
||||||
|
} else if (mType == StorageItemType::Binary) {
|
||||||
|
outSize = std::get<std::vector<uint8_t>>(mData).size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageItem::attemptBinaryConversion() {
|
||||||
|
if (mBinaryConversionDone) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mType == StorageItemType::String) {
|
||||||
|
auto &tmp = std::get<std::string>(mData);
|
||||||
|
auto dec_size = b64_decoded_size(tmp.c_str());
|
||||||
|
if (dec_size > 0) {
|
||||||
|
auto *dec = (uint8_t *) malloc(dec_size);
|
||||||
|
if (dec) {
|
||||||
|
if (b64_decode(tmp.c_str(), dec, dec_size)) {
|
||||||
|
setValue(dec, dec_size);
|
||||||
|
}
|
||||||
|
free(dec);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Malloc failed for string->binary parsing");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mBinaryConversionDone = true;
|
||||||
|
return true;
|
||||||
|
}
|
86
source/utils/storage/StorageItem.h
Normal file
86
source/utils/storage/StorageItem.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils/base64.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
enum class StorageItemType { None,
|
||||||
|
Boolean,
|
||||||
|
String,
|
||||||
|
Binary,
|
||||||
|
S64,
|
||||||
|
U64,
|
||||||
|
Double };
|
||||||
|
|
||||||
|
class StorageItem {
|
||||||
|
public:
|
||||||
|
explicit StorageItem(std::string key) : mData(std::monostate{}), mType(StorageItemType::None), mKey(std::move(key)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] uint32_t getHandle() const {
|
||||||
|
return (uint32_t) this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setters for different types
|
||||||
|
void setValue(bool value);
|
||||||
|
|
||||||
|
void setValue(const std::string &value);
|
||||||
|
|
||||||
|
void setValue(int32_t value);
|
||||||
|
|
||||||
|
void setValue(int64_t value);
|
||||||
|
|
||||||
|
void setValue(uint64_t value);
|
||||||
|
|
||||||
|
void setValue(uint32_t value);
|
||||||
|
|
||||||
|
void setValue(float value);
|
||||||
|
|
||||||
|
void setValue(double value);
|
||||||
|
|
||||||
|
void setValue(const std::vector<uint8_t> &data);
|
||||||
|
|
||||||
|
void setValue(const uint8_t *data, size_t size);
|
||||||
|
|
||||||
|
bool getValue(bool &result) const;
|
||||||
|
|
||||||
|
bool getValue(int32_t &result) const;
|
||||||
|
|
||||||
|
bool getValue(int64_t &result) const;
|
||||||
|
|
||||||
|
bool getValue(uint32_t &result) const;
|
||||||
|
|
||||||
|
bool getValue(uint64_t &result) const;
|
||||||
|
|
||||||
|
bool getValue(float &result) const;
|
||||||
|
|
||||||
|
bool getValue(double &result) const;
|
||||||
|
|
||||||
|
bool getValue(std::string &result) const;
|
||||||
|
|
||||||
|
bool getValue(std::vector<uint8_t> &result);
|
||||||
|
|
||||||
|
[[nodiscard]] StorageItemType getType() const {
|
||||||
|
return mType;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string &getKey() const {
|
||||||
|
return mKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getItemSize(uint32_t &outSize) const;
|
||||||
|
|
||||||
|
bool attemptBinaryConversion();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<std::monostate, std::string, bool, int64_t, uint64_t, double, std::vector<uint8_t>> mData = std::monostate{};
|
||||||
|
StorageItemType mType = StorageItemType::None;
|
||||||
|
std::string mKey = {};
|
||||||
|
|
||||||
|
bool mBinaryConversionDone = true;
|
||||||
|
};
|
24
source/utils/storage/StorageItemRoot.h
Normal file
24
source/utils/storage/StorageItemRoot.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "StorageItem.h"
|
||||||
|
#include "StorageSubItem.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include <wups/storage.h>
|
||||||
|
|
||||||
|
class StorageItemRoot : public StorageSubItem {
|
||||||
|
public:
|
||||||
|
explicit StorageItemRoot(const std::string &plugin_name) : StorageSubItem(plugin_name), mPluginName(plugin_name) {
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::string &getPluginId() const {
|
||||||
|
return mPluginName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string mPluginName;
|
||||||
|
};
|
93
source/utils/storage/StorageSubItem.cpp
Normal file
93
source/utils/storage/StorageSubItem.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include "StorageSubItem.h"
|
||||||
|
|
||||||
|
StorageSubItem *StorageSubItem::getSubItem(wups_storage_item item) const {
|
||||||
|
// Try to find the sub-item based on item handle.
|
||||||
|
for (const auto &cur : mSubCategories) {
|
||||||
|
if (cur->getHandle() == (uint32_t) item) {
|
||||||
|
return cur.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not found in current category, recursively search in sub-categories.
|
||||||
|
for (const auto &cur : mSubCategories) {
|
||||||
|
auto res = cur->getSubItem(item);
|
||||||
|
if (res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StorageSubItem::deleteItem(const char *key) {
|
||||||
|
if (remove_first_if(mSubCategories, [key](auto &cur) { return cur->getKey() == key; })) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto itemItr = mItems.find(key);
|
||||||
|
if (itemItr != mItems.end()) {
|
||||||
|
mItems.erase(itemItr);
|
||||||
|
return true; // Item found and deleted.
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageItem *StorageSubItem::createItem(const char *key, StorageSubItem::StorageSubItemError &error) {
|
||||||
|
for (const auto &cur : mSubCategories) {
|
||||||
|
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 = res.get();
|
||||||
|
mItems[key] = std::move(res);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageSubItem *StorageSubItem::createSubItem(const char *key, StorageSubItem::StorageSubItemError &error) {
|
||||||
|
auto resItr = mItems.find(key);
|
||||||
|
if (resItr != mItems.end()) {
|
||||||
|
error = STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
for (const auto &cur : mSubCategories) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageItem *StorageSubItem::getItem(const char *name) {
|
||||||
|
auto resItr = mItems.find(name);
|
||||||
|
if (resItr != mItems.end()) {
|
||||||
|
return resItr->second.get();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
46
source/utils/storage/StorageSubItem.h
Normal file
46
source/utils/storage/StorageSubItem.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "StorageItem.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include <wups/storage.h>
|
||||||
|
|
||||||
|
class StorageSubItem : public StorageItem {
|
||||||
|
public:
|
||||||
|
enum StorageSubItemError {
|
||||||
|
STORAGE_SUB_ITEM_ERROR_NONE = 0,
|
||||||
|
STORAGE_SUB_ITEM_ERROR_MALLOC_FAILED = 1,
|
||||||
|
STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit StorageSubItem(const std::string &key) : StorageItem(key) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageSubItem *getSubItem(wups_storage_item item) const;
|
||||||
|
|
||||||
|
const StorageSubItem *getSubItem(const char *key) const;
|
||||||
|
|
||||||
|
bool deleteItem(const char *key);
|
||||||
|
|
||||||
|
StorageItem *createItem(const char *key, StorageSubItem::StorageSubItemError &error);
|
||||||
|
|
||||||
|
StorageSubItem *createSubItem(const char *key, StorageSubItem::StorageSubItemError &error);
|
||||||
|
|
||||||
|
StorageItem *getItem(const char *name);
|
||||||
|
|
||||||
|
[[nodiscard]] const std::forward_list<std::unique_ptr<StorageSubItem>> &getSubItems() const {
|
||||||
|
return mSubCategories;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::map<std::string, std::unique_ptr<StorageItem>> &getItems() const {
|
||||||
|
return mItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::forward_list<std::unique_ptr<StorageSubItem>> mSubCategories;
|
||||||
|
std::map<std::string, std::unique_ptr<StorageItem>> mItems;
|
||||||
|
};
|
616
source/utils/storage/StorageUtils.cpp
Normal file
616
source/utils/storage/StorageUtils.cpp
Normal file
@ -0,0 +1,616 @@
|
|||||||
|
#include "StorageUtils.h"
|
||||||
|
#include "NotificationsUtils.h"
|
||||||
|
#include "StorageItemRoot.h"
|
||||||
|
#include "fs/CFile.hpp"
|
||||||
|
#include "fs/FSUtils.h"
|
||||||
|
#include "utils/StringTools.h"
|
||||||
|
#include "utils/base64.h"
|
||||||
|
#include "utils/json.hpp"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
namespace StorageUtils {
|
||||||
|
std::forward_list<std::shared_ptr<StorageItemRoot>> gStorage;
|
||||||
|
std::mutex gStorageMutex;
|
||||||
|
|
||||||
|
namespace Helper {
|
||||||
|
static WUPSStorageError ConvertToWUPSError(const StorageSubItem::StorageSubItemError &error) {
|
||||||
|
switch (error) {
|
||||||
|
case StorageSubItem::STORAGE_SUB_ITEM_ERROR_NONE:
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
case StorageSubItem::STORAGE_SUB_ITEM_ERROR_MALLOC_FAILED:
|
||||||
|
return WUPS_STORAGE_ERROR_MALLOC_FAILED;
|
||||||
|
case StorageSubItem::STORAGE_SUB_ITEM_KEY_ALREADY_IN_USE:
|
||||||
|
return WUPS_STORAGE_ERROR_ALREADY_EXISTS;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool deserializeFromJson(const nlohmann::json &json, StorageSubItem &item) {
|
||||||
|
for (auto it = json.begin(); it != json.end(); ++it) {
|
||||||
|
StorageSubItem::StorageSubItemError subItemError = StorageSubItem::STORAGE_SUB_ITEM_ERROR_NONE;
|
||||||
|
if (it.value().is_object()) {
|
||||||
|
auto res = item.createSubItem(it.key().c_str(), subItemError);
|
||||||
|
if (!res) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Failed to create sub item: Error %d", subItemError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!it.value().empty()) {
|
||||||
|
if (!deserializeFromJson(it.value(), *res)) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Deserialization of sub item failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
auto res = item.createItem(it.key().c_str(), subItemError);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Failed to create Item for key %s. Error %d", it.key().c_str(), subItemError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (it.value().is_string()) {
|
||||||
|
auto val = it.value().get<std::string>();
|
||||||
|
res->setValue(val);
|
||||||
|
} else if (it.value().is_boolean()) {
|
||||||
|
auto val = it.value().get<bool>();
|
||||||
|
res->setValue(val);
|
||||||
|
} else if (it.value().is_number_unsigned()) {
|
||||||
|
auto val = it.value().get<std::uint64_t>();
|
||||||
|
res->setValue(val);
|
||||||
|
} else if (it.value().is_number_integer()) {
|
||||||
|
auto val = it.value().get<std::int64_t>();
|
||||||
|
res->setValue(val);
|
||||||
|
} else if (it.value().is_number_float()) {
|
||||||
|
auto val = it.value().get<std::double_t>();
|
||||||
|
res->setValue(val);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Unknown type %s for value %s", it.value().type_name(), it.key().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unique_ptr<StorageItemRoot> deserializeFromJson(const nlohmann::json &json, const std::string &key) {
|
||||||
|
if (json.empty() || !json.is_object()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
auto root = make_unique_nothrow<StorageItemRoot>(key);
|
||||||
|
if (root) {
|
||||||
|
if (deserializeFromJson(json, *root)) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static nlohmann::json serializeToJson(const StorageSubItem &baseItem) {
|
||||||
|
nlohmann::json json = nlohmann::json::object();
|
||||||
|
|
||||||
|
for (const auto &curSubItem : baseItem.getSubItems()) {
|
||||||
|
json[curSubItem->getKey()] = serializeToJson(*curSubItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[key, value] : baseItem.getItems()) {
|
||||||
|
switch ((StorageItemType) value->getType()) {
|
||||||
|
case StorageItemType::String: {
|
||||||
|
std::string res;
|
||||||
|
if (value->getValue(res)) {
|
||||||
|
json[key] = res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StorageItemType::Boolean: {
|
||||||
|
bool res;
|
||||||
|
if (value->getValue(res)) {
|
||||||
|
json[key] = res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StorageItemType::S64: {
|
||||||
|
int64_t res;
|
||||||
|
if (value->getValue(res)) {
|
||||||
|
json[key] = res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StorageItemType::U64: {
|
||||||
|
uint64_t res;
|
||||||
|
if (value->getValue(res)) {
|
||||||
|
json[key] = res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StorageItemType::Double: {
|
||||||
|
double res;
|
||||||
|
if (value->getValue(res)) {
|
||||||
|
json[key] = res;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StorageItemType::Binary: {
|
||||||
|
std::vector<uint8_t> tmp;
|
||||||
|
if (value->getValue(tmp)) {
|
||||||
|
auto *enc = b64_encode(tmp.data(), tmp.size());
|
||||||
|
if (enc) {
|
||||||
|
json[key] = enc;
|
||||||
|
free(enc);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Failed to store binary item: Malloc failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case StorageItemType::None:
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Skip: StorageItemType::None");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StorageSubItem *getRootItem(wups_storage_root_item root) {
|
||||||
|
for (const auto &cur : gStorage) {
|
||||||
|
if (cur->getHandle() == (uint32_t) root) {
|
||||||
|
return cur.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StorageSubItem *getSubItem(wups_storage_root_item root, wups_storage_item parent) {
|
||||||
|
auto rootItem = getRootItem(root);
|
||||||
|
if (rootItem) {
|
||||||
|
if (parent == nullptr) {
|
||||||
|
return rootItem;
|
||||||
|
}
|
||||||
|
return rootItem->getSubItem(parent);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static WUPSStorageError WriteStorageToSD(const char *plugin_id) {
|
||||||
|
std::shared_ptr<StorageItemRoot> rootItem;
|
||||||
|
for (const auto &cur : gStorage) {
|
||||||
|
if (cur->getPluginId() == plugin_id) {
|
||||||
|
rootItem = cur;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!rootItem) {
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string folderPath = getPluginPath() + "/config/";
|
||||||
|
std::string filePath = folderPath + rootItem->getPluginId() + ".json";
|
||||||
|
|
||||||
|
FSUtils::CreateSubfolder(folderPath);
|
||||||
|
|
||||||
|
CFile file(filePath, CFile::WriteOnly);
|
||||||
|
if (!file.isOpen()) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Cannot create file %s", filePath.c_str());
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static StorageItem *createOrGetItem(wups_storage_root_item root, wups_storage_item parent, const char *key, WUPSStorageError &error) {
|
||||||
|
const auto subItem = getSubItem(root, parent);
|
||||||
|
if (!subItem) {
|
||||||
|
error = WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
auto res = subItem->getItem(key);
|
||||||
|
StorageSubItem::StorageSubItemError subItemError = StorageSubItem::STORAGE_SUB_ITEM_ERROR_NONE;
|
||||||
|
if (!res) {
|
||||||
|
if (!(res = subItem->createItem(key, subItemError))) {
|
||||||
|
error = StorageUtils::Helper::ConvertToWUPSError(subItemError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
error = WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
WUPSStorageError StoreItemGeneric(wups_storage_root_item root, wups_storage_item parent, const char *key, T value) {
|
||||||
|
WUPSStorageError err;
|
||||||
|
auto item = createOrGetItem(root, parent, key, err);
|
||||||
|
if (item && err == WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
item->setValue(value);
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
WUPSStorageError GetItemEx(wups_storage_root_item root, wups_storage_item parent, const char *key, T &result) {
|
||||||
|
auto subItem = getSubItem(root, parent);
|
||||||
|
if (!subItem) {
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
auto item = subItem->getItem(key);
|
||||||
|
if (item) {
|
||||||
|
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) {
|
||||||
|
if (!result) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
T tmp;
|
||||||
|
auto res = GetItemEx<T>(root, parent, key, tmp);
|
||||||
|
if (res == WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
*result = tmp;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Binary items are serialized as base64 encoded string. The first time they are read they'll get converted into binary data.
|
||||||
|
*/
|
||||||
|
WUPSStorageError GetAndFixBinaryItem(wups_storage_root_item root, wups_storage_item parent, const char *key, std::vector<uint8_t> &result) {
|
||||||
|
auto subItem = getSubItem(root, parent);
|
||||||
|
if (!subItem) {
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
WUPSStorageError err = WUPS_STORAGE_ERROR_UNEXPECTED_DATA_TYPE;
|
||||||
|
auto item = subItem->getItem(key);
|
||||||
|
if (item) {
|
||||||
|
// Trigger potential string->binary conversion
|
||||||
|
if (!item->attemptBinaryConversion()) {
|
||||||
|
return WUPS_STORAGE_ERROR_MALLOC_FAILED;
|
||||||
|
}
|
||||||
|
if (item->getValue(result)) {
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WUPSStorageError GetStringItem(wups_storage_root_item root, wups_storage_item parent, const char *key, void *data, uint32_t maxSize, uint32_t *outSize) {
|
||||||
|
std::string tmp;
|
||||||
|
auto res = GetItemEx<std::string>(root, parent, key, tmp);
|
||||||
|
if (res == WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
if (maxSize <= tmp.size()) { // maxSize needs to be bigger because of the null-terminator
|
||||||
|
return WUPS_STORAGE_ERROR_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
strncpy((char *) data, tmp.c_str(), tmp.size());
|
||||||
|
((char *) data)[maxSize - 1] = '\0';
|
||||||
|
if (outSize) {
|
||||||
|
*outSize = strlen((char *) data) + 1;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static WUPSStorageError GetBinaryItem(wups_storage_root_item root, wups_storage_item parent, const char *key, const void *data, uint32_t maxSize, uint32_t *outSize) {
|
||||||
|
std::vector<uint8_t> tmp;
|
||||||
|
auto res = GetAndFixBinaryItem(root, parent, key, tmp);
|
||||||
|
if (res == WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
if (maxSize < tmp.size()) {
|
||||||
|
return WUPS_STORAGE_ERROR_BUFFER_TOO_SMALL;
|
||||||
|
}
|
||||||
|
memcpy((uint8_t *) data, tmp.data(), tmp.size());
|
||||||
|
if (outSize) {
|
||||||
|
*outSize = tmp.size();
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} // namespace Helper
|
||||||
|
|
||||||
|
namespace API {
|
||||||
|
WUPSStorageError OpenStorage(const char *plugin_id, wups_storage_root_item *item) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPSStorageError CloseStorage(const char *plugin_id) {
|
||||||
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
|
||||||
|
auto res = StorageUtils::Helper::WriteStorageToSD(plugin_id);
|
||||||
|
// TODO: handle write error?
|
||||||
|
|
||||||
|
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);
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPSStorageError CreateSubItem(wups_storage_root_item root, wups_storage_item parent, const char *key, wups_storage_item *outItem) {
|
||||||
|
if (!outItem) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
auto subItem = StorageUtils::Helper::getSubItem(root, parent);
|
||||||
|
if (subItem) {
|
||||||
|
StorageSubItem::StorageSubItemError error = StorageSubItem::STORAGE_SUB_ITEM_ERROR_NONE;
|
||||||
|
auto res = subItem->createSubItem(key, error);
|
||||||
|
if (!res) {
|
||||||
|
return StorageUtils::Helper::ConvertToWUPSError(error);
|
||||||
|
}
|
||||||
|
*outItem = (wups_storage_item) res->getHandle();
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPSStorageError GetSubItem(wups_storage_root_item root, wups_storage_item parent, const char *key, wups_storage_item *outItem) {
|
||||||
|
if (!outItem) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
auto subItem = StorageUtils::Helper::getSubItem(root, parent);
|
||||||
|
if (subItem) {
|
||||||
|
auto res = subItem->getSubItem(key);
|
||||||
|
if (!res) {
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
*outItem = (wups_storage_item) res->getHandle();
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPSStorageError DeleteItem(wups_storage_root_item root, wups_storage_item parent, const char *key) {
|
||||||
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
auto subItem = StorageUtils::Helper::getSubItem(root, parent);
|
||||||
|
if (subItem) {
|
||||||
|
auto res = subItem->deleteItem(key);
|
||||||
|
if (!res) {
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPSStorageError GetItemSize(wups_storage_root_item root, wups_storage_item parent, const char *key, uint32_t *outSize) {
|
||||||
|
if (!outSize) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
auto subItem = StorageUtils::Helper::getSubItem(root, parent);
|
||||||
|
if (!subItem) {
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
auto item = subItem->getItem(key);
|
||||||
|
if (item) {
|
||||||
|
// Trigger potential string -> binary conversion.
|
||||||
|
if (!item->attemptBinaryConversion()) {
|
||||||
|
return WUPS_STORAGE_ERROR_MALLOC_FAILED;
|
||||||
|
}
|
||||||
|
uint32_t tmp = 0;
|
||||||
|
if (item->getItemSize(tmp)) {
|
||||||
|
*outSize = tmp;
|
||||||
|
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_UNEXPECTED_DATA_TYPE;
|
||||||
|
}
|
||||||
|
return WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPSStorageError StoreItem(wups_storage_root_item root, wups_storage_item parent, const char *key, WUPSStorageItemType itemType, void *data, uint32_t length) {
|
||||||
|
std::lock_guard lock(gStorageMutex);
|
||||||
|
switch ((WUPSStorageItemTypes) itemType) {
|
||||||
|
case WUPS_STORAGE_ITEM_S32: {
|
||||||
|
if (data == nullptr || length != sizeof(int32_t)) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as S32: %d", key, *(int32_t *) data);
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<int32_t>(root, parent, key, *(int32_t *) data);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_S64: {
|
||||||
|
if (data == nullptr || length != sizeof(int64_t)) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as S64: %lld", key, *(int64_t *) data);
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<int64_t>(root, parent, key, *(int64_t *) data);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_U32: {
|
||||||
|
if (data == nullptr || length != sizeof(uint32_t)) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as u32: %u", key, *(uint32_t *) data);
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<uint32_t>(root, parent, key, *(uint32_t *) data);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_U64: {
|
||||||
|
if (data == nullptr || length != sizeof(uint64_t)) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as u64: %llu", key, *(uint64_t *) data);
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<uint64_t>(root, parent, key, *(uint64_t *) data);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_STRING: {
|
||||||
|
if (data == nullptr || length == 0) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
std::string tmp((const char *) data, length);
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as string: %s", key, tmp.c_str());
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<std::string>(root, parent, key, tmp);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_BINARY: {
|
||||||
|
if (data == nullptr || length == 0) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> tmp((uint8_t *) data, ((uint8_t *) data) + length);
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as binary: size %d", key, tmp.size());
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<std::vector<uint8_t>>(root, parent, key, tmp);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_BOOL: {
|
||||||
|
if (data == nullptr || length != sizeof(bool)) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as bool: %d", key, *(bool *) data);
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<bool>(root, parent, key, *(bool *) data);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_FLOAT: {
|
||||||
|
if (data == nullptr || length != sizeof(float)) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as float: %f", key, *(float *) data);
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<float>(root, parent, key, *(float *) data);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_DOUBLE: {
|
||||||
|
if (data == nullptr || length != sizeof(double)) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Store %s as double: %f", key, *(double *) data);
|
||||||
|
return StorageUtils::Helper::StoreItemGeneric<double>(root, parent, key, *(double *) data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Store failed!");
|
||||||
|
return WUPS_STORAGE_ERROR_UNEXPECTED_DATA_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
switch ((WUPSStorageItemTypes) itemType) {
|
||||||
|
case WUPS_STORAGE_ITEM_STRING: {
|
||||||
|
if (!data || maxSize == 0) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
return StorageUtils::Helper::GetStringItem(root, parent, key, data, maxSize, outSize);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_BINARY: {
|
||||||
|
if (!data || maxSize == 0) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
return StorageUtils::Helper::GetBinaryItem(root, parent, key, data, maxSize, outSize);
|
||||||
|
}
|
||||||
|
case WUPS_STORAGE_ITEM_BOOL: {
|
||||||
|
if (!data || maxSize != sizeof(bool)) {
|
||||||
|
return WUPS_STORAGE_ERROR_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
return StorageUtils::Helper::GetItemGeneric<bool>(root, parent, key, (bool *) data);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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 WUPS_STORAGE_ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
} // namespace API
|
||||||
|
} // namespace StorageUtils
|
14
source/utils/storage/StorageUtils.h
Normal file
14
source/utils/storage/StorageUtils.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <wups/storage.h>
|
||||||
|
|
||||||
|
namespace StorageUtils::API {
|
||||||
|
WUPSStorageError OpenStorage(const char *plugin_id, wups_storage_root_item *item);
|
||||||
|
WUPSStorageError CloseStorage(const char *plugin_id);
|
||||||
|
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);
|
||||||
|
WUPSStorageError StoreItem(wups_storage_root_item root, wups_storage_item parent, const char *key, WUPSStorageItemType itemType, void *data, uint32_t length);
|
||||||
|
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 GetItemSize(wups_storage_root_item root, wups_storage_item parent, const char *key, uint32_t *outSize);
|
||||||
|
} // namespace StorageUtils::API
|
@ -63,18 +63,40 @@ std::shared_ptr<T> make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std::
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename Container, typename Predicate>
|
template<typename Container, typename Predicate>
|
||||||
bool remove_locked_first_if(std::mutex &mutex, Container &container, Predicate pred) {
|
typename std::enable_if<std::is_same<Container, std::forward_list<typename Container::value_type>>::value, bool>::type
|
||||||
std::lock_guard<std::mutex> lock(mutex);
|
remove_first_if(Container &container, Predicate pred) {
|
||||||
|
auto it = container.before_begin();
|
||||||
|
|
||||||
auto it = std::find_if(container.begin(), container.end(), pred);
|
for (auto prev = it, current = ++it; current != container.end(); ++prev, ++current) {
|
||||||
if (it != container.end()) {
|
if (pred(*current)) {
|
||||||
container.erase(it);
|
container.erase_after(prev);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Container, typename Predicate>
|
||||||
|
typename std::enable_if<std::is_same<Container, std::set<typename Container::value_type>>::value, bool>::type
|
||||||
|
remove_first_if(Container &container, Predicate pred) {
|
||||||
|
auto it = container.begin();
|
||||||
|
while (it != container.end()) {
|
||||||
|
if (pred(*it)) {
|
||||||
|
container.erase(it);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Container, typename Predicate>
|
||||||
|
bool remove_locked_first_if(std::mutex &mutex, Container &container, Predicate pred) {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
return remove_first_if(container, pred);
|
||||||
|
}
|
||||||
|
|
||||||
std::string getPluginPath();
|
std::string getPluginPath();
|
||||||
|
|
||||||
OSDynLoad_Error CustomDynLoadAlloc(int32_t size, int32_t align, void **outAddr);
|
OSDynLoad_Error CustomDynLoadAlloc(int32_t size, int32_t align, void **outAddr);
|
||||||
|
Loading…
Reference in New Issue
Block a user