mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-25 14:16:53 +01:00
Add support for the config and storage API. Bump version to 0.6
This commit is contained in:
parent
ed792716fe
commit
13ed348f43
10
Dockerfile
10
Dockerfile
@ -1,7 +1,9 @@
|
||||
FROM wiiuenv/devkitppc:20210917
|
||||
FROM wiiuenv/devkitppc:20210920
|
||||
|
||||
COPY --from=wiiuenv/wiiumodulesystem:20210917 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiupluginsystem:20210917 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libfunctionpatcher:20210109 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiumodulesystem:20210924 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiupluginsystem:20210924 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libfunctionpatcher:20210924 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libmappedmemory:20210924 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libwupsbackend:20210924 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR project
|
8
Makefile
8
Makefile
@ -23,6 +23,8 @@ WUT_ROOT := $(DEVKITPRO)/wut
|
||||
TARGET := PluginBackend
|
||||
BUILD := build
|
||||
SOURCES := source \
|
||||
source/fs \
|
||||
source/config \
|
||||
source/elfio \
|
||||
source/patcher \
|
||||
source/plugin \
|
||||
@ -41,9 +43,9 @@ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libfunctionpatcher.ld $(WUMSSPECS)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libfunctionpatcher.ld -T$(WUMS_ROOT)/share/libmappedmemory.ld $(WUMSSPECS)
|
||||
|
||||
LIBS := -lwums -lwut -lwups -lfunctionpatcher -lz
|
||||
LIBS := -lwums -lwut -lwups -lfunctionpatcher -lmappedmemory -lfreetype -lbz2 -lpng -lz
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
@ -93,7 +95,7 @@ export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
-I$(CURDIR)/$(BUILD) -I$(DEVKITPRO)/portlibs/ppc/include/freetype2
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
|
@ -155,6 +155,7 @@ void PluginManagement::unloadPlugins(plugin_information_t *gPluginInformation, M
|
||||
}
|
||||
|
||||
void PluginManagement::callInitHooks(plugin_information_t *pluginInformation) {
|
||||
CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_STORAGE);
|
||||
CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_PLUGIN);
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks");
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ struct plugin_meta_info_t {
|
||||
char license[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
||||
char buildTimestamp[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
||||
char descripion[MAXIMUM_PLUGIN_DESCRIPTION_LENGTH] = "";
|
||||
char id[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
|
90
source/config/WUPSConfig.h
Normal file
90
source/config/WUPSConfig.h
Normal file
@ -0,0 +1,90 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018-2021 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <wups/config.h>
|
||||
#include "WUPSConfigCategory.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
class WUPSConfig {
|
||||
public:
|
||||
explicit WUPSConfig(const std::string &name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
~WUPSConfig() {
|
||||
for (auto &element : categories) {
|
||||
delete element;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns the name of this WUPSConfig
|
||||
**/
|
||||
std::string getName() {
|
||||
return this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Creates a new WUPSCategory add its to this WUPSConfig.
|
||||
The category will be added to the end of the list.
|
||||
This class holds responsibility for deleting the created instance.
|
||||
|
||||
\param categoryName: The name of the category that will be created.
|
||||
|
||||
\return On success, the created and inserted category will be returned.
|
||||
**/
|
||||
std::optional<WUPSConfigCategory *> addCategory(const std::string &categoryName) {
|
||||
auto curCat = new WUPSConfigCategory(categoryName);
|
||||
if (curCat == nullptr) {
|
||||
return {};
|
||||
}
|
||||
categories.push_back(curCat);
|
||||
return curCat;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Adds a given WUPSConfigCategory to this WUPSConfig.
|
||||
The category will be added to the end of the list.
|
||||
This class holds responsibility for deleting the created instance.
|
||||
|
||||
\param category: The category that will be added to this config.
|
||||
|
||||
\return On success, the inserted category will be returned.
|
||||
On error NULL will be returned. In this case the caller still has the responsibility
|
||||
for deleting the WUPSConfigCategory instance.
|
||||
**/
|
||||
WUPSConfigCategory *addCategory(WUPSConfigCategory *category) {
|
||||
categories.push_back(category);
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns a vector with all categories.
|
||||
**/
|
||||
const std::vector<WUPSConfigCategory *> &getCategories() {
|
||||
return this->categories;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<WUPSConfigCategory *> categories = {};
|
||||
};
|
73
source/config/WUPSConfigCategory.h
Normal file
73
source/config/WUPSConfigCategory.h
Normal file
@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018-2021 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <wups/config.h>
|
||||
#include "WUPSConfigItem.h"
|
||||
|
||||
class WUPSConfigCategory {
|
||||
public:
|
||||
explicit WUPSConfigCategory(const std::string &name) {
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
~WUPSConfigCategory() {
|
||||
for (auto &element : items) {
|
||||
delete element;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns the name of this WUPSConfigCategory
|
||||
**/
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Adds a given WUPSConfigItem to this WUPSConfigCategory.
|
||||
The item will be added to the end of the list.
|
||||
This class holds responsibility for deleting the created instance.
|
||||
|
||||
\param item: The item that will be added to this config.
|
||||
|
||||
\return On success, true will be returned.
|
||||
On error false will be returned. In this case the caller still has the responsibility
|
||||
for deleting the WUPSConfigItem instance.
|
||||
**/
|
||||
[[nodiscard]] bool addItem(WUPSConfigItem *item) {
|
||||
if(item != nullptr){
|
||||
items.push_back(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns a vector with all items.
|
||||
**/
|
||||
[[nodiscard]] const std::vector<WUPSConfigItem *> &getItems() const {
|
||||
return this->items;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
std::vector<WUPSConfigItem *> items{};
|
||||
};
|
81
source/config/WUPSConfigCategoryExport.cpp
Normal file
81
source/config/WUPSConfigCategoryExport.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#include <wums.h>
|
||||
#include <wups/config.h>
|
||||
#include "WUPSConfigCategory.h"
|
||||
#include "../utils/logger.h"
|
||||
|
||||
int32_t WUPSConfigCategory_Create(WUPSConfigCategoryHandle *out, const char *name) {
|
||||
if (name == nullptr || out == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = (WUPSConfigCategoryHandle) new WUPSConfigCategory(name);
|
||||
if (*out != 0) {
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
};
|
||||
|
||||
int32_t WUPSConfigCategory_Destroy(WUPSConfigCategoryHandle handle) {
|
||||
if (handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
delete config;
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32_t WUPSConfigCategory_GetName(WUPSConfigCategoryHandle handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
snprintf(out_buf, out_len, "%s", config->getName().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigCategory_AddItem(WUPSConfigCategoryHandle handle, WUPSConfigItemHandle item_Handle) {
|
||||
if (handle == 0 || item_Handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
auto *category = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
auto *item = reinterpret_cast<WUPSConfigItem *>(item_Handle);
|
||||
if (category->addItem(item)) {
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
/*
|
||||
int32_t WUPSConfigCategory_GetItemCount(WUPSConfigCategoryHandle handle, int32_t *item_count) {
|
||||
if (handle == 0 || item_count == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
*item_count = config->getItems().size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigCategory_GetItems(WUPSConfigCategoryHandle handle, WUPSConfigItemHandle *items_out, int32_t items_out_size) {
|
||||
if (handle == 0 || items_out == nullptr || items_out_size == 0) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigCategory *>(handle);
|
||||
auto items = config->getItems();
|
||||
int32_t index = 0;
|
||||
for (auto const &item: items) {
|
||||
if (index >= items_out_size) {
|
||||
break;
|
||||
}
|
||||
items_out[index] = (WUPSConfigItemHandle) item;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_GetName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_AddItem);
|
||||
/*
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_GetItemCount);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigCategory_GetItems);*/
|
97
source/config/WUPSConfigExport.cpp
Normal file
97
source/config/WUPSConfigExport.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include <wums.h>
|
||||
#include <wups/config.h>
|
||||
#include "WUPSConfig.h"
|
||||
#include "../utils/logger.h"
|
||||
|
||||
int32_t WUPSConfig_Create(WUPSConfigHandle *out, const char *name) {
|
||||
if (name == nullptr || out == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = (WUPSConfigHandle) new WUPSConfig(name);
|
||||
if (*out != 0) {
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
};
|
||||
|
||||
int32_t WUPSConfig_Destroy(WUPSConfigHandle handle) {
|
||||
if (handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
delete config;
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32_t WUPSConfig_GetName(WUPSConfigHandle handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
snprintf(out_buf, out_len, "%s", config->getName().c_str());
|
||||
DEBUG_FUNCTION_LINE("%s", out_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_AddCategoryByName(WUPSConfigHandle handle, const char *categoryName, WUPSConfigCategoryHandle *out) {
|
||||
if (categoryName == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
auto res = config->addCategory(std::string(categoryName));
|
||||
if (res.has_value()) {
|
||||
if (out != nullptr) {
|
||||
*out = reinterpret_cast<WUPSConfigCategoryHandle>(res.value());
|
||||
}else{
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_AddCategory(WUPSConfigHandle handle, WUPSConfigCategoryHandle category) {
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
auto res = config->addCategory(reinterpret_cast<WUPSConfigCategory *>(category));
|
||||
if (res == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
int32_t WUPSConfig_GetCategoryCount(WUPSConfigHandle handle, int32_t *category_count) {
|
||||
if (category_count == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
*category_count = config->getCategories().size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfig_GetCategories(WUPSConfigHandle handle, WUPSConfigCategoryHandle *categories_out, int32_t categories_out_size) {
|
||||
if (categories_out == nullptr || categories_out_size == 0) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfig *>(handle);
|
||||
auto cats = config->getCategories();
|
||||
int32_t index = 0;
|
||||
for (auto const &cat: cats) {
|
||||
if (index >= categories_out_size) {
|
||||
break;
|
||||
}
|
||||
categories_out[index] = (WUPSConfigCategoryHandle) cat;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_GetName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_AddCategoryByName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_AddCategory);
|
||||
/*
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_GetCategoryCount);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfig_GetCategories);*/
|
176
source/config/WUPSConfigItem.h
Normal file
176
source/config/WUPSConfigItem.h
Normal file
@ -0,0 +1,176 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <wups/config.h>
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
class WUPSConfigItem {
|
||||
public:
|
||||
/**
|
||||
Sets the display name of this WUPSConfigItem
|
||||
This is the value which will be shown in the configuration menu.
|
||||
**/
|
||||
virtual void setDisplayName(const std::string &_displayName) {
|
||||
this->displayName = _displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns the display name of this WUPSConfigItem
|
||||
**/
|
||||
virtual const std::string &getDisplayName() {
|
||||
return this->displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the config ID name of this WUPSConfigItem.
|
||||
This config ID is used to persist the configuration values and needs
|
||||
to be unique in the context of this WUPSConfig.
|
||||
Items in different categories are NOT allowed to have the config ID.
|
||||
**/
|
||||
virtual void setConfigID(const std::string &_configID) {
|
||||
this->configID = _configID;
|
||||
}
|
||||
|
||||
/**
|
||||
\return Returns the configID of this WUPSConfigItem.
|
||||
**/
|
||||
[[nodiscard]] virtual const std::string &getConfigID() const {
|
||||
return this->configID;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a string that displays the current value.
|
||||
This string is shown next to the display name when the cursor is NOT on this item
|
||||
**/
|
||||
[[nodiscard]] std::string getCurrentValueDisplay() const {
|
||||
if (this->callbacks.getCurrentValueDisplay != nullptr) {
|
||||
char buf[256];
|
||||
int res = this->callbacks.getCurrentValueDisplay(context, buf, sizeof(buf));
|
||||
if (res == 0) {
|
||||
return buf;
|
||||
} else {
|
||||
return StringTools::strfmt("[ERROR %d]", res);
|
||||
}
|
||||
}
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a string that displays the current value when selected.
|
||||
This string is shown next to the display name when the cursor IS on this item
|
||||
**/
|
||||
[[nodiscard]] std::string getCurrentValueSelectedDisplay() const {
|
||||
if (this->callbacks.getCurrentValueSelectedDisplay != nullptr) {
|
||||
char buf[256];
|
||||
int res = this->callbacks.getCurrentValueSelectedDisplay(context, buf, sizeof(buf));
|
||||
if (res == 0) {
|
||||
return buf;
|
||||
} else {
|
||||
return StringTools::strfmt("[ERROR %d]", res);
|
||||
}
|
||||
}
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
|
||||
/**
|
||||
Is called when the cursor enters or leaves the item.
|
||||
When the cursor enters the item, "isSelected" will be true.
|
||||
When the cursor leaves the item, "isSelected" will be false.
|
||||
**/
|
||||
void onSelected(bool isSelected) const {
|
||||
if (this->callbacks.onSelected != nullptr) {
|
||||
this->callbacks.onSelected(context, isSelected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Is called when a button is pressed while the cursor on this item.
|
||||
See the WUPSConfigButtons enum for possible values.
|
||||
**/
|
||||
void onButtonPressed(WUPSConfigButtons buttons) const {
|
||||
if (this->callbacks.onButtonPressed != nullptr) {
|
||||
this->callbacks.onButtonPressed(context, buttons);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
When the cursor is on this item, the configuration menu asks this item
|
||||
if it's allowed to leave it.
|
||||
If it returns true, the item can be leaved.
|
||||
It it returns false, leaves is not allowed.
|
||||
**/
|
||||
[[nodiscard]] bool isMovementAllowed() const {
|
||||
if (this->callbacks.isMovementAllowed != nullptr) {
|
||||
return this->callbacks.isMovementAllowed(context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
Restores the default value
|
||||
**/
|
||||
void restoreDefault() {
|
||||
if (this->callbacks.restoreDefault != nullptr) {
|
||||
this->callbacks.restoreDefault(context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Call callback with with current value.
|
||||
This function will be called whenever this item should call it's (optional) given
|
||||
callback with the current value.
|
||||
Returns true if a valid callback could be called
|
||||
Returns false if no callback was called (e.g. callback was NULL)
|
||||
**/
|
||||
bool callCallback() {
|
||||
if (this->callbacks.callCallback != nullptr) {
|
||||
return this->callbacks.callCallback(context);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDirty() {
|
||||
return defaultValue != getCurrentValueDisplay();
|
||||
}
|
||||
|
||||
WUPSConfigItem(const std::string &_configID, const std::string &_displayName, WUPSConfigCallbacks_t callbacks, void *_context) {
|
||||
this->configID = _configID;
|
||||
this->displayName = _displayName;
|
||||
this->context = _context;
|
||||
this->callbacks = callbacks;
|
||||
this->defaultValue = getCurrentValueDisplay();
|
||||
}
|
||||
|
||||
virtual ~WUPSConfigItem() {
|
||||
if (this->callbacks.onDelete != nullptr) {
|
||||
this->callbacks.onDelete(context);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
void *context;
|
||||
std::string displayName;
|
||||
std::string configID;
|
||||
std::string defaultValue;
|
||||
WUPSConfigCallbacks_t callbacks{};
|
||||
};
|
72
source/config/WUPSConfigItemExport.cpp
Normal file
72
source/config/WUPSConfigItemExport.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include <wums.h>
|
||||
#include <wups/config.h>
|
||||
#include "WUPSConfigItem.h"
|
||||
|
||||
typedef uint32_t WUPSConfigItemHandle;
|
||||
|
||||
int32_t WUPSConfigItem_Create(WUPSConfigItemHandle *out, const char *configID, const char *displayName, WUPSConfigCallbacks_t callbacks, void* context) {
|
||||
if (configID == nullptr || displayName == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out = (WUPSConfigItemHandle) new WUPSConfigItem(configID, displayName, callbacks, context);
|
||||
if (*out != 0) {
|
||||
return 0;
|
||||
}
|
||||
return -2;
|
||||
};
|
||||
|
||||
int32_t WUPSConfigItem_Destroy(WUPSConfigItemHandle handle) {
|
||||
if (handle == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
delete config;
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32_t WUPSConfigItem_SetDisplayName(WUPSConfigItemHandle handle, const char *displayName) {
|
||||
if (displayName == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
config->setDisplayName(displayName);
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32_t WUPSConfigItem_GetDisplayName(WUPSConfigItemHandle handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
snprintf(out_buf, out_len, "%s", config->getDisplayName().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WUPSConfigItem_SetConfigID(WUPSConfigItemHandle handle, const char *configID) {
|
||||
if (configID == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
config->setConfigID(configID);
|
||||
return 0;
|
||||
};
|
||||
|
||||
int32_t WUPSConfigItem_GetConfigID(WUPSConfigItemHandle handle, char *out_buf, int32_t out_len) {
|
||||
if (out_buf == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
auto *config = reinterpret_cast<WUPSConfigItem *>(handle);
|
||||
snprintf(out_buf, out_len, "%s", config->getConfigID().c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_Create);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_Destroy);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_SetDisplayName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_GetDisplayName);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_SetConfigID);
|
||||
WUMS_EXPORT_FUNCTION(WUPSConfigItem_GetConfigID);
|
175
source/fs/CFile.cpp
Normal file
175
source/fs/CFile.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <fs/CFile.hpp>
|
||||
|
||||
CFile::CFile() {
|
||||
iFd = -1;
|
||||
mem_file = NULL;
|
||||
filesize = 0;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
CFile::CFile(const std::string &filepath, eOpenTypes mode) {
|
||||
iFd = -1;
|
||||
this->open(filepath, mode);
|
||||
}
|
||||
|
||||
CFile::CFile(const uint8_t *mem, int32_t size) {
|
||||
iFd = -1;
|
||||
this->open(mem, size);
|
||||
}
|
||||
|
||||
CFile::~CFile() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
int32_t CFile::open(const std::string &filepath, eOpenTypes mode) {
|
||||
this->close();
|
||||
int32_t openMode = 0;
|
||||
|
||||
// This depend on the devoptab implementation.
|
||||
// see https://github.com/devkitPro/wut/blob/master/libraries/wutdevoptab/devoptab_fs_open.c#L21 fpr reference
|
||||
|
||||
switch (mode) {
|
||||
default:
|
||||
case ReadOnly: // file must exist
|
||||
openMode = O_RDONLY;
|
||||
break;
|
||||
case WriteOnly: // file will be created / zerod
|
||||
openMode = O_TRUNC | O_CREAT | O_WRONLY;
|
||||
break;
|
||||
case ReadWrite: // file must exist
|
||||
openMode = O_RDWR;
|
||||
break;
|
||||
case Append: // append to file, file will be created if missing. write only
|
||||
openMode = O_CREAT | O_APPEND | O_WRONLY;
|
||||
break;
|
||||
}
|
||||
|
||||
//! Using fopen works only on the first launch as expected
|
||||
//! on the second launch it causes issues because we don't overwrite
|
||||
//! the .data sections which is needed for a normal application to re-init
|
||||
//! this will be added with launching as RPX
|
||||
iFd = ::open(filepath.c_str(), openMode);
|
||||
if (iFd < 0)
|
||||
return iFd;
|
||||
|
||||
|
||||
filesize = ::lseek(iFd, 0, SEEK_END);
|
||||
::lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t CFile::open(const uint8_t *mem, int32_t size) {
|
||||
this->close();
|
||||
|
||||
mem_file = mem;
|
||||
filesize = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CFile::close() {
|
||||
if (iFd >= 0)
|
||||
::close(iFd);
|
||||
|
||||
iFd = -1;
|
||||
mem_file = NULL;
|
||||
filesize = 0;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
int32_t CFile::read(uint8_t *ptr, size_t size) {
|
||||
if (iFd >= 0) {
|
||||
int32_t ret = ::read(iFd, ptr, size);
|
||||
if (ret > 0)
|
||||
pos += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t readsize = size;
|
||||
|
||||
if (readsize > (int64_t) (filesize - pos))
|
||||
readsize = filesize - pos;
|
||||
|
||||
if (readsize <= 0)
|
||||
return readsize;
|
||||
|
||||
if (mem_file != NULL) {
|
||||
memcpy(ptr, mem_file + pos, readsize);
|
||||
pos += readsize;
|
||||
return readsize;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t CFile::write(const uint8_t *ptr, size_t size) {
|
||||
if (iFd >= 0) {
|
||||
size_t done = 0;
|
||||
while (done < size) {
|
||||
int32_t ret = ::write(iFd, ptr, size - done);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
ptr += ret;
|
||||
done += ret;
|
||||
pos += ret;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t CFile::seek(long int offset, int32_t origin) {
|
||||
int32_t ret = 0;
|
||||
int64_t newPos = pos;
|
||||
|
||||
if (origin == SEEK_SET) {
|
||||
newPos = offset;
|
||||
} else if (origin == SEEK_CUR) {
|
||||
newPos += offset;
|
||||
} else if (origin == SEEK_END) {
|
||||
newPos = filesize + offset;
|
||||
}
|
||||
|
||||
if (newPos < 0) {
|
||||
pos = 0;
|
||||
} else {
|
||||
pos = newPos;
|
||||
}
|
||||
|
||||
if (iFd >= 0)
|
||||
ret = ::lseek(iFd, pos, SEEK_SET);
|
||||
|
||||
if (mem_file != NULL) {
|
||||
if (pos > filesize) {
|
||||
pos = filesize;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t CFile::fwrite(const char *format, ...) {
|
||||
char tmp[512];
|
||||
tmp[0] = 0;
|
||||
int32_t result = -1;
|
||||
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
||||
result = this->write((uint8_t *) tmp, strlen(tmp));
|
||||
}
|
||||
va_end(va);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
71
source/fs/CFile.hpp
Normal file
71
source/fs/CFile.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef CFILE_HPP_
|
||||
#define CFILE_HPP_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <wut_types.h>
|
||||
|
||||
class CFile {
|
||||
public:
|
||||
enum eOpenTypes {
|
||||
ReadOnly,
|
||||
WriteOnly,
|
||||
ReadWrite,
|
||||
Append
|
||||
};
|
||||
|
||||
CFile();
|
||||
|
||||
CFile(const std::string &filepath, eOpenTypes mode);
|
||||
|
||||
CFile(const uint8_t *memory, int32_t memsize);
|
||||
|
||||
virtual ~CFile();
|
||||
|
||||
int32_t open(const std::string &filepath, eOpenTypes mode);
|
||||
|
||||
int32_t open(const uint8_t *memory, int32_t memsize);
|
||||
|
||||
BOOL isOpen() const {
|
||||
if (iFd >= 0)
|
||||
return true;
|
||||
|
||||
if (mem_file)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void close();
|
||||
|
||||
int32_t read(uint8_t *ptr, size_t size);
|
||||
|
||||
int32_t write(const uint8_t *ptr, size_t size);
|
||||
|
||||
int32_t fwrite(const char *format, ...);
|
||||
|
||||
int32_t seek(long int offset, int32_t origin);
|
||||
|
||||
uint64_t tell() {
|
||||
return pos;
|
||||
};
|
||||
|
||||
uint64_t size() {
|
||||
return filesize;
|
||||
};
|
||||
|
||||
void rewind() {
|
||||
this->seek(0, SEEK_SET);
|
||||
};
|
||||
|
||||
protected:
|
||||
int32_t iFd;
|
||||
const uint8_t *mem_file;
|
||||
uint64_t filesize;
|
||||
uint64_t pos;
|
||||
};
|
||||
|
||||
#endif
|
218
source/fs/DirList.cpp
Normal file
218
source/fs/DirList.cpp
Normal file
@ -0,0 +1,218 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* DirList Class
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <algorithm>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/dirent.h>
|
||||
|
||||
#include <fs/DirList.h>
|
||||
#include <utils/StringTools.h>
|
||||
|
||||
DirList::DirList() {
|
||||
Flags = 0;
|
||||
Filter = 0;
|
||||
Depth = 0;
|
||||
}
|
||||
|
||||
DirList::DirList(const std::string &path, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||
this->LoadPath(path, filter, flags, maxDepth);
|
||||
this->SortList();
|
||||
}
|
||||
|
||||
DirList::~DirList() {
|
||||
ClearList();
|
||||
}
|
||||
|
||||
BOOL DirList::LoadPath(const std::string &folder, const char *filter, uint32_t flags, uint32_t maxDepth) {
|
||||
if (folder.empty())
|
||||
return false;
|
||||
|
||||
Flags = flags;
|
||||
Filter = filter;
|
||||
Depth = maxDepth;
|
||||
|
||||
std::string folderpath(folder);
|
||||
uint32_t length = folderpath.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
StringTools::RemoveDoubleSlashs(folderpath);
|
||||
|
||||
//! remove last slash if exists
|
||||
if (length > 0 && folderpath[length - 1] == '/')
|
||||
folderpath.erase(length - 1);
|
||||
|
||||
//! add root slash if missing
|
||||
if (folderpath.find('/') == std::string::npos) {
|
||||
folderpath += '/';
|
||||
}
|
||||
|
||||
return InternalLoadPath(folderpath);
|
||||
}
|
||||
|
||||
BOOL DirList::InternalLoadPath(std::string &folderpath) {
|
||||
if (folderpath.size() < 3)
|
||||
return false;
|
||||
|
||||
struct dirent *dirent = NULL;
|
||||
DIR *dir = NULL;
|
||||
|
||||
dir = opendir(folderpath.c_str());
|
||||
if (dir == NULL)
|
||||
return false;
|
||||
|
||||
while ((dirent = readdir(dir)) != 0) {
|
||||
BOOL isDir = dirent->d_type & DT_DIR;
|
||||
const char *filename = dirent->d_name;
|
||||
|
||||
if (isDir) {
|
||||
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
|
||||
continue;
|
||||
|
||||
if ((Flags & CheckSubfolders) && (Depth > 0)) {
|
||||
int32_t length = folderpath.size();
|
||||
if (length > 2 && folderpath[length - 1] != '/') {
|
||||
folderpath += '/';
|
||||
}
|
||||
folderpath += filename;
|
||||
|
||||
Depth--;
|
||||
InternalLoadPath(folderpath);
|
||||
folderpath.erase(length);
|
||||
Depth++;
|
||||
}
|
||||
|
||||
if (!(Flags & Dirs))
|
||||
continue;
|
||||
} else if (!(Flags & Files)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Filter) {
|
||||
char *fileext = strrchr(filename, '.');
|
||||
if (!fileext)
|
||||
continue;
|
||||
|
||||
if (StringTools::strtokcmp(fileext, Filter, ",") == 0)
|
||||
AddEntrie(folderpath, filename, isDir);
|
||||
} else {
|
||||
AddEntrie(folderpath, filename, isDir);
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DirList::AddEntrie(const std::string &filepath, const char *filename, BOOL isDir) {
|
||||
if (!filename)
|
||||
return;
|
||||
|
||||
int32_t pos = FileInfo.size();
|
||||
|
||||
FileInfo.resize(pos + 1);
|
||||
|
||||
FileInfo[pos].FilePath = (char *) malloc(filepath.size() + strlen(filename) + 2);
|
||||
if (!FileInfo[pos].FilePath) {
|
||||
FileInfo.resize(pos);
|
||||
return;
|
||||
}
|
||||
|
||||
sprintf(FileInfo[pos].FilePath, "%s/%s", filepath.c_str(), filename);
|
||||
FileInfo[pos].isDir = isDir;
|
||||
}
|
||||
|
||||
void DirList::ClearList() {
|
||||
for (uint32_t i = 0; i < FileInfo.size(); ++i) {
|
||||
if (FileInfo[i].FilePath) {
|
||||
free(FileInfo[i].FilePath);
|
||||
FileInfo[i].FilePath = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
FileInfo.clear();
|
||||
std::vector<DirEntry>().swap(FileInfo);
|
||||
}
|
||||
|
||||
const char *DirList::GetFilename(int32_t ind) const {
|
||||
if (!valid(ind))
|
||||
return "";
|
||||
|
||||
return StringTools::FullpathToFilename(FileInfo[ind].FilePath);
|
||||
}
|
||||
|
||||
static BOOL SortCallback(const DirEntry &f1, const DirEntry &f2) {
|
||||
if (f1.isDir && !(f2.isDir))
|
||||
return true;
|
||||
if (!(f1.isDir) && f2.isDir)
|
||||
return false;
|
||||
|
||||
if (f1.FilePath && !f2.FilePath)
|
||||
return true;
|
||||
if (!f1.FilePath)
|
||||
return false;
|
||||
|
||||
if (strcasecmp(f1.FilePath, f2.FilePath) > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DirList::SortList() {
|
||||
if (FileInfo.size() > 1)
|
||||
std::sort(FileInfo.begin(), FileInfo.end(), SortCallback);
|
||||
}
|
||||
|
||||
void DirList::SortList(BOOL (*SortFunc)(const DirEntry &a, const DirEntry &b)) {
|
||||
if (FileInfo.size() > 1)
|
||||
std::sort(FileInfo.begin(), FileInfo.end(), SortFunc);
|
||||
}
|
||||
|
||||
uint64_t DirList::GetFilesize(int32_t index) const {
|
||||
struct stat st;
|
||||
const char *path = GetFilepath(index);
|
||||
|
||||
if (!path || stat(path, &st) != 0)
|
||||
return 0;
|
||||
|
||||
return st.st_size;
|
||||
}
|
||||
|
||||
int32_t DirList::GetFileIndex(const char *filename) const {
|
||||
if (!filename)
|
||||
return -1;
|
||||
|
||||
for (uint32_t i = 0; i < FileInfo.size(); ++i) {
|
||||
if (strcasecmp(GetFilename(i), filename) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
121
source/fs/DirList.h
Normal file
121
source/fs/DirList.h
Normal file
@ -0,0 +1,121 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* DirList Class
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#ifndef ___DIRLIST_H_
|
||||
#define ___DIRLIST_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <wut_types.h>
|
||||
|
||||
typedef struct {
|
||||
char *FilePath;
|
||||
BOOL isDir;
|
||||
} DirEntry;
|
||||
|
||||
class DirList {
|
||||
public:
|
||||
//!Constructor
|
||||
DirList(void);
|
||||
|
||||
//!\param path Path from where to load the filelist of all files
|
||||
//!\param filter A fileext that needs to be filtered
|
||||
//!\param flags search/filter flags from the enum
|
||||
DirList(const std::string &path, const char *filter = NULL, uint32_t flags = Files | Dirs, uint32_t maxDepth = 0xffffffff);
|
||||
|
||||
//!Destructor
|
||||
virtual ~DirList();
|
||||
|
||||
//! Load all the files from a directory
|
||||
BOOL LoadPath(const std::string &path, const char *filter = NULL, uint32_t flags = Files | Dirs, uint32_t maxDepth = 0xffffffff);
|
||||
|
||||
//! Get a filename of the list
|
||||
//!\param list index
|
||||
const char *GetFilename(int32_t index) const;
|
||||
|
||||
//! Get the a filepath of the list
|
||||
//!\param list index
|
||||
const char *GetFilepath(int32_t index) const {
|
||||
if (!valid(index))
|
||||
return "";
|
||||
else
|
||||
return FileInfo[index].FilePath;
|
||||
}
|
||||
|
||||
//! Get the a filesize of the list
|
||||
//!\param list index
|
||||
uint64_t GetFilesize(int32_t index) const;
|
||||
|
||||
//! Is index a dir or a file
|
||||
//!\param list index
|
||||
BOOL IsDir(int32_t index) const {
|
||||
if (!valid(index))
|
||||
return false;
|
||||
return FileInfo[index].isDir;
|
||||
};
|
||||
|
||||
//! Get the filecount of the whole list
|
||||
int32_t GetFilecount() const {
|
||||
return FileInfo.size();
|
||||
};
|
||||
|
||||
//! Sort list by filepath
|
||||
void SortList();
|
||||
|
||||
//! Custom sort command for custom sort functions definitions
|
||||
void SortList(BOOL (*SortFunc)(const DirEntry &a, const DirEntry &b));
|
||||
|
||||
//! Get the index of the specified filename
|
||||
int32_t GetFileIndex(const char *filename) const;
|
||||
|
||||
//! Enum for search/filter flags
|
||||
enum {
|
||||
Files = 0x01,
|
||||
Dirs = 0x02,
|
||||
CheckSubfolders = 0x08,
|
||||
};
|
||||
protected:
|
||||
// Internal parser
|
||||
BOOL InternalLoadPath(std::string &path);
|
||||
|
||||
//!Add a list entrie
|
||||
void AddEntrie(const std::string &filepath, const char *filename, BOOL isDir);
|
||||
|
||||
//! Clear the list
|
||||
void ClearList();
|
||||
|
||||
//! Check if valid pos is requested
|
||||
inline BOOL valid(uint32_t pos) const {
|
||||
return (pos < FileInfo.size());
|
||||
};
|
||||
|
||||
uint32_t Flags;
|
||||
uint32_t Depth;
|
||||
const char *Filter;
|
||||
std::vector<DirEntry> FileInfo;
|
||||
};
|
||||
|
||||
#endif
|
142
source/fs/FSUtils.cpp
Normal file
142
source/fs/FSUtils.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "fs/FSUtils.h"
|
||||
#include "fs/CFile.hpp"
|
||||
#include "utils/logger.h"
|
||||
|
||||
int32_t FSUtils::LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||
//! always initialze input
|
||||
*inbuffer = NULL;
|
||||
if (size)
|
||||
*size = 0;
|
||||
|
||||
int32_t iFd = open(filepath, O_RDONLY);
|
||||
if (iFd < 0)
|
||||
return -1;
|
||||
|
||||
uint32_t filesize = lseek(iFd, 0, SEEK_END);
|
||||
lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
uint8_t *buffer = (uint8_t *) malloc(filesize);
|
||||
if (buffer == NULL) {
|
||||
close(iFd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint32_t blocksize = 0x4000;
|
||||
uint32_t done = 0;
|
||||
int32_t readBytes = 0;
|
||||
|
||||
while (done < filesize) {
|
||||
if (done + blocksize > filesize) {
|
||||
blocksize = filesize - done;
|
||||
}
|
||||
readBytes = read(iFd, buffer + done, blocksize);
|
||||
if (readBytes <= 0)
|
||||
break;
|
||||
done += readBytes;
|
||||
}
|
||||
|
||||
close(iFd);
|
||||
|
||||
if (done != filesize) {
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
return -3;
|
||||
}
|
||||
|
||||
*inbuffer = buffer;
|
||||
|
||||
//! sign is optional input
|
||||
if (size) {
|
||||
*size = filesize;
|
||||
}
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
int32_t FSUtils::CheckFile(const char *filepath) {
|
||||
if (!filepath)
|
||||
return 0;
|
||||
|
||||
struct stat filestat;
|
||||
|
||||
char dirnoslash[strlen(filepath) + 2];
|
||||
snprintf(dirnoslash, sizeof(dirnoslash), "%s", filepath);
|
||||
|
||||
while (dirnoslash[strlen(dirnoslash) - 1] == '/')
|
||||
dirnoslash[strlen(dirnoslash) - 1] = '\0';
|
||||
|
||||
char *notRoot = strrchr(dirnoslash, '/');
|
||||
if (!notRoot) {
|
||||
strcat(dirnoslash, "/");
|
||||
}
|
||||
|
||||
if (stat(dirnoslash, &filestat) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t FSUtils::CreateSubfolder(const char *fullpath) {
|
||||
if (!fullpath)
|
||||
return 0;
|
||||
|
||||
int32_t result = 0;
|
||||
|
||||
char dirnoslash[strlen(fullpath) + 1];
|
||||
strcpy(dirnoslash, fullpath);
|
||||
|
||||
int32_t pos = strlen(dirnoslash) - 1;
|
||||
while (dirnoslash[pos] == '/') {
|
||||
dirnoslash[pos] = '\0';
|
||||
pos--;
|
||||
}
|
||||
|
||||
if (CheckFile(dirnoslash)) {
|
||||
return 1;
|
||||
} else {
|
||||
char parentpath[strlen(dirnoslash) + 2];
|
||||
strcpy(parentpath, dirnoslash);
|
||||
char *ptr = strrchr(parentpath, '/');
|
||||
|
||||
if (!ptr) {
|
||||
//!Device root directory (must be with '/')
|
||||
strcat(parentpath, "/");
|
||||
struct stat filestat;
|
||||
if (stat(parentpath, &filestat) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr++;
|
||||
ptr[0] = '\0';
|
||||
|
||||
result = CreateSubfolder(parentpath);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
if (mkdir(dirnoslash, 0777) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t FSUtils::saveBufferToFile(const char *path, void *buffer, uint32_t size) {
|
||||
CFile file(path, CFile::WriteOnly);
|
||||
if (!file.isOpen()) {
|
||||
DEBUG_FUNCTION_LINE("Failed to open %s\n", path);
|
||||
return 0;
|
||||
}
|
||||
int32_t written = file.write((const uint8_t *) buffer, size);
|
||||
file.close();
|
||||
return written;
|
||||
}
|
||||
|
18
source/fs/FSUtils.h
Normal file
18
source/fs/FSUtils.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __FS_UTILS_H_
|
||||
#define __FS_UTILS_H_
|
||||
|
||||
#include <wut_types.h>
|
||||
|
||||
class FSUtils {
|
||||
public:
|
||||
static int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size);
|
||||
|
||||
//! todo: C++ class
|
||||
static int32_t CreateSubfolder(const char *fullpath);
|
||||
|
||||
static int32_t CheckFile(const char *filepath);
|
||||
|
||||
static int32_t saveBufferToFile(const char *path, void *buffer, uint32_t size);
|
||||
};
|
||||
|
||||
#endif // __FS_UTILS_H_
|
@ -10,3 +10,6 @@ relocation_trampolin_entry_t *gTrampolineData __attribute__((section(".data")))
|
||||
uint32_t gPluginDataHeapSize = 0;
|
||||
uint32_t gPluginInformationHeapSize = 0;
|
||||
uint32_t gTrampolineDataSize = 0;
|
||||
|
||||
StoredBuffer storedTVBuffer{};
|
||||
StoredBuffer storedDRCBuffer{};
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "plugin/PluginContainer.h"
|
||||
#include "common/plugin_defines.h"
|
||||
#include "utils/ConfigUtils.h"
|
||||
|
||||
extern plugin_information_t *gPluginInformation;
|
||||
extern MEMHeapHandle gPluginDataHeap;
|
||||
@ -14,6 +15,8 @@ extern plugin_information_on_reload_t gLinkOnReload;
|
||||
extern module_information_t *gModuleData;
|
||||
extern relocation_trampolin_entry_t *gTrampolineData;
|
||||
extern uint32_t gTrampolineDataSize;
|
||||
extern StoredBuffer storedTVBuffer;
|
||||
extern StoredBuffer storedDRCBuffer;
|
||||
|
||||
#define PLUGIN_DATA_HEAP_SIZE (8 * 1024 * 1024)
|
||||
#define NUMBER_OF_TRAMPS 1024
|
@ -1,5 +1,6 @@
|
||||
#include "hooks.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/StorageUtils.h"
|
||||
|
||||
void CallHook(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type) {
|
||||
CallHookEx(pluginInformation, hook_type, -1);
|
||||
@ -31,6 +32,11 @@ static const char **hook_names = (const char *[]) {
|
||||
"WUPS_LOADER_HOOK_INIT_WUT_SOCKETS",
|
||||
"WUPS_LOADER_HOOK_FINI_WUT_SOCKETS",
|
||||
|
||||
"WUPS_LOADER_HOOK_GET_CONFIG",
|
||||
"WUPS_LOADER_HOOK_CONFIG_CLOSED",
|
||||
|
||||
"WUPS_LOADER_HOOK_INIT_STORAGE",
|
||||
|
||||
"WUPS_LOADER_HOOK_INIT_PLUGIN",
|
||||
"WUPS_LOADER_HOOK_DEINIT_PLUGIN",
|
||||
"WUPS_LOADER_HOOK_APPLICATION_STARTS",
|
||||
@ -38,13 +44,10 @@ static const char **hook_names = (const char *[]) {
|
||||
"WUPS_LOADER_HOOK_RELEASE_FOREGROUND",
|
||||
"WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND",
|
||||
"WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT",
|
||||
"WUPS_LOADER_HOOK_APPLICATION_ENDS",
|
||||
"WUPS_LOADER_HOOK_VSYNC"};
|
||||
"WUPS_LOADER_HOOK_APPLICATION_ENDS"};
|
||||
|
||||
void CallHookEx(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type, int32_t plugin_index_needed) {
|
||||
if(hook_type != WUPS_LOADER_HOOK_VSYNC) {
|
||||
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);
|
||||
for (int32_t plugin_index = 0; plugin_index < pluginInformation->number_used_plugins; plugin_index++) {
|
||||
plugin_information_single_t *plugin_data = &pluginInformation->plugin_data[plugin_index];
|
||||
if (plugin_index_needed != -1 && plugin_index_needed != plugin_index) {
|
||||
@ -56,9 +59,7 @@ void CallHookEx(plugin_information_t *pluginInformation, wups_loader_hook_type_t
|
||||
for (uint32_t j = 0; j < plugin_data->info.number_used_hooks; j++) {
|
||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j];
|
||||
if (hook_data->type == hook_type) {
|
||||
if(hook_data->type != WUPS_LOADER_HOOK_VSYNC){
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s for plugin %s [%d]", hook_names[hook_data->type], plugin_data->meta.name, hook_type);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Calling hook of type %s for plugin %s [%d]", hook_names[hook_data->type], plugin_data->meta.name, hook_type);
|
||||
void *func_ptr = hook_data->func_pointer;
|
||||
if (func_ptr != nullptr) {
|
||||
//DEBUG_FUNCTION_LINE("function pointer is %08x",func_ptr);
|
||||
@ -78,11 +79,18 @@ void CallHookEx(plugin_information_t *pluginInformation, wups_loader_hook_type_t
|
||||
hook_type == WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB ||
|
||||
hook_type == WUPS_LOADER_HOOK_INIT_WUT_SOCKETS ||
|
||||
hook_type == WUPS_LOADER_HOOK_FINI_WUT_SOCKETS ||
|
||||
hook_type == WUPS_LOADER_HOOK_GET_CONFIG ||
|
||||
hook_type == WUPS_LOADER_HOOK_CONFIG_CLOSED ||
|
||||
hook_type == WUPS_LOADER_HOOK_RELEASE_FOREGROUND ||
|
||||
hook_type == WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND ||
|
||||
hook_type == WUPS_LOADER_HOOK_VSYNC
|
||||
hook_type == WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND
|
||||
){
|
||||
((void (*)()) ((uint32_t *) func_ptr))();
|
||||
} else if (hook_type == WUPS_LOADER_HOOK_INIT_STORAGE) {
|
||||
wups_loader_init_storage_args_t args;
|
||||
args.open_storage_ptr = &StorageUtils::OpenStorage;
|
||||
args.close_storage_ptr = &StorageUtils::CloseStorage;
|
||||
args.plugin_id = plugin_data->meta.id;
|
||||
((void (*)(wups_loader_init_storage_args_t)) ((uint32_t *) func_ptr))(args);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("######################################");
|
||||
DEBUG_FUNCTION_LINE("Hook is not implemented %s [%d]", hook_names[hook_type], hook_type);
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
WUMS_MODULE_EXPORT_NAME("homebrew_wupsbackend");
|
||||
|
||||
WUMS_USE_WUT_DEVOPTAB()
|
||||
WUMS_USE_WUT_DEVOPTAB();
|
||||
|
||||
WUMS_INITIALIZE(args) {
|
||||
WHBLogUdpInit();
|
||||
|
@ -1,17 +1,47 @@
|
||||
#include "hooks_patcher_static.h"
|
||||
#include <malloc.h>
|
||||
#include <wups.h>
|
||||
#include <vpad/input.h>
|
||||
#include <padscore/wpad.h>
|
||||
#include <coreinit/messagequeue.h>
|
||||
#include <coreinit/core.h>
|
||||
|
||||
#include "../utils/logger.h"
|
||||
#include "../utils/ConfigUtils.h"
|
||||
#include "../globals.h"
|
||||
#include "../hooks.h"
|
||||
|
||||
DECL_FUNCTION(void, GX2WaitForVsync, void) {
|
||||
CallHook(gPluginInformation, WUPS_LOADER_HOOK_VSYNC);
|
||||
real_GX2WaitForVsync();
|
||||
uint8_t vpadPressCooldown = 0xFF;
|
||||
bool configMenuOpened = false;
|
||||
bool wantsToOpenConfigMenu = false;
|
||||
|
||||
DECL_FUNCTION(void, GX2SwapScanBuffers, void) {
|
||||
real_GX2SwapScanBuffers();
|
||||
|
||||
if (wantsToOpenConfigMenu && !configMenuOpened) {
|
||||
configMenuOpened = true;
|
||||
ConfigUtils::openConfigMenu();
|
||||
configMenuOpened = false;
|
||||
wantsToOpenConfigMenu = false;
|
||||
}
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, GX2SetTVBuffer, void *buffer, uint32_t buffer_size, int32_t tv_render_mode, GX2SurfaceFormat format, GX2BufferingMode buffering_mode) {
|
||||
storedTVBuffer.buffer = buffer;
|
||||
storedTVBuffer.buffer_size = buffer_size;
|
||||
storedTVBuffer.mode = tv_render_mode;
|
||||
storedTVBuffer.surface_format = format;
|
||||
storedTVBuffer.buffering_mode = buffering_mode;
|
||||
|
||||
return real_GX2SetTVBuffer(buffer,buffer_size,tv_render_mode,format,buffering_mode);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, GX2SetDRCBuffer, void *buffer, uint32_t buffer_size, uint32_t drc_mode, GX2SurfaceFormat surface_format, GX2BufferingMode buffering_mode) {
|
||||
storedDRCBuffer.buffer = buffer;
|
||||
storedDRCBuffer.buffer_size = buffer_size;
|
||||
storedDRCBuffer.mode = drc_mode;
|
||||
storedDRCBuffer.surface_format = surface_format;
|
||||
storedDRCBuffer.buffering_mode = buffering_mode;
|
||||
|
||||
return real_GX2SetDRCBuffer(buffer,buffer_size,drc_mode,surface_format,buffering_mode);
|
||||
}
|
||||
|
||||
static uint32_t lastData0 = 0;
|
||||
@ -39,10 +69,46 @@ DECL_FUNCTION(void, OSReleaseForeground) {
|
||||
real_OSReleaseForeground();
|
||||
}
|
||||
|
||||
DECL_FUNCTION(int32_t, VPADRead, int32_t chan, VPADStatus *buffer, uint32_t buffer_size, int32_t *error) {
|
||||
int32_t result = real_VPADRead(chan, buffer, buffer_size, error);
|
||||
|
||||
if (result > 0 && (buffer[0].hold == (VPAD_BUTTON_L | VPAD_BUTTON_DOWN | VPAD_BUTTON_MINUS)) && vpadPressCooldown == 0 && !configMenuOpened) {
|
||||
wantsToOpenConfigMenu = true;
|
||||
vpadPressCooldown = 0x3C;
|
||||
}
|
||||
|
||||
if (vpadPressCooldown > 0) {
|
||||
vpadPressCooldown--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, WPADRead, WPADChan chan, WPADStatusProController *data) {
|
||||
real_WPADRead(chan, data);
|
||||
|
||||
if (!configMenuOpened && data[0].err == 0) {
|
||||
if (data[0].extensionType == WPAD_EXT_CORE || data[0].extensionType == WPAD_EXT_NUNCHUK) {
|
||||
// button data is in the first 2 bytes for wiimotes
|
||||
if (((uint16_t*)data)[0] == (WPAD_BUTTON_B | WPAD_BUTTON_DOWN | WPAD_BUTTON_MINUS)) {
|
||||
wantsToOpenConfigMenu = true;
|
||||
}
|
||||
} else {
|
||||
// TODO does this work for classic controllers?
|
||||
if (data[0].buttons == (WPAD_CLASSIC_BUTTON_L | WPAD_CLASSIC_BUTTON_DOWN | WPAD_CLASSIC_BUTTON_MINUS)) {
|
||||
wantsToOpenConfigMenu = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function_replacement_data_t method_hooks_hooks_static[] __attribute__((section(".data"))) = {
|
||||
REPLACE_FUNCTION(GX2WaitForVsync, LIBRARY_GX2, GX2WaitForVsync),
|
||||
REPLACE_FUNCTION(OSReceiveMessage, LIBRARY_COREINIT, OSReceiveMessage),
|
||||
REPLACE_FUNCTION(OSReleaseForeground, LIBRARY_COREINIT, OSReleaseForeground)
|
||||
REPLACE_FUNCTION(GX2SwapScanBuffers, LIBRARY_GX2, GX2SwapScanBuffers),
|
||||
REPLACE_FUNCTION(GX2SetTVBuffer, LIBRARY_GX2, GX2SetTVBuffer),
|
||||
REPLACE_FUNCTION(GX2SetDRCBuffer, LIBRARY_GX2, GX2SetDRCBuffer),
|
||||
REPLACE_FUNCTION(OSReceiveMessage, LIBRARY_COREINIT, OSReceiveMessage),
|
||||
REPLACE_FUNCTION(OSReleaseForeground, LIBRARY_COREINIT, OSReleaseForeground),
|
||||
REPLACE_FUNCTION(VPADRead, LIBRARY_VPAD, VPADRead),
|
||||
REPLACE_FUNCTION(WPADRead, LIBRARY_PADSCORE, WPADRead),
|
||||
};
|
||||
|
||||
uint32_t method_hooks_size_hooks_static __attribute__((section(".data"))) = sizeof(method_hooks_hooks_static) / sizeof(function_replacement_data_t);
|
@ -48,7 +48,7 @@ bool PluginContainerPersistence::savePlugin(plugin_information_t *pluginInformat
|
||||
strncpy(plugin_meta_data->license, pluginMetaInfo.getLicense().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
|
||||
if (pluginMetaInfo.getBuildTimestamp().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Warning: build timestampt will be truncated.");
|
||||
DEBUG_FUNCTION_LINE("Warning: build timestamp will be truncated.");
|
||||
}
|
||||
strncpy(plugin_meta_data->buildTimestamp, pluginMetaInfo.getBuildTimestamp().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
|
||||
@ -58,6 +58,11 @@ bool PluginContainerPersistence::savePlugin(plugin_information_t *pluginInformat
|
||||
}
|
||||
strncpy(plugin_meta_data->descripion, pluginMetaInfo.getDescription().c_str(), MAXIMUM_PLUGIN_DESCRIPTION_LENGTH - 1);
|
||||
|
||||
if (pluginMetaInfo.getId().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) {
|
||||
DEBUG_FUNCTION_LINE("Warning: plugin id will be truncated.");
|
||||
}
|
||||
strncpy(plugin_meta_data->id, pluginMetaInfo.getId().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
|
||||
|
||||
plugin_meta_data->size = pluginMetaInfo.getSize();
|
||||
|
||||
auto pluginInfo = plugin.getPluginInformation();
|
||||
|
@ -8,4 +8,5 @@ PluginMetaInformation::PluginMetaInformation(const PluginMetaInformation &other)
|
||||
this->buildtimestamp = other.buildtimestamp;
|
||||
this->description = other.description;
|
||||
this->size = other.size;
|
||||
this->id = other.id;
|
||||
}
|
@ -52,6 +52,10 @@ public:
|
||||
return this->size;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string getId() const {
|
||||
return this->id;
|
||||
}
|
||||
|
||||
private:
|
||||
PluginMetaInformation() = default;
|
||||
|
||||
@ -83,12 +87,17 @@ private:
|
||||
this->size = _size;
|
||||
}
|
||||
|
||||
void setId(const std::string &id) {
|
||||
this->id = id;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string version;
|
||||
std::string license;
|
||||
std::string buildtimestamp;
|
||||
std::string description;
|
||||
std::string id;
|
||||
size_t size{};
|
||||
|
||||
friend class PluginMetaInformationFactory;
|
||||
|
@ -81,7 +81,7 @@ std::optional<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(co
|
||||
}
|
||||
|
||||
// Get meta information and check WUPS version:
|
||||
if (psec->get_name().compare(".wups.meta") == 0) {
|
||||
if (psec->get_name() == ".wups.meta") {
|
||||
const void *sectionData = psec->get_data();
|
||||
uint32_t sectionSize = psec->get_size();
|
||||
|
||||
@ -92,7 +92,7 @@ std::optional<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(co
|
||||
continue;
|
||||
}
|
||||
|
||||
auto firstFound = std::string(curEntry).find_first_of("=");
|
||||
auto firstFound = std::string(curEntry).find_first_of('=');
|
||||
if (firstFound != std::string::npos) {
|
||||
curEntry[firstFound] = '\0';
|
||||
std::string key(curEntry);
|
||||
@ -110,8 +110,10 @@ std::optional<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(co
|
||||
pluginInfo.setBuildTimestamp(value);
|
||||
} else if (key.compare("description") == 0) {
|
||||
pluginInfo.setDescription(value);
|
||||
} else if (key.compare("id") == 0) {
|
||||
pluginInfo.setId(value);
|
||||
} else if (key.compare("wups") == 0) {
|
||||
if (value.compare("0.5") != 0) {
|
||||
if (value.compare("0.6") != 0) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
679
source/utils/ConfigUtils.cpp
Normal file
679
source/utils/ConfigUtils.cpp
Normal file
@ -0,0 +1,679 @@
|
||||
#include "ConfigUtils.h"
|
||||
|
||||
#include "logger.h"
|
||||
#include "../config/WUPSConfig.h"
|
||||
#include "../globals.h"
|
||||
#include "DrawUtils.h"
|
||||
#include "StringTools.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <coreinit/screen.h>
|
||||
#include <coreinit/cache.h>
|
||||
#include <memory/mappedmemory.h>
|
||||
#include <vpad/input.h>
|
||||
#include <padscore/kpad.h>
|
||||
#include <padscore/wpad.h>
|
||||
#include <gx2/display.h>
|
||||
|
||||
#define COLOR_BACKGROUND Color(238, 238, 238, 255)
|
||||
#define COLOR_TEXT Color(51, 51, 51, 255)
|
||||
#define COLOR_TEXT2 Color(72, 72, 72, 255)
|
||||
#define COLOR_DISABLED Color(255, 0, 0, 255)
|
||||
#define COLOR_BORDER Color(204, 204, 204, 255)
|
||||
#define COLOR_BORDER_HIGHLIGHTED Color(0x3478e4FF)
|
||||
#define COLOR_WHITE Color(0xFFFFFFFF)
|
||||
#define COLOR_BLACK Color(0, 0, 0, 255)
|
||||
|
||||
struct ConfigDisplayItem {
|
||||
WUPSConfig* config;
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string version;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
#define MAX_BUTTONS_ON_SCREEN 8
|
||||
|
||||
static uint32_t remapWiiMoteButtons(uint32_t buttons)
|
||||
{
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if(buttons & WPAD_BUTTON_LEFT)
|
||||
conv_buttons |= VPAD_BUTTON_LEFT;
|
||||
|
||||
if(buttons & WPAD_BUTTON_RIGHT)
|
||||
conv_buttons |= VPAD_BUTTON_RIGHT;
|
||||
|
||||
if(buttons & WPAD_BUTTON_DOWN)
|
||||
conv_buttons |= VPAD_BUTTON_DOWN;
|
||||
|
||||
if(buttons & WPAD_BUTTON_UP)
|
||||
conv_buttons |= VPAD_BUTTON_UP;
|
||||
|
||||
if(buttons & WPAD_BUTTON_PLUS)
|
||||
conv_buttons |= VPAD_BUTTON_PLUS;
|
||||
|
||||
if(buttons & WPAD_BUTTON_B)
|
||||
conv_buttons |= VPAD_BUTTON_B;
|
||||
|
||||
if(buttons & WPAD_BUTTON_A)
|
||||
conv_buttons |= VPAD_BUTTON_A;
|
||||
|
||||
if(buttons & WPAD_BUTTON_MINUS)
|
||||
conv_buttons |= VPAD_BUTTON_MINUS;
|
||||
|
||||
if(buttons & WPAD_BUTTON_HOME)
|
||||
conv_buttons |= VPAD_BUTTON_HOME;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
static uint32_t remapClassicButtons(uint32_t buttons)
|
||||
{
|
||||
uint32_t conv_buttons = 0;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_LEFT)
|
||||
conv_buttons |= VPAD_BUTTON_LEFT;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
conv_buttons |= VPAD_BUTTON_RIGHT;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_DOWN)
|
||||
conv_buttons |= VPAD_BUTTON_DOWN;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_UP)
|
||||
conv_buttons |= VPAD_BUTTON_UP;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_PLUS)
|
||||
conv_buttons |= VPAD_BUTTON_PLUS;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_X)
|
||||
conv_buttons |= VPAD_BUTTON_X;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_Y)
|
||||
conv_buttons |= VPAD_BUTTON_Y;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_B)
|
||||
conv_buttons |= VPAD_BUTTON_B;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_A)
|
||||
conv_buttons |= VPAD_BUTTON_A;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_MINUS)
|
||||
conv_buttons |= VPAD_BUTTON_MINUS;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_HOME)
|
||||
conv_buttons |= VPAD_BUTTON_HOME;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_ZR)
|
||||
conv_buttons |= VPAD_BUTTON_ZR;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_ZL)
|
||||
conv_buttons |= VPAD_BUTTON_ZL;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_R)
|
||||
conv_buttons |= VPAD_BUTTON_R;
|
||||
|
||||
if(buttons & WPAD_CLASSIC_BUTTON_L)
|
||||
conv_buttons |= VPAD_BUTTON_L;
|
||||
|
||||
return conv_buttons;
|
||||
}
|
||||
|
||||
void ConfigUtils::displayMenu() {
|
||||
std::vector<ConfigDisplayItem> configs;
|
||||
for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) {
|
||||
plugin_information_single_t *plugin_data = &gPluginInformation->plugin_data[plugin_index];
|
||||
if (plugin_data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
ConfigDisplayItem cfg;
|
||||
cfg.name = std::string(plugin_data->meta.name);
|
||||
cfg.author = std::string(plugin_data->meta.author);
|
||||
cfg.version = std::string(plugin_data->meta.version);
|
||||
cfg.enabled = true;
|
||||
|
||||
for (uint32_t j = 0; j < plugin_data->info.number_used_hooks; j++) {
|
||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j];
|
||||
if (hook_data->type == WUPS_LOADER_HOOK_GET_CONFIG/*WUPS_LOADER_HOOK_GET_CONFIG*/) {
|
||||
if (hook_data->func_pointer == nullptr) {
|
||||
break;
|
||||
}
|
||||
WUPSConfig *cur_config = reinterpret_cast<WUPSConfig *>(((WUPSConfigHandle (*)()) ((uint32_t *) hook_data->func_pointer))());
|
||||
if(cur_config == nullptr){
|
||||
break;
|
||||
}
|
||||
|
||||
//if(cur_config > 0x8000000);
|
||||
//DCFlushRange(&cur_config, sizeof(WUPSConfig*));
|
||||
//DCFlushRange(cur_config, sizeof(WUPSConfig));
|
||||
cfg.config = cur_config;
|
||||
|
||||
DEBUG_FUNCTION_LINE("name %s author %s version %s enabled %d config %08X",cfg.name.c_str(),cfg.author.c_str(),cfg.version.c_str(),cfg.enabled, cfg.config)
|
||||
configs.push_back(cfg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConfigDisplayItem* currentConfig = nullptr;
|
||||
WUPSConfigCategory* currentCategory = nullptr;
|
||||
|
||||
uint32_t selectedBtn = 0;
|
||||
uint32_t start = 0;
|
||||
uint32_t end = MAX_BUTTONS_ON_SCREEN;
|
||||
if (configs.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = configs.size();
|
||||
}
|
||||
|
||||
bool redraw = true;
|
||||
uint32_t buttonsTriggered;
|
||||
uint32_t buttonsReleased;
|
||||
|
||||
VPADStatus vpad_data{};
|
||||
VPADReadError vpad_error;
|
||||
KPADStatus kpad_data{};
|
||||
int32_t kpad_error;
|
||||
|
||||
while (true) {
|
||||
buttonsTriggered = 0;
|
||||
buttonsReleased = 0;
|
||||
|
||||
VPADRead(VPAD_CHAN_0, &vpad_data, 1, &vpad_error);
|
||||
if (vpad_error == VPAD_READ_SUCCESS) {
|
||||
buttonsTriggered = vpad_data.trigger;
|
||||
buttonsReleased = vpad_data.release;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (KPADReadEx((KPADChan)i, &kpad_data, 1, &kpad_error) > 0) {
|
||||
if (kpad_error == KPAD_ERROR_OK) {
|
||||
if (kpad_data.extensionType == WPAD_EXT_CORE || kpad_data.extensionType == WPAD_EXT_NUNCHUK) {
|
||||
buttonsTriggered |= remapWiiMoteButtons(kpad_data.trigger);
|
||||
buttonsReleased |= remapWiiMoteButtons(kpad_data.release);
|
||||
} else {
|
||||
buttonsTriggered |= remapClassicButtons(kpad_data.classic.trigger);
|
||||
buttonsReleased |= remapClassicButtons(kpad_data.classic.release);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buttonsTriggered & VPAD_BUTTON_HOME) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!currentConfig || !currentConfig->config) {
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedBtn < configs.size() - 1) {
|
||||
selectedBtn++;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedBtn > 0) {
|
||||
selectedBtn--;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_X) {
|
||||
configs[selectedBtn].enabled = !configs[selectedBtn].enabled;
|
||||
redraw = true;
|
||||
}
|
||||
else if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
currentConfig = &configs[selectedBtn];
|
||||
if(currentConfig == nullptr){
|
||||
DEBUG_FUNCTION_LINE("BYEBYE");
|
||||
break;
|
||||
}
|
||||
|
||||
selectedBtn = 0;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
|
||||
auto cats = currentConfig->config->getCategories();
|
||||
if (cats.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = cats.size();
|
||||
}
|
||||
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedBtn >= end) {
|
||||
end = selectedBtn + 1;
|
||||
start = end - MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
else if (selectedBtn < start) {
|
||||
start = selectedBtn;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
if (configs[i].enabled) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
} else {
|
||||
DrawUtils::setFontColor(COLOR_DISABLED);
|
||||
}
|
||||
|
||||
if (i == selectedBtn) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16*2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16*2, 44, 2, configs[i].enabled ? COLOR_BORDER : COLOR_DISABLED);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16*2, index + 8 + 24, configs[i].name.c_str());
|
||||
uint32_t sz = DrawUtils::getTextWidth(configs[i].name.c_str());
|
||||
DrawUtils::setFontSize(12);
|
||||
DrawUtils::print(16*2 + sz + 4, index + 8 + 24, configs[i].author.c_str());
|
||||
DrawUtils::print(SCREEN_WIDTH - 16*2, index + 8 + 24, configs[i].version.c_str(), true);
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, "Wii U Plugin System Config Menu");
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, "v1.0", true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8*2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 8, "\ue07d Navigate ");
|
||||
if (configs[selectedBtn].enabled) {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue002 Disable / \ue000 Select", true);
|
||||
} else {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue002 Enable / \ue000 Select", true);
|
||||
}
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < configs.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char* exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 8, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!currentCategory){
|
||||
auto cats = currentConfig->config->getCategories();
|
||||
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedBtn < cats.size() - 1) {
|
||||
selectedBtn++;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedBtn > 0) {
|
||||
selectedBtn--;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
else if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
currentCategory = cats[selectedBtn];
|
||||
if(currentCategory == nullptr){
|
||||
DEBUG_FUNCTION_LINE("BYEBYE");
|
||||
break;
|
||||
}
|
||||
|
||||
selectedBtn = 0;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
|
||||
auto items = currentCategory->getItems();
|
||||
if (items.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = items.size();
|
||||
}
|
||||
|
||||
redraw = true;
|
||||
continue;
|
||||
} else if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
currentConfig = nullptr;
|
||||
currentCategory = nullptr;
|
||||
selectedBtn = 0;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
if (configs.size() < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = configs.size();
|
||||
}
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (selectedBtn >= end) {
|
||||
end = selectedBtn + 1;
|
||||
start = end - MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
else if (selectedBtn < start) {
|
||||
start = selectedBtn;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (i == selectedBtn) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16*2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16*2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16*2, index + 8 + 24, cats[i]->getName().c_str());
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, currentConfig->config->getName().c_str());
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, currentConfig->version.c_str(), true);
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8*2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 8, "\ue07d Navigate ");
|
||||
if (configs[selectedBtn].enabled) {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue002 Disable / \ue000 Select", true);
|
||||
} else {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue002 Enable / \ue000 Select", true);
|
||||
}
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < configs.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char* exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 8, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::vector<WUPSConfigItem *> config_items = currentCategory->getItems();
|
||||
|
||||
if (buttonsTriggered & VPAD_BUTTON_DOWN) {
|
||||
if (selectedBtn < config_items.size() - 1) {
|
||||
selectedBtn++;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
else if (buttonsTriggered & VPAD_BUTTON_UP) {
|
||||
if (selectedBtn > 0) {
|
||||
selectedBtn--;
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
else if (buttonsTriggered & VPAD_BUTTON_B) {
|
||||
currentCategory = nullptr;
|
||||
selectedBtn = 0;
|
||||
start = 0;
|
||||
end = MAX_BUTTONS_ON_SCREEN;
|
||||
auto catSize = currentConfig->config->getCategories().size();
|
||||
if (catSize < MAX_BUTTONS_ON_SCREEN) {
|
||||
end = catSize;
|
||||
}
|
||||
redraw = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
WUPSConfigButtons pressedButtons = WUPS_CONFIG_BUTTON_NONE;
|
||||
if (buttonsTriggered & VPAD_BUTTON_A) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_A;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_LEFT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_LEFT;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_RIGHT) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_RIGHT;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_L) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_L;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_R) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_R;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_ZL) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZL;
|
||||
}
|
||||
if (buttonsTriggered & VPAD_BUTTON_ZR) {
|
||||
pressedButtons |= WUPS_CONFIG_BUTTON_ZR;
|
||||
}
|
||||
if (pressedButtons != WUPS_CONFIG_BUTTON_NONE) {
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if (selectedBtn >= end) {
|
||||
end = selectedBtn + 1;
|
||||
start = end - MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
else if (selectedBtn < start) {
|
||||
start = selectedBtn;
|
||||
end = start + MAX_BUTTONS_ON_SCREEN;
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
DrawUtils::beginDraw();
|
||||
DrawUtils::clear(COLOR_BACKGROUND);
|
||||
|
||||
// draw buttons
|
||||
uint32_t index = 8 + 24 + 8 + 4;
|
||||
for (uint32_t i = start; i < end; i++) {
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
if (i == selectedBtn) {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16*2, 44, 4, COLOR_BORDER_HIGHLIGHTED);
|
||||
} else {
|
||||
DrawUtils::drawRect(16, index, SCREEN_WIDTH - 16*2, 44, 2, COLOR_BORDER);
|
||||
}
|
||||
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16*2, index + 8 + 24, config_items[i]->getDisplayName().c_str());
|
||||
if (i == selectedBtn) {
|
||||
if (pressedButtons != WUPS_CONFIG_BUTTON_NONE) {
|
||||
config_items[i]->onButtonPressed(pressedButtons);
|
||||
}
|
||||
DrawUtils::print(SCREEN_WIDTH - 16*2, index + 8 + 24, config_items[i]->getCurrentValueSelectedDisplay().c_str(), true);
|
||||
}
|
||||
else {
|
||||
DrawUtils::print(SCREEN_WIDTH - 16*2, index + 8 + 24, config_items[i]->getCurrentValueDisplay().c_str(), true);
|
||||
}
|
||||
index += 42 + 8;
|
||||
}
|
||||
|
||||
DrawUtils::setFontColor(COLOR_TEXT);
|
||||
|
||||
std::string headline;
|
||||
StringTools::strprintf(headline, "%s - %s",currentConfig->config->getName().c_str(), currentCategory->getName().c_str());
|
||||
// draw top bar
|
||||
DrawUtils::setFontSize(24);
|
||||
DrawUtils::print(16, 6 + 24, headline.c_str());
|
||||
DrawUtils::drawRectFilled(8, 8 + 24 + 4, SCREEN_WIDTH - 8 * 2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, 8 + 24, currentConfig->version.c_str(), true);
|
||||
|
||||
// draw bottom bar
|
||||
DrawUtils::drawRectFilled(8, SCREEN_HEIGHT - 24 - 8 - 4, SCREEN_WIDTH - 8*2, 3, COLOR_BLACK);
|
||||
DrawUtils::setFontSize(18);
|
||||
DrawUtils::print(16, SCREEN_HEIGHT - 8, "\ue07d Navigate ");
|
||||
DrawUtils::print(SCREEN_WIDTH - 16, SCREEN_HEIGHT - 8, "\ue001 Back", true);
|
||||
|
||||
// draw scroll indicator
|
||||
DrawUtils::setFontSize(24);
|
||||
if (end < configs.size()) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, SCREEN_HEIGHT - 32, "\ufe3e", true);
|
||||
}
|
||||
if (start > 0) {
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + 12, 32 + 20, "\ufe3d", true);
|
||||
}
|
||||
|
||||
// draw home button
|
||||
DrawUtils::setFontSize(18);
|
||||
const char* exitHint = "\ue044 Exit";
|
||||
DrawUtils::print(SCREEN_WIDTH / 2 + DrawUtils::getTextWidth(exitHint) / 2, SCREEN_HEIGHT - 8, exitHint, true);
|
||||
|
||||
DrawUtils::endDraw();
|
||||
redraw = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& element : configs) {
|
||||
for (const auto& cat : element.config->getCategories()) {
|
||||
for (const auto& item : cat->getItems()) {
|
||||
if(item->isDirty()){
|
||||
item->callCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t plugin_index = 0; plugin_index < gPluginInformation->number_used_plugins; plugin_index++) {
|
||||
plugin_information_single_t *plugin_data = &gPluginInformation->plugin_data[plugin_index];
|
||||
if (plugin_data == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < plugin_data->info.number_used_hooks; j++) {
|
||||
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j];
|
||||
if (hook_data->type == WUPS_LOADER_HOOK_CONFIG_CLOSED) {
|
||||
if (hook_data->func_pointer == nullptr) {
|
||||
break;
|
||||
}
|
||||
((void (*)()) ((uint32_t *) hook_data->func_pointer))();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& element : configs) {
|
||||
DEBUG_FUNCTION_LINE("Delete %08X", element.config);
|
||||
delete element.config;
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigUtils::openConfigMenu()
|
||||
{
|
||||
bool wasHomeButtonMenuEnabled = OSIsHomeButtonMenuEnabled();
|
||||
|
||||
OSScreenInit();
|
||||
|
||||
uint32_t screen_buf0_size = OSScreenGetBufferSizeEx(SCREEN_TV);
|
||||
uint32_t screen_buf1_size = OSScreenGetBufferSizeEx(SCREEN_DRC);
|
||||
void* screenbuffer0 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf0_size, 0x100);
|
||||
void* screenbuffer1 = MEMAllocFromMappedMemoryForGX2Ex(screen_buf1_size, 0x100);
|
||||
|
||||
bool skipScreen0Free = false;
|
||||
bool skipScreen1Free = false;
|
||||
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
if(screenbuffer0 == nullptr){
|
||||
if(storedTVBuffer.buffer_size >= screen_buf0_size){
|
||||
screenbuffer0 = storedTVBuffer.buffer;
|
||||
skipScreen0Free = true;
|
||||
DEBUG_FUNCTION_LINE("Use storedTVBuffer");
|
||||
}
|
||||
}
|
||||
if(screenbuffer1 == nullptr){
|
||||
if(storedDRCBuffer.buffer_size >= screen_buf1_size){
|
||||
screenbuffer1 = storedDRCBuffer.buffer;
|
||||
skipScreen1Free = true;
|
||||
DEBUG_FUNCTION_LINE("Use storedDRCBuffer");
|
||||
}
|
||||
}
|
||||
if (!screenbuffer0 || !screenbuffer1) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc buffers");
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
OSScreenSetBufferEx(SCREEN_TV, screenbuffer0);
|
||||
OSScreenSetBufferEx(SCREEN_DRC, screenbuffer1);
|
||||
|
||||
OSScreenEnableEx(SCREEN_TV, 1);
|
||||
OSScreenEnableEx(SCREEN_DRC, 1);
|
||||
|
||||
// Clear screens
|
||||
OSScreenClearBufferEx(SCREEN_TV, 0);
|
||||
OSScreenClearBufferEx(SCREEN_DRC, 0);
|
||||
|
||||
// Flip buffers
|
||||
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||
|
||||
DrawUtils::initBuffers(screenbuffer0, screen_buf0_size, screenbuffer1, screen_buf1_size);
|
||||
DrawUtils::initFont();
|
||||
|
||||
// disable the home button menu to prevent opening it when exiting
|
||||
OSEnableHomeButtonMenu(false);
|
||||
|
||||
displayMenu();
|
||||
|
||||
OSEnableHomeButtonMenu(wasHomeButtonMenuEnabled);
|
||||
|
||||
DrawUtils::deinitFont();
|
||||
|
||||
error_exit:
|
||||
|
||||
if(storedTVBuffer.buffer != nullptr) {
|
||||
GX2SetTVBuffer(storedTVBuffer.buffer, storedTVBuffer.buffer_size, static_cast<GX2TVRenderMode>(storedTVBuffer.mode),
|
||||
storedTVBuffer.surface_format, storedTVBuffer.buffering_mode);
|
||||
}
|
||||
|
||||
if(storedDRCBuffer.buffer != nullptr) {
|
||||
GX2SetDRCBuffer(storedDRCBuffer.buffer, storedDRCBuffer.buffer_size, static_cast<GX2DrcRenderMode>(storedDRCBuffer.mode),
|
||||
storedDRCBuffer.surface_format, storedDRCBuffer.buffering_mode);
|
||||
}
|
||||
if (!skipScreen0Free && screenbuffer0) {
|
||||
MEMFreeToMappedMemory(screenbuffer0);
|
||||
screenbuffer0 = nullptr;
|
||||
}
|
||||
|
||||
if (!skipScreen1Free && screenbuffer1) {
|
||||
MEMFreeToMappedMemory(screenbuffer1);
|
||||
screenbuffer1 = nullptr;
|
||||
}
|
||||
}
|
19
source/utils/ConfigUtils.h
Normal file
19
source/utils/ConfigUtils.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <gx2/enum.h>
|
||||
|
||||
struct StoredBuffer {
|
||||
void* buffer;
|
||||
uint32_t buffer_size;
|
||||
uint32_t mode;
|
||||
GX2SurfaceFormat surface_format;
|
||||
GX2BufferingMode buffering_mode;
|
||||
};
|
||||
|
||||
class ConfigUtils {
|
||||
public:
|
||||
static void openConfigMenu();
|
||||
|
||||
private:
|
||||
static void displayMenu();
|
||||
};
|
306
source/utils/DrawUtils.cpp
Normal file
306
source/utils/DrawUtils.cpp
Normal file
@ -0,0 +1,306 @@
|
||||
#include "DrawUtils.h"
|
||||
|
||||
#include <coreinit/memory.h>
|
||||
#include <coreinit/screen.h>
|
||||
#include <png.h>
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
// buffer width
|
||||
#define TV_WIDTH 0x500
|
||||
#define DRC_WIDTH 0x380
|
||||
|
||||
bool DrawUtils::isBackBuffer;
|
||||
|
||||
uint8_t *DrawUtils::tvBuffer = nullptr;
|
||||
uint32_t DrawUtils::tvSize = 0;
|
||||
uint8_t *DrawUtils::drcBuffer = nullptr;
|
||||
uint32_t DrawUtils::drcSize = 0;
|
||||
|
||||
// Don't put those into the clase or we have to include ft everywhere
|
||||
static FT_Library ft_lib = nullptr;
|
||||
static FT_Face ft_face = nullptr;
|
||||
static Color font_col(0xFFFFFFFF);
|
||||
|
||||
void DrawUtils::initBuffers(void *tvBuffer_, uint32_t tvSize_, void *drcBuffer_, uint32_t drcSize_) {
|
||||
DrawUtils::tvBuffer = (uint8_t *) tvBuffer_;
|
||||
DrawUtils::tvSize = tvSize_;
|
||||
DrawUtils::drcBuffer = (uint8_t *) drcBuffer_;
|
||||
DrawUtils::drcSize = drcSize_;
|
||||
}
|
||||
|
||||
void DrawUtils::beginDraw() {
|
||||
uint32_t pixel = *(uint32_t *) tvBuffer;
|
||||
|
||||
// check which buffer is currently used
|
||||
OSScreenPutPixelEx(SCREEN_TV, 0, 0, 0xABCDEF90);
|
||||
if (*(uint32_t *) tvBuffer == 0xABCDEF90) {
|
||||
isBackBuffer = false;
|
||||
} else {
|
||||
isBackBuffer = true;
|
||||
}
|
||||
|
||||
// restore the pixel we used for checking
|
||||
*(uint32_t *) tvBuffer = pixel;
|
||||
}
|
||||
|
||||
void DrawUtils::endDraw() {
|
||||
// OSScreenFlipBuffersEx already flushes the cache?
|
||||
// DCFlushRange(tvBuffer, tvSize);
|
||||
// DCFlushRange(drcBuffer, drcSize);
|
||||
|
||||
OSScreenFlipBuffersEx(SCREEN_DRC);
|
||||
OSScreenFlipBuffersEx(SCREEN_TV);
|
||||
}
|
||||
|
||||
void DrawUtils::clear(Color col) {
|
||||
OSScreenClearBufferEx(SCREEN_TV, col.color);
|
||||
OSScreenClearBufferEx(SCREEN_DRC, col.color);
|
||||
}
|
||||
|
||||
void DrawUtils::drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
float opacity = a / 255.0f;
|
||||
|
||||
// put pixel in the drc buffer
|
||||
uint32_t i = (x + y * DRC_WIDTH) * 4;
|
||||
if (i + 3 < drcSize / 2) {
|
||||
if (isBackBuffer) {
|
||||
i += drcSize / 2;
|
||||
}
|
||||
if (a == 0xFF) {
|
||||
drcBuffer[i] = r;
|
||||
drcBuffer[i + 1] = g;
|
||||
drcBuffer[i + 2] = b;
|
||||
} else {
|
||||
drcBuffer[i] = r * opacity + drcBuffer[i] * (1 - opacity);
|
||||
drcBuffer[i + 1] = g * opacity + drcBuffer[i + 1] * (1 - opacity);
|
||||
drcBuffer[i + 2] = b * opacity + drcBuffer[i + 2] * (1 - opacity);
|
||||
}
|
||||
}
|
||||
|
||||
// scale and put pixel in the tv buffer
|
||||
for (uint32_t yy = (y * 1.5); yy < ((y * 1.5) + 1); yy++) {
|
||||
for (uint32_t xx = (x * 1.5); xx < ((x * 1.5) + 1); xx++) {
|
||||
uint32_t i = (xx + yy * TV_WIDTH) * 4;
|
||||
if (i + 3 < tvSize / 2) {
|
||||
if (isBackBuffer) {
|
||||
i += tvSize / 2;
|
||||
}
|
||||
if (a == 0xFF) {
|
||||
tvBuffer[i] = r;
|
||||
tvBuffer[i + 1] = g;
|
||||
tvBuffer[i + 2] = b;
|
||||
} else {
|
||||
tvBuffer[i] = r * opacity + tvBuffer[i] * (1 - opacity);
|
||||
tvBuffer[i + 1] = g * opacity + tvBuffer[i + 1] * (1 - opacity);
|
||||
tvBuffer[i + 2] = b * opacity + tvBuffer[i + 2] * (1 - opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawUtils::drawRectFilled(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color col) {
|
||||
for (uint32_t yy = y; yy < y + h; yy++) {
|
||||
for (uint32_t xx = x; xx < x + w; xx++) {
|
||||
drawPixel(xx, yy, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawUtils::drawRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t borderSize, Color col) {
|
||||
drawRectFilled(x, y, w, borderSize, col);
|
||||
drawRectFilled(x, y + h - borderSize, w, borderSize, col);
|
||||
drawRectFilled(x, y, borderSize, h, col);
|
||||
drawRectFilled(x + w - borderSize, y, borderSize, h, col);
|
||||
}
|
||||
|
||||
void DrawUtils::drawBitmap(uint32_t x, uint32_t y, uint32_t target_width, uint32_t target_height, const uint8_t *data) {
|
||||
if (data[0] != 'B' || data[1] != 'M') {
|
||||
// invalid header
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t dataPos = __builtin_bswap32(*(uint32_t *) &(data[0x0A]));
|
||||
uint32_t width = __builtin_bswap32(*(uint32_t *) &(data[0x12]));
|
||||
uint32_t height = __builtin_bswap32(*(uint32_t *) &(data[0x16]));
|
||||
|
||||
if (dataPos == 0) {
|
||||
dataPos = 54;
|
||||
}
|
||||
|
||||
data += dataPos;
|
||||
|
||||
// TODO flip image since bitmaps are stored upside down
|
||||
|
||||
for (uint32_t yy = y; yy < y + target_height; yy++) {
|
||||
for (uint32_t xx = x; xx < x + target_width; xx++) {
|
||||
uint32_t i = (((xx - x) * width / target_width) + ((yy - y) * height / target_height) * width) * 3;
|
||||
drawPixel(xx, yy, data[i + 2], data[i + 1], data[i], 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void png_read_data(png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead) {
|
||||
void **data = (void **) png_get_io_ptr(png_ptr);
|
||||
|
||||
memcpy(outBytes, *data, byteCountToRead);
|
||||
*((uint8_t **) data) += byteCountToRead;
|
||||
}
|
||||
|
||||
void DrawUtils::drawPNG(uint32_t x, uint32_t y, const uint8_t *data) {
|
||||
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
if (png_ptr == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == nullptr) {
|
||||
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
png_set_read_fn(png_ptr, (void *) &data, png_read_data);
|
||||
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
uint32_t width = 0;
|
||||
uint32_t height = 0;
|
||||
int bitDepth = 0;
|
||||
int colorType = -1;
|
||||
uint32_t retval = png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType, nullptr, nullptr, nullptr);
|
||||
if (retval != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t bytesPerRow = png_get_rowbytes(png_ptr, info_ptr);
|
||||
auto *rowData = new uint8_t[bytesPerRow];
|
||||
|
||||
for (uint32_t yy = y; yy < y + height; yy++) {
|
||||
png_read_row(png_ptr, (png_bytep) rowData, nullptr);
|
||||
|
||||
for (uint32_t xx = x; xx < x + width; xx++) {
|
||||
if (colorType == PNG_COLOR_TYPE_RGB_ALPHA) {
|
||||
uint32_t i = (xx - x) * 4;
|
||||
drawPixel(xx, yy, rowData[i], rowData[i + 1], rowData[i + 2], rowData[i + 3]);
|
||||
} else if (colorType == PNG_COLOR_TYPE_RGB) {
|
||||
uint32_t i = (xx - x) * 3;
|
||||
drawPixel(xx, yy, rowData[i], rowData[i + 1], rowData[i + 2], 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete[] rowData;
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
}
|
||||
|
||||
void DrawUtils::initFont() {
|
||||
void *font = nullptr;
|
||||
uint32_t size = 0;
|
||||
OSGetSharedData(OS_SHAREDDATATYPE_FONT_STANDARD, 0, &font, &size);
|
||||
|
||||
if (font && size) {
|
||||
FT_Init_FreeType(&ft_lib);
|
||||
FT_New_Memory_Face(ft_lib, (FT_Byte *) font, size, 0, &ft_face);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawUtils::deinitFont() {
|
||||
FT_Done_Face(ft_face);
|
||||
FT_Done_FreeType(ft_lib);
|
||||
}
|
||||
|
||||
void DrawUtils::setFontSize(uint32_t size) {
|
||||
FT_Set_Pixel_Sizes(ft_face, 0, size);
|
||||
}
|
||||
|
||||
void DrawUtils::setFontColor(Color col) {
|
||||
font_col = col;
|
||||
}
|
||||
|
||||
static void draw_freetype_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y) {
|
||||
FT_Int i, j, p, q;
|
||||
FT_Int x_max = x + bitmap->width;
|
||||
FT_Int y_max = y + bitmap->rows;
|
||||
|
||||
for (i = x, p = 0; i < x_max; i++, p++) {
|
||||
for (j = y, q = 0; j < y_max; j++, q++) {
|
||||
if (i < 0 || j < 0 || i >= SCREEN_WIDTH || j >= SCREEN_HEIGHT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float opacity = bitmap->buffer[q * bitmap->pitch + p] / 255.0f;
|
||||
DrawUtils::drawPixel(i, j, font_col.r, font_col.g, font_col.b, font_col.a * opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawUtils::print(uint32_t x, uint32_t y, const char *string, bool alignRight) {
|
||||
auto *buffer = new wchar_t[strlen(string) + 1];
|
||||
|
||||
size_t num = mbstowcs(buffer, string, strlen(string));
|
||||
if (num > 0) {
|
||||
buffer[num] = 0;
|
||||
} else {
|
||||
wchar_t *tmp = buffer;
|
||||
while ((*tmp++ = *string++));
|
||||
}
|
||||
|
||||
print(x, y, buffer, alignRight);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
void DrawUtils::print(uint32_t x, uint32_t y, const wchar_t *string, bool alignRight) {
|
||||
FT_GlyphSlot slot = ft_face->glyph;
|
||||
FT_Vector pen = {(int) x, (int) y};
|
||||
|
||||
if (alignRight) {
|
||||
pen.x -= getTextWidth(string);
|
||||
}
|
||||
|
||||
for (; *string; string++) {
|
||||
uint32_t charcode = *string;
|
||||
|
||||
if (charcode == '\n') {
|
||||
pen.y += ft_face->size->metrics.height >> 6;
|
||||
pen.x = x;
|
||||
continue;
|
||||
}
|
||||
|
||||
FT_Load_Glyph(ft_face, FT_Get_Char_Index(ft_face, charcode), FT_LOAD_DEFAULT);
|
||||
FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
|
||||
|
||||
draw_freetype_bitmap(&slot->bitmap, pen.x + slot->bitmap_left, pen.y - slot->bitmap_top);
|
||||
pen.x += slot->advance.x >> 6;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DrawUtils::getTextWidth(const char *string) {
|
||||
auto *buffer = new wchar_t[strlen(string) + 1];
|
||||
|
||||
size_t num = mbstowcs(buffer, string, strlen(string));
|
||||
if (num > 0) {
|
||||
buffer[num] = 0;
|
||||
} else {
|
||||
wchar_t *tmp = buffer;
|
||||
while ((*tmp++ = *string++));
|
||||
}
|
||||
|
||||
uint32_t width = getTextWidth(buffer);
|
||||
delete[] buffer;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
uint32_t DrawUtils::getTextWidth(const wchar_t *string) {
|
||||
FT_GlyphSlot slot = ft_face->glyph;
|
||||
uint32_t width = 0;
|
||||
|
||||
for (; *string; string++) {
|
||||
FT_Load_Glyph(ft_face, FT_Get_Char_Index(ft_face, *string), FT_LOAD_BITMAP_METRICS_ONLY);
|
||||
|
||||
width += slot->advance.x >> 6;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
57
source/utils/DrawUtils.h
Normal file
57
source/utils/DrawUtils.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// visible screen sizes
|
||||
#define SCREEN_WIDTH 854
|
||||
#define SCREEN_HEIGHT 480
|
||||
|
||||
union Color {
|
||||
explicit Color(uint32_t color) {
|
||||
this->color = color;
|
||||
}
|
||||
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
this->r = r; this->g = g; this->b = b; this->a = a;
|
||||
}
|
||||
|
||||
uint32_t color{};
|
||||
struct {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
};
|
||||
};
|
||||
|
||||
class DrawUtils {
|
||||
public:
|
||||
static void initBuffers(void* tvBuffer, uint32_t tvSize, void* drcBuffer, uint32_t drcSize);
|
||||
static void beginDraw();
|
||||
static void endDraw();
|
||||
static void clear(Color col);
|
||||
static void drawPixel(uint32_t x, uint32_t y, Color col) { drawPixel(x, y, col.r, col.g, col.b, col.a); }
|
||||
static void drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||
|
||||
static void drawRectFilled(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color col);
|
||||
static void drawRect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t borderSize, Color col);
|
||||
|
||||
static void drawBitmap(uint32_t x, uint32_t y, uint32_t target_width, uint32_t target_height, const uint8_t* data);
|
||||
static void drawPNG(uint32_t x, uint32_t y, const uint8_t* data);
|
||||
|
||||
static void initFont();
|
||||
static void deinitFont();
|
||||
static void setFontSize(uint32_t size);
|
||||
static void setFontColor(Color col);
|
||||
static void print(uint32_t x, uint32_t y, const char* string, bool alignRight = false);
|
||||
static void print(uint32_t x, uint32_t y, const wchar_t* string, bool alignRight = false);
|
||||
static uint32_t getTextWidth(const char* string);
|
||||
static uint32_t getTextWidth(const wchar_t* string);
|
||||
|
||||
private:
|
||||
static bool isBackBuffer;
|
||||
|
||||
static uint8_t* tvBuffer;
|
||||
static uint32_t tvSize;
|
||||
static uint8_t* drcBuffer;
|
||||
static uint32_t drcSize;
|
||||
};
|
133
source/utils/StorageUtils.cpp
Normal file
133
source/utils/StorageUtils.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "StorageUtils.h"
|
||||
#include <string>
|
||||
|
||||
#include "utils/logger.h"
|
||||
#include "utils/json.hpp"
|
||||
#include "fs/CFile.hpp"
|
||||
#include "fs/FSUtils.h"
|
||||
|
||||
static void processJson(wups_storage_item_t* items, nlohmann::json json) {
|
||||
if (items == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
items->data = (wups_storage_item_t*) malloc(json.size() * sizeof(wups_storage_item_t));
|
||||
items->data_size = json.size();
|
||||
|
||||
uint32_t index = 0;
|
||||
for (auto it = json.begin(); it != json.end(); ++it) {
|
||||
wups_storage_item_t* item = &((wups_storage_item_t*) items->data)[index];
|
||||
item->type = WUPS_STORAGE_TYPE_INVALID;
|
||||
item->pending_delete = false;
|
||||
item->data = nullptr;
|
||||
item->key = nullptr;
|
||||
|
||||
item->key = (char*) malloc(it.key().size() + 1);
|
||||
strcpy(item->key, it.key().c_str());
|
||||
|
||||
if (it.value().is_string()) {
|
||||
item->type = WUPS_STORAGE_TYPE_STRING;
|
||||
uint32_t size = it.value().get<std::string>().size() + 1;
|
||||
item->data = malloc(size);
|
||||
item->data_size = size;
|
||||
strcpy((char*) item->data, it.value().get<std::string>().c_str());
|
||||
} else if (it.value().is_number_integer()) {
|
||||
item->type = WUPS_STORAGE_TYPE_INT;
|
||||
item->data = malloc(sizeof(int32_t));
|
||||
item->data_size = sizeof(int32_t);
|
||||
*(int32_t*) item->data = it.value().get<int32_t>();
|
||||
} else if (it.value().is_object()) {
|
||||
if (it.value().size() > 0) {
|
||||
item->type = WUPS_STORAGE_TYPE_ITEM;
|
||||
processJson(item, it.value());
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Unknown type %s for value %s", it.value().type_name(), it.key().c_str());
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
int StorageUtils::OpenStorage(const char* plugin_id, wups_storage_item_t* items) {
|
||||
if (!plugin_id || !items) {
|
||||
return WUPS_STORAGE_ERROR_INVALID_BACKEND_PARAMS;
|
||||
}
|
||||
|
||||
std::string filePath = std::string("fs:/vol/external01/wiiu/plugins/config/") + plugin_id + ".json";
|
||||
|
||||
nlohmann::json j;
|
||||
CFile file(filePath, CFile::ReadOnly);
|
||||
if (file.isOpen() && file.size() > 0) {
|
||||
uint8_t* json_data = new uint8_t[file.size() + 1];
|
||||
json_data[file.size()] = '\0';
|
||||
|
||||
file.read(json_data, file.size());
|
||||
file.close();
|
||||
|
||||
j = nlohmann::json::parse(json_data, nullptr, false);
|
||||
delete[] json_data;
|
||||
|
||||
if (j == nlohmann::detail::value_t::discarded || j.empty() || !j.is_object()) {
|
||||
return WUPS_STORAGE_ERROR_INVALID_JSON;
|
||||
}
|
||||
} else { // empty or no config exists yet
|
||||
DEBUG_FUNCTION_LINE("open failed");
|
||||
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
processJson(items, j["storageitems"]);
|
||||
|
||||
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static nlohmann::json processItems(wups_storage_item_t* items) {
|
||||
nlohmann::json json;
|
||||
|
||||
if (!items) {
|
||||
return json;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < items->data_size; i++) {
|
||||
wups_storage_item_t* item = &((wups_storage_item_t*) items->data)[i];
|
||||
|
||||
if (item->pending_delete || item->type == WUPS_STORAGE_TYPE_INVALID || !item->data || !item->key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->type == WUPS_STORAGE_TYPE_STRING) {
|
||||
json[item->key] = (const char*) item->data;
|
||||
} else if (item->type == WUPS_STORAGE_TYPE_INT) {
|
||||
json[item->key] = *(int32_t*) item->data;
|
||||
} else if (item->type == WUPS_STORAGE_TYPE_ITEM) {
|
||||
json[item->key] = processItems(item);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Saving type %d not implemented", item->type);
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
int StorageUtils::CloseStorage(const char* plugin_id, wups_storage_item_t* items) {
|
||||
if (!plugin_id || !items) {
|
||||
return WUPS_STORAGE_ERROR_INVALID_BACKEND_PARAMS;
|
||||
}
|
||||
|
||||
std::string folderPath = "fs:/vol/external01/wiiu/plugins/config/";
|
||||
std::string filePath = folderPath + plugin_id + ".json";
|
||||
|
||||
FSUtils::CreateSubfolder(folderPath.c_str());
|
||||
|
||||
CFile file(filePath, CFile::WriteOnly);
|
||||
if (!file.isOpen()) {
|
||||
DEBUG_FUNCTION_LINE("Cannot create file %s", filePath.c_str());
|
||||
return WUPS_STORAGE_ERROR_IO;
|
||||
};
|
||||
|
||||
nlohmann::json j;
|
||||
j["storageitems"] = processItems(items);
|
||||
|
||||
std::string jsonString = j.dump(4);
|
||||
file.write((const uint8_t*) jsonString.c_str(), jsonString.size());
|
||||
file.close();
|
||||
return WUPS_STORAGE_ERROR_SUCCESS;
|
||||
}
|
9
source/utils/StorageUtils.h
Normal file
9
source/utils/StorageUtils.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <wups.h>
|
||||
|
||||
class StorageUtils {
|
||||
public:
|
||||
static int OpenStorage(const char* plugin_id, wups_storage_item_t* items);
|
||||
static int CloseStorage(const char* plugin_id, wups_storage_item_t* items);
|
||||
};
|
@ -16,10 +16,11 @@ void fillPluginInformation(plugin_information *out, PluginMetaInformation *metaI
|
||||
strncpy(out->name, metaInformation->getName().c_str(), 255);
|
||||
strncpy(out->license, metaInformation->getLicense().c_str(), 255);
|
||||
strncpy(out->version, metaInformation->getVersion().c_str(), 255);
|
||||
strncpy(out->id, metaInformation->getId().c_str(), 255);
|
||||
out->size = metaInformation->getSize();
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
|
||||
extern "C" PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
|
||||
gLinkOnReload.number_used_plugins = 0;
|
||||
if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 0) {
|
||||
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
|
||||
@ -35,12 +36,12 @@ extern "C" int32_t WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_
|
||||
}
|
||||
DCFlushRange(&gLinkOnReload, sizeof(gLinkOnReload));
|
||||
} else {
|
||||
return ERROR_INVALID_ARG;
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
return ERROR_NONE;
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSDeletePluginContainer(const plugin_container_handle *handle_list, uint32_t handle_list_size) {
|
||||
extern "C" PluginBackendApiErrorType WUPSDeletePluginContainer(const plugin_container_handle *handle_list, uint32_t handle_list_size) {
|
||||
if (handle_list != nullptr && handle_list_size != 0) {
|
||||
for (uint32_t i = 0; i < handle_list_size; i++) {
|
||||
auto handle = handle_list[i];
|
||||
@ -49,10 +50,10 @@ extern "C" int32_t WUPSDeletePluginContainer(const plugin_container_handle *hand
|
||||
delete pluginContainer;
|
||||
}
|
||||
}
|
||||
return ERROR_NONE;
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSDeletePluginData(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
|
||||
extern "C" PluginBackendApiErrorType WUPSDeletePluginData(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size) {
|
||||
if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 0) {
|
||||
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
|
||||
auto handle = plugin_data_handle_list[i];
|
||||
@ -61,10 +62,10 @@ extern "C" int32_t WUPSDeletePluginData(const plugin_data_handle *plugin_data_ha
|
||||
delete pluginData;
|
||||
}
|
||||
}
|
||||
return ERROR_NONE;
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSLoadPluginAsData(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_data_handle *out) {
|
||||
extern "C" PluginBackendApiErrorType WUPSLoadPluginAsData(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_data_handle *out) {
|
||||
std::optional<PluginData> pluginData;
|
||||
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
|
||||
pluginData = PluginDataFactory::load(path, gPluginDataHeap);
|
||||
@ -73,35 +74,35 @@ extern "C" int32_t WUPSLoadPluginAsData(GetPluginInformationInputType inputType,
|
||||
memcpy(&data[0], buffer, size);
|
||||
pluginData = PluginDataFactory::load(data, gPluginDataHeap);
|
||||
} else {
|
||||
return ERROR_INVALID_ARG;
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!pluginData) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc plugin data");
|
||||
return ERROR_FAILED_ALLOC;
|
||||
return PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC;
|
||||
}
|
||||
|
||||
if (out == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("out was NULL");
|
||||
return ERROR_INVALID_ARG;
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
} else {
|
||||
auto *pluginDataHandle = new PluginData(pluginData.value());
|
||||
DEBUG_FUNCTION_LINE("Saving plugin data handle: %08X", pluginDataHandle);
|
||||
*out = (uint32_t) pluginDataHandle;
|
||||
}
|
||||
|
||||
return ERROR_NONE;
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSLoadPluginAsDataByPath(plugin_data_handle *output, const char *path) {
|
||||
extern "C" PluginBackendApiErrorType WUPSLoadPluginAsDataByPath(plugin_data_handle *output, const char *path) {
|
||||
return WUPSLoadPluginAsData(PLUGIN_INFORMATION_INPUT_TYPE_PATH, path, nullptr, 0, output);
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSLoadPluginAsDataByBuffer(plugin_data_handle *output, char *buffer, size_t size) {
|
||||
extern "C" PluginBackendApiErrorType WUPSLoadPluginAsDataByBuffer(plugin_data_handle *output, char *buffer, size_t size) {
|
||||
return WUPSLoadPluginAsData(PLUGIN_INFORMATION_INPUT_TYPE_BUFFER, nullptr, buffer, size, output);
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSGetPluginMetaInformation(GetPluginInformationInputType inputType, const char* path, char *buffer, size_t size, plugin_information *output) {
|
||||
extern "C" PluginBackendApiErrorType WUPSGetPluginMetaInformation(GetPluginInformationInputType inputType, const char* path, char *buffer, size_t size, plugin_information *output) {
|
||||
std::optional<PluginMetaInformation> pluginInfo;
|
||||
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
|
||||
std::string pathStr(path);
|
||||
@ -111,34 +112,34 @@ extern "C" int32_t WUPSGetPluginMetaInformation(GetPluginInformationInputType in
|
||||
DEBUG_FUNCTION_LINE("PLUGIN_INFORMATION_INPUT_TYPE_BUFFER %08X %d", buffer, size);
|
||||
pluginInfo = PluginMetaInformationFactory::loadPlugin(buffer, size);
|
||||
} else {
|
||||
return ERROR_INVALID_ARG;
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!pluginInfo) {
|
||||
DEBUG_FUNCTION_LINE("Failed to load plugin meta information");
|
||||
return ERROR_FILE_NOT_FOUND;
|
||||
return PLUGIN_BACKEND_API_ERROR_FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Loaded plugin meta information");
|
||||
|
||||
if (output == nullptr) {
|
||||
return ERROR_INVALID_ARG;
|
||||
return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
} else {
|
||||
fillPluginInformation(output, &pluginInfo.value());
|
||||
}
|
||||
return ERROR_NONE;
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSGetPluginMetaInformationByPath(plugin_information *output, const char *path) {
|
||||
extern "C" PluginBackendApiErrorType WUPSGetPluginMetaInformationByPath(plugin_information *output, const char *path) {
|
||||
return WUPSGetPluginMetaInformation(PLUGIN_INFORMATION_INPUT_TYPE_PATH, path, nullptr, 0, output);
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSGetPluginMetaInformationByBuffer(plugin_information *output, char *buffer, size_t size) {
|
||||
extern "C" PluginBackendApiErrorType WUPSGetPluginMetaInformationByBuffer(plugin_information *output, char *buffer, size_t size) {
|
||||
return WUPSGetPluginMetaInformation(PLUGIN_INFORMATION_INPUT_TYPE_BUFFER, nullptr, buffer, size, output);
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSGetPluginDataForContainerHandles(const plugin_container_handle *plugin_container_handle_list, plugin_data_handle *plugin_data_list, uint32_t buffer_size) {
|
||||
int res = ERROR_NONE;
|
||||
extern "C" PluginBackendApiErrorType WUPSGetPluginDataForContainerHandles(const plugin_container_handle *plugin_container_handle_list, plugin_data_handle *plugin_data_list, uint32_t buffer_size) {
|
||||
PluginBackendApiErrorType res = PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
if (plugin_container_handle_list != nullptr && buffer_size != 0) {
|
||||
for (uint32_t i = 0; i < buffer_size; i++) {
|
||||
auto handle = plugin_container_handle_list[i];
|
||||
@ -148,18 +149,19 @@ extern "C" int32_t WUPSGetPluginDataForContainerHandles(const plugin_container_h
|
||||
plugin_data_list[i] = (uint32_t) pluginData;
|
||||
}
|
||||
} else {
|
||||
res = ERROR_INVALID_ARG;
|
||||
res = PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSGetMetaInformation(const plugin_container_handle *plugin_container_handle_list, plugin_information *plugin_information_list, uint32_t buffer_size) {
|
||||
int res = ERROR_NONE;
|
||||
extern "C" PluginBackendApiErrorType WUPSGetMetaInformation(const plugin_container_handle *plugin_container_handle_list, plugin_information *plugin_information_list, uint32_t buffer_size) {
|
||||
PluginBackendApiErrorType res = PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
if (plugin_container_handle_list != nullptr && buffer_size != 0) {
|
||||
for (uint32_t i = 0; i < buffer_size; i++) {
|
||||
auto handle = plugin_container_handle_list[i];
|
||||
auto *container = (PluginContainer *) handle;
|
||||
|
||||
strncpy(plugin_information_list[i].id, container->metaInformation.getId().c_str(), 255);
|
||||
strncpy(plugin_information_list[i].author, container->metaInformation.getAuthor().c_str(), 255);
|
||||
strncpy(plugin_information_list[i].buildTimestamp, container->metaInformation.getBuildTimestamp().c_str(), 255);
|
||||
strncpy(plugin_information_list[i].description, container->metaInformation.getDescription().c_str(), 255);
|
||||
@ -169,12 +171,12 @@ extern "C" int32_t WUPSGetMetaInformation(const plugin_container_handle *plugin_
|
||||
plugin_information_list[i].size = container->metaInformation.getSize();
|
||||
}
|
||||
} else {
|
||||
res = ERROR_INVALID_ARG;
|
||||
res = PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
extern "C" int32_t WUPSGetLoadedPlugins(plugin_container_handle *io_handles, uint32_t buffer_size, uint32_t *outSize) {
|
||||
extern "C" PluginBackendApiErrorType WUPSGetLoadedPlugins(plugin_container_handle *io_handles, uint32_t buffer_size, uint32_t *outSize) {
|
||||
auto plugins = PluginContainerPersistence::loadPlugins(gPluginInformation);
|
||||
uint32_t counter = 0;
|
||||
for (auto &plugin: plugins) {
|
||||
@ -190,10 +192,9 @@ extern "C" int32_t WUPSGetLoadedPlugins(plugin_container_handle *io_handles, uin
|
||||
if (outSize != nullptr) {
|
||||
*outSize = counter;
|
||||
}
|
||||
return 0;
|
||||
return PLUGIN_BACKEND_API_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByPath);
|
||||
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByBuffer);
|
||||
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsData);
|
||||
|
@ -1,61 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <wums.h>
|
||||
#include <wups_backend/import_defines.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ERROR_NONE 0
|
||||
#define ERROR_INVALID_SIZE 0xFFFFFFFF
|
||||
#define ERROR_INVALID_ARG 0xFFFFFFFE
|
||||
#define ERROR_FAILED_ALLOC 0xFFFFFFFD
|
||||
#define ERROR_FILE_NOT_FOUND 0xFFFFFFFC
|
||||
|
||||
typedef enum GetPluginInformationInputType {
|
||||
PLUGIN_INFORMATION_INPUT_TYPE_PATH = 0,
|
||||
PLUGIN_INFORMATION_INPUT_TYPE_BUFFER = 1,
|
||||
} GetPluginInformationInputType;
|
||||
|
||||
typedef uint32_t plugin_container_handle;
|
||||
typedef uint32_t plugin_data_handle;
|
||||
|
||||
/* plugin_information message */
|
||||
typedef struct __attribute__((__packed__)) plugin_information {
|
||||
char name[256];
|
||||
char author[256];
|
||||
char buildTimestamp[256];
|
||||
char description[256];
|
||||
char license[256];
|
||||
char version[256];
|
||||
size_t size;
|
||||
} plugin_information;
|
||||
|
||||
void fillPluginInformation(plugin_information *out, PluginMetaInformation *metaInformation);
|
||||
|
||||
int32_t WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size);
|
||||
PluginBackendApiErrorType WUPSLoadAndLinkByDataHandle(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size);
|
||||
|
||||
int32_t WUPSDeletePluginContainer(const plugin_container_handle *handle_list, uint32_t handle_list_size);
|
||||
PluginBackendApiErrorType WUPSDeletePluginContainer(const plugin_container_handle *handle_list, uint32_t handle_list_size);
|
||||
|
||||
int32_t WUPSDeletePluginData(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size);
|
||||
PluginBackendApiErrorType WUPSDeletePluginData(const plugin_data_handle *plugin_data_handle_list, uint32_t plugin_data_handle_list_size);
|
||||
|
||||
int32_t WUPSLoadPluginAsData(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_data_handle *out);
|
||||
PluginBackendApiErrorType WUPSLoadPluginAsData(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_data_handle *out);
|
||||
|
||||
int32_t WUPSLoadPluginAsDataByPath(plugin_data_handle *output, const char *path);
|
||||
PluginBackendApiErrorType WUPSLoadPluginAsDataByPath(plugin_data_handle *output, const char *path);
|
||||
|
||||
int32_t WUPSLoadPluginAsDataByBuffer(plugin_data_handle *output, char *buffer, size_t size);
|
||||
PluginBackendApiErrorType WUPSLoadPluginAsDataByBuffer(plugin_data_handle *output, char *buffer, size_t size);
|
||||
|
||||
int32_t WUPSGetPluginMetaInformation(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_information *output);
|
||||
PluginBackendApiErrorType WUPSGetPluginMetaInformation(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_information *output);
|
||||
|
||||
int32_t WUPSGetPluginMetaInformationByPath(plugin_information *output, const char *path);
|
||||
PluginBackendApiErrorType WUPSGetPluginMetaInformationByPath(plugin_information *output, const char *path);
|
||||
|
||||
int32_t WUPSGetPluginMetaInformationByBuffer(plugin_information *output, char *buffer, size_t size);
|
||||
PluginBackendApiErrorType WUPSGetPluginMetaInformationByBuffer(plugin_information *output, char *buffer, size_t size);
|
||||
|
||||
int32_t WUPSGetPluginDataForContainerHandles(const plugin_container_handle *plugin_container_handle_list, plugin_data_handle *plugin_data_list, uint32_t buffer_size);
|
||||
PluginBackendApiErrorType WUPSGetPluginDataForContainerHandles(const plugin_container_handle *plugin_container_handle_list, plugin_data_handle *plugin_data_list, uint32_t buffer_size);
|
||||
|
||||
int32_t WUPSGetMetaInformation(const plugin_container_handle *plugin_container_handle_list, plugin_information *plugin_information_list, uint32_t buffer_size);
|
||||
PluginBackendApiErrorType WUPSGetMetaInformation(const plugin_container_handle *plugin_container_handle_list, plugin_information *plugin_information_list, uint32_t buffer_size);
|
||||
|
||||
int32_t WUPSGetLoadedPlugins(plugin_container_handle *io_handles, uint32_t buffer_size, uint32_t *outSize);
|
||||
PluginBackendApiErrorType WUPSGetLoadedPlugins(plugin_container_handle *io_handles, uint32_t buffer_size, uint32_t *outSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
25447
source/utils/json.hpp
Normal file
25447
source/utils/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user