Add support for the config and storage API. Bump version to 0.6

This commit is contained in:
Maschell 2021-04-07 00:23:23 +02:00
parent ed792716fe
commit 13ed348f43
34 changed files with 28162 additions and 98 deletions

View File

@ -1,7 +1,9 @@
FROM wiiuenv/devkitppc:20210917 FROM wiiuenv/devkitppc:20210920
COPY --from=wiiuenv/wiiumodulesystem:20210917 /artifacts $DEVKITPRO COPY --from=wiiuenv/wiiumodulesystem:20210924 /artifacts $DEVKITPRO
COPY --from=wiiuenv/wiiupluginsystem:20210917 /artifacts $DEVKITPRO COPY --from=wiiuenv/wiiupluginsystem:20210924 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libfunctionpatcher:20210109 /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 WORKDIR project

View File

@ -23,6 +23,8 @@ WUT_ROOT := $(DEVKITPRO)/wut
TARGET := PluginBackend TARGET := PluginBackend
BUILD := build BUILD := build
SOURCES := source \ SOURCES := source \
source/fs \
source/config \
source/elfio \ source/elfio \
source/patcher \ source/patcher \
source/plugin \ source/plugin \
@ -41,9 +43,9 @@ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
CXXFLAGS := $(CFLAGS) -std=c++20 CXXFLAGS := $(CFLAGS) -std=c++20
ASFLAGS := -g $(ARCH) 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 # 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)) \ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \ $(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) export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)

View File

@ -155,6 +155,7 @@ void PluginManagement::unloadPlugins(plugin_information_t *gPluginInformation, M
} }
void PluginManagement::callInitHooks(plugin_information_t *pluginInformation) { void PluginManagement::callInitHooks(plugin_information_t *pluginInformation) {
CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_STORAGE);
CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_PLUGIN); CallHook(pluginInformation, WUPS_LOADER_HOOK_INIT_PLUGIN);
DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks"); DEBUG_FUNCTION_LINE_VERBOSE("Done calling init hooks");
} }

View File

@ -56,6 +56,7 @@ struct plugin_meta_info_t {
char license[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = ""; char license[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
char buildTimestamp[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = ""; char buildTimestamp[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
char descripion[MAXIMUM_PLUGIN_DESCRIPTION_LENGTH] = ""; char descripion[MAXIMUM_PLUGIN_DESCRIPTION_LENGTH] = "";
char id[MAXIMUM_PLUGIN_META_FIELD_LENGTH] = "";
uint32_t size; uint32_t size;
}; };

View 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 = {};
};

View 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{};
};

View 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);*/

View 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);*/

View 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{};
};

View 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
View 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
View 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
View 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
View 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
View 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
View 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_

View File

@ -9,4 +9,7 @@ relocation_trampolin_entry_t *gTrampolineData __attribute__((section(".data")))
uint32_t gPluginDataHeapSize = 0; uint32_t gPluginDataHeapSize = 0;
uint32_t gPluginInformationHeapSize = 0; uint32_t gPluginInformationHeapSize = 0;
uint32_t gTrampolineDataSize = 0; uint32_t gTrampolineDataSize = 0;
StoredBuffer storedTVBuffer{};
StoredBuffer storedDRCBuffer{};

View File

@ -4,6 +4,7 @@
#include "plugin/PluginContainer.h" #include "plugin/PluginContainer.h"
#include "common/plugin_defines.h" #include "common/plugin_defines.h"
#include "utils/ConfigUtils.h"
extern plugin_information_t *gPluginInformation; extern plugin_information_t *gPluginInformation;
extern MEMHeapHandle gPluginDataHeap; extern MEMHeapHandle gPluginDataHeap;
@ -14,6 +15,8 @@ extern plugin_information_on_reload_t gLinkOnReload;
extern module_information_t *gModuleData; extern module_information_t *gModuleData;
extern relocation_trampolin_entry_t *gTrampolineData; extern relocation_trampolin_entry_t *gTrampolineData;
extern uint32_t gTrampolineDataSize; extern uint32_t gTrampolineDataSize;
extern StoredBuffer storedTVBuffer;
extern StoredBuffer storedDRCBuffer;
#define PLUGIN_DATA_HEAP_SIZE (8 * 1024 * 1024) #define PLUGIN_DATA_HEAP_SIZE (8 * 1024 * 1024)
#define NUMBER_OF_TRAMPS 1024 #define NUMBER_OF_TRAMPS 1024

View File

@ -1,5 +1,6 @@
#include "hooks.h" #include "hooks.h"
#include "utils/logger.h" #include "utils/logger.h"
#include "utils/StorageUtils.h"
void CallHook(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type) { void CallHook(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type) {
CallHookEx(pluginInformation, hook_type, -1); 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_INIT_WUT_SOCKETS",
"WUPS_LOADER_HOOK_FINI_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_INIT_PLUGIN",
"WUPS_LOADER_HOOK_DEINIT_PLUGIN", "WUPS_LOADER_HOOK_DEINIT_PLUGIN",
"WUPS_LOADER_HOOK_APPLICATION_STARTS", "WUPS_LOADER_HOOK_APPLICATION_STARTS",
@ -38,13 +44,10 @@ static const char **hook_names = (const char *[]) {
"WUPS_LOADER_HOOK_RELEASE_FOREGROUND", "WUPS_LOADER_HOOK_RELEASE_FOREGROUND",
"WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND", "WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND",
"WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT", "WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT",
"WUPS_LOADER_HOOK_APPLICATION_ENDS", "WUPS_LOADER_HOOK_APPLICATION_ENDS"};
"WUPS_LOADER_HOOK_VSYNC"};
void CallHookEx(plugin_information_t *pluginInformation, wups_loader_hook_type_t hook_type, int32_t plugin_index_needed) { 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++) { 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]; plugin_information_single_t *plugin_data = &pluginInformation->plugin_data[plugin_index];
if (plugin_index_needed != -1 && plugin_index_needed != 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++) { for (uint32_t j = 0; j < plugin_data->info.number_used_hooks; j++) {
replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j]; replacement_data_hook_t *hook_data = &plugin_data->info.hooks[j];
if (hook_data->type == hook_type) { 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; void *func_ptr = hook_data->func_pointer;
if (func_ptr != nullptr) { if (func_ptr != nullptr) {
//DEBUG_FUNCTION_LINE("function pointer is %08x",func_ptr); //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_FINI_WUT_DEVOPTAB ||
hook_type == WUPS_LOADER_HOOK_INIT_WUT_SOCKETS || hook_type == WUPS_LOADER_HOOK_INIT_WUT_SOCKETS ||
hook_type == WUPS_LOADER_HOOK_FINI_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_RELEASE_FOREGROUND ||
hook_type == WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND || hook_type == WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND
hook_type == WUPS_LOADER_HOOK_VSYNC
){ ){
((void (*)()) ((uint32_t *) func_ptr))(); ((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 { } else {
DEBUG_FUNCTION_LINE("######################################"); DEBUG_FUNCTION_LINE("######################################");
DEBUG_FUNCTION_LINE("Hook is not implemented %s [%d]", hook_names[hook_type], hook_type); DEBUG_FUNCTION_LINE("Hook is not implemented %s [%d]", hook_names[hook_type], hook_type);

View File

@ -15,7 +15,7 @@
WUMS_MODULE_EXPORT_NAME("homebrew_wupsbackend"); WUMS_MODULE_EXPORT_NAME("homebrew_wupsbackend");
WUMS_USE_WUT_DEVOPTAB() WUMS_USE_WUT_DEVOPTAB();
WUMS_INITIALIZE(args) { WUMS_INITIALIZE(args) {
WHBLogUdpInit(); WHBLogUdpInit();

View File

@ -1,17 +1,47 @@
#include "hooks_patcher_static.h" #include "hooks_patcher_static.h"
#include <malloc.h>
#include <wups.h> #include <wups.h>
#include <vpad/input.h> #include <vpad/input.h>
#include <padscore/wpad.h>
#include <coreinit/messagequeue.h> #include <coreinit/messagequeue.h>
#include <coreinit/core.h> #include <coreinit/core.h>
#include "../utils/logger.h" #include "../utils/ConfigUtils.h"
#include "../globals.h" #include "../globals.h"
#include "../hooks.h" #include "../hooks.h"
DECL_FUNCTION(void, GX2WaitForVsync, void) { uint8_t vpadPressCooldown = 0xFF;
CallHook(gPluginInformation, WUPS_LOADER_HOOK_VSYNC); bool configMenuOpened = false;
real_GX2WaitForVsync(); 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; static uint32_t lastData0 = 0;
@ -39,10 +69,46 @@ DECL_FUNCTION(void, OSReleaseForeground) {
real_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"))) = { function_replacement_data_t method_hooks_hooks_static[] __attribute__((section(".data"))) = {
REPLACE_FUNCTION(GX2WaitForVsync, LIBRARY_GX2, GX2WaitForVsync), REPLACE_FUNCTION(GX2SwapScanBuffers, LIBRARY_GX2, GX2SwapScanBuffers),
REPLACE_FUNCTION(OSReceiveMessage, LIBRARY_COREINIT, OSReceiveMessage), REPLACE_FUNCTION(GX2SetTVBuffer, LIBRARY_GX2, GX2SetTVBuffer),
REPLACE_FUNCTION(OSReleaseForeground, LIBRARY_COREINIT, OSReleaseForeground) 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); uint32_t method_hooks_size_hooks_static __attribute__((section(".data"))) = sizeof(method_hooks_hooks_static) / sizeof(function_replacement_data_t);

View File

@ -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); strncpy(plugin_meta_data->license, pluginMetaInfo.getLicense().c_str(), MAXIMUM_PLUGIN_META_FIELD_LENGTH - 1);
if (pluginMetaInfo.getBuildTimestamp().size() >= MAXIMUM_PLUGIN_META_FIELD_LENGTH) { 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); 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); 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(); plugin_meta_data->size = pluginMetaInfo.getSize();
auto pluginInfo = plugin.getPluginInformation(); auto pluginInfo = plugin.getPluginInformation();

View File

@ -8,4 +8,5 @@ PluginMetaInformation::PluginMetaInformation(const PluginMetaInformation &other)
this->buildtimestamp = other.buildtimestamp; this->buildtimestamp = other.buildtimestamp;
this->description = other.description; this->description = other.description;
this->size = other.size; this->size = other.size;
this->id = other.id;
} }

View File

@ -52,6 +52,10 @@ public:
return this->size; return this->size;
} }
[[nodiscard]] const std::string getId() const {
return this->id;
}
private: private:
PluginMetaInformation() = default; PluginMetaInformation() = default;
@ -83,12 +87,17 @@ private:
this->size = _size; this->size = _size;
} }
void setId(const std::string &id) {
this->id = id;
}
std::string name; std::string name;
std::string author; std::string author;
std::string version; std::string version;
std::string license; std::string license;
std::string buildtimestamp; std::string buildtimestamp;
std::string description; std::string description;
std::string id;
size_t size{}; size_t size{};
friend class PluginMetaInformationFactory; friend class PluginMetaInformationFactory;

View File

@ -81,7 +81,7 @@ std::optional<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(co
} }
// Get meta information and check WUPS version: // 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(); const void *sectionData = psec->get_data();
uint32_t sectionSize = psec->get_size(); uint32_t sectionSize = psec->get_size();
@ -92,7 +92,7 @@ std::optional<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(co
continue; continue;
} }
auto firstFound = std::string(curEntry).find_first_of("="); auto firstFound = std::string(curEntry).find_first_of('=');
if (firstFound != std::string::npos) { if (firstFound != std::string::npos) {
curEntry[firstFound] = '\0'; curEntry[firstFound] = '\0';
std::string key(curEntry); std::string key(curEntry);
@ -110,8 +110,10 @@ std::optional<PluginMetaInformation> PluginMetaInformationFactory::loadPlugin(co
pluginInfo.setBuildTimestamp(value); pluginInfo.setBuildTimestamp(value);
} else if (key.compare("description") == 0) { } else if (key.compare("description") == 0) {
pluginInfo.setDescription(value); pluginInfo.setDescription(value);
} else if (key.compare("id") == 0) {
pluginInfo.setId(value);
} else if (key.compare("wups") == 0) { } 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()); DEBUG_FUNCTION_LINE("Warning: Ignoring plugin - Unsupported WUPS version: %s.", value.c_str());
return std::nullopt; return std::nullopt;
} }

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

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

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

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

View File

@ -16,10 +16,11 @@ void fillPluginInformation(plugin_information *out, PluginMetaInformation *metaI
strncpy(out->name, metaInformation->getName().c_str(), 255); strncpy(out->name, metaInformation->getName().c_str(), 255);
strncpy(out->license, metaInformation->getLicense().c_str(), 255); strncpy(out->license, metaInformation->getLicense().c_str(), 255);
strncpy(out->version, metaInformation->getVersion().c_str(), 255); strncpy(out->version, metaInformation->getVersion().c_str(), 255);
strncpy(out->id, metaInformation->getId().c_str(), 255);
out->size = metaInformation->getSize(); 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; gLinkOnReload.number_used_plugins = 0;
if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 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++) { 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)); DCFlushRange(&gLinkOnReload, sizeof(gLinkOnReload));
} else { } 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) { if (handle_list != nullptr && handle_list_size != 0) {
for (uint32_t i = 0; i < handle_list_size; i++) { for (uint32_t i = 0; i < handle_list_size; i++) {
auto handle = handle_list[i]; auto handle = handle_list[i];
@ -49,10 +50,10 @@ extern "C" int32_t WUPSDeletePluginContainer(const plugin_container_handle *hand
delete pluginContainer; 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) { if (plugin_data_handle_list != nullptr && plugin_data_handle_list_size != 0) {
for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) { for (uint32_t i = 0; i < plugin_data_handle_list_size; i++) {
auto handle = plugin_data_handle_list[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; 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; std::optional<PluginData> pluginData;
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) { if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
pluginData = PluginDataFactory::load(path, gPluginDataHeap); pluginData = PluginDataFactory::load(path, gPluginDataHeap);
@ -73,35 +74,35 @@ extern "C" int32_t WUPSLoadPluginAsData(GetPluginInformationInputType inputType,
memcpy(&data[0], buffer, size); memcpy(&data[0], buffer, size);
pluginData = PluginDataFactory::load(data, gPluginDataHeap); pluginData = PluginDataFactory::load(data, gPluginDataHeap);
} else { } else {
return ERROR_INVALID_ARG; return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} }
if (!pluginData) { if (!pluginData) {
DEBUG_FUNCTION_LINE("Failed to alloc plugin data"); DEBUG_FUNCTION_LINE("Failed to alloc plugin data");
return ERROR_FAILED_ALLOC; return PLUGIN_BACKEND_API_ERROR_FAILED_ALLOC;
} }
if (out == nullptr) { if (out == nullptr) {
DEBUG_FUNCTION_LINE("out was NULL"); DEBUG_FUNCTION_LINE("out was NULL");
return ERROR_INVALID_ARG; return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} else { } else {
auto *pluginDataHandle = new PluginData(pluginData.value()); auto *pluginDataHandle = new PluginData(pluginData.value());
DEBUG_FUNCTION_LINE("Saving plugin data handle: %08X", pluginDataHandle); DEBUG_FUNCTION_LINE("Saving plugin data handle: %08X", pluginDataHandle);
*out = (uint32_t) 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); 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); 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; std::optional<PluginMetaInformation> pluginInfo;
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) { if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) {
std::string pathStr(path); 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); DEBUG_FUNCTION_LINE("PLUGIN_INFORMATION_INPUT_TYPE_BUFFER %08X %d", buffer, size);
pluginInfo = PluginMetaInformationFactory::loadPlugin(buffer, size); pluginInfo = PluginMetaInformationFactory::loadPlugin(buffer, size);
} else { } else {
return ERROR_INVALID_ARG; return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} }
if (!pluginInfo) { if (!pluginInfo) {
DEBUG_FUNCTION_LINE("Failed to load plugin meta information"); 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"); DEBUG_FUNCTION_LINE("Loaded plugin meta information");
if (output == nullptr) { if (output == nullptr) {
return ERROR_INVALID_ARG; return PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} else { } else {
fillPluginInformation(output, &pluginInfo.value()); 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); 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); 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) { extern "C" PluginBackendApiErrorType WUPSGetPluginDataForContainerHandles(const plugin_container_handle *plugin_container_handle_list, plugin_data_handle *plugin_data_list, uint32_t buffer_size) {
int res = ERROR_NONE; PluginBackendApiErrorType res = PLUGIN_BACKEND_API_ERROR_NONE;
if (plugin_container_handle_list != nullptr && buffer_size != 0) { if (plugin_container_handle_list != nullptr && buffer_size != 0) {
for (uint32_t i = 0; i < buffer_size; i++) { for (uint32_t i = 0; i < buffer_size; i++) {
auto handle = plugin_container_handle_list[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; plugin_data_list[i] = (uint32_t) pluginData;
} }
} else { } else {
res = ERROR_INVALID_ARG; res = PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} }
return res; return res;
} }
extern "C" int32_t WUPSGetMetaInformation(const plugin_container_handle *plugin_container_handle_list, plugin_information *plugin_information_list, uint32_t buffer_size) { extern "C" PluginBackendApiErrorType WUPSGetMetaInformation(const plugin_container_handle *plugin_container_handle_list, plugin_information *plugin_information_list, uint32_t buffer_size) {
int res = ERROR_NONE; PluginBackendApiErrorType res = PLUGIN_BACKEND_API_ERROR_NONE;
if (plugin_container_handle_list != nullptr && buffer_size != 0) { if (plugin_container_handle_list != nullptr && buffer_size != 0) {
for (uint32_t i = 0; i < buffer_size; i++) { for (uint32_t i = 0; i < buffer_size; i++) {
auto handle = plugin_container_handle_list[i]; auto handle = plugin_container_handle_list[i];
auto *container = (PluginContainer *) handle; 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].author, container->metaInformation.getAuthor().c_str(), 255);
strncpy(plugin_information_list[i].buildTimestamp, container->metaInformation.getBuildTimestamp().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); 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(); plugin_information_list[i].size = container->metaInformation.getSize();
} }
} else { } else {
res = ERROR_INVALID_ARG; res = PLUGIN_BACKEND_API_ERROR_INVALID_ARG;
} }
return res; 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); auto plugins = PluginContainerPersistence::loadPlugins(gPluginInformation);
uint32_t counter = 0; uint32_t counter = 0;
for (auto &plugin: plugins) { for (auto &plugin: plugins) {
@ -190,10 +192,9 @@ extern "C" int32_t WUPSGetLoadedPlugins(plugin_container_handle *io_handles, uin
if (outSize != nullptr) { if (outSize != nullptr) {
*outSize = counter; *outSize = counter;
} }
return 0; return PLUGIN_BACKEND_API_ERROR_NONE;
} }
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByPath); WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByPath);
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByBuffer); WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsDataByBuffer);
WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsData); WUMS_EXPORT_FUNCTION(WUPSLoadPluginAsData);

View File

@ -1,61 +1,37 @@
#pragma once #pragma once
#include <wums.h> #include <wums.h>
#include <wups_backend/import_defines.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #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); 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 #ifdef __cplusplus
} }

25447
source/utils/json.hpp Normal file

File diff suppressed because it is too large Load Diff