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