diff --git a/Dockerfile b/Dockerfile index b93feba..6bcb434 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,9 @@ -FROM wiiuenv/devkitppc:20220303 +FROM wiiuenv/devkitppc:20220417 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/libwuhbutils:20220415 /artifacts $DEVKITPRO +COPY --from=wiiuenv/libcontentredirection:20220414 /artifacts $DEVKITPRO WORKDIR project \ No newline at end of file diff --git a/Makefile b/Makefile index 8c9ad02..5a11fb3 100644 --- a/Makefile +++ b/Makefile @@ -36,17 +36,17 @@ CFLAGS := -Wall -O2 -ffunction-sections \ 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) -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) CXXFLAGS += -DDEBUG -g CFLAGS += -DDEBUG -g endif -LIBS := -lwups -lwut -lrpxloader -lsdutils +LIBS := -lwups -lwut -lwuhbutils -lcontentredirection -lrpxloader -lsdutils #------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level diff --git a/src/FileWrapper.cpp b/src/FileWrapper.cpp index 04ad28f..d670ba5 100644 --- a/src/FileWrapper.cpp +++ b/src/FileWrapper.cpp @@ -1,19 +1,20 @@ #include "FileWrapper.h" #include "fileinfos.h" +#include "utils/StringTools.h" #include "utils/logger.h" #include -#include #include #include #include -#include +#include +#include FileHandleWrapper gFileHandleWrapper[FILE_WRAPPER_SIZE] __attribute__((section(".data"))); -extern OSMutex fileWrapperMutex; +std::mutex fileWrapperMutex; int FileHandleWrapper_GetSlot() { - OSLockMutex(&fileWrapperMutex); + std::lock_guard lock(fileWrapperMutex); int res = -1; for (int i = 0; i < FILE_WRAPPER_SIZE; i++) { if (!gFileHandleWrapper[i].inUse) { @@ -23,7 +24,6 @@ int FileHandleWrapper_GetSlot() { } } OSMemoryBarrier(); - OSUnlockMutex(&fileWrapperMutex); return res; } @@ -31,24 +31,22 @@ bool FileHandleWrapper_FreeSlot(uint32_t slot) { if (slot >= FILE_WRAPPER_SIZE) { return false; } - OSLockMutex(&fileWrapperMutex); + std::lock_guard lock(fileWrapperMutex); gFileHandleWrapper[slot].handle = 0; gFileHandleWrapper[slot].inUse = false; OSMemoryBarrier(); - OSUnlockMutex(&fileWrapperMutex); return -1; } bool FileHandleWrapper_FreeAll() { - OSLockMutex(&fileWrapperMutex); + std::lock_guard lock(fileWrapperMutex); for (int i = 0; i < FILE_WRAPPER_SIZE; i++) { FileHandleWrapper_FreeSlot(i); } - OSUnlockMutex(&fileWrapperMutex); return -1; } -int OpenFileForID(int id, const char *filepath, int *handle) { +int OpenFileForID(int id, const char *filepath, uint32_t *handle) { if (!mountRomfs(id)) { return -1; } @@ -68,29 +66,29 @@ int OpenFileForID(int id, const char *filepath, int *handle) { } last = filepath[i]; } - dyn_path[j++] = 0; + dyn_path[j] = 0; - char completePath[256]; - snprintf(completePath, 256, "%s:/%s", romName, dyn_path); - free(dyn_path); + auto completePath = string_format("%s:/%s", romName, dyn_path); - uint32_t out_handle = 0; - if (RL_FileOpen(completePath, &out_handle) == 0) { + WUHBFileHandle fileHandle = 0; + if (WUHBUtils_FileOpen(completePath.c_str(), &fileHandle) == WUHB_UTILS_RESULT_SUCCESS) { int handle_wrapper_slot = FileHandleWrapper_GetSlot(); if (handle_wrapper_slot < 0) { - DEBUG_FUNCTION_LINE("No free slot"); - RL_FileClose(out_handle); + DEBUG_FUNCTION_LINE_ERR("No free slot"); + if (WUHBUtils_FileClose(fileHandle) != WUHB_UTILS_RESULT_SUCCESS) { + DEBUG_FUNCTION_LINE_ERR("Failed to close file %08X", fileHandle); + } unmountRomfs(id); return -2; } - gFileHandleWrapper[handle_wrapper_slot].handle = out_handle; + gFileHandleWrapper[handle_wrapper_slot].handle = fileHandle; *handle = 0xFF000000 | (id << 12) | (handle_wrapper_slot & 0x00000FFF); gFileInfos[id].openedFiles++; return 0; } else { + DEBUG_FUNCTION_LINE_ERR("Failed to open file %s", filepath); if (gFileInfos[id].openedFiles == 0) { - DEBUG_FUNCTION_LINE("unmount"); unmountRomfs(id); } } diff --git a/src/FileWrapper.h b/src/FileWrapper.h index 9aa69a2..2fd6c4b 100644 --- a/src/FileWrapper.h +++ b/src/FileWrapper.h @@ -9,5 +9,5 @@ typedef struct FileHandleWrapper_t { #define FILE_WRAPPER_SIZE 64 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(); \ No newline at end of file diff --git a/src/SaveRedirection.cpp b/src/SaveRedirection.cpp index 97f79cb..483898e 100644 --- a/src/SaveRedirection.cpp +++ b/src/SaveRedirection.cpp @@ -1,5 +1,5 @@ #include "SaveRedirection.h" -#include +#include #include #include #include @@ -10,25 +10,18 @@ #include #include -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 &callFunctionWithPath) { - if (!sSDIsMounted || !gInWiiUMenu || strncmp(oldPath, "/vol/save/", 10) != 0) { - return callFunctionWithPath(oldPath); +void SaveRedirectionCleanUp() { + if (saveLayer != 0) { + 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() { nn::act::Initialize(); nn::act::PersistentId persistentId = nn::act::GetPersistentId(); @@ -36,8 +29,8 @@ void initSaveData() { std::string common = "fs:" SAVE_REPLACEMENT_PATH "/save/common"; std::string commonOriginal = "fs:/vol/save/common"; - std::string user = StringTools::strfmt("fs:" SAVE_REPLACEMENT_PATH "/save/%08X", 0x80000000 | persistentId); - std::string userOriginal = StringTools::strfmt("fs:/vol/save/%08X", 0x80000000 | persistentId); + std::string user = string_format("fs:" SAVE_REPLACEMENT_PATH "/save/%08X", 0x80000000 | persistentId); + std::string userOriginal = string_format("fs:/vol/save/%08X", 0x80000000 | persistentId); FSUtils::CreateSubfolder(common.c_str()); FSUtils::CreateSubfolder(user.c_str()); @@ -46,77 +39,39 @@ void initSaveData() { auto BaristaAccountSaveFilePathOriginal = userOriginal + "/BaristaAccountSaveFile.dat"; if (!FSUtils::CheckFile(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 BaristaCommonSaveFileOriginal = commonOriginal + "/BaristaCommonSaveFile.dat"; if (!FSUtils::CheckFile(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 BaristaIconDataBaseOriginal = commonOriginal + "/BaristaIconDataBase.dat"; if (!FSUtils::CheckFile(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) { int32_t result = real_LoadConsoleAccount__Q2_2nn3actFUc13ACTLoadOptionPCcb(slot, unk1, unk2, unk3); 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 // Calls our function replacement. SAVEInit(); @@ -131,7 +86,6 @@ DECL_FUNCTION(int32_t, SAVEInit) { if (OSGetTitleID() == 0x0005001010040000L || // Wii U Menu JPN OSGetTitleID() == 0x0005001010040100L || // Wii U Menu USA OSGetTitleID() == 0x0005001010040200L) { // Wii U Menu EUR - DEBUG_FUNCTION_LINE("Init Save redirection"); initSaveData(); gInWiiUMenu = true; @@ -143,14 +97,5 @@ DECL_FUNCTION(int32_t, SAVEInit) { return res; } - 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); \ No newline at end of file diff --git a/src/SaveRedirection.h b/src/SaveRedirection.h index 9d1df21..949b8ba 100644 --- a/src/SaveRedirection.h +++ b/src/SaveRedirection.h @@ -1,9 +1,7 @@ #pragma once -#include extern bool gInWiiUMenu; -extern bool sSDIsMounted; #define SAVE_REPLACEMENT_PATH "/vol/external01/wiiu/homebrew_on_menu_plugin" -void InitSaveData(); \ No newline at end of file +void SaveRedirectionCleanUp(); \ No newline at end of file diff --git a/src/fileinfos.cpp b/src/fileinfos.cpp index c2a5172..943f727 100644 --- a/src/fileinfos.cpp +++ b/src/fileinfos.cpp @@ -1,16 +1,16 @@ #include "fileinfos.h" #include "utils/logger.h" #include -#include #include #include -#include +#include +#include FileInfos gFileInfos[FILE_INFO_SIZE] __attribute__((section(".data"))); -extern OSMutex fileinfoMutex; +std::mutex fileinfoMutex; int32_t getIDByLowerTitleID(uint32_t lowerTitleID) { - OSLockMutex(&fileinfoMutex); + std::lock_guard lock(fileinfoMutex); int res = -1; for (int i = 0; i < FILE_INFO_SIZE; i++) { if (strlen(gFileInfos[i].path) > 0 && gFileInfos[i].lowerTitleID == lowerTitleID) { @@ -19,7 +19,6 @@ int32_t getIDByLowerTitleID(uint32_t lowerTitleID) { } } OSMemoryBarrier(); - OSUnlockMutex(&fileinfoMutex); return res; } @@ -27,17 +26,17 @@ void unmountRomfs(uint32_t id) { if (id >= FILE_INFO_SIZE) { return; } - OSLockMutex(&fileinfoMutex); + std::lock_guard lock(fileinfoMutex); if (gFileInfos[id].romfsMounted) { char romName[10]; snprintf(romName, 10, "%08X", id); - DEBUG_FUNCTION_LINE("Unmounting %s", romName); - int res = RL_UnmountBundle(romName); - DEBUG_FUNCTION_LINE("res: %d", res); + int32_t outRes; + if (WUHBUtils_UnmountBundle(romName, &outRes) || outRes != 0) { + DEBUG_FUNCTION_LINE_ERR("Failed to unmount \"%s\"", romName); + } gFileInfos[id].romfsMounted = false; } OSMemoryBarrier(); - OSUnlockMutex(&fileinfoMutex); } void unmountAllRomfs() { @@ -48,10 +47,10 @@ void unmountAllRomfs() { bool mountRomfs(uint32_t id) { 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; } - OSLockMutex(&fileinfoMutex); + std::lock_guard lock(fileinfoMutex); bool result = false; if (!gFileInfos[id].romfsMounted) { char buffer[256]; @@ -60,17 +59,16 @@ bool mountRomfs(uint32_t id) { snprintf(romName, 10, "%08X", id); DEBUG_FUNCTION_LINE("Mount %s as %s", buffer, romName); 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 "); gFileInfos[id].romfsMounted = true; result = true; } else { - DEBUG_FUNCTION_LINE("Mounting failed %d", res); + DEBUG_FUNCTION_LINE_ERR("Mounting failed %d", res); result = false; } } OSMemoryBarrier(); - OSUnlockMutex(&fileinfoMutex); return result; } \ No newline at end of file diff --git a/src/fileinfos.h b/src/fileinfos.h index 9d0ca18..fc1170f 100644 --- a/src/fileinfos.h +++ b/src/fileinfos.h @@ -2,6 +2,9 @@ #include #include +#include + +extern std::mutex fileinfoMutex; typedef struct WUT_PACKED FileInfos_ { char path[256]; diff --git a/src/main.cpp b/src/main.cpp index f979f9e..9fd1a47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "fs/FSUtils.h" #include "utils/StringTools.h" #include "utils/ini.h" +#include #include #include #include @@ -15,11 +16,14 @@ #include #include #include +#include #include -#include +#include #include +#include #include #include +#include #include typedef struct ACPMetaData { @@ -43,30 +47,44 @@ BOOL gHomebrewLaunched __attribute__((section(".data"))); void readCustomTitlesFromSD(); -extern "C" void _SYSLaunchTitleWithStdArgsInNoSplash(uint64_t, uint32_t); - WUPS_USE_WUT_DEVOPTAB(); -OSMutex fileWrapperMutex; -OSMutex fileinfoMutex; - INITIALIZE_PLUGIN() { memset((void *) ¤t_launched_title_info, 0, sizeof(current_launched_title_info)); memset((void *) &gLaunchXML, 0, sizeof(gLaunchXML)); memset((void *) &gFileInfos, 0, sizeof(gFileInfos)); memset((void *) &gFileHandleWrapper, 0, sizeof(gFileHandleWrapper)); 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 sSDIsMounted = false; bool sTitleRebooting = false; -void SDAttachedHandler(SDUtilsAttachStatus status) { +void SDAttachedHandler([[maybe_unused]] SDUtilsAttachStatus status) { if (!sTitleRebooting) { - _SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), 0); + _SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr); sTitleRebooting = true; } } @@ -97,6 +115,7 @@ ON_APPLICATION_START() { } ON_APPLICATION_ENDS() { + SaveRedirectionCleanUp(); unmountAllRomfs(); memset((void *) &gFileInfos, 0, sizeof(gFileInfos)); FileHandleWrapper_FreeAll(); @@ -113,7 +132,7 @@ ON_APPLICATION_ENDS() { void fillXmlForTitleID(uint32_t titleid_upper, uint32_t titleid_lower, ACPMetaXml *out_buf) { int32_t id = getIDByLowerTitleID(titleid_lower); if (id < 0) { - DEBUG_FUNCTION_LINE("Failed to get id by titleid"); + DEBUG_FUNCTION_LINE_ERR("Failed to get id by titleid"); return; } if (id >= FILE_INFO_SIZE) { @@ -160,7 +179,6 @@ static int handler(void *user, const char *section, const char *name, auto *fInfo = (FileInfos *) user; #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")) { strncpy(fInfo->longname, value, 64 - 1); } else if (MATCH("menu", "shortname")) { @@ -174,6 +192,7 @@ static int handler(void *user, const char *section, const char *name, return 1; } +bool CheckFileExistsHelper(const char *path); void readCustomTitlesFromSD() { // Reset current infos unmountAllRomfs(); @@ -185,7 +204,7 @@ void readCustomTitlesFromSD() { int j = 0; for (int i = 0; i < dirList.GetFilecount(); i++) { if (j >= FILE_INFO_SIZE) { - DEBUG_FUNCTION_LINE("TOO MANY TITLES"); + DEBUG_FUNCTION_LINE_ERR("TOO MANY TITLES"); break; } @@ -209,14 +228,14 @@ void readCustomTitlesFromSD() { continue; } - char *repl = (char *) "fs:/vol/external01/"; - char *with = (char *) ""; - char *input = (char *) dirList.GetFilepath(i); + auto repl = "fs:/vol/external01/"; + auto input = dirList.GetFilepath(i); - char *path = StringTools::str_replace(input, repl, with); - if (path != nullptr) { - strncpy(gFileInfos[j].path, path, 255); - free(path); + if (std::string_view(input).starts_with(repl)) { + strncpy(gFileInfos[j].path, &input[strlen(repl)], sizeof(gFileInfos[j].path)); + } else { + 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); @@ -237,52 +256,45 @@ void readCustomTitlesFromSD() { // System apps don't have a splash screen. cur_title_info->appType = MCP_APP_TYPE_SYSTEM_APPS; - // Check if the have bootTvTex and bootDrcTex that could be shown. - if (StringTools::EndsWith(gFileInfos[j].filename, ".wuhb")) { + // Check if the bootTvTex and bootDrcTex exists + if (std::string_view(gFileInfos[j].filename).ends_with(".wuhb")) { 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(&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) { - DEBUG_FUNCTION_LINE("Failed to parse ini"); - } - free(ini_buffer); - } else { - DEBUG_FUNCTION_LINE("Failed to alloc memory"); +#define TMP_BUNDLE_NAME "romfscheck" + + if (WUHBUtils_MountBundle(TMP_BUNDLE_NAME, dirList.GetFilepath(i), BundleSource_FileDescriptor, &result) == WUHB_UTILS_RESULT_SUCCESS && result >= 0) { + uint8_t *buffer; + uint32_t bufferSize; + + 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"); } - - RL_FileClose(file_handle); + free(buffer); + buffer = nullptr; + } else { + DEBUG_FUNCTION_LINE_ERR("Failed to open or read meta.ini: %d", readRes); } - bool foundSplashScreens = true; - if (!RL_FileExists("romfscheck:/meta/bootTvTex.tga")) { - foundSplashScreens = false; - } - if (!RL_FileExists("romfscheck:/meta/bootDrcTex.tga")) { - foundSplashScreens = false; - } - if (foundSplashScreens) { + auto bootTvTexPath = TMP_BUNDLE_NAME ":/meta/bootTvTex.tga"; + auto bootDrcTexPath = TMP_BUNDLE_NAME ":/meta/bootDrcTex.tga"; + if (CheckFileExistsHelper(bootTvTexPath) && CheckFileExistsHelper(bootDrcTexPath)) { // Show splash screens 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 { - 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; } } @@ -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) { int32_t result = real_MCP_TitleList(handle, outTitleCount, titleList, size); uint32_t titlecount = *outTitleCount; - OSLockMutex(&fileinfoMutex); + std::lock_guard lock(fileinfoMutex); for (auto &gFileInfo : gFileInfos) { if (gFileInfo.lowerTitleID == 0) { 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)); titlecount++; } - OSUnlockMutex(&fileinfoMutex); *outTitleCount = titlecount; @@ -330,10 +356,10 @@ DECL_FUNCTION(int32_t, ACPCheckTitleLaunchByTitleListTypeEx, MCPTitleListType *t gHomebrewLaunched = TRUE; - RL_LoadFromSDOnNextLaunch(gFileInfos[id].path); + RPXLoader_LoadFromSDOnNextLaunch(gFileInfos[id].path); return 0; } 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; } -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 *icon = ".tga"; const char *iconTex = "iconTex.tga"; 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) { 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 *handle = 0x13371338; res = FS_STATUS_OK; @@ -364,14 +392,14 @@ DECL_FUNCTION(int, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, sscanf(id, "%08X", &lowerTitleID); int32_t idVal = getIDByLowerTitleID(lowerTitleID); if (idVal >= 0) { - if (!StringTools::EndsWith(gFileInfos[idVal].filename, ".wuhb")) { + if (!std::string_view(gFileInfos[idVal].filename).ends_with(".wuhb")) { return res; } if (OpenFileForID(idVal, ending, handle) >= 0) { return FS_STATUS_OK; } } 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; } @@ -387,17 +415,18 @@ DECL_FUNCTION(FSStatus, FSCloseFile, FSClient *client, FSCmdBlock *block, FSFile } else if ((handle & 0xFF000000) == 0xFF000000) { int32_t fd = (handle & 0x00000FFF); int32_t romid = (handle & 0x00FFF000) >> 12; - OSLockMutex(&fileinfoMutex); + std::lock_guard lock(fileinfoMutex); 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--) { DCFlushRange(&gFileInfos[romid].openedFiles, 4); if (gFileInfos[romid].openedFiles <= 0) { - DEBUG_FUNCTION_LINE("unmount romfs no more handles"); + DEBUG_FUNCTION_LINE_VERBOSE("unmount romfs no more handles"); unmountRomfs(romid); } } - OSUnlockMutex(&fileinfoMutex); return FS_STATUS_OK; } 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); return (FSStatus) (cpySize / size); } else if ((handle & 0xFF000000) == 0xFF000000) { - int32_t fd = (handle & 0x00000FFF); - int32_t romid = (handle & 0x00FFF000) >> 12; + uint32_t fd = (handle & 0x00000FFF); + [[maybe_unused]] uint32_t romid = (handle & 0x00FFF000) >> 12; uint32_t rl_handle = gFileHandleWrapper[fd].handle; - int readSize = RL_FileRead(rl_handle, buffer, (size * count)); - - return (FSStatus) (readSize / size); + int readSize = 0; + if (WUHBUtils_FileRead(rl_handle, buffer, (size * count), &readSize) == WUHB_UTILS_RESULT_SUCCESS) { + 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); return result; @@ -577,7 +610,7 @@ DECL_FUNCTION(uint32_t, MCPGetTitleInternal, uint32_t mcp_handle, void *input, u 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]); } } diff --git a/src/utils/StringTools.cpp b/src/utils/StringTools.cpp index 7ffed91..88e1c8e 100644 --- a/src/utils/StringTools.cpp +++ b/src/utils/StringTools.cpp @@ -23,137 +23,13 @@ * * for WiiXplorer 2010 ***************************************************************************/ -#include -#include -#include -#include + +#include #include #include #include -#include -#include #include - -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) { if (!string || !compare) return -1; @@ -164,52 +40,15 @@ int32_t StringTools::strtokcmp(const char *string, const char *compare, const ch char *strTok = strtok(TokCopy, separator); - while (strTok != NULL) { + while (strTok != nullptr) { if (strcasecmp(string, strTok) == 0) { return 0; } - strTok = strtok(NULL, separator); + strTok = strtok(nullptr, separator); } 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 StringTools::stringSplit(const std::string &inValue, const std::string &splitter) { - std::string value = inValue; - std::vector 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) { if (!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; -} diff --git a/src/utils/StringTools.h b/src/utils/StringTools.h index d1a1570..5a96490 100644 --- a/src/utils/StringTools.h +++ b/src/utils/StringTools.h @@ -23,42 +23,26 @@ * * for WiiXplorer 2010 ***************************************************************************/ -#ifndef __STRING_TOOLS_H -#define __STRING_TOOLS_H +#pragma once +#include #include #include -#include + +template +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_s); + auto buf = std::make_unique(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 { 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 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 void RemoveDoubleSlashs(std::string &str); - - static std::vector stringSplit(const std::string &value, const std::string &splitter); }; - -#endif /* __STRING_TOOLS_H */ diff --git a/src/utils/logger.h b/src/utils/logger.h index 061d52e..a3538e1 100644 --- a/src/utils/logger.h +++ b/src/utils/logger.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -7,12 +8,21 @@ extern "C" { #endif +#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) + +// #define VERBOSE_DEBUG + #ifdef DEBUG -#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) - +#ifdef VERBOSE_DEBUG +#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) +#endif #define DEBUG_FUNCTION_LINE(FMT, ARGS...) \ do { \ @@ -34,6 +44,11 @@ extern "C" { #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 deinitLogging();