diff --git a/.gitignore b/.gitignore index b627c6b..97099d5 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ debug/ *.cbp lib/ cmake-build-debug/ +CMakeLists.txt diff --git a/Dockerfile b/Dockerfile index 0289876..c036558 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM wiiuenv/devkitppc:20210917 +FROM wiiuenv/devkitppc:20210920 WORKDIR tmp_build COPY . . diff --git a/Makefile b/Makefile index add0c2a..05eeae9 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/include/wups.h b/include/wups.h index b4e8a34..011afab 100644 --- a/include/wups.h +++ b/include/wups.h @@ -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_ */ \ No newline at end of file +#include "wups/config_imports.h" +#include "wups/storage.h" diff --git a/include/wups/common.h b/include/wups/common.h index 1614f49..f15b227 100644 --- a/include/wups/common.h +++ b/include/wups/common.h @@ -23,8 +23,7 @@ * SOFTWARE. */ -#ifndef WUPS_COMMON_DEF_H_ -#define WUPS_COMMON_DEF_H_ +#pragma once #include #include @@ -48,5 +47,3 @@ extern "C" { #ifdef __cplusplus } #endif - -#endif /* WUPS_COMMON_DEF_H_ */ diff --git a/include/wups/config.h b/include/wups/config.h new file mode 100644 index 0000000..9be6004 --- /dev/null +++ b/include/wups/config.h @@ -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 . + ****************************************************************************/ + +#pragma once + +#include + +#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; \ No newline at end of file diff --git a/include/wups/config/WUPSConfigItemBoolean.h b/include/wups/config/WUPSConfigItemBoolean.h new file mode 100644 index 0000000..157e0dd --- /dev/null +++ b/include/wups/config/WUPSConfigItemBoolean.h @@ -0,0 +1,40 @@ +#include + +#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 \ No newline at end of file diff --git a/include/wups/config/WUPSConfigItemIntegerRange.h b/include/wups/config/WUPSConfigItemIntegerRange.h new file mode 100644 index 0000000..0dab835 --- /dev/null +++ b/include/wups/config/WUPSConfigItemIntegerRange.h @@ -0,0 +1,33 @@ +#include + +#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 \ No newline at end of file diff --git a/include/wups/config/WUPSConfigItemMultipleValues.h b/include/wups/config/WUPSConfigItemMultipleValues.h new file mode 100644 index 0000000..f297744 --- /dev/null +++ b/include/wups/config/WUPSConfigItemMultipleValues.h @@ -0,0 +1,37 @@ +#include + +#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 \ No newline at end of file diff --git a/include/wups/config_imports.h b/include/wups/config_imports.h new file mode 100644 index 0000000..f759c5a --- /dev/null +++ b/include/wups/config_imports.h @@ -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) diff --git a/include/wups/function_patching.h b/include/wups/function_patching.h index 33caf88..2cd5e8b 100644 --- a/include/wups/function_patching.h +++ b/include/wups/function_patching.h @@ -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 \ No newline at end of file diff --git a/include/wups/hooks.h b/include/wups/hooks.h index e4c4feb..43476d6 100644 --- a/include/wups/hooks.h +++ b/include/wups/hooks.h @@ -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 . ****************************************************************************/ -#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_ */ diff --git a/include/wups/meta.h b/include/wups/meta.h index ca8b870..1c9c005 100644 --- a/include/wups/meta.h +++ b/include/wups/meta.h @@ -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_ */ diff --git a/include/wups/storage.h b/include/wups/storage.h new file mode 100644 index 0000000..bd2b4b8 --- /dev/null +++ b/include/wups/storage.h @@ -0,0 +1,79 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +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 diff --git a/libraries/libwups/WUPSConfigItemBoolean.cpp b/libraries/libwups/WUPSConfigItemBoolean.cpp new file mode 100644 index 0000000..9ebf759 --- /dev/null +++ b/libraries/libwups/WUPSConfigItemBoolean.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#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"); +} diff --git a/libraries/libwups/WUPSConfigItemIntegerRange.cpp b/libraries/libwups/WUPSConfigItemIntegerRange.cpp new file mode 100644 index 0000000..9a4809f --- /dev/null +++ b/libraries/libwups/WUPSConfigItemIntegerRange.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#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; +} \ No newline at end of file diff --git a/libraries/libwups/WUPSConfigItemMultipleValues.cpp b/libraries/libwups/WUPSConfigItemMultipleValues.cpp new file mode 100644 index 0000000..4df0be1 --- /dev/null +++ b/libraries/libwups/WUPSConfigItemMultipleValues.cpp @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#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); +} \ No newline at end of file diff --git a/libraries/libwups/config.def b/libraries/libwups/config.def new file mode 100644 index 0000000..797f37c --- /dev/null +++ b/libraries/libwups/config.def @@ -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 \ No newline at end of file diff --git a/libraries/libwups/main.cpp b/libraries/libwups/main.cpp index 2b8d01f..3b482cf 100644 --- a/libraries/libwups/main.cpp +++ b/libraries/libwups/main.cpp @@ -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; diff --git a/libraries/libwups/storage.cpp b/libraries/libwups/storage.cpp new file mode 100644 index 0000000..53e7d94 --- /dev/null +++ b/libraries/libwups/storage.cpp @@ -0,0 +1,452 @@ +#include +#include +#include + +#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; +} diff --git a/libraries/libwups/utils/base64.cpp b/libraries/libwups/utils/base64.cpp new file mode 100644 index 0000000..f54d06b --- /dev/null +++ b/libraries/libwups/utils/base64.cpp @@ -0,0 +1,128 @@ +#include "base64.h" + +#include + +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; +} diff --git a/libraries/libwups/utils/base64.h b/libraries/libwups/utils/base64.h new file mode 100644 index 0000000..ca4abc5 --- /dev/null +++ b/libraries/libwups/utils/base64.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +// 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 diff --git a/plugins/example_plugin/src/main.cpp b/plugins/example_plugin/src/main.cpp index 4fe1858..30a7280 100644 --- a/plugins/example_plugin/src/main.cpp +++ b/plugins/example_plugin/src/main.cpp @@ -2,17 +2,18 @@ #include #include #include -#include #include #include #include #include #include +#include /** 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; } diff --git a/share/wups.ld b/share/wups.ld index 587d330..5eca072 100644 --- a/share/wups.ld +++ b/share/wups.ld @@ -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*))