mirror of
https://github.com/wiiu-env/homebrew_on_menu_plugin.git
synced 2024-11-22 10:39:16 +01:00
Use libwuhbutils to get data from .whb and libcontentredirection for /vol/save redirection.
This commit is contained in:
parent
f5d8fced32
commit
d044b62b3e
@ -1,7 +1,9 @@
|
|||||||
FROM wiiuenv/devkitppc:20220303
|
FROM wiiuenv/devkitppc:20220417
|
||||||
|
|
||||||
COPY --from=wiiuenv/wiiupluginsystem:20220123 /artifacts $DEVKITPRO
|
COPY --from=wiiuenv/wiiupluginsystem:20220123 /artifacts $DEVKITPRO
|
||||||
COPY --from=wiiuenv/librpxloader:20220212 /artifacts $DEVKITPRO
|
COPY --from=wiiuenv/librpxloader:20220417 /artifacts $DEVKITPRO
|
||||||
COPY --from=wiiuenv/libsdutils:20220303 /artifacts $DEVKITPRO
|
COPY --from=wiiuenv/libsdutils:20220303 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/libwuhbutils:20220415 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/libcontentredirection:20220414 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
WORKDIR project
|
WORKDIR project
|
6
Makefile
6
Makefile
@ -36,17 +36,17 @@ CFLAGS := -Wall -O2 -ffunction-sections \
|
|||||||
|
|
||||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
|
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti
|
CXXFLAGS := $(CFLAGS) -fno-exceptions -fno-rtti -std=c++20
|
||||||
|
|
||||||
ASFLAGS := -g $(ARCH)
|
ASFLAGS := -g $(ARCH)
|
||||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/librpxloader.ld $(WUPSSPECS)
|
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUPSSPECS)
|
||||||
|
|
||||||
ifeq ($(DEBUG),1)
|
ifeq ($(DEBUG),1)
|
||||||
CXXFLAGS += -DDEBUG -g
|
CXXFLAGS += -DDEBUG -g
|
||||||
CFLAGS += -DDEBUG -g
|
CFLAGS += -DDEBUG -g
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIBS := -lwups -lwut -lrpxloader -lsdutils
|
LIBS := -lwups -lwut -lwuhbutils -lcontentredirection -lrpxloader -lsdutils
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level
|
# list of directories containing libraries, this must be the top level
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
#include "FileWrapper.h"
|
#include "FileWrapper.h"
|
||||||
#include "fileinfos.h"
|
#include "fileinfos.h"
|
||||||
|
#include "utils/StringTools.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
#include <coreinit/mutex.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <rpxloader.h>
|
#include <mutex>
|
||||||
|
#include <wuhb_utils/utils.h>
|
||||||
|
|
||||||
FileHandleWrapper gFileHandleWrapper[FILE_WRAPPER_SIZE] __attribute__((section(".data")));
|
FileHandleWrapper gFileHandleWrapper[FILE_WRAPPER_SIZE] __attribute__((section(".data")));
|
||||||
|
|
||||||
extern OSMutex fileWrapperMutex;
|
std::mutex fileWrapperMutex;
|
||||||
|
|
||||||
int FileHandleWrapper_GetSlot() {
|
int FileHandleWrapper_GetSlot() {
|
||||||
OSLockMutex(&fileWrapperMutex);
|
std::lock_guard<std::mutex> lock(fileWrapperMutex);
|
||||||
int res = -1;
|
int res = -1;
|
||||||
for (int i = 0; i < FILE_WRAPPER_SIZE; i++) {
|
for (int i = 0; i < FILE_WRAPPER_SIZE; i++) {
|
||||||
if (!gFileHandleWrapper[i].inUse) {
|
if (!gFileHandleWrapper[i].inUse) {
|
||||||
@ -23,7 +24,6 @@ int FileHandleWrapper_GetSlot() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
OSMemoryBarrier();
|
OSMemoryBarrier();
|
||||||
OSUnlockMutex(&fileWrapperMutex);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,24 +31,22 @@ bool FileHandleWrapper_FreeSlot(uint32_t slot) {
|
|||||||
if (slot >= FILE_WRAPPER_SIZE) {
|
if (slot >= FILE_WRAPPER_SIZE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
OSLockMutex(&fileWrapperMutex);
|
std::lock_guard<std::mutex> lock(fileWrapperMutex);
|
||||||
gFileHandleWrapper[slot].handle = 0;
|
gFileHandleWrapper[slot].handle = 0;
|
||||||
gFileHandleWrapper[slot].inUse = false;
|
gFileHandleWrapper[slot].inUse = false;
|
||||||
OSMemoryBarrier();
|
OSMemoryBarrier();
|
||||||
OSUnlockMutex(&fileWrapperMutex);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileHandleWrapper_FreeAll() {
|
bool FileHandleWrapper_FreeAll() {
|
||||||
OSLockMutex(&fileWrapperMutex);
|
std::lock_guard<std::mutex> lock(fileWrapperMutex);
|
||||||
for (int i = 0; i < FILE_WRAPPER_SIZE; i++) {
|
for (int i = 0; i < FILE_WRAPPER_SIZE; i++) {
|
||||||
FileHandleWrapper_FreeSlot(i);
|
FileHandleWrapper_FreeSlot(i);
|
||||||
}
|
}
|
||||||
OSUnlockMutex(&fileWrapperMutex);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int OpenFileForID(int id, const char *filepath, int *handle) {
|
int OpenFileForID(int id, const char *filepath, uint32_t *handle) {
|
||||||
if (!mountRomfs(id)) {
|
if (!mountRomfs(id)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -68,29 +66,29 @@ int OpenFileForID(int id, const char *filepath, int *handle) {
|
|||||||
}
|
}
|
||||||
last = filepath[i];
|
last = filepath[i];
|
||||||
}
|
}
|
||||||
dyn_path[j++] = 0;
|
dyn_path[j] = 0;
|
||||||
|
|
||||||
char completePath[256];
|
auto completePath = string_format("%s:/%s", romName, dyn_path);
|
||||||
snprintf(completePath, 256, "%s:/%s", romName, dyn_path);
|
|
||||||
free(dyn_path);
|
|
||||||
|
|
||||||
uint32_t out_handle = 0;
|
WUHBFileHandle fileHandle = 0;
|
||||||
if (RL_FileOpen(completePath, &out_handle) == 0) {
|
if (WUHBUtils_FileOpen(completePath.c_str(), &fileHandle) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||||
int handle_wrapper_slot = FileHandleWrapper_GetSlot();
|
int handle_wrapper_slot = FileHandleWrapper_GetSlot();
|
||||||
|
|
||||||
if (handle_wrapper_slot < 0) {
|
if (handle_wrapper_slot < 0) {
|
||||||
DEBUG_FUNCTION_LINE("No free slot");
|
DEBUG_FUNCTION_LINE_ERR("No free slot");
|
||||||
RL_FileClose(out_handle);
|
if (WUHBUtils_FileClose(fileHandle) != WUHB_UTILS_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to close file %08X", fileHandle);
|
||||||
|
}
|
||||||
unmountRomfs(id);
|
unmountRomfs(id);
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
gFileHandleWrapper[handle_wrapper_slot].handle = out_handle;
|
gFileHandleWrapper[handle_wrapper_slot].handle = fileHandle;
|
||||||
*handle = 0xFF000000 | (id << 12) | (handle_wrapper_slot & 0x00000FFF);
|
*handle = 0xFF000000 | (id << 12) | (handle_wrapper_slot & 0x00000FFF);
|
||||||
gFileInfos[id].openedFiles++;
|
gFileInfos[id].openedFiles++;
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to open file %s", filepath);
|
||||||
if (gFileInfos[id].openedFiles == 0) {
|
if (gFileInfos[id].openedFiles == 0) {
|
||||||
DEBUG_FUNCTION_LINE("unmount");
|
|
||||||
unmountRomfs(id);
|
unmountRomfs(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,5 +9,5 @@ typedef struct FileHandleWrapper_t {
|
|||||||
#define FILE_WRAPPER_SIZE 64
|
#define FILE_WRAPPER_SIZE 64
|
||||||
extern FileHandleWrapper gFileHandleWrapper[FILE_WRAPPER_SIZE];
|
extern FileHandleWrapper gFileHandleWrapper[FILE_WRAPPER_SIZE];
|
||||||
|
|
||||||
int OpenFileForID(int id, const char *path, int32_t *handle);
|
int OpenFileForID(int id, const char *path, uint32_t *handle);
|
||||||
bool FileHandleWrapper_FreeAll();
|
bool FileHandleWrapper_FreeAll();
|
@ -1,5 +1,5 @@
|
|||||||
#include "SaveRedirection.h"
|
#include "SaveRedirection.h"
|
||||||
#include <coreinit/filesystem.h>
|
#include <content_redirection/redirection.h>
|
||||||
#include <coreinit/title.h>
|
#include <coreinit/title.h>
|
||||||
#include <fs/FSUtils.h>
|
#include <fs/FSUtils.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -10,25 +10,18 @@
|
|||||||
#include <utils/logger.h>
|
#include <utils/logger.h>
|
||||||
#include <wups.h>
|
#include <wups.h>
|
||||||
|
|
||||||
bool gInWiiUMenu __attribute__((section(".data")));
|
bool gInWiiUMenu __attribute__((section(".data"))) = false;
|
||||||
|
CRLayerHandle saveLayer __attribute__((section(".data"))) = 0;
|
||||||
|
|
||||||
static FSStatus CallWithNewPath(const char *oldPath, const std::function<FSStatus(const char *)> &callFunctionWithPath) {
|
void SaveRedirectionCleanUp() {
|
||||||
if (!sSDIsMounted || !gInWiiUMenu || strncmp(oldPath, "/vol/save/", 10) != 0) {
|
if (saveLayer != 0) {
|
||||||
return callFunctionWithPath(oldPath);
|
auto res = ContentRedirection_RemoveFSLayer(saveLayer);
|
||||||
|
if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to remove save FSLayer");
|
||||||
|
}
|
||||||
|
saveLayer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *newPath = (char *) malloc(0x280);
|
|
||||||
if (!newPath) {
|
|
||||||
return FS_STATUS_FATAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(newPath, 0x27F, SAVE_REPLACEMENT_PATH "/save/%s", &oldPath[10]);
|
|
||||||
|
|
||||||
auto res = callFunctionWithPath(newPath);
|
|
||||||
free(newPath);
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initSaveData() {
|
void initSaveData() {
|
||||||
nn::act::Initialize();
|
nn::act::Initialize();
|
||||||
nn::act::PersistentId persistentId = nn::act::GetPersistentId();
|
nn::act::PersistentId persistentId = nn::act::GetPersistentId();
|
||||||
@ -36,8 +29,8 @@ void initSaveData() {
|
|||||||
|
|
||||||
std::string common = "fs:" SAVE_REPLACEMENT_PATH "/save/common";
|
std::string common = "fs:" SAVE_REPLACEMENT_PATH "/save/common";
|
||||||
std::string commonOriginal = "fs:/vol/save/common";
|
std::string commonOriginal = "fs:/vol/save/common";
|
||||||
std::string user = StringTools::strfmt("fs:" SAVE_REPLACEMENT_PATH "/save/%08X", 0x80000000 | persistentId);
|
std::string user = string_format("fs:" SAVE_REPLACEMENT_PATH "/save/%08X", 0x80000000 | persistentId);
|
||||||
std::string userOriginal = StringTools::strfmt("fs:/vol/save/%08X", 0x80000000 | persistentId);
|
std::string userOriginal = string_format("fs:/vol/save/%08X", 0x80000000 | persistentId);
|
||||||
|
|
||||||
FSUtils::CreateSubfolder(common.c_str());
|
FSUtils::CreateSubfolder(common.c_str());
|
||||||
FSUtils::CreateSubfolder(user.c_str());
|
FSUtils::CreateSubfolder(user.c_str());
|
||||||
@ -46,77 +39,39 @@ void initSaveData() {
|
|||||||
auto BaristaAccountSaveFilePathOriginal = userOriginal + "/BaristaAccountSaveFile.dat";
|
auto BaristaAccountSaveFilePathOriginal = userOriginal + "/BaristaAccountSaveFile.dat";
|
||||||
if (!FSUtils::CheckFile(BaristaAccountSaveFilePathNew.c_str())) {
|
if (!FSUtils::CheckFile(BaristaAccountSaveFilePathNew.c_str())) {
|
||||||
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str());
|
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str());
|
||||||
FSUtils::copyFile(BaristaAccountSaveFilePathOriginal, BaristaAccountSaveFilePathNew);
|
if (!FSUtils::copyFile(BaristaAccountSaveFilePathOriginal, BaristaAccountSaveFilePathNew)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaAccountSaveFilePathOriginal.c_str(), BaristaAccountSaveFilePathNew.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto BaristaCommonSaveFile = common + "/BaristaCommonSaveFile.dat";
|
auto BaristaCommonSaveFile = common + "/BaristaCommonSaveFile.dat";
|
||||||
auto BaristaCommonSaveFileOriginal = commonOriginal + "/BaristaCommonSaveFile.dat";
|
auto BaristaCommonSaveFileOriginal = commonOriginal + "/BaristaCommonSaveFile.dat";
|
||||||
if (!FSUtils::CheckFile(BaristaCommonSaveFile.c_str())) {
|
if (!FSUtils::CheckFile(BaristaCommonSaveFile.c_str())) {
|
||||||
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str());
|
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str());
|
||||||
FSUtils::copyFile(BaristaCommonSaveFileOriginal, BaristaCommonSaveFile);
|
if (!FSUtils::copyFile(BaristaCommonSaveFileOriginal, BaristaCommonSaveFile)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaCommonSaveFileOriginal.c_str(), BaristaCommonSaveFile.c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto BaristaIconDataBase = common + "/BaristaIconDataBase.dat";
|
auto BaristaIconDataBase = common + "/BaristaIconDataBase.dat";
|
||||||
auto BaristaIconDataBaseOriginal = commonOriginal + "/BaristaIconDataBase.dat";
|
auto BaristaIconDataBaseOriginal = commonOriginal + "/BaristaIconDataBase.dat";
|
||||||
if (!FSUtils::CheckFile(BaristaIconDataBase.c_str())) {
|
if (!FSUtils::CheckFile(BaristaIconDataBase.c_str())) {
|
||||||
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str());
|
DEBUG_FUNCTION_LINE("Copy %s to %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str());
|
||||||
FSUtils::copyFile(BaristaIconDataBaseOriginal, BaristaIconDataBase);
|
if (!FSUtils::copyFile(BaristaIconDataBaseOriginal, BaristaIconDataBase)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to copy file: %s -> %s", BaristaIconDataBaseOriginal.c_str(), BaristaIconDataBase.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SaveRedirectionCleanUp();
|
||||||
|
auto res = ContentRedirection_AddFSLayer(&saveLayer, "homp_save_redirection", "fs:" SAVE_REPLACEMENT_PATH "/save/", FS_LAYER_TYPE_SAVE_REPLACE);
|
||||||
|
if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add save FS Layer: %d", res);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
DECL_FUNCTION(FSStatus, FSOpenFileAsync, FSClient *client, FSCmdBlock *block, const char *path, const char *mode, FSFileHandle *outHandle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
|
||||||
return CallWithNewPath(path, [client, block, mode, outHandle, errorMask, asyncData](const char *_path) -> FSStatus {
|
|
||||||
DEBUG_FUNCTION_LINE("Call FSOpenFileAsync %s", _path);
|
|
||||||
return real_FSOpenFileAsync(client, block, _path, mode, outHandle, errorMask, asyncData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DECL_FUNCTION(FSStatus, FSGetStatAsync, FSClient *client, FSCmdBlock *block, const char *path, FSStat *stat, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
|
||||||
return CallWithNewPath(path, [client, block, stat, errorMask, asyncData](const char *_path) -> FSStatus {
|
|
||||||
DEBUG_FUNCTION_LINE("Call FSGetStatAsync %s", _path);
|
|
||||||
return real_FSGetStatAsync(client, block, _path, stat, errorMask, asyncData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DECL_FUNCTION(FSStatus, FSRemoveAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
|
||||||
return CallWithNewPath(path, [client, block, errorMask, asyncData](const char *_path) -> FSStatus {
|
|
||||||
DEBUG_FUNCTION_LINE("Call FSRemoveAsync %s", _path);
|
|
||||||
return real_FSRemoveAsync(client, block, _path, errorMask, asyncData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DECL_FUNCTION(FSStatus, FSOpenDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
|
||||||
return CallWithNewPath(path, [client, block, handle, errorMask, asyncData](const char *_path) -> FSStatus {
|
|
||||||
DEBUG_FUNCTION_LINE("Call FSOpenDirAsync %s", _path);
|
|
||||||
return real_FSOpenDirAsync(client, block, _path, handle, errorMask, asyncData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DECL_FUNCTION(FSStatus, FSMakeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
|
||||||
return CallWithNewPath(path, [client, block, errorMask, asyncData](const char *_path) -> FSStatus {
|
|
||||||
DEBUG_FUNCTION_LINE("Call FSMakeDirAsync %s", _path);
|
|
||||||
return real_FSMakeDirAsync(client, block, _path, errorMask, asyncData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DECL_FUNCTION(FSStatus, FSChangeModeAsync, FSClient *client, FSCmdBlock *block, const char *path, FSMode mode, FSMode modeMask, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
|
||||||
return CallWithNewPath(path, [client, block, mode, modeMask, errorMask, asyncData](const char *_path) -> FSStatus {
|
|
||||||
DEBUG_FUNCTION_LINE("Call FSChangeModeAsync %s", _path);
|
|
||||||
return real_FSChangeModeAsync(client, block, _path, mode, modeMask, errorMask, asyncData);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
|
||||||
return CallWithNewPath(path, [client, block, errorMask, asyncData](const char *_path) -> FSStatus {
|
|
||||||
DEBUG_FUNCTION_LINE("Call FSChangeDirAsync %s", _path);
|
|
||||||
return real_FSChangeDirAsync(client, block, _path, errorMask, asyncData);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DECL_FUNCTION(int32_t, LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb, nn::act::SlotNo slot, nn::act::ACTLoadOption unk1, char const *unk2, bool unk3) {
|
DECL_FUNCTION(int32_t, LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb, nn::act::SlotNo slot, nn::act::ACTLoadOption unk1, char const *unk2, bool unk3) {
|
||||||
int32_t result = real_LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb(slot, unk1, unk2, unk3);
|
int32_t result = real_LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb(slot, unk1, unk2, unk3);
|
||||||
if (result >= 0 && gInWiiUMenu) {
|
if (result >= 0 && gInWiiUMenu) {
|
||||||
DEBUG_FUNCTION_LINE("changed account, init save data");
|
DEBUG_FUNCTION_LINE_VERBOSE("Changed account, we need to init the save data");
|
||||||
// If the account has changed, we need to init save data for this account
|
// If the account has changed, we need to init save data for this account
|
||||||
// Calls our function replacement.
|
// Calls our function replacement.
|
||||||
SAVEInit();
|
SAVEInit();
|
||||||
@ -131,7 +86,6 @@ DECL_FUNCTION(int32_t, SAVEInit) {
|
|||||||
if (OSGetTitleID() == 0x0005001010040000L || // Wii U Menu JPN
|
if (OSGetTitleID() == 0x0005001010040000L || // Wii U Menu JPN
|
||||||
OSGetTitleID() == 0x0005001010040100L || // Wii U Menu USA
|
OSGetTitleID() == 0x0005001010040100L || // Wii U Menu USA
|
||||||
OSGetTitleID() == 0x0005001010040200L) { // Wii U Menu EUR
|
OSGetTitleID() == 0x0005001010040200L) { // Wii U Menu EUR
|
||||||
DEBUG_FUNCTION_LINE("Init Save redirection");
|
|
||||||
|
|
||||||
initSaveData();
|
initSaveData();
|
||||||
gInWiiUMenu = true;
|
gInWiiUMenu = true;
|
||||||
@ -143,14 +97,5 @@ DECL_FUNCTION(int32_t, SAVEInit) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WUPS_MUST_REPLACE(SAVEInit, WUPS_LOADER_LIBRARY_NN_SAVE, SAVEInit);
|
WUPS_MUST_REPLACE(SAVEInit, WUPS_LOADER_LIBRARY_NN_SAVE, SAVEInit);
|
||||||
WUPS_MUST_REPLACE(FSOpenFileAsync, WUPS_LOADER_LIBRARY_COREINIT, FSOpenFileAsync);
|
|
||||||
WUPS_MUST_REPLACE(FSOpenDirAsync, WUPS_LOADER_LIBRARY_COREINIT, FSOpenDirAsync);
|
|
||||||
WUPS_MUST_REPLACE(FSRemoveAsync, WUPS_LOADER_LIBRARY_COREINIT, FSRemoveAsync);
|
|
||||||
WUPS_MUST_REPLACE(FSMakeDirAsync, WUPS_LOADER_LIBRARY_COREINIT, FSMakeDirAsync);
|
|
||||||
// WUPS_MUST_REPLACE(FSRenameAsync, WUPS_LOADER_LIBRARY_COREINIT, FSRenameAsync);
|
|
||||||
WUPS_MUST_REPLACE(FSChangeDirAsync, WUPS_LOADER_LIBRARY_COREINIT, FSChangeDirAsync);
|
|
||||||
WUPS_MUST_REPLACE(FSChangeModeAsync, WUPS_LOADER_LIBRARY_COREINIT, FSChangeModeAsync);
|
|
||||||
WUPS_MUST_REPLACE(FSGetStatAsync, WUPS_LOADER_LIBRARY_COREINIT, FSGetStatAsync);
|
|
||||||
WUPS_MUST_REPLACE(LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb, WUPS_LOADER_LIBRARY_NN_ACT, LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb);
|
WUPS_MUST_REPLACE(LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb, WUPS_LOADER_LIBRARY_NN_ACT, LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb);
|
@ -1,9 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
extern bool gInWiiUMenu;
|
extern bool gInWiiUMenu;
|
||||||
extern bool sSDIsMounted;
|
|
||||||
|
|
||||||
#define SAVE_REPLACEMENT_PATH "/vol/external01/wiiu/homebrew_on_menu_plugin"
|
#define SAVE_REPLACEMENT_PATH "/vol/external01/wiiu/homebrew_on_menu_plugin"
|
||||||
|
|
||||||
void InitSaveData();
|
void SaveRedirectionCleanUp();
|
@ -1,16 +1,16 @@
|
|||||||
#include "fileinfos.h"
|
#include "fileinfos.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
#include <coreinit/mutex.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <rpxloader.h>
|
#include <mutex>
|
||||||
|
#include <wuhb_utils/utils.h>
|
||||||
|
|
||||||
FileInfos gFileInfos[FILE_INFO_SIZE] __attribute__((section(".data")));
|
FileInfos gFileInfos[FILE_INFO_SIZE] __attribute__((section(".data")));
|
||||||
extern OSMutex fileinfoMutex;
|
std::mutex fileinfoMutex;
|
||||||
|
|
||||||
int32_t getIDByLowerTitleID(uint32_t lowerTitleID) {
|
int32_t getIDByLowerTitleID(uint32_t lowerTitleID) {
|
||||||
OSLockMutex(&fileinfoMutex);
|
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||||
int res = -1;
|
int res = -1;
|
||||||
for (int i = 0; i < FILE_INFO_SIZE; i++) {
|
for (int i = 0; i < FILE_INFO_SIZE; i++) {
|
||||||
if (strlen(gFileInfos[i].path) > 0 && gFileInfos[i].lowerTitleID == lowerTitleID) {
|
if (strlen(gFileInfos[i].path) > 0 && gFileInfos[i].lowerTitleID == lowerTitleID) {
|
||||||
@ -19,7 +19,6 @@ int32_t getIDByLowerTitleID(uint32_t lowerTitleID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
OSMemoryBarrier();
|
OSMemoryBarrier();
|
||||||
OSUnlockMutex(&fileinfoMutex);
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,17 +26,17 @@ void unmountRomfs(uint32_t id) {
|
|||||||
if (id >= FILE_INFO_SIZE) {
|
if (id >= FILE_INFO_SIZE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OSLockMutex(&fileinfoMutex);
|
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||||
if (gFileInfos[id].romfsMounted) {
|
if (gFileInfos[id].romfsMounted) {
|
||||||
char romName[10];
|
char romName[10];
|
||||||
snprintf(romName, 10, "%08X", id);
|
snprintf(romName, 10, "%08X", id);
|
||||||
DEBUG_FUNCTION_LINE("Unmounting %s", romName);
|
int32_t outRes;
|
||||||
int res = RL_UnmountBundle(romName);
|
if (WUHBUtils_UnmountBundle(romName, &outRes) || outRes != 0) {
|
||||||
DEBUG_FUNCTION_LINE("res: %d", res);
|
DEBUG_FUNCTION_LINE_ERR("Failed to unmount \"%s\"", romName);
|
||||||
|
}
|
||||||
gFileInfos[id].romfsMounted = false;
|
gFileInfos[id].romfsMounted = false;
|
||||||
}
|
}
|
||||||
OSMemoryBarrier();
|
OSMemoryBarrier();
|
||||||
OSUnlockMutex(&fileinfoMutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unmountAllRomfs() {
|
void unmountAllRomfs() {
|
||||||
@ -48,10 +47,10 @@ void unmountAllRomfs() {
|
|||||||
|
|
||||||
bool mountRomfs(uint32_t id) {
|
bool mountRomfs(uint32_t id) {
|
||||||
if (id >= FILE_INFO_SIZE) {
|
if (id >= FILE_INFO_SIZE) {
|
||||||
DEBUG_FUNCTION_LINE("HANDLE WAS TOO BIG %d", id);
|
DEBUG_FUNCTION_LINE_ERR("HANDLE WAS TOO BIG %d", id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
OSLockMutex(&fileinfoMutex);
|
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if (!gFileInfos[id].romfsMounted) {
|
if (!gFileInfos[id].romfsMounted) {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
@ -60,17 +59,16 @@ bool mountRomfs(uint32_t id) {
|
|||||||
snprintf(romName, 10, "%08X", id);
|
snprintf(romName, 10, "%08X", id);
|
||||||
DEBUG_FUNCTION_LINE("Mount %s as %s", buffer, romName);
|
DEBUG_FUNCTION_LINE("Mount %s as %s", buffer, romName);
|
||||||
int32_t res = 0;
|
int32_t res = 0;
|
||||||
if ((res = RL_MountBundle(romName, buffer, BundleSource_FileDescriptor_CafeOS)) == 0) {
|
if (WUHBUtils_MountBundle(romName, buffer, BundleSource_FileDescriptor_CafeOS, &res) == WUHB_UTILS_RESULT_SUCCESS && res == 0) {
|
||||||
DEBUG_FUNCTION_LINE("Mounted successfully ");
|
DEBUG_FUNCTION_LINE("Mounted successfully ");
|
||||||
gFileInfos[id].romfsMounted = true;
|
gFileInfos[id].romfsMounted = true;
|
||||||
result = true;
|
result = true;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("Mounting failed %d", res);
|
DEBUG_FUNCTION_LINE_ERR("Mounting failed %d", res);
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OSMemoryBarrier();
|
OSMemoryBarrier();
|
||||||
OSUnlockMutex(&fileinfoMutex);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
#include <coreinit/mcp.h>
|
#include <coreinit/mcp.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
extern std::mutex fileinfoMutex;
|
||||||
|
|
||||||
typedef struct WUT_PACKED FileInfos_ {
|
typedef struct WUT_PACKED FileInfos_ {
|
||||||
char path[256];
|
char path[256];
|
||||||
|
185
src/main.cpp
185
src/main.cpp
@ -5,6 +5,7 @@
|
|||||||
#include "fs/FSUtils.h"
|
#include "fs/FSUtils.h"
|
||||||
#include "utils/StringTools.h"
|
#include "utils/StringTools.h"
|
||||||
#include "utils/ini.h"
|
#include "utils/ini.h"
|
||||||
|
#include <content_redirection/redirection.h>
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
#include <coreinit/debug.h>
|
#include <coreinit/debug.h>
|
||||||
#include <coreinit/filesystem.h>
|
#include <coreinit/filesystem.h>
|
||||||
@ -15,11 +16,14 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fs/DirList.h>
|
#include <fs/DirList.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
#include <mutex>
|
||||||
#include <nn/acp.h>
|
#include <nn/acp.h>
|
||||||
#include <rpxloader.h>
|
#include <rpxloader/rpxloader.h>
|
||||||
#include <sdutils/sdutils.h>
|
#include <sdutils/sdutils.h>
|
||||||
|
#include <sysapp/launch.h>
|
||||||
#include <sysapp/title.h>
|
#include <sysapp/title.h>
|
||||||
#include <utils/logger.h>
|
#include <utils/logger.h>
|
||||||
|
#include <wuhb_utils/utils.h>
|
||||||
#include <wups.h>
|
#include <wups.h>
|
||||||
|
|
||||||
typedef struct ACPMetaData {
|
typedef struct ACPMetaData {
|
||||||
@ -43,30 +47,44 @@ BOOL gHomebrewLaunched __attribute__((section(".data")));
|
|||||||
|
|
||||||
void readCustomTitlesFromSD();
|
void readCustomTitlesFromSD();
|
||||||
|
|
||||||
extern "C" void _SYSLaunchTitleWithStdArgsInNoSplash(uint64_t, uint32_t);
|
|
||||||
|
|
||||||
WUPS_USE_WUT_DEVOPTAB();
|
WUPS_USE_WUT_DEVOPTAB();
|
||||||
|
|
||||||
OSMutex fileWrapperMutex;
|
|
||||||
OSMutex fileinfoMutex;
|
|
||||||
|
|
||||||
INITIALIZE_PLUGIN() {
|
INITIALIZE_PLUGIN() {
|
||||||
memset((void *) ¤t_launched_title_info, 0, sizeof(current_launched_title_info));
|
memset((void *) ¤t_launched_title_info, 0, sizeof(current_launched_title_info));
|
||||||
memset((void *) &gLaunchXML, 0, sizeof(gLaunchXML));
|
memset((void *) &gLaunchXML, 0, sizeof(gLaunchXML));
|
||||||
memset((void *) &gFileInfos, 0, sizeof(gFileInfos));
|
memset((void *) &gFileInfos, 0, sizeof(gFileInfos));
|
||||||
memset((void *) &gFileHandleWrapper, 0, sizeof(gFileHandleWrapper));
|
memset((void *) &gFileHandleWrapper, 0, sizeof(gFileHandleWrapper));
|
||||||
gHomebrewLaunched = FALSE;
|
gHomebrewLaunched = FALSE;
|
||||||
OSInitMutex(&fileWrapperMutex);
|
|
||||||
OSInitMutex(&fileinfoMutex);
|
// Use libwuhbutils.
|
||||||
|
WUHBUtilsStatus error;
|
||||||
|
if ((error = WUHBUtils_Init()) != WUHB_UTILS_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Homebrew on Menu Plugin: Failed to init WUHBUtils. Error %d", error);
|
||||||
|
OSFatal("Homebrew on Menu Plugin: Failed to init WUHBUtils.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use libcontentredirection.
|
||||||
|
ContentRedirectionStatus error2;
|
||||||
|
if ((error2 = ContentRedirection_Init()) != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Homebrew on Menu Plugin: Failed to init ContentRedirection. Error %d", error2);
|
||||||
|
OSFatal("Homebrew on Menu Plugin: Failed to init ContentRedirection.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use librpxloader.
|
||||||
|
RPXLoaderStatus error3;
|
||||||
|
if ((error3 = RPXLoader_Init()) != RPX_LOADER_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Homebrew on Menu Plugin: Failed to init RPXLoader. Error %d", error3);
|
||||||
|
OSFatal("Homebrew on Menu Plugin: Failed to init RPXLoader.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sSDUtilsInitDone = false;
|
bool sSDUtilsInitDone = false;
|
||||||
bool sSDIsMounted = false;
|
bool sSDIsMounted = false;
|
||||||
bool sTitleRebooting = false;
|
bool sTitleRebooting = false;
|
||||||
|
|
||||||
void SDAttachedHandler(SDUtilsAttachStatus status) {
|
void SDAttachedHandler([[maybe_unused]] SDUtilsAttachStatus status) {
|
||||||
if (!sTitleRebooting) {
|
if (!sTitleRebooting) {
|
||||||
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), 0);
|
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
|
||||||
sTitleRebooting = true;
|
sTitleRebooting = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -97,6 +115,7 @@ ON_APPLICATION_START() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ON_APPLICATION_ENDS() {
|
ON_APPLICATION_ENDS() {
|
||||||
|
SaveRedirectionCleanUp();
|
||||||
unmountAllRomfs();
|
unmountAllRomfs();
|
||||||
memset((void *) &gFileInfos, 0, sizeof(gFileInfos));
|
memset((void *) &gFileInfos, 0, sizeof(gFileInfos));
|
||||||
FileHandleWrapper_FreeAll();
|
FileHandleWrapper_FreeAll();
|
||||||
@ -113,7 +132,7 @@ ON_APPLICATION_ENDS() {
|
|||||||
void fillXmlForTitleID(uint32_t titleid_upper, uint32_t titleid_lower, ACPMetaXml *out_buf) {
|
void fillXmlForTitleID(uint32_t titleid_upper, uint32_t titleid_lower, ACPMetaXml *out_buf) {
|
||||||
int32_t id = getIDByLowerTitleID(titleid_lower);
|
int32_t id = getIDByLowerTitleID(titleid_lower);
|
||||||
if (id < 0) {
|
if (id < 0) {
|
||||||
DEBUG_FUNCTION_LINE("Failed to get id by titleid");
|
DEBUG_FUNCTION_LINE_ERR("Failed to get id by titleid");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (id >= FILE_INFO_SIZE) {
|
if (id >= FILE_INFO_SIZE) {
|
||||||
@ -160,7 +179,6 @@ static int handler(void *user, const char *section, const char *name,
|
|||||||
auto *fInfo = (FileInfos *) user;
|
auto *fInfo = (FileInfos *) user;
|
||||||
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("%s %s %s", section, name, value);
|
|
||||||
if (MATCH("menu", "longname")) {
|
if (MATCH("menu", "longname")) {
|
||||||
strncpy(fInfo->longname, value, 64 - 1);
|
strncpy(fInfo->longname, value, 64 - 1);
|
||||||
} else if (MATCH("menu", "shortname")) {
|
} else if (MATCH("menu", "shortname")) {
|
||||||
@ -174,6 +192,7 @@ static int handler(void *user, const char *section, const char *name,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckFileExistsHelper(const char *path);
|
||||||
void readCustomTitlesFromSD() {
|
void readCustomTitlesFromSD() {
|
||||||
// Reset current infos
|
// Reset current infos
|
||||||
unmountAllRomfs();
|
unmountAllRomfs();
|
||||||
@ -185,7 +204,7 @@ void readCustomTitlesFromSD() {
|
|||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < dirList.GetFilecount(); i++) {
|
for (int i = 0; i < dirList.GetFilecount(); i++) {
|
||||||
if (j >= FILE_INFO_SIZE) {
|
if (j >= FILE_INFO_SIZE) {
|
||||||
DEBUG_FUNCTION_LINE("TOO MANY TITLES");
|
DEBUG_FUNCTION_LINE_ERR("TOO MANY TITLES");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,14 +228,14 @@ void readCustomTitlesFromSD() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *repl = (char *) "fs:/vol/external01/";
|
auto repl = "fs:/vol/external01/";
|
||||||
char *with = (char *) "";
|
auto input = dirList.GetFilepath(i);
|
||||||
char *input = (char *) dirList.GetFilepath(i);
|
|
||||||
|
|
||||||
char *path = StringTools::str_replace(input, repl, with);
|
if (std::string_view(input).starts_with(repl)) {
|
||||||
if (path != nullptr) {
|
strncpy(gFileInfos[j].path, &input[strlen(repl)], sizeof(gFileInfos[j].path));
|
||||||
strncpy(gFileInfos[j].path, path, 255);
|
} else {
|
||||||
free(path);
|
DEBUG_FUNCTION_LINE_ERR("Skip %s, Path doesn't start with %s (This should never happen", input, repl);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
gFileInfos[j].lowerTitleID = hash(gFileInfos[j].path);
|
gFileInfos[j].lowerTitleID = hash(gFileInfos[j].path);
|
||||||
@ -237,52 +256,45 @@ void readCustomTitlesFromSD() {
|
|||||||
// System apps don't have a splash screen.
|
// System apps don't have a splash screen.
|
||||||
cur_title_info->appType = MCP_APP_TYPE_SYSTEM_APPS;
|
cur_title_info->appType = MCP_APP_TYPE_SYSTEM_APPS;
|
||||||
|
|
||||||
// Check if the have bootTvTex and bootDrcTex that could be shown.
|
// Check if the bootTvTex and bootDrcTex exists
|
||||||
if (StringTools::EndsWith(gFileInfos[j].filename, ".wuhb")) {
|
if (std::string_view(gFileInfos[j].filename).ends_with(".wuhb")) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
if ((result = RL_MountBundle("romfscheck", dirList.GetFilepath(i), BundleSource_FileDescriptor)) == 0) {
|
|
||||||
uint32_t file_handle = 0;
|
|
||||||
if (RL_FileOpen("romfscheck:/meta/meta.ini", &file_handle) == 0) {
|
|
||||||
// this buffer should be big enough for our .ini
|
|
||||||
char *ini_buffer = (char *) memalign(0x40, 0x1000);
|
|
||||||
if (ini_buffer) {
|
|
||||||
memset(ini_buffer, 0, 0x1000);
|
|
||||||
uint32_t offset = 0;
|
|
||||||
uint32_t toRead = 0x1000;
|
|
||||||
do {
|
|
||||||
int res = RL_FileRead(file_handle, reinterpret_cast<uint8_t *>(&ini_buffer[offset]), toRead);
|
|
||||||
if (res <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
offset += res;
|
|
||||||
toRead -= res;
|
|
||||||
} while (offset < sizeof(ini_buffer));
|
|
||||||
|
|
||||||
if (ini_parse_string(ini_buffer, handler, &gFileInfos[j]) < 0) {
|
#define TMP_BUNDLE_NAME "romfscheck"
|
||||||
DEBUG_FUNCTION_LINE("Failed to parse ini");
|
|
||||||
}
|
if (WUHBUtils_MountBundle(TMP_BUNDLE_NAME, dirList.GetFilepath(i), BundleSource_FileDescriptor, &result) == WUHB_UTILS_RESULT_SUCCESS && result >= 0) {
|
||||||
free(ini_buffer);
|
uint8_t *buffer;
|
||||||
} else {
|
uint32_t bufferSize;
|
||||||
DEBUG_FUNCTION_LINE("Failed to alloc memory");
|
|
||||||
|
auto readRes = WUHBUtils_ReadWholeFile(TMP_BUNDLE_NAME ":/meta/meta.ini", &buffer, &bufferSize);
|
||||||
|
if (readRes == WUHB_UTILS_RESULT_SUCCESS) {
|
||||||
|
buffer[bufferSize - 1] = '\0';
|
||||||
|
if (ini_parse_string((const char *) buffer, handler, &gFileInfos[j]) < 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to parse meta.ini");
|
||||||
}
|
}
|
||||||
|
free(buffer);
|
||||||
RL_FileClose(file_handle);
|
buffer = nullptr;
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to open or read meta.ini: %d", readRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool foundSplashScreens = true;
|
auto bootTvTexPath = TMP_BUNDLE_NAME ":/meta/bootTvTex.tga";
|
||||||
if (!RL_FileExists("romfscheck:/meta/bootTvTex.tga")) {
|
auto bootDrcTexPath = TMP_BUNDLE_NAME ":/meta/bootDrcTex.tga";
|
||||||
foundSplashScreens = false;
|
if (CheckFileExistsHelper(bootTvTexPath) && CheckFileExistsHelper(bootDrcTexPath)) {
|
||||||
}
|
|
||||||
if (!RL_FileExists("romfscheck:/meta/bootDrcTex.tga")) {
|
|
||||||
foundSplashScreens = false;
|
|
||||||
}
|
|
||||||
if (foundSplashScreens) {
|
|
||||||
// Show splash screens
|
// Show splash screens
|
||||||
cur_title_info->appType = MCP_APP_TYPE_GAME;
|
cur_title_info->appType = MCP_APP_TYPE_GAME;
|
||||||
}
|
}
|
||||||
RL_UnmountBundle("romfscheck");
|
|
||||||
|
int32_t unmountRes;
|
||||||
|
if (WUHBUtils_UnmountBundle(TMP_BUNDLE_NAME, &unmountRes) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||||
|
if (unmountRes != 0) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Unmount result was \"%s\"", TMP_BUNDLE_NAME);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to unmount \"%s\"", TMP_BUNDLE_NAME);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("%s is not a valid .wuhb file: %d", dirList.GetFilepath(i), result);
|
DEBUG_FUNCTION_LINE("%s is not a .wuhb file: %d", dirList.GetFilepath(i), result);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -299,11 +311,26 @@ void readCustomTitlesFromSD() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CheckFileExistsHelper(const char *path) {
|
||||||
|
int32_t exists;
|
||||||
|
int32_t res;
|
||||||
|
if ((res = WUHBUtils_FileExists(path, &exists)) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||||
|
if (!exists) {
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("## WARN ##: Missing %s", path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to check if %s exists: %d", path, res);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
DECL_FUNCTION(int32_t, MCP_TitleList, uint32_t handle, uint32_t *outTitleCount, MCPTitleListType *titleList, uint32_t size) {
|
DECL_FUNCTION(int32_t, MCP_TitleList, uint32_t handle, uint32_t *outTitleCount, MCPTitleListType *titleList, uint32_t size) {
|
||||||
int32_t result = real_MCP_TitleList(handle, outTitleCount, titleList, size);
|
int32_t result = real_MCP_TitleList(handle, outTitleCount, titleList, size);
|
||||||
uint32_t titlecount = *outTitleCount;
|
uint32_t titlecount = *outTitleCount;
|
||||||
|
|
||||||
OSLockMutex(&fileinfoMutex);
|
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||||
for (auto &gFileInfo : gFileInfos) {
|
for (auto &gFileInfo : gFileInfos) {
|
||||||
if (gFileInfo.lowerTitleID == 0) {
|
if (gFileInfo.lowerTitleID == 0) {
|
||||||
break;
|
break;
|
||||||
@ -311,7 +338,6 @@ DECL_FUNCTION(int32_t, MCP_TitleList, uint32_t handle, uint32_t *outTitleCount,
|
|||||||
memcpy(&(titleList[titlecount]), &(gFileInfo.titleInfo), sizeof(gFileInfo.titleInfo));
|
memcpy(&(titleList[titlecount]), &(gFileInfo.titleInfo), sizeof(gFileInfo.titleInfo));
|
||||||
titlecount++;
|
titlecount++;
|
||||||
}
|
}
|
||||||
OSUnlockMutex(&fileinfoMutex);
|
|
||||||
|
|
||||||
*outTitleCount = titlecount;
|
*outTitleCount = titlecount;
|
||||||
|
|
||||||
@ -330,10 +356,10 @@ DECL_FUNCTION(int32_t, ACPCheckTitleLaunchByTitleListTypeEx, MCPTitleListType *t
|
|||||||
|
|
||||||
gHomebrewLaunched = TRUE;
|
gHomebrewLaunched = TRUE;
|
||||||
|
|
||||||
RL_LoadFromSDOnNextLaunch(gFileInfos[id].path);
|
RPXLoader_LoadFromSDOnNextLaunch(gFileInfos[id].path);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("Failed to get the id for titleID %016llX", title->titleId);
|
DEBUG_FUNCTION_LINE_ERR("Failed to get the id for titleID %016llX", title->titleId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,17 +367,19 @@ DECL_FUNCTION(int32_t, ACPCheckTitleLaunchByTitleListTypeEx, MCPTitleListType *t
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DECL_FUNCTION(int, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, int *handle, int error) {
|
DECL_FUNCTION(int, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, uint32_t *handle, int error) {
|
||||||
const char *start = "/vol/storage_mlc01/sys/title/0005000F";
|
const char *start = "/vol/storage_mlc01/sys/title/0005000F";
|
||||||
const char *icon = ".tga";
|
const char *icon = ".tga";
|
||||||
const char *iconTex = "iconTex.tga";
|
const char *iconTex = "iconTex.tga";
|
||||||
const char *sound = ".btsnd";
|
const char *sound = ".btsnd";
|
||||||
|
|
||||||
if (StringTools::EndsWith(path, icon) || StringTools::EndsWith(path, sound)) {
|
std::string_view pathStr = path;
|
||||||
|
|
||||||
|
if (pathStr.ends_with(icon) || pathStr.ends_with(sound)) {
|
||||||
if (strncmp(path, start, strlen(start)) == 0) {
|
if (strncmp(path, start, strlen(start)) == 0) {
|
||||||
int res = FS_STATUS_NOT_FOUND;
|
int res = FS_STATUS_NOT_FOUND;
|
||||||
|
|
||||||
if (StringTools::EndsWith(path, iconTex)) {
|
if (pathStr.ends_with(iconTex)) {
|
||||||
// fallback to dummy icon if loaded homebrew is no .wuhb
|
// fallback to dummy icon if loaded homebrew is no .wuhb
|
||||||
*handle = 0x13371338;
|
*handle = 0x13371338;
|
||||||
res = FS_STATUS_OK;
|
res = FS_STATUS_OK;
|
||||||
@ -364,14 +392,14 @@ DECL_FUNCTION(int, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path,
|
|||||||
sscanf(id, "%08X", &lowerTitleID);
|
sscanf(id, "%08X", &lowerTitleID);
|
||||||
int32_t idVal = getIDByLowerTitleID(lowerTitleID);
|
int32_t idVal = getIDByLowerTitleID(lowerTitleID);
|
||||||
if (idVal >= 0) {
|
if (idVal >= 0) {
|
||||||
if (!StringTools::EndsWith(gFileInfos[idVal].filename, ".wuhb")) {
|
if (!std::string_view(gFileInfos[idVal].filename).ends_with(".wuhb")) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (OpenFileForID(idVal, ending, handle) >= 0) {
|
if (OpenFileForID(idVal, ending, handle) >= 0) {
|
||||||
return FS_STATUS_OK;
|
return FS_STATUS_OK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_FUNCTION_LINE("Failed to find id for titleID %08X", lowerTitleID);
|
DEBUG_FUNCTION_LINE_ERR("Failed to find id for titleID %08X", lowerTitleID);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -387,17 +415,18 @@ DECL_FUNCTION(FSStatus, FSCloseFile, FSClient *client, FSCmdBlock *block, FSFile
|
|||||||
} else if ((handle & 0xFF000000) == 0xFF000000) {
|
} else if ((handle & 0xFF000000) == 0xFF000000) {
|
||||||
int32_t fd = (handle & 0x00000FFF);
|
int32_t fd = (handle & 0x00000FFF);
|
||||||
int32_t romid = (handle & 0x00FFF000) >> 12;
|
int32_t romid = (handle & 0x00FFF000) >> 12;
|
||||||
OSLockMutex(&fileinfoMutex);
|
std::lock_guard<std::mutex> lock(fileinfoMutex);
|
||||||
uint32_t rl_handle = gFileHandleWrapper[fd].handle;
|
uint32_t rl_handle = gFileHandleWrapper[fd].handle;
|
||||||
RL_FileClose(rl_handle);
|
if (WUHBUtils_FileClose(rl_handle) != WUHB_UTILS_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to close file %08X", rl_handle);
|
||||||
|
}
|
||||||
if (gFileInfos[romid].openedFiles--) {
|
if (gFileInfos[romid].openedFiles--) {
|
||||||
DCFlushRange(&gFileInfos[romid].openedFiles, 4);
|
DCFlushRange(&gFileInfos[romid].openedFiles, 4);
|
||||||
if (gFileInfos[romid].openedFiles <= 0) {
|
if (gFileInfos[romid].openedFiles <= 0) {
|
||||||
DEBUG_FUNCTION_LINE("unmount romfs no more handles");
|
DEBUG_FUNCTION_LINE_VERBOSE("unmount romfs no more handles");
|
||||||
unmountRomfs(romid);
|
unmountRomfs(romid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OSUnlockMutex(&fileinfoMutex);
|
|
||||||
return FS_STATUS_OK;
|
return FS_STATUS_OK;
|
||||||
}
|
}
|
||||||
return real_FSCloseFile(client, block, handle, flags);
|
return real_FSCloseFile(client, block, handle, flags);
|
||||||
@ -412,14 +441,18 @@ DECL_FUNCTION(FSStatus, FSReadFile, FSClient *client, FSCmdBlock *block, uint8_t
|
|||||||
memcpy(buffer, iconTex_tga, cpySize);
|
memcpy(buffer, iconTex_tga, cpySize);
|
||||||
return (FSStatus) (cpySize / size);
|
return (FSStatus) (cpySize / size);
|
||||||
} else if ((handle & 0xFF000000) == 0xFF000000) {
|
} else if ((handle & 0xFF000000) == 0xFF000000) {
|
||||||
int32_t fd = (handle & 0x00000FFF);
|
uint32_t fd = (handle & 0x00000FFF);
|
||||||
int32_t romid = (handle & 0x00FFF000) >> 12;
|
[[maybe_unused]] uint32_t romid = (handle & 0x00FFF000) >> 12;
|
||||||
|
|
||||||
uint32_t rl_handle = gFileHandleWrapper[fd].handle;
|
uint32_t rl_handle = gFileHandleWrapper[fd].handle;
|
||||||
|
|
||||||
int readSize = RL_FileRead(rl_handle, buffer, (size * count));
|
int readSize = 0;
|
||||||
|
if (WUHBUtils_FileRead(rl_handle, buffer, (size * count), &readSize) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||||
return (FSStatus) (readSize / size);
|
return (FSStatus) (readSize / size);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to read file");
|
||||||
|
OSFatal("Failed to read file");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FSStatus result = real_FSReadFile(client, block, buffer, size, count, handle, unk1, flags);
|
FSStatus result = real_FSReadFile(client, block, buffer, size, count, handle, unk1, flags);
|
||||||
return result;
|
return result;
|
||||||
@ -577,7 +610,7 @@ DECL_FUNCTION(uint32_t, MCPGetTitleInternal, uint32_t mcp_handle, void *input, u
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE("Failed to find lower TID %08X", inputPtrAsU32[1]);
|
DEBUG_FUNCTION_LINE_ERR("Failed to find lower TID %08X", inputPtrAsU32[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,137 +23,13 @@
|
|||||||
*
|
*
|
||||||
* for WiiXplorer 2010
|
* for WiiXplorer 2010
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
#include <cstring>
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <utils/StringTools.h>
|
#include <utils/StringTools.h>
|
||||||
#include <vector>
|
|
||||||
#include <wchar.h>
|
|
||||||
#include <wut_types.h>
|
#include <wut_types.h>
|
||||||
|
|
||||||
|
|
||||||
BOOL StringTools::EndsWith(const std::string &a, const std::string &b) {
|
|
||||||
if (b.size() > a.size())
|
|
||||||
return false;
|
|
||||||
return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *StringTools::byte_to_binary(int32_t x) {
|
|
||||||
static char b[9];
|
|
||||||
b[0] = '\0';
|
|
||||||
|
|
||||||
int32_t z;
|
|
||||||
for (z = 128; z > 0; z >>= 1) {
|
|
||||||
strcat(b, ((x & z) == z) ? "1" : "0");
|
|
||||||
}
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string StringTools::removeCharFromString(std::string &input, char toBeRemoved) {
|
|
||||||
std::string output = input;
|
|
||||||
size_t position;
|
|
||||||
while (1) {
|
|
||||||
position = output.find(toBeRemoved);
|
|
||||||
if (position == std::string::npos)
|
|
||||||
break;
|
|
||||||
output.erase(position, 1);
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *StringTools::fmt(const char *format, ...) {
|
|
||||||
static char strChar[512];
|
|
||||||
strChar[0] = 0;
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
if ((vsprintf(strChar, format, va) >= 0)) {
|
|
||||||
va_end(va);
|
|
||||||
return (const char *) strChar;
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wchar_t *StringTools::wfmt(const char *format, ...) {
|
|
||||||
static char tmp[512];
|
|
||||||
static wchar_t strWChar[512];
|
|
||||||
strWChar[0] = 0;
|
|
||||||
tmp[0] = 0;
|
|
||||||
|
|
||||||
if (!format)
|
|
||||||
return (const wchar_t *) strWChar;
|
|
||||||
|
|
||||||
if (strcmp(format, "") == 0)
|
|
||||||
return (const wchar_t *) strWChar;
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
|
||||||
int bt;
|
|
||||||
int32_t strlength = strlen(tmp);
|
|
||||||
bt = mbstowcs(strWChar, tmp, (strlength < 512) ? strlength : 512);
|
|
||||||
|
|
||||||
if (bt > 0) {
|
|
||||||
strWChar[bt] = 0;
|
|
||||||
return (const wchar_t *) strWChar;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t StringTools::strprintf(std::string &str, const char *format, ...) {
|
|
||||||
static char tmp[512];
|
|
||||||
tmp[0] = 0;
|
|
||||||
int32_t result = 0;
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
|
||||||
str = tmp;
|
|
||||||
result = str.size();
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string StringTools::strfmt(const char *format, ...) {
|
|
||||||
std::string str;
|
|
||||||
static char tmp[512];
|
|
||||||
tmp[0] = 0;
|
|
||||||
|
|
||||||
va_list va;
|
|
||||||
va_start(va, format);
|
|
||||||
if ((vsprintf(tmp, format, va) >= 0)) {
|
|
||||||
str = tmp;
|
|
||||||
}
|
|
||||||
va_end(va);
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL StringTools::char2wchar_t(const char *strChar, wchar_t *dest) {
|
|
||||||
if (!strChar || !dest)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int bt;
|
|
||||||
bt = mbstowcs(dest, strChar, strlen(strChar));
|
|
||||||
if (bt > 0) {
|
|
||||||
dest[bt] = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
int32_t StringTools::strtokcmp(const char *string, const char *compare, const char *separator) {
|
||||||
if (!string || !compare)
|
if (!string || !compare)
|
||||||
return -1;
|
return -1;
|
||||||
@ -164,52 +40,15 @@ int32_t StringTools::strtokcmp(const char *string, const char *compare, const ch
|
|||||||
|
|
||||||
char *strTok = strtok(TokCopy, separator);
|
char *strTok = strtok(TokCopy, separator);
|
||||||
|
|
||||||
while (strTok != NULL) {
|
while (strTok != nullptr) {
|
||||||
if (strcasecmp(string, strTok) == 0) {
|
if (strcasecmp(string, strTok) == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
strTok = strtok(NULL, separator);
|
strTok = strtok(nullptr, separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t StringTools::strextcmp(const char *string, const char *extension, char seperator) {
|
|
||||||
if (!string || !extension)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
char *ptr = strrchr(string, seperator);
|
|
||||||
if (!ptr)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return strcasecmp(ptr + 1, extension);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> StringTools::stringSplit(const std::string &inValue, const std::string &splitter) {
|
|
||||||
std::string value = inValue;
|
|
||||||
std::vector<std::string> result;
|
|
||||||
while (true) {
|
|
||||||
uint32_t index = value.find(splitter);
|
|
||||||
if (index == std::string::npos) {
|
|
||||||
result.push_back(value);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::string first = value.substr(0, index);
|
|
||||||
result.push_back(first);
|
|
||||||
if (index + splitter.size() == value.length()) {
|
|
||||||
result.push_back("");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (index + splitter.size() > value.length()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
value = value.substr(index + splitter.size(), value.length());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *StringTools::FullpathToFilename(const char *path) {
|
const char *StringTools::FullpathToFilename(const char *path) {
|
||||||
if (!path)
|
if (!path)
|
||||||
return path;
|
return path;
|
||||||
@ -239,51 +78,3 @@ void StringTools::RemoveDoubleSlashs(std::string &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// You must free the result if result is non-NULL.
|
|
||||||
char *StringTools::str_replace(char *orig, char *rep, char *with) {
|
|
||||||
char *result; // the return string
|
|
||||||
char *ins; // the next insert point
|
|
||||||
char *tmp; // varies
|
|
||||||
int len_rep; // length of rep (the string to remove)
|
|
||||||
int len_with; // length of with (the string to replace rep with)
|
|
||||||
int len_front; // distance between rep and end of last rep
|
|
||||||
int count; // number of replacements
|
|
||||||
|
|
||||||
// sanity checks and initialization
|
|
||||||
if (!orig || !rep)
|
|
||||||
return NULL;
|
|
||||||
len_rep = strlen(rep);
|
|
||||||
if (len_rep == 0)
|
|
||||||
return NULL; // empty rep causes infinite loop during count
|
|
||||||
if (!with)
|
|
||||||
with = "";
|
|
||||||
len_with = strlen(with);
|
|
||||||
|
|
||||||
// count the number of replacements needed
|
|
||||||
ins = orig;
|
|
||||||
for (count = 0; tmp = strstr(ins, rep); ++count) {
|
|
||||||
ins = tmp + len_rep;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = result = (char *) malloc(strlen(orig) + (len_with - len_rep) * count + 1);
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// first time through the loop, all the variable are set correctly
|
|
||||||
// from here on,
|
|
||||||
// tmp points to the end of the result string
|
|
||||||
// ins points to the next occurrence of rep in orig
|
|
||||||
// orig points to the remainder of orig after "end of rep"
|
|
||||||
while (count--) {
|
|
||||||
ins = strstr(orig, rep);
|
|
||||||
len_front = ins - orig;
|
|
||||||
tmp = strncpy(tmp, orig, len_front) + len_front;
|
|
||||||
tmp = strcpy(tmp, with) + len_with;
|
|
||||||
orig += len_front + len_rep; // move to next "end of rep"
|
|
||||||
}
|
|
||||||
strcpy(tmp, orig);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
@ -23,42 +23,26 @@
|
|||||||
*
|
*
|
||||||
* for WiiXplorer 2010
|
* for WiiXplorer 2010
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#ifndef __STRING_TOOLS_H
|
#pragma once
|
||||||
#define __STRING_TOOLS_H
|
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <wut_types.h>
|
|
||||||
|
template<typename... Args>
|
||||||
|
std::string string_format(const std::string &format, Args... args) {
|
||||||
|
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
|
||||||
|
auto size = static_cast<size_t>(size_s);
|
||||||
|
auto buf = std::make_unique<char[]>(size);
|
||||||
|
std::snprintf(buf.get(), size, format.c_str(), args...);
|
||||||
|
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||||
|
}
|
||||||
|
|
||||||
class StringTools {
|
class StringTools {
|
||||||
public:
|
public:
|
||||||
static BOOL EndsWith(const std::string &a, const std::string &b);
|
|
||||||
|
|
||||||
static const char *byte_to_binary(int32_t x);
|
|
||||||
|
|
||||||
static std::string removeCharFromString(std::string &input, char toBeRemoved);
|
|
||||||
|
|
||||||
static const char *fmt(const char *format, ...);
|
|
||||||
|
|
||||||
static const wchar_t *wfmt(const char *format, ...);
|
|
||||||
|
|
||||||
static int32_t strprintf(std::string &str, const char *format, ...);
|
|
||||||
|
|
||||||
static std::string strfmt(const char *format, ...);
|
|
||||||
|
|
||||||
static BOOL char2wchar_t(const char *src, wchar_t *dest);
|
|
||||||
|
|
||||||
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
static int32_t strtokcmp(const char *string, const char *compare, const char *separator);
|
||||||
|
|
||||||
static int32_t strextcmp(const char *string, const char *extension, char seperator);
|
|
||||||
|
|
||||||
static char *str_replace(char *orig, char *rep, char *with);
|
|
||||||
|
|
||||||
static const char *FullpathToFilename(const char *path);
|
static const char *FullpathToFilename(const char *path);
|
||||||
|
|
||||||
static void RemoveDoubleSlashs(std::string &str);
|
static void RemoveDoubleSlashs(std::string &str);
|
||||||
|
|
||||||
static std::vector<std::string> stringSplit(const std::string &value, const std::string &splitter);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __STRING_TOOLS_H */
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <coreinit/debug.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <whb/log.h>
|
#include <whb/log.h>
|
||||||
|
|
||||||
@ -7,12 +8,21 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||||
|
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||||
|
|
||||||
|
// #define VERBOSE_DEBUG
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
#ifdef VERBOSE_DEBUG
|
||||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) \
|
||||||
|
do { \
|
||||||
|
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
||||||
do { \
|
do { \
|
||||||
@ -34,6 +44,11 @@ extern "C" {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) \
|
||||||
|
do { \
|
||||||
|
OSReport("## ERROR ## [%23s]%30s@L%04d: ##ERROR## " FMT "\n", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
void initLogging();
|
void initLogging();
|
||||||
|
|
||||||
void deinitLogging();
|
void deinitLogging();
|
||||||
|
Loading…
Reference in New Issue
Block a user