mirror of
https://github.com/wiiu-env/homebrew_on_menu_plugin.git
synced 2024-11-22 02:29:15 +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/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
|
6
Makefile
6
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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
@ -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);
|
@ -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();
|
@ -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;
|
||||
}
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include <coreinit/mcp.h>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
|
||||
extern std::mutex fileinfoMutex;
|
||||
|
||||
typedef struct WUT_PACKED FileInfos_ {
|
||||
char path[256];
|
||||
|
185
src/main.cpp
185
src/main.cpp
@ -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 *) ¤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<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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user