Use libwuhbutils to get data from .whb and libcontentredirection for /vol/save redirection.

This commit is contained in:
Maschell 2022-04-17 21:56:14 +02:00
parent f5d8fced32
commit d044b62b3e
12 changed files with 212 additions and 445 deletions

View File

@ -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

View File

@ -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

View File

@ -1,19 +1,20 @@
#include "FileWrapper.h"
#include "fileinfos.h"
#include "utils/StringTools.h"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/mutex.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <rpxloader.h>
#include <mutex>
#include <wuhb_utils/utils.h>
FileHandleWrapper gFileHandleWrapper[FILE_WRAPPER_SIZE] __attribute__((section(".data")));
extern OSMutex fileWrapperMutex;
std::mutex fileWrapperMutex;
int FileHandleWrapper_GetSlot() {
OSLockMutex(&fileWrapperMutex);
std::lock_guard<std::mutex> 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<std::mutex> lock(fileWrapperMutex);
gFileHandleWrapper[slot].handle = 0;
gFileHandleWrapper[slot].inUse = false;
OSMemoryBarrier();
OSUnlockMutex(&fileWrapperMutex);
return -1;
}
bool FileHandleWrapper_FreeAll() {
OSLockMutex(&fileWrapperMutex);
std::lock_guard<std::mutex> 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);
}
}

View File

@ -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();

View File

@ -1,5 +1,5 @@
#include "SaveRedirection.h"
#include <coreinit/filesystem.h>
#include <content_redirection/redirection.h>
#include <coreinit/title.h>
#include <fs/FSUtils.h>
#include <functional>
@ -10,25 +10,18 @@
#include <utils/logger.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) {
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);

View File

@ -1,9 +1,7 @@
#pragma once
#include <stdbool.h>
extern bool gInWiiUMenu;
extern bool sSDIsMounted;
#define SAVE_REPLACEMENT_PATH "/vol/external01/wiiu/homebrew_on_menu_plugin"
void InitSaveData();
void SaveRedirectionCleanUp();

View File

@ -1,16 +1,16 @@
#include "fileinfos.h"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/mutex.h>
#include <cstdio>
#include <cstring>
#include <rpxloader.h>
#include <mutex>
#include <wuhb_utils/utils.h>
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<std::mutex> 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<std::mutex> 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<std::mutex> 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;
}

View File

@ -2,6 +2,9 @@
#include <coreinit/mcp.h>
#include <cstdint>
#include <mutex>
extern std::mutex fileinfoMutex;
typedef struct WUT_PACKED FileInfos_ {
char path[256];

View File

@ -5,6 +5,7 @@
#include "fs/FSUtils.h"
#include "utils/StringTools.h"
#include "utils/ini.h"
#include <content_redirection/redirection.h>
#include <coreinit/cache.h>
#include <coreinit/debug.h>
#include <coreinit/filesystem.h>
@ -15,11 +16,14 @@
#include <cstring>
#include <fs/DirList.h>
#include <malloc.h>
#include <mutex>
#include <nn/acp.h>
#include <rpxloader.h>
#include <rpxloader/rpxloader.h>
#include <sdutils/sdutils.h>
#include <sysapp/launch.h>
#include <sysapp/title.h>
#include <utils/logger.h>
#include <wuhb_utils/utils.h>
#include <wups.h>
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 *) &current_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<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) {
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<std::mutex> 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<std::mutex> 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]);
}
}

View File

@ -23,137 +23,13 @@
*
* for WiiXplorer 2010
***************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstring>
#include <string>
#include <strings.h>
#include <utils/StringTools.h>
#include <vector>
#include <wchar.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) {
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<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) {
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;
}

View File

@ -23,42 +23,26 @@
*
* for WiiXplorer 2010
***************************************************************************/
#ifndef __STRING_TOOLS_H
#define __STRING_TOOLS_H
#pragma once
#include <memory>
#include <string>
#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 {
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<std::string> stringSplit(const std::string &value, const std::string &splitter);
};
#endif /* __STRING_TOOLS_H */

View File

@ -1,5 +1,6 @@
#pragma once
#include <coreinit/debug.h>
#include <string.h>
#include <whb/log.h>
@ -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();