WUPS 0.6, add support for config and storage

This commit is contained in:
Maschell 2021-09-24 19:57:15 +02:00
parent 77e931969a
commit 6510dd5c21
24 changed files with 1403 additions and 62 deletions

1
.gitignore vendored
View File

@ -29,3 +29,4 @@ debug/
*.cbp
lib/
cmake-build-debug/
CMakeLists.txt

View File

@ -1,4 +1,4 @@
FROM wiiuenv/devkitppc:20210917
FROM wiiuenv/devkitppc:20210920
WORKDIR tmp_build
COPY . .

View File

@ -2,7 +2,7 @@ TOPDIR ?= $(CURDIR)
include $(TOPDIR)/share/wups_rules
export WUT_MAJOR := 0
export WUT_MINOR := 5
export WUT_MINOR := 6
export WUT_PATCH := 0
VERSION := $(WUT_MAJOR).$(WUT_MINOR).$(WUT_PATCH)
@ -16,7 +16,8 @@ VERSION := $(WUT_MAJOR).$(WUT_MINOR).$(WUT_PATCH)
#---------------------------------------------------------------------------------
TARGET := wups
#BUILD := build
SOURCES := libraries/libwups/
SOURCES := libraries/libwups/ \
libraries/libwups/utils
DATA := data
INCLUDES := include
@ -25,12 +26,13 @@ INCLUDES := include
#---------------------------------------------------------------------------------
CFLAGS := -g -Wall -Werror -save-temps \
-ffunction-sections -fdata-sections \
-fno-exceptions -fno-rtti \
$(MACHDEP) \
$(BUILD_CFLAGS)
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
CXXFLAGS := $(CFLAGS) -std=gnu++17
CXXFLAGS := $(CFLAGS) -std=gnu++20
ASFLAGS := -g $(MACHDEP)

View File

@ -2,7 +2,7 @@
* by Alex Chadwick
*
* Copyright (C) 2014, Alex Chadwick
* Modified by Maschell, 2018
* Modified by Maschell, 2018-2021
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -23,12 +23,12 @@
* SOFTWARE.
*/
#ifndef WUPS_H_
#define WUPS_H_
#pragma once
#include "wups/common.h"
#include "wups/meta.h"
#include "wups/function_patching.h"
#include "wups/config.h"
#include "wups/hooks.h"
#endif /* WUPS_WUPS_H_ */
#include "wups/config_imports.h"
#include "wups/storage.h"

View File

@ -23,8 +23,7 @@
* SOFTWARE.
*/
#ifndef WUPS_COMMON_DEF_H_
#define WUPS_COMMON_DEF_H_
#pragma once
#include <stddef.h>
#include <stdint.h>
@ -48,5 +47,3 @@ extern "C" {
#ifdef __cplusplus
}
#endif
#endif /* WUPS_COMMON_DEF_H_ */

55
include/wups/config.h Normal file
View File

@ -0,0 +1,55 @@
/****************************************************************************
* Copyright (C) 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 <stdint.h>
#define WUPS_CONFIG_BUTTON_NONE 0
#define WUPS_CONFIG_BUTTON_LEFT (1<<0)
#define WUPS_CONFIG_BUTTON_RIGHT (1<<1)
#define WUPS_CONFIG_BUTTON_UP (1<<2)
#define WUPS_CONFIG_BUTTON_DOWN (1<<3)
#define WUPS_CONFIG_BUTTON_A (1<<4)
#define WUPS_CONFIG_BUTTON_B (1<<5)
#define WUPS_CONFIG_BUTTON_ZL (1<<6)
#define WUPS_CONFIG_BUTTON_ZR (1<<7)
#define WUPS_CONFIG_BUTTON_L (1<<8)
#define WUPS_CONFIG_BUTTON_R (1<<9)
typedef int32_t WUPSConfigButtons;
typedef struct {
int32_t (*getCurrentValueDisplay)(void *context, char *out_buf, int32_t out_size);
int32_t (*getCurrentValueSelectedDisplay)(void *context, char *out_buf, int32_t out_size);
void (*onSelected)(void *context, bool isSelected);
void (*restoreDefault)(void *context);
bool (*isMovementAllowed)(void *context);
bool (*callCallback)(void *context);
void (*onButtonPressed)(void *context, WUPSConfigButtons button);
void (*onDelete)(void *context);
} WUPSConfigCallbacks_t;
typedef uint32_t WUPSConfigItemHandle;
typedef uint32_t WUPSConfigHandle;
typedef uint32_t WUPSConfigCategoryHandle;

View File

@ -0,0 +1,40 @@
#include <wups.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ConfigItemBoolean {
WUPSConfigItemHandle handle;
bool defaultValue;
bool value;
char trueValue[32];
char falseValue[32];
void *callback;
} ConfigItemBoolean;
typedef void (*BooleanValueChangedCallback)(ConfigItemBoolean *, bool);
bool WUPSConfigItemBoolean_AddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, bool defaultValue, BooleanValueChangedCallback callback);
bool WUPSConfigItemBoolean_AddToCategoryEx(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, bool defaultValue, BooleanValueChangedCallback callback, const char *trueValue,
const char *falseValue);
#define WUPSConfigItemBoolean_AddToCategoryHandled(__config__, __cat__, __configID__, __displayName__, __defaultValue__, __callback__) \
do { \
if (!WUPSConfigItemBoolean_AddToCategory(__cat__, __configID__, __displayName__, __defaultValue__, __callback__)) { \
WUPSConfig_Destroy(__config__); \
return 0; \
} \
} while(0)
#define WUPSConfigItemBoolean_AddToCategoryHandledEx(__config__, __cat__, __configID__, __displayName__, __defaultValue__, __callback__, __trueValue__, __falseValue__) \
do { \
if (!WUPSConfigItemBoolean_AddToCategoryEx(__cat__, __configID__, __displayName__, __defaultValue__, __callback__, __trueValue__, __falseValue__)) { \
WUPSConfig_Destroy(__config__); \
return 0; \
} \
} while(0)
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,33 @@
#include <wups.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ConfigItemIntegerRange {
WUPSConfigItemHandle handle;
int defaultValue;
int value;
int minValue;
int maxValue;
void *callback;
} ConfigItemIntegerRange;
typedef void (*IntegerRangeValueChangedCallback)(ConfigItemIntegerRange *, int32_t);
bool
WUPSConfigItemIntegerRange_AddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName,
int32_t defaultValue, int32_t minValue, int32_t maxValue,
IntegerRangeValueChangedCallback callback);
#define WUPSConfigItemIntegerRange_AddToCategoryHandled(__config__, __cat__, __configID__, __displayName__, __defaultValue__, __minValue__, __maxValue__, __callback__) \
do { \
if (!WUPSConfigItemIntegerRange_AddToCategory(__cat__, __configID__, __displayName__, __defaultValue__, __minValue__, __maxValue__, __callback__)) { \
WUPSConfig_Destroy(__config__); \
return 0; \
} \
} while(0)
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,37 @@
#include <wups.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct ConfigItemMultipleValuesPair {
uint32_t value;
char *valueName;
} ConfigItemMultipleValuesPair;
typedef struct ConfigItemMultipleValues {
char *configID;
WUPSConfigItemHandle handle;
int32_t defaultValueIndex;
int32_t valueIndex;
void *callback;
ConfigItemMultipleValuesPair *values;
int valueCount;
} ConfigItemMultipleValues;
typedef void (*MultipleValuesChangedCallback)(ConfigItemMultipleValues *, uint32_t);
bool WUPSConfigItemMultipleValues_AddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, int defaultValueIndex, ConfigItemMultipleValuesPair *possibleValues,
int pairCount, MultipleValuesChangedCallback callback);
#define WUPSConfigItemMultipleValues_AddToCategoryHandled(__config__, __cat__, __configID__, __displayName__, __defaultValueIndex__, __possibleValues__, __pairCount__, __callback__) \
do { \
if(!WUPSConfigItemMultipleValues_AddToCategory(__cat__, __configID__, __displayName__, __defaultValueIndex__, __possibleValues__, __pairCount__, __callback__)) { \
WUPSConfig_Destroy(__config__); \
return 0; \
} \
} while(0)
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,53 @@
#pragma once
#include "stdint.h"
#include "config.h"
extern "C" int32_t WUPSConfigItem_Create(WUPSConfigItemHandle *out, const char *configID, const char *displayName, WUPSConfigCallbacks_t callbacks, void *context);
extern "C" int32_t WUPSConfig_Destroy(WUPSConfigHandle handle);
extern "C" int32_t WUPSConfigItem_SetDisplayName(WUPSConfigItemHandle handle, const char *displayName);
extern "C" int32_t WUPSConfigItem_GetDisplayName(WUPSConfigItemHandle handle, char *out_buf, int32_t out_len);
extern "C" int32_t WUPSConfigItem_SetConfigID(WUPSConfigItemHandle handle, const char *configID);
extern "C" int32_t WUPSConfigItem_GetConfigID(WUPSConfigItemHandle handle, char *out_buf, int32_t out);
extern "C" int32_t WUPSConfig_Create(WUPSConfigHandle *out, const char *name);
extern "C" int32_t WUPSConfigCategory_Destroy(WUPSConfigCategoryHandle handle);
extern "C" int32_t WUPSConfig_GetName(WUPSConfigHandle handle, char *out_buf, int32_t out_len);
extern "C" int32_t WUPSConfig_AddCategoryByName(WUPSConfigHandle handle, const char *categoryName, WUPSConfigCategoryHandle *out);
extern "C" int32_t WUPSConfig_AddCategory(WUPSConfigHandle handle, WUPSConfigCategoryHandle category);
/*
extern "C" int32_t WUPSConfig_GetCategoryCount(WUPSConfigHandle handle, int32_t *category_count);
extern "C" int32_t WUPSConfig_GetCategories(WUPSConfigHandle handle, WUPSConfigCategoryHandle *categories_out, int32_t categories_out_size);
*/
extern "C" int32_t WUPSConfigCategory_Create(WUPSConfigCategoryHandle *out, const char *name);
extern "C" int32_t WUPSConfigCategory_GetName(WUPSConfigCategoryHandle handle, char *out_buf, int32_t out_len);
extern "C" int32_t WUPSConfigCategory_AddItem(WUPSConfigCategoryHandle handle, WUPSConfigItemHandle item_Handle);
#define WUPSConfig_AddCategoryByNameHandled(__config__, __categoryName__, __out__) \
do { \
if (WUPSConfig_AddCategoryByName(__config__, __categoryName__, __out__) < 0) { \
WUPSConfig_Destroy(__config__); \
return 0;\
} \
} while(0)
#define WUPSConfig_CreateHandled(__config__, __configName__) \
do { \
if (WUPSConfig_Create(__config__, __configName__) < 0) { \
return 0; \
} \
} while(0)

View File

@ -23,8 +23,7 @@
* SOFTWARE.
*/
#ifndef WUPS_FUNCTION_PATCHING_DEF_H_
#define WUPS_FUNCTION_PATCHING_DEF_H_
#pragma once
#include "common.h"
@ -100,8 +99,7 @@ typedef enum wups_loader_library_type_t {
WUPS_LOADER_LIBRARY_VPADBASE,
WUPS_LOADER_LIBRARY_ZLIB125,
WUPS_LOADER_LIBRARY_OTHER,
}
wups_loader_library_type_t;
} wups_loader_library_type_t;
typedef enum wups_loader_entry_type_t {
WUPS_LOADER_ENTRY_FUNCTION,
@ -143,11 +141,11 @@ typedef struct wups_loader_entry_t {
} _function;
} wups_loader_entry_t;
#define WUPS_MUST_REPLACE_PHYSICAL(x, physical_address, virtual_address) WUPS_MUST_REPLACE_PHYSICAL_FOR_PROCESS(x, physical_address, virtual_address, WUPS_FP_TARGET_PROCESS_GAME_AND_MENU);
#define WUPS_MUST_REPLACE_PHYSICAL_FOR_PROCESS(x, physical_address, virtual_address, targetProcess) WUPS_MUST_REPLACE_EX(physical_address, virtual_address, real_ ## x, WUPS_LOADER_LIBRARY_OTHER, my_ ## x, x, targetProcess);
#define WUPS_MUST_REPLACE_PHYSICAL(x, physical_address, virtual_address) WUPS_MUST_REPLACE_PHYSICAL_FOR_PROCESS(x, physical_address, virtual_address, WUPS_FP_TARGET_PROCESS_GAME_AND_MENU)
#define WUPS_MUST_REPLACE_PHYSICAL_FOR_PROCESS(x, physical_address, virtual_address, targetProcess) WUPS_MUST_REPLACE_EX(physical_address, virtual_address, real_ ## x, WUPS_LOADER_LIBRARY_OTHER, my_ ## x, x, targetProcess)
#define WUPS_MUST_REPLACE(x, lib, function_name) WUPS_MUST_REPLACE_FOR_PROCESS(x, lib, function_name, WUPS_FP_TARGET_PROCESS_GAME_AND_MENU);
#define WUPS_MUST_REPLACE_FOR_PROCESS(x, lib, function_name, targetProcess) WUPS_MUST_REPLACE_EX(NULL, NULL, real_ ## x, lib, my_ ## x, function_name, targetProcess);
#define WUPS_MUST_REPLACE(x, lib, function_name) WUPS_MUST_REPLACE_FOR_PROCESS(x, lib, function_name, WUPS_FP_TARGET_PROCESS_GAME_AND_MENU)
#define WUPS_MUST_REPLACE_FOR_PROCESS(x, lib, function_name, targetProcess) WUPS_MUST_REPLACE_EX(NULL, NULL, real_ ## x, lib, my_ ## x, function_name, targetProcess)
#define WUPS_MUST_REPLACE_EX(pAddress, vAddress, original_func, rpl_type, replace_func, replace_function_name, process) \
extern const wups_loader_entry_t wups_load_ ## replace_func \
@ -172,6 +170,4 @@ typedef struct wups_loader_entry_t {
#ifdef __cplusplus
}
#endif
#endif /* WUPS_FUNCTION_PATCHING_DEF_H_ */
#endif

View File

@ -1,5 +1,5 @@
/****************************************************************************
* Copyright (C) 2018 Maschell
* 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
@ -15,8 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#ifndef WUPS_HOOKS_DEF_H_
#define WUPS_HOOKS_DEF_H_
#pragma once
#include "common.h"
@ -24,7 +23,7 @@
extern "C" {
#endif
#define WUPS_HOOK_EX(type_def,original_func) \
#define WUPS_HOOK_EX(type_def, original_func) \
extern const wups_loader_hook_t wups_hooks_ ## original_func WUPS_SECTION("hooks"); \
const wups_loader_hook_t wups_hooks_ ## original_func = { \
.type = type_def, \
@ -43,6 +42,11 @@ typedef enum wups_loader_hook_type_t {
WUPS_LOADER_HOOK_INIT_WUT_SOCKETS,
WUPS_LOADER_HOOK_FINI_WUT_SOCKETS,
WUPS_LOADER_HOOK_GET_CONFIG,
WUPS_LOADER_HOOK_CONFIG_CLOSED,
WUPS_LOADER_HOOK_INIT_STORAGE, /* Only for internal usage */
WUPS_LOADER_HOOK_INIT_PLUGIN, /* Called when exiting the plugin loader */
WUPS_LOADER_HOOK_DEINIT_PLUGIN, /* Called when re-entering the plugin loader */
WUPS_LOADER_HOOK_APPLICATION_STARTS, /* Called when an application gets started */
@ -51,7 +55,6 @@ typedef enum wups_loader_hook_type_t {
WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND, /* Called when an foreground is acquired */
WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT, /* Called when an application wants to exit */
WUPS_LOADER_HOOK_APPLICATION_ENDS, /* Called when an application ends */
WUPS_LOADER_HOOK_VSYNC, /* Called when an application calls GX2WaitForVsync (most times each frame) */
} wups_loader_hook_type_t;
typedef struct wups_loader_hook_t {
@ -88,7 +91,7 @@ typedef struct wups_loader_hook_t {
void on_acquired_foreground(void);\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_ACQUIRED_FOREGROUND,on_acquired_foreground); \
void on_acquired_foreground(void)
#define ON_APPLICATION_REQUESTS_EXIT() \
void on_app_requests_exit(void);\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT,on_app_requests_exit); \
@ -99,14 +102,25 @@ typedef struct wups_loader_hook_t {
WUPS_HOOK_EX(WUPS_LOADER_HOOK_APPLICATION_ENDS,on_app_ending); \
void on_app_ending(void)
#define ON_VYSNC() \
void on_vsync(void);\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_VSYNC,on_vsync); \
void on_vsync(void)
#define WUPS_GET_CONFIG() \
WUPSConfigHandle on_get_wups_config(void);\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_GET_CONFIG,on_get_wups_config); \
WUPSConfigHandle on_get_wups_config(void)
#define WUPS_CONFIG_CLOSED() \
void on_wups_config_closed(void);\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_CONFIG_CLOSED,on_wups_config_closed); \
void on_wups_config_closed(void)
#define WUPS_USE_STORAGE() \
void init_storage(wups_loader_init_storage_args_t);\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_INIT_STORAGE,init_storage); \
void init_storage(wups_loader_init_storage_args_t args){ \
WUPS_InitStorage(args);\
}
#ifdef __cplusplus
#define __EXTERN_C_MACRO extern "C"
#define __EXTERN_C_MACRO extern "C"
#else
#define __EXTERN_C_MACRO
#endif
@ -121,7 +135,7 @@ typedef struct wups_loader_hook_t {
void on_fini_wut_malloc(){ \
__fini_wut_malloc(); \
} \
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_MALLOC,on_fini_wut_malloc); \
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_MALLOC,on_fini_wut_malloc)
#define WUPS_USE_WUT_DEVOPTAB() \
__EXTERN_C_MACRO void __init_wut_devoptab(); \
@ -133,7 +147,7 @@ typedef struct wups_loader_hook_t {
void on_fini_wut_devoptab(){ \
__fini_wut_devoptab(); \
}\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB,on_fini_wut_devoptab);
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB,on_fini_wut_devoptab)
#define WUPS_USE_WUT_NEWLIB() \
__EXTERN_C_MACRO void __init_wut_newlib(); \
@ -145,8 +159,8 @@ typedef struct wups_loader_hook_t {
void on_fini_wut_newlib(){ \
__fini_wut_newlib(); \
}\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_NEWLIB,on_fini_wut_newlib);
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_NEWLIB,on_fini_wut_newlib)
#define WUPS_USE_WUT_STDCPP() \
__EXTERN_C_MACRO void __init_wut_stdcpp(); \
void on_init_wut_stdcpp(){ \
@ -157,7 +171,7 @@ typedef struct wups_loader_hook_t {
void on_fini_wut_stdcpp(){ \
__fini_wut_stdcpp(); \
}\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_STDCPP,on_fini_wut_stdcpp);
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_STDCPP,on_fini_wut_stdcpp)
#define WUPS_USE_WUT_SOCKETS() \
__EXTERN_C_MACRO void __attribute__((weak)) __init_wut_socket(); \
@ -169,10 +183,8 @@ typedef struct wups_loader_hook_t {
void on_fini_wut_sockets(){ \
if (&__fini_wut_socket) __fini_wut_socket(); \
}\
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_SOCKETS,on_fini_wut_sockets);
WUPS_HOOK_EX(WUPS_LOADER_HOOK_FINI_WUT_SOCKETS,on_fini_wut_sockets)
#ifdef __cplusplus
}
#endif
#endif /* WUPS_WUPS_H_ */

View File

@ -23,8 +23,7 @@
* SOFTWARE.
*/
#ifndef WUPS_META_DEF_H_
#define WUPS_META_DEF_H_
#pragma once
#include "common.h"
#include "hooks.h"
@ -33,16 +32,21 @@
extern "C" {
#endif
#define WUPS_PLUGIN_NAME(x) WUPS_META(name, x); WUPS_META(wups, "0.5"); WUPS_USE_WUT_MALLOC() WUPS_USE_WUT_SOCKETS() WUPS_USE_WUT_NEWLIB() WUPS_USE_WUT_STDCPP() WUPS_META(buildtimestamp, __DATE__ " " __TIME__);
#define WUPS_PLUGIN_AUTHOR(x) WUPS_META(author, x)
#define WUPS_PLUGIN_VERSION(x) WUPS_META(version, x)
#define WUPS_PLUGIN_LICENSE(x) WUPS_META(license, x)
#define WUPS_PLUGIN_DESCRIPTION(x) WUPS_META(description, x)
#define WUPS_PLUGIN_ID(x) WUPS_META(id, x)
#define WUPS_PLUGIN_CONFIG_REVISION(x) WUPS_META(config_revision, #x)
#define WUPS_PLUGIN_NAME(x) WUPS_META(name, x); \
WUPS_META(wups, "0.6"); \
WUPS_USE_WUT_MALLOC(); \
WUPS_USE_WUT_SOCKETS(); \
WUPS_USE_WUT_NEWLIB(); \
WUPS_USE_WUT_STDCPP(); \
WUPS_META(buildtimestamp, __DATE__ " " __TIME__);
#define WUPS_PLUGIN_AUTHOR(x) WUPS_META(author, x)
#define WUPS_PLUGIN_VERSION(x) WUPS_META(version, x)
#define WUPS_PLUGIN_LICENSE(x) WUPS_META(license, x)
#define WUPS_PLUGIN_DESCRIPTION(x) WUPS_META(description, x)
#define WUPS_PLUGIN_ID(x) WUPS_META(id, x)
#define WUPS_PLUGIN_CONFIG_REVISION(x) WUPS_META(config_revision, #x)
#ifdef __cplusplus
}
#endif
#endif /* WUPS_COMMON_DEF_H_ */

79
include/wups/storage.h Normal file
View File

@ -0,0 +1,79 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
typedef enum wups_storage_type_t_ {
WUPS_STORAGE_TYPE_INVALID,
WUPS_STORAGE_TYPE_STRING,
WUPS_STORAGE_TYPE_INT,
WUPS_STORAGE_TYPE_ITEM,
} wups_storage_type_t;
enum {
WUPS_STORAGE_ERROR_SUCCESS = 0,
WUPS_STORAGE_ERROR_NOT_OPENED = -1,
WUPS_STORAGE_ERROR_ALREADY_OPENED = -2,
WUPS_STORAGE_ERROR_INVALID_ARGS = -3,
WUPS_STORAGE_ERROR_NOT_FOUND = -4,
WUPS_STORAGE_ERROR_NOT_INITIALIZED = -5,
WUPS_STORAGE_ERROR_INVALID_BACKEND_PARAMS = -6,
WUPS_STORAGE_ERROR_INVALID_JSON = -7,
WUPS_STORAGE_ERROR_IO = -8,
WUPS_STORAGE_ERROR_B64_DECODE_FAILED = -9,
WUPS_STORAGE_ERROR_BUFFER_TOO_SMALL = -10,
};
typedef struct wups_storage_item_t_ {
char *key;
void *data;
uint32_t data_size;
uint32_t pending_delete;
wups_storage_type_t type;
} wups_storage_item_t;
typedef int32_t (*OpenStorageFunction)(const char *plugin_id, wups_storage_item_t *items);
typedef int32_t (*CloseStorageFunction)(const char *plugin_id, wups_storage_item_t *items);
typedef struct wups_loader_init_storage_args_t_ {
OpenStorageFunction open_storage_ptr;
CloseStorageFunction close_storage_ptr;
const char *plugin_id;
} wups_loader_init_storage_args_t;
/* called by backend */
void WUPS_InitStorage(wups_loader_init_storage_args_t args);
/* opens storage for reading and writing */
int32_t WUPS_OpenStorage(void);
/* closes storage and saves changes */
int32_t WUPS_CloseStorage(void);
/* deletes key from storage */
int32_t WUPS_DeleteItem(wups_storage_item_t *parent, const char *key);
/* returns the size of key on success, or an error code */
// TODO do we need this? what about binary data?
// int32_t WUPS_GetSize(const char* key);
int32_t WUPS_CreateSubItem(wups_storage_item_t *parent, const char *key, wups_storage_item_t **outItem);
int32_t WUPS_GetSubItem(wups_storage_item_t *parent, const char *key, wups_storage_item_t **outItem);
int32_t WUPS_StoreString(wups_storage_item_t *parent, const char *key, const char *string);
int32_t WUPS_StoreBool(wups_storage_item_t *parent, const char *key, bool value);
int32_t WUPS_StoreInt(wups_storage_item_t *parent, const char *key, int32_t value);
int32_t WUPS_StoreBinary(wups_storage_item_t *parent, const char *key, const void *data, uint32_t size);
int32_t WUPS_GetString(wups_storage_item_t *parent, const char *key, char *outString, uint32_t maxSize);
int32_t WUPS_GetBool(wups_storage_item_t *parent, const char *key, bool *outBool);
int32_t WUPS_GetInt(wups_storage_item_t *parent, const char *key, int32_t *outInt);
int32_t WUPS_GetBinary(wups_storage_item_t *parent, const char *key, void *outData, uint32_t maxSize);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,106 @@
#include <wups.h>
#include <cstdio>
#include <cstdlib>
#include "wups/config/WUPSConfigItemBoolean.h"
void WUPSConfigItemBoolean_onDelete(void *context);
int32_t WUPSConfigItemBoolean_getCurrentValueDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemBoolean *) context;
snprintf(out_buf, out_size, " %s", item->value ? item->trueValue : item->falseValue);
return 0;
}
void toggleValue(ConfigItemBoolean *item) {
item->value = !item->value;
}
bool WUPSConfigItemBoolean_callCallback(void *context) {
auto *item = (ConfigItemBoolean *) context;
if (item->callback != nullptr) {
((BooleanValueChangedCallback) (item->callback))(item, item->value);
return true;
}
return false;
}
void WUPSConfigItemBoolean_onButtonPressed(void *context, WUPSConfigButtons buttons) {
auto *item = (ConfigItemBoolean *) context;
if ((buttons & WUPS_CONFIG_BUTTON_A) == WUPS_CONFIG_BUTTON_A) {
toggleValue(item);
} else if (buttons & WUPS_CONFIG_BUTTON_LEFT && !item->value) {
toggleValue(item);
} else if ((buttons & WUPS_CONFIG_BUTTON_RIGHT) && item->value) {
toggleValue(item);
}
}
bool WUPSConfigItemBoolean_isMovementAllowed(void *context) {
return true;
}
int32_t WUPSConfigItemBoolean_getCurrentValueSelectedDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemBoolean *) context;
if (item->value) {
snprintf(out_buf, out_size, " %s >", item->trueValue);
} else {
snprintf(out_buf, out_size, "< %s ", item->falseValue);
}
return 0;
}
void WUPSConfigItemBoolean_restoreDefault(void *context) {
auto *item = (ConfigItemBoolean *) context;
item->value = item->defaultValue;
}
void WUPSConfigItemBoolean_onSelected(void *context, bool isSelected) {
}
extern "C" bool
WUPSConfigItemBoolean_AddToCategoryEx(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, bool defaultValue, BooleanValueChangedCallback callback, const char *trueValue,
const char *falseValue) {
if (cat == 0) {
return false;
}
auto *item = (ConfigItemBoolean *) malloc(sizeof(ConfigItemBoolean));
if (item == nullptr) {
return false;
}
item->defaultValue = defaultValue;
item->value = defaultValue;
item->callback = (void *) callback;
snprintf(item->trueValue, sizeof(item->trueValue), "%s", trueValue);
snprintf(item->falseValue, sizeof(item->falseValue), "%s", falseValue);
WUPSConfigCallbacks_t callbacks = {
.getCurrentValueDisplay = &WUPSConfigItemBoolean_getCurrentValueDisplay,
.getCurrentValueSelectedDisplay = &WUPSConfigItemBoolean_getCurrentValueSelectedDisplay,
.onSelected = &WUPSConfigItemBoolean_onSelected,
.restoreDefault = &WUPSConfigItemBoolean_restoreDefault,
.isMovementAllowed = &WUPSConfigItemBoolean_isMovementAllowed,
.callCallback = &WUPSConfigItemBoolean_callCallback,
.onButtonPressed = &WUPSConfigItemBoolean_onButtonPressed,
.onDelete = &WUPSConfigItemBoolean_onDelete
};
if (WUPSConfigItem_Create(&item->handle, configID, displayName, callbacks, item) < 0) {
free(item);
return false;
}
if (WUPSConfigCategory_AddItem(cat, item->handle) < 0) {
return false;
}
return true;
}
void WUPSConfigItemBoolean_onDelete(void *context) {
auto *item = (ConfigItemBoolean *) context;
free(item);
}
extern "C" bool WUPSConfigItemBoolean_AddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, bool defaultValue, BooleanValueChangedCallback callback) {
return WUPSConfigItemBoolean_AddToCategoryEx(cat, configID, displayName, defaultValue, callback, "true", "false");
}

View File

@ -0,0 +1,106 @@
#include <wups.h>
#include <cstdio>
#include <cstdlib>
#include "wups/config/WUPSConfigItemIntegerRange.h"
int32_t WUPSConfigItemIntegerRange_getCurrentValueDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemIntegerRange *) context;
snprintf(out_buf, out_size, "%d", item->value);
return 0;
}
bool WUPSConfigItemIntegerRange_callCallback(void *context) {
auto *item = (ConfigItemIntegerRange *) context;
if (item->callback != nullptr) {
((IntegerRangeValueChangedCallback) item->callback)(item, item->value);
return true;
}
return false;
}
void WUPSConfigItemIntegerRange_onButtonPressed(void *context, WUPSConfigButtons buttons) {
auto *item = (ConfigItemIntegerRange *) context;
if (buttons & WUPS_CONFIG_BUTTON_LEFT) {
item->value--;
} else if ((buttons & WUPS_CONFIG_BUTTON_RIGHT)) {
item->value++;
} else if ((buttons & WUPS_CONFIG_BUTTON_L)) {
item->value = item->value - 50;
} else if ((buttons & WUPS_CONFIG_BUTTON_R)) {
item->value = item->value + 50;
}
if (item->value < item->minValue) {
item->value = item->minValue;
} else if (item->value > item->maxValue) {
item->value = item->maxValue;
}
}
bool WUPSConfigItemIntegerRange_isMovementAllowed(void *context) {
return true;
}
int32_t WUPSConfigItemIntegerRange_getCurrentValueSelectedDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemIntegerRange *) context;
if (item->value == item->minValue) {
snprintf(out_buf, out_size, " %d >", item->value);
} else if (item->value == item->maxValue) {
snprintf(out_buf, out_size, "< %d ", item->value);
} else {
snprintf(out_buf, out_size, "< %d >", item->value);
}
return 0;
}
void WUPSConfigItemIntegerRange_restoreDefault(void *context) {
auto *item = (ConfigItemIntegerRange *) context;
item->value = item->defaultValue;
}
void WUPSConfigItemIntegerRange_onDelete(void *context) {
auto *item = (ConfigItemIntegerRange *) context;
free(item);
}
void WUPSConfigItemIntegerRange_onSelected(void *context, bool isSelected) {
}
extern "C" bool WUPSConfigItemIntegerRange_AddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName, int32_t defaultValue, int32_t minValue, int32_t maxValue,
IntegerRangeValueChangedCallback callback) {
if (cat == 0) {
return false;
}
auto *item = (ConfigItemIntegerRange *) malloc(sizeof(ConfigItemIntegerRange));
if (item == nullptr) {
return false;
}
item->defaultValue = defaultValue;
item->value = defaultValue;
item->minValue = minValue;
item->maxValue = maxValue;
item->callback = (void *) callback;
WUPSConfigCallbacks_t callbacks = {
.getCurrentValueDisplay = &WUPSConfigItemIntegerRange_getCurrentValueDisplay,
.getCurrentValueSelectedDisplay = &WUPSConfigItemIntegerRange_getCurrentValueSelectedDisplay,
.onSelected = &WUPSConfigItemIntegerRange_onSelected,
.restoreDefault = &WUPSConfigItemIntegerRange_restoreDefault,
.isMovementAllowed = &WUPSConfigItemIntegerRange_isMovementAllowed,
.callCallback = &WUPSConfigItemIntegerRange_callCallback,
.onButtonPressed = &WUPSConfigItemIntegerRange_onButtonPressed,
.onDelete = &WUPSConfigItemIntegerRange_onDelete
};
if (WUPSConfigItem_Create(&(item->handle), configID, displayName, callbacks, item) < 0) {
free(item);
return false;
};
if (WUPSConfigCategory_AddItem(cat, item->handle) < 0) {
return false;
}
return true;
}

View File

@ -0,0 +1,147 @@
#include <wups.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "wups/config/WUPSConfigItemMultipleValues.h"
void WUPSConfigItemMultipleValues_onDelete(void *context);
int32_t WUPSConfigItemMultipleValues_getCurrentValueDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemMultipleValues *) context;
if (item->values && item->valueIndex >= 0 && item->valueIndex < item->valueCount) {
if (item->values[item->valueIndex].valueName == nullptr) {
return -2;
}
strncpy(out_buf, item->values[item->valueIndex].valueName, out_size);
return 0;
}
return -1;
}
bool WUPSConfigItemMultipleValues_callCallback(void *context) {
auto *item = (ConfigItemMultipleValues *) context;
if (item->callback != nullptr && item->values && item->valueIndex >= 0 && item->valueIndex < item->valueCount) {
((MultipleValuesChangedCallback) (item->callback))(item, item->values[item->valueIndex].value);
return true;
}
return false;
}
void WUPSConfigItemMultipleValues_onButtonPressed(void *context, WUPSConfigButtons buttons) {
auto *item = (ConfigItemMultipleValues *) context;
if (buttons & WUPS_CONFIG_BUTTON_LEFT) {
item->valueIndex--;
} else if (buttons & WUPS_CONFIG_BUTTON_RIGHT) {
item->valueIndex++;
}
if (item->valueIndex < 0) {
item->valueIndex = 0;
} else if (item->valueIndex >= item->valueCount) {
item->valueIndex = item->valueCount - 1;
}
}
bool WUPSConfigItemMultipleValues_isMovementAllowed(void *context) {
return true;
}
int32_t WUPSConfigItemMultipleValues_getCurrentValueSelectedDisplay(void *context, char *out_buf, int32_t out_size) {
auto *item = (ConfigItemMultipleValues *) context;
if (item->values && item->valueIndex >= 0 && item->valueIndex < item->valueCount) {
if (item->valueCount == 1) {
snprintf(out_buf, out_size, " %s ", item->values[item->valueIndex].valueName);
} else if (item->valueIndex == 0) {
snprintf(out_buf, out_size, " %s >", item->values[item->valueIndex].valueName);
} else if (item->valueIndex + 1 == item->valueCount) {
snprintf(out_buf, out_size, "< %s ", item->values[item->valueIndex].valueName);
} else {
snprintf(out_buf, out_size, "< %s >", item->values[item->valueIndex].valueName);
}
} else {
return -1;
}
return 0;
}
void WUPSConfigItemMultipleValues_restoreDefault(void *context) {
auto *item = (ConfigItemMultipleValues *) context;
item->valueIndex = item->defaultValueIndex;
}
void WUPSConfigItemMultipleValues_onSelected(void *context, bool isSelected) {
}
extern "C" bool
WUPSConfigItemMultipleValues_AddToCategory(WUPSConfigCategoryHandle cat, const char *configID, const char *displayName,
int32_t defaultValueIndex, ConfigItemMultipleValuesPair *possibleValues,
int pairCount, MultipleValuesChangedCallback callback) {
if (cat == 0 || displayName == nullptr || possibleValues == nullptr || pairCount < 0) {
return false;
}
auto *item = (ConfigItemMultipleValues *) malloc(sizeof(ConfigItemMultipleValues));
if (item == nullptr) {
return false;
}
auto *values = (ConfigItemMultipleValuesPair *) malloc(sizeof(ConfigItemMultipleValuesPair) * pairCount);
for (int i = 0; i < pairCount; ++i) {
values[i].value = possibleValues[i].value;
if (possibleValues[i].valueName == nullptr) {
values[i].valueName = nullptr;
continue;
}
auto bufLen = strlen(possibleValues[i].valueName) + 1;
values[i].valueName = (char *) malloc(bufLen);
strncpy(values[i].valueName, possibleValues[i].valueName, bufLen);
}
item->valueCount = pairCount;
item->values = values;
item->valueIndex = defaultValueIndex;
item->defaultValueIndex = defaultValueIndex;
item->callback = (void *) callback;
if (configID != nullptr) {
auto configIDLen = strlen(configID) + 1;
item->configID = (char *) malloc(configIDLen);
strncpy(item->configID, configID, configIDLen);
} else {
item->configID = nullptr;
}
WUPSConfigCallbacks_t callbacks = {
.getCurrentValueDisplay = &WUPSConfigItemMultipleValues_getCurrentValueDisplay,
.getCurrentValueSelectedDisplay = &WUPSConfigItemMultipleValues_getCurrentValueSelectedDisplay,
.onSelected = &WUPSConfigItemMultipleValues_onSelected,
.restoreDefault = &WUPSConfigItemMultipleValues_restoreDefault,
.isMovementAllowed = &WUPSConfigItemMultipleValues_isMovementAllowed,
.callCallback = &WUPSConfigItemMultipleValues_callCallback,
.onButtonPressed = &WUPSConfigItemMultipleValues_onButtonPressed,
.onDelete = &WUPSConfigItemMultipleValues_onDelete
};
if (WUPSConfigItem_Create(&item->handle, configID, displayName, callbacks, item) < 0) {
free(item);
return false;
}
if (WUPSConfigCategory_AddItem(cat, item->handle) < 0) {
return false;
}
return true;
}
void WUPSConfigItemMultipleValues_onDelete(void *context) {
auto *item = (ConfigItemMultipleValues *) context;
for (int i = 0; i < item->valueCount; ++i) {
free(item->values[i].valueName);
}
free(item->configID);
free(item->values);
free(item);
}

View File

@ -0,0 +1,19 @@
:NAME homebrew_wupsbackend
:TEXT
WUPSConfigItem_Create
WUPSConfigItem_SetDisplayName
WUPSConfigItem_GetDisplayName
WUPSConfigItem_SetConfigID
WUPSConfigItem_GetConfigID
WUPSConfig_Create
WUPSConfig_Destroy
WUPSConfig_GetName
WUPSConfig_AddCategoryByName
WUPSConfig_AddCategory
WUPSConfigCategory_Create
WUPSConfigCategory_Destroy
WUPSConfigCategory_GetName
WUPSConfigCategory_AddItem

View File

@ -1,10 +1,11 @@
extern "C" void OSFatal(const char *msg);
extern "C" void __wups_start(){
extern "C" void __wups_start() {
OSFatal("This file needs to be run with the Wii U Plugin System.");
}
extern __attribute__((weak)) void __wut_socket_init_devoptab();
extern __attribute__((weak)) void __wut_socket_fini_devoptab();
static int __wut_socket_devoptab_added = 0;
@ -12,7 +13,7 @@ static int __wut_socket_devoptab_added = 0;
extern void socket_lib_init();
void __attribute__((weak)) __init_wut_socket() {
if(!&__wut_socket_init_devoptab) return;
if (!&__wut_socket_init_devoptab) return;
if (!__wut_socket_devoptab_added) {
socket_lib_init();
__wut_socket_init_devoptab();
@ -21,7 +22,7 @@ void __attribute__((weak)) __init_wut_socket() {
}
void __attribute__((weak)) __fini_wut_socket() {
if(!&__wut_socket_init_devoptab || !&__wut_socket_fini_devoptab) return;
if (!&__wut_socket_init_devoptab || !&__wut_socket_fini_devoptab) return;
if (__wut_socket_devoptab_added) {
__wut_socket_fini_devoptab();
__wut_socket_devoptab_added = 0;

View File

@ -0,0 +1,452 @@
#include <wups.h>
#include <cstring>
#include <cstdlib>
#include "utils/base64.h"
static OpenStorageFunction openfunction_ptr __attribute__((section(".data"))) = nullptr;
static CloseStorageFunction closefunction_ptr __attribute__((section(".data"))) = nullptr;
static const char *plugin_id __attribute__((section(".data"))) = nullptr;
static uint32_t storage_initialized __attribute__((section(".data"))) = false;
static uint32_t isOpened __attribute__((section(".data")));
static uint32_t isDirty __attribute__((section(".data")));
static wups_storage_item_t rootItem __attribute__((section(".data")));
void WUPS_InitStorage(wups_loader_init_storage_args_t args) {
openfunction_ptr = args.open_storage_ptr;
closefunction_ptr = args.close_storage_ptr;
plugin_id = args.plugin_id;
storage_initialized = true;
isOpened = false;
isDirty = false;
rootItem.key = nullptr;
rootItem.data = nullptr;
rootItem.data_size = 0;
rootItem.pending_delete = false;
rootItem.type = WUPS_STORAGE_TYPE_ITEM;
}
int32_t WUPS_OpenStorage(void) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (isOpened) {
return WUPS_STORAGE_ERROR_ALREADY_OPENED;
}
int32_t result = openfunction_ptr(plugin_id, &rootItem);
if (result == WUPS_STORAGE_ERROR_SUCCESS || result == WUPS_STORAGE_ERROR_INVALID_JSON) {
isOpened = true;
isDirty = false;
}
return result;
}
static void closeItem(wups_storage_item_t *item) {
if (!item) {
return;
}
auto *items = (wups_storage_item_t *) item->data;
for (uint32_t i = 0; i < item->data_size; i++) {
if (items[i].type == WUPS_STORAGE_TYPE_ITEM) {
closeItem(&items[i]);
}
free(items[i].data);
free(items[i].key);
}
}
int32_t WUPS_CloseStorage(void) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
int32_t result = 0;
if (isDirty) {
result = closefunction_ptr(plugin_id, &rootItem);
}
if (result == 0) {
isOpened = false;
isDirty = false;
closeItem(&rootItem);
free(rootItem.data);
rootItem.data_size = 0;
rootItem.data = nullptr;
}
return result;
}
int32_t WUPS_DeleteItem(wups_storage_item_t *parent, const char *key) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
isDirty = true;
if (!parent) {
parent = &rootItem;
}
for (uint32_t i = 0; i < parent->data_size; i++) {
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
if (item->pending_delete || item->type == WUPS_STORAGE_TYPE_INVALID) {
continue;
}
if (strcmp(item->key, key) == 0) {
item->pending_delete = true;
return WUPS_STORAGE_ERROR_SUCCESS;
}
}
return WUPS_STORAGE_ERROR_NOT_FOUND;
}
// int32_t WUPS_GetSize(const char* key) {
// if (!storage_initialized) {
// return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
// }
// if (!isOpened) {
// return WUPS_STORAGE_ERROR_NOT_OPENED;
// }
// for (uint32_t i = 0; i < amount_of_items; i++) {
// wups_loader_storage_item_t* item = &items[i];
// if (item->pending_delete || item->type == WUPS_STORAGE_TYPE_INVALID) {
// continue;
// }
// if (strcmp(item->key, key) == 0) {
// return item->data_size;
// }
// }
// return WUPS_STORAGE_ERROR_NOT_FOUND;
// }
static wups_storage_item_t *addItem(wups_storage_item_t *parent, const char *key, wups_storage_type_t type) {
wups_storage_item_t *foundItem = nullptr;
for (uint32_t i = 0; i < parent->data_size; i++) {
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
if (strcmp(item->key, key) == 0) {
free(item->data);
foundItem = item;
break;
}
if (item->pending_delete) {
free(item->data);
free(item->key);
item->key = (char *) malloc(strlen(key) + 1);
strcpy(item->key, key);
foundItem = item;
break;
}
}
if (!foundItem) {
parent->data_size++;
parent->data = (wups_storage_item_t *) realloc(parent->data, parent->data_size * sizeof(wups_storage_item_t));
foundItem = &((wups_storage_item_t *) parent->data)[parent->data_size - 1];
foundItem->key = (char *) malloc(strlen(key) + 1);
strcpy(foundItem->key, key);
}
foundItem->type = type;
foundItem->pending_delete = false;
foundItem->data = nullptr;
foundItem->data_size = 0;
return foundItem;
}
int32_t WUPS_CreateSubItem(wups_storage_item_t *parent, const char *key, wups_storage_item_t **outItem) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key || !outItem) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
isDirty = true;
if (!parent) {
parent = &rootItem;
}
wups_storage_item_t *item = addItem(parent, key, WUPS_STORAGE_TYPE_ITEM);
*outItem = item;
return WUPS_STORAGE_ERROR_SUCCESS;
}
int32_t WUPS_GetSubItem(wups_storage_item_t *parent, const char *key, wups_storage_item_t **outItem) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key || outItem == nullptr) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
if (!parent) {
parent = &rootItem;
}
for (uint32_t i = 0; i < parent->data_size; i++) {
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
if (item->pending_delete || item->type != WUPS_STORAGE_TYPE_ITEM) {
continue;
}
if (strcmp(item->key, key) == 0) {
*outItem = item;
return WUPS_STORAGE_ERROR_SUCCESS;
}
}
return WUPS_STORAGE_ERROR_NOT_FOUND;
}
int32_t WUPS_StoreString(wups_storage_item_t *parent, const char *key, const char *string) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key || !string) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
isDirty = true;
if (!parent) {
parent = &rootItem;
}
wups_storage_item_t *item = addItem(parent, key, WUPS_STORAGE_TYPE_STRING);
uint32_t size = strlen(string) + 1;
item->data = malloc(size);
item->data_size = size;
strcpy((char *) item->data, string);
return WUPS_STORAGE_ERROR_SUCCESS;
}
int32_t WUPS_StoreBool(wups_storage_item_t *parent, const char *key, bool value) {
return WUPS_StoreInt(parent, key, (int32_t) value);
}
int32_t WUPS_StoreInt(wups_storage_item_t *parent, const char *key, int32_t value) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
isDirty = true;
if (!parent) {
parent = &rootItem;
}
wups_storage_item_t *item = addItem(parent, key, WUPS_STORAGE_TYPE_INT);
item->data = malloc(sizeof(int32_t));
item->data_size = sizeof(int32_t);
*(int32_t *) item->data = value;
return WUPS_STORAGE_ERROR_SUCCESS;
}
int32_t WUPS_StoreBinary(wups_storage_item_t *parent, const char *key, const void *data, uint32_t size) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key || !data || size == 0) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
if (!parent) {
parent = &rootItem;
}
wups_storage_item_t *item = addItem(parent, key, WUPS_STORAGE_TYPE_STRING);
item->data = b64_encode((const uint8_t *) data, size);
item->data_size = strlen((char *) data) + 1;
return WUPS_STORAGE_ERROR_SUCCESS;
}
int32_t WUPS_GetString(wups_storage_item_t *parent, const char *key, char *outString, uint32_t maxSize) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key || !outString || maxSize == 0) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
if (!parent) {
parent = &rootItem;
}
for (uint32_t i = 0; i < parent->data_size; i++) {
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
if (item->pending_delete || item->type != WUPS_STORAGE_TYPE_STRING) {
continue;
}
if (strcmp(item->key, key) == 0) {
strncpy(outString, (char *) item->data, maxSize);
return WUPS_STORAGE_ERROR_SUCCESS;
}
}
return WUPS_STORAGE_ERROR_NOT_FOUND;
}
int32_t WUPS_GetBool(wups_storage_item_t *parent, const char *key, bool *outBool) {
int32_t out;
int32_t result = WUPS_GetInt(parent, key, &out);
if (result != WUPS_STORAGE_ERROR_SUCCESS) {
return result;
}
*outBool = out != 0;
return WUPS_STORAGE_ERROR_SUCCESS;
}
int32_t WUPS_GetInt(wups_storage_item_t *parent, const char *key, int32_t *outInt) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key || !outInt) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
if (!parent) {
parent = &rootItem;
}
for (uint32_t i = 0; i < parent->data_size; i++) {
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
if (item->pending_delete || item->type != WUPS_STORAGE_TYPE_INT) {
continue;
}
if (strcmp(item->key, key) == 0) {
*outInt = *(int32_t *) item->data;
return WUPS_STORAGE_ERROR_SUCCESS;
}
}
return WUPS_STORAGE_ERROR_NOT_FOUND;
}
int32_t WUPS_GetBinary(wups_storage_item_t *parent, const char *key, void *outData, uint32_t maxSize) {
if (!storage_initialized) {
return WUPS_STORAGE_ERROR_NOT_INITIALIZED;
}
if (!isOpened) {
return WUPS_STORAGE_ERROR_NOT_OPENED;
}
if (!key || !outData || maxSize == 0) {
return WUPS_STORAGE_ERROR_INVALID_ARGS;
}
if (!parent) {
parent = &rootItem;
}
for (uint32_t i = 0; i < parent->data_size; i++) {
wups_storage_item_t *item = &((wups_storage_item_t *) parent->data)[i];
if (item->pending_delete || item->type != WUPS_STORAGE_TYPE_STRING) {
continue;
}
if (strcmp(item->key, key) == 0) {
if (b64_decoded_size((char *) item->data) > maxSize) {
return WUPS_STORAGE_ERROR_BUFFER_TOO_SMALL;
}
if (b64_decode((char *) item->data, (uint8_t *) outData, item->data_size)) {
return WUPS_STORAGE_ERROR_SUCCESS;
} else {
return WUPS_STORAGE_ERROR_B64_DECODE_FAILED;
}
}
}
return WUPS_STORAGE_ERROR_NOT_FOUND;
}

View File

@ -0,0 +1,128 @@
#include "base64.h"
#include <string.h>
static const char b64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
size_t b64_encoded_size(size_t inlen) {
size_t ret;
ret = inlen;
if (inlen % 3 != 0)
ret += 3 - (inlen % 3);
ret /= 3;
ret *= 4;
return ret;
}
char *b64_encode(const uint8_t *in, size_t len) {
char *out;
size_t elen;
size_t i;
size_t j;
size_t v;
if (in == NULL || len == 0)
return NULL;
elen = b64_encoded_size(len);
out = (char *) malloc(elen + 1);
out[elen] = '\0';
for (i = 0, j = 0; i < len; i += 3, j += 4) {
v = in[i];
v = i + 1 < len ? v << 8 | in[i + 1] : v << 8;
v = i + 2 < len ? v << 8 | in[i + 2] : v << 8;
out[j] = b64chars[(v >> 18) & 0x3F];
out[j + 1] = b64chars[(v >> 12) & 0x3F];
if (i + 1 < len) {
out[j + 2] = b64chars[(v >> 6) & 0x3F];
} else {
out[j + 2] = '=';
}
if (i + 2 < len) {
out[j + 3] = b64chars[v & 0x3F];
} else {
out[j + 3] = '=';
}
}
return out;
}
size_t b64_decoded_size(const char *in) {
size_t len;
size_t ret;
size_t i;
if (in == NULL)
return 0;
len = strlen(in);
ret = len / 4 * 3;
for (i = len; i-- > 0;) {
if (in[i] == '=') {
ret--;
} else {
break;
}
}
return ret;
}
static const int b64invs[] = {
62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
static int b64_isvalidchar(char c) {
if (c >= '0' && c <= '9')
return 1;
if (c >= 'A' && c <= 'Z')
return 1;
if (c >= 'a' && c <= 'z')
return 1;
if (c == '+' || c == '/' || c == '=')
return 1;
return 0;
}
int b64_decode(const char *in, uint8_t *out, size_t outlen) {
size_t len;
size_t i;
size_t j;
int v;
if (in == NULL || out == NULL)
return 0;
len = strlen(in);
if (outlen < b64_decoded_size(in) || len % 4 != 0)
return 0;
for (i = 0; i < len; i++) {
if (!b64_isvalidchar(in[i])) {
return 0;
}
}
for (i = 0, j = 0; i < len; i += 4, j += 3) {
v = b64invs[in[i] - 43];
v = (v << 6) | b64invs[in[i + 1] - 43];
v = in[i + 2] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 2] - 43];
v = in[i + 3] == '=' ? v << 6 : (v << 6) | b64invs[in[i + 3] - 43];
out[j] = (v >> 16) & 0xFF;
if (in[i + 2] != '=')
out[j + 1] = (v >> 8) & 0xFF;
if (in[i + 3] != '=')
out[j + 2] = v & 0xFF;
}
return 1;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <stdlib.h>
#include <stdint.h>
// based on https://nachtimwald.com/2017/11/18/base64-encode-and-decode-in-c/
#ifdef __cplusplus
extern "C" {
#endif
size_t b64_encoded_size(size_t inlen);
char *b64_encode(const uint8_t *in, size_t len);
size_t b64_decoded_size(const char *in);
int b64_decode(const char *in, uint8_t *out, size_t outlen);
#ifdef __cplusplus
}
#endif

View File

@ -2,17 +2,18 @@
#include <whb/libmanager.h>
#include <malloc.h>
#include <string.h>
#include <nsysnet/socket.h>
#include <utils/logger.h>
#include <coreinit/time.h>
#include <coreinit/thread.h>
#include <coreinit/filesystem.h>
#include <whb/log_udp.h>
#include <wups/config/WUPSConfigItemBoolean.h>
/**
Mandatory plugin information.
If not set correctly, the loader will refuse to use the plugin.
**/
WUPS_PLUGIN_ID("example_plugin");
WUPS_PLUGIN_NAME("Example plugin");
WUPS_PLUGIN_DESCRIPTION("This is just an example plugin and will log the FSOpenFile function.");
WUPS_PLUGIN_VERSION("v1.0");
@ -25,7 +26,10 @@ WUPS_PLUGIN_LICENSE("BSD");
**/
WUPS_USE_WUT_DEVOPTAB() // Use the wut devoptabs
WUPS_USE_WUT_DEVOPTAB(); // Use the wut devoptabs
WUPS_USE_STORAGE(); // Use the storage API
bool logFSOpen = true;
/**
Get's called ONCE when the loader exits, but BEFORE the ON_APPLICATION_START gets called or functions are overridden.
@ -33,6 +37,18 @@ WUPS_USE_WUT_DEVOPTAB() // Use the wut devoptabs
INITIALIZE_PLUGIN(){
WHBLogUdpInit();
DEBUG_FUNCTION_LINE("INITIALIZE_PLUGIN of example_plugin!");
// Open storage to read values
WUPS_OpenStorage();
// Try to get value from storage
if(WUPS_GetBool(nullptr, "logFSOpen", &logFSOpen) != WUPS_STORAGE_ERROR_SUCCESS){
// Add the value to the storage if it's missing.
WUPS_StoreBool(nullptr, "logFSOpen", logFSOpen);
}
// Close storage
WUPS_CloseStorage();
}
/**
@ -61,6 +77,33 @@ ON_APPLICATION_REQUESTS_EXIT(){
DEBUG_FUNCTION_LINE("ON_APPLICATION_REQUESTS_EXIT of example_plugin!");
}
void logFSOpenChanged(ConfigItemBoolean *item, bool newValue) {
DEBUG_FUNCTION_LINE("New value in logFSOpenChanged: %d", newValue);
logFSOpen = newValue;
// If the value has changed, we store it in the storage.
WUPS_StoreInt(nullptr, "logFSOpen", logFSOpen);
}
WUPS_GET_CONFIG() {
// We open the storage so we can persist the configuration the user did.
WUPS_OpenStorage();
WUPSConfigHandle config;
WUPSConfig_CreateHandled(&config, "Example Plugin");
WUPSConfigCategoryHandle cat;
WUPSConfig_AddCategoryByNameHandled(config, "Logging", &cat);
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, "logFSOpen", "Log FSOpen calls", logFSOpen, &logFSOpenChanged);
return config;
}
WUPS_CONFIG_CLOSED() {
// Save all changes
WUPS_CloseStorage();
}
/**
This defines a function replacement.
It allows to replace the system function with an own function.
@ -91,8 +134,9 @@ ON_APPLICATION_REQUESTS_EXIT(){
**/
DECL_FUNCTION(int, FSOpenFile, FSClient *pClient, FSCmdBlock *pCmd, const char *path, const char *mode, int *handle, int error) {
int result = real_FSOpenFile(pClient, pCmd, path, mode, handle, error);
DEBUG_FUNCTION_LINE("FSOpenFile called for folder %s! Result %d\n",path,result);
if (logFSOpen) {
DEBUG_FUNCTION_LINE("FSOpenFile called for folder %s! Result %d",path,result);
}
return result;
}

View File

@ -1,5 +1,14 @@
SECTIONS
{
.fimport_homebrew_wupsbackend ALIGN(16) : {
KEEP ( *(.fimport_homebrew_wupsbackend) )
*(.fimport_homebrew_wupsbackend.*)
} > loadmem
.dimport_homebrew_wupsbackend ALIGN(16) : {
KEEP ( *(.dimport_homebrew_wupsbackend) )
*(.dimport_homebrew_wupsbackend.*)
} > loadmem
.wups.meta : {
*(.wups.meta*)
KEEP(*(.wups.meta*))