mirror of
https://github.com/wiiu-env/RPXLoadingModule.git
synced 2024-11-25 11:26:53 +01:00
Rewrite to use libcontentredirection and libwuhbutils.
This commit is contained in:
parent
533c25d6bf
commit
ebe901ebdc
@ -1,8 +1,10 @@
|
||||
FROM wiiuenv/devkitppc:20220303
|
||||
FROM wiiuenv/devkitppc:20220417
|
||||
|
||||
COPY --from=wiiuenv/librpxloader:20220212 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/librpxloader:20220417 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libfunctionpatcher:20220211 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/wiiumodulesystem:20220204 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libromfs_wiiu:20220305 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libwuhbutils:20220415 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libcontentredirection:20220414 /artifacts $DEVKITPRO
|
||||
COPY --from=wiiuenv/libromfs_wiiu:20220414 /artifacts $DEVKITPRO
|
||||
|
||||
WORKDIR project
|
20
Makefile
20
Makefile
@ -34,17 +34,17 @@ CFLAGS := -Wall -Wextra -Os -ffunction-sections\
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -std=c++17
|
||||
CXXFLAGS := $(CFLAGS) -std=c++20
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libfunctionpatcher.ld $(WUMSSPECS)
|
||||
LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libfunctionpatcher.ld -Tcontentredirection.ld -Twuhbutils.ld $(WUMSSPECS)
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
CXXFLAGS += -DDEBUG -g
|
||||
CFLAGS += -DDEBUG -g
|
||||
endif
|
||||
|
||||
LIBS := -lwums -lwut -lfunctionpatcher -lromfs -lz
|
||||
LIBS := -lwums -lwut -lfunctionpatcher -lcontentredirection -lwuhbutils -lromfs
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level
|
||||
@ -71,6 +71,7 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
DEFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.def)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@ -88,7 +89,7 @@ endif
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES_SRC := $(DEFFILES:.def=.o) $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
@ -128,11 +129,18 @@ $(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# you need a rule like this for each extension you use as binary data
|
||||
#-------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#-------------------------------------------------------------------------------
|
||||
%.o: %.def
|
||||
$(SILENTMSG) $(notdir $<)
|
||||
$(SILENTCMD)rplimportgen $< $*.s $*.ld $(ERROR_FILTER)
|
||||
$(SILENTCMD)$(CC) -x assembler-with-cpp $(ASFLAGS) -c $*.s -o $@ $(ERROR_FILTER)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%_bin.h %.bin.o : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
|
@ -1,194 +0,0 @@
|
||||
#include "FSDirReplacements.h"
|
||||
#include "FSWrapper.h"
|
||||
#include "FileUtils.h"
|
||||
#include "globals.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
|
||||
#define SYNC_RESULT_HANDLER [](FSStatus res) -> FSStatus { \
|
||||
return res; \
|
||||
}
|
||||
|
||||
#define ASYNC_RESULT_HANDLER [client, block, asyncData](FSStatus res) -> FSStatus { \
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Result was %d", res); \
|
||||
return send_result_async(client, block, asyncData, res); \
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenDir, FSClient *client, FSCmdBlock *block, char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSOpenDirWrapper(
|
||||
path, handle, errorMask,
|
||||
[client, block, handle, errorMask](char *_path) -> FSStatus {
|
||||
return real_FSOpenDir(client, block, _path, handle, errorMask);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Result was %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSOpenDir(client, block, path, handle, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenDirAsync, FSClient *client, FSCmdBlock *block, char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
|
||||
// Even real_FSOpenDir is still calling our FSOpenDirAsync hook. To bypass our code we use "FORCE_REAL_FUNC_WITH_FULL_ERRORS" as an errorMask.
|
||||
if ((errorMask & ERROR_FLAG_MASK) != FORCE_REAL_FUNC_MAGIC) {
|
||||
FSStatus result = FSOpenDirWrapper(
|
||||
path, handle, errorMask,
|
||||
[client, block, handle, errorMask, asyncData](char *_path) -> FSStatus {
|
||||
return real_FSOpenDirAsync(client, block, _path, handle, errorMask, asyncData);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
|
||||
return real_FSOpenDirAsync(client, block, path, handle, realErrorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSStatus result = FSReadDirWrapper(handle, entry, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSReadDir(client, block, handle, entry, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
// Even real_FSReadDir is still calling our FSReadDirAsync hook. To bypass our code we use "FORCE_REAL_FUNC_WITH_FULL_ERRORS" as an errorMask.
|
||||
if ((errorMask & ERROR_FLAG_MASK) != FORCE_REAL_FUNC_MAGIC) {
|
||||
FSStatus result = FSReadDirWrapper(handle, entry, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
|
||||
return real_FSReadDirAsync(client, block, handle, entry, realErrorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSStatus result = FSCloseDirWrapper(handle, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSCloseDir(client, block, handle, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
// Even real_FSCloseDir is still calling our FSCloseDirAsync hook. To bypass our code we use "FORCE_REAL_FUNC_WITH_FULL_ERRORS" as an errorMask.
|
||||
if ((errorMask & ERROR_FLAG_MASK) != FORCE_REAL_FUNC_MAGIC) {
|
||||
FSStatus result = FSCloseDirWrapper(handle, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
|
||||
return real_FSCloseDirAsync(client, block, handle, realErrorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRewindDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSStatus result = FSRewindDirWrapper(handle, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSRewindDir(client, block, handle, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRewindDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
// Even real_FSRewindDir is still calling our FSRewindDirAsync hook. To bypass our code we use "FORCE_REAL_FUNC_WITH_FULL_ERRORS" as an errorMask.
|
||||
if ((errorMask & ERROR_FLAG_MASK) != FORCE_REAL_FUNC_MAGIC) {
|
||||
FSStatus result = FSRewindDirWrapper(handle, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
|
||||
return real_FSRewindDirAsync(client, block, handle, realErrorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSMakeDir, FSClient *client, FSCmdBlock *block, char *path, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSMakeDirWrapper(
|
||||
path, errorMask,
|
||||
[client, block, errorMask](char *_path) -> FSStatus {
|
||||
return real_FSMakeDir(client, block, _path, errorMask);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSMakeDir(client, block, path, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSMakeDirAsync, FSClient *client, FSCmdBlock *block, char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSMakeDirWrapper(
|
||||
path, errorMask,
|
||||
[client, block, errorMask, asyncData](char *_path) -> FSStatus {
|
||||
return real_FSMakeDirAsync(client, block, _path, errorMask, asyncData);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
return real_FSMakeDirAsync(client, block, path, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("FSChangeDirAsync %s", path);
|
||||
snprintf(gReplacementInfo.contentReplacementInfo.workingDir, sizeof(gReplacementInfo.contentReplacementInfo.workingDir), "%s", path);
|
||||
auto len = strlen(gReplacementInfo.contentReplacementInfo.workingDir);
|
||||
if (len > 0 && gReplacementInfo.contentReplacementInfo.workingDir[len - 1] != '/') {
|
||||
gReplacementInfo.contentReplacementInfo.workingDir[len - 1] = '/';
|
||||
gReplacementInfo.contentReplacementInfo.workingDir[len] = 0;
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
return real_FSChangeDirAsync(client, block, path, errorMask, asyncData);
|
||||
}
|
||||
|
||||
function_replacement_data_t fs_dir_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSOpenDir, LIBRARY_COREINIT, FSOpenDir),
|
||||
REPLACE_FUNCTION(FSOpenDirAsync, LIBRARY_COREINIT, FSOpenDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSReadDir, LIBRARY_COREINIT, FSReadDir),
|
||||
REPLACE_FUNCTION(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSCloseDir, LIBRARY_COREINIT, FSCloseDir),
|
||||
REPLACE_FUNCTION(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSRewindDir, LIBRARY_COREINIT, FSRewindDir),
|
||||
REPLACE_FUNCTION(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSMakeDir, LIBRARY_COREINIT, FSMakeDir),
|
||||
REPLACE_FUNCTION(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync),
|
||||
};
|
||||
|
||||
uint32_t fs_dir_function_replacements_size = sizeof(fs_dir_function_replacements) / sizeof(function_replacement_data_t);
|
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern function_replacement_data_t fs_dir_function_replacements[];
|
||||
extern uint32_t fs_dir_function_replacements_size;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,399 +0,0 @@
|
||||
#include "FSFileReplacements.h"
|
||||
#include "globals.h"
|
||||
|
||||
#include <coreinit/dynload.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "FSWrapper.h"
|
||||
#include "FileUtils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
#define SYNC_RESULT_HANDLER [](FSStatus res) -> FSStatus { \
|
||||
return res; \
|
||||
}
|
||||
|
||||
#define ASYNC_RESULT_HANDLER [client, block, asyncData](FSStatus res) -> FSStatus { \
|
||||
return send_result_async(client, block, asyncData, res); \
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, FSFileHandle *handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSOpenFileWrapper(
|
||||
path, mode, handle, errorMask,
|
||||
[client, block, mode, handle, errorMask](char *_path) -> FSStatus {
|
||||
return real_FSOpenFile(client, block, _path, mode, handle, errorMask);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
FSStatus res = real_FSOpenFile(client, block, path, mode, handle, errorMask);
|
||||
return res;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenFileAsync, FSClient *client, FSCmdBlock *block, char *path, const char *mode, FSFileHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSOpenFileWrapper(
|
||||
path, mode, handle, errorMask,
|
||||
[client, block, mode, handle, errorMask, asyncData](char *_path) -> FSStatus {
|
||||
return real_FSOpenFileAsync(client, block, _path, mode, handle, errorMask, asyncData);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSOpenFileAsync(client, block, path, mode, handle, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSCloseFileWrapper(handle, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
FSStatus res = real_FSCloseFile(client, block, handle, errorMask);
|
||||
return res;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSCloseFileWrapper(handle, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSCloseFileAsync(client, block, handle, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetStat, FSClient *client, FSCmdBlock *block, char *path, FSStat *stats, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSGetStatWrapper(
|
||||
path, stats, errorMask,
|
||||
[client, block, stats, errorMask](char *_path) -> FSStatus {
|
||||
return real_FSGetStat(client, block, _path, stats, errorMask);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
return real_FSGetStat(client, block, path, stats, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetStatAsync, FSClient *client, FSCmdBlock *block, char *path, FSStat *stats, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSGetStatWrapper(
|
||||
path, stats, errorMask,
|
||||
[client, block, stats, errorMask, asyncData](char *_path) -> FSStatus {
|
||||
return real_FSGetStatAsync(client, block, _path, stats, errorMask, asyncData);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
return real_FSGetStatAsync(client, block, path, stats, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetStatFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSStat *stats, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSGetStatFileWrapper(handle, stats, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSGetStatFile(client, block, handle, stats, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetStatFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSStat *stats, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSGetStatFileWrapper(handle, stats, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSGetStatFileAsync(client, block, handle, stats, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(int32_t, FSReadFile, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSReadFileWrapper(buffer, size, count, handle, unk1, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSReadFile(client, block, buffer, size, count, handle, unk1, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(int32_t, FSReadFileAsync, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask,
|
||||
FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSReadFileWrapper(buffer, size, count, handle, unk1, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return send_result_async(client, block, asyncData, result);
|
||||
}
|
||||
|
||||
return real_FSReadFileAsync(client, block, buffer, size, count, handle, unk1, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadFileWithPos, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSReadFileWithPosWrapper(buffer, size, count, pos, handle, unk1, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%d", size * count);
|
||||
|
||||
FSStatus res = real_FSReadFileWithPos(client, block, buffer, size, count, pos, handle, unk1, errorMask);
|
||||
return res;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(int32_t, FSReadFileWithPosAsync, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, int32_t unk1, FSErrorFlag errorMask,
|
||||
FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSReadFileWithPosWrapper(buffer, size, count, pos, handle, unk1, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSReadFileWithPosAsync(client, block, buffer, size, count, pos, handle, unk1, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSSetPosFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t pos, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSSetPosFileWrapper(handle, pos, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
return real_FSSetPosFile(client, block, handle, pos, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSSetPosFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t pos, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSSetPosFileWrapper(handle, pos, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSSetPosFileAsync(client, block, handle, pos, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetPosFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t *pos, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSGetPosFileWrapper(handle, pos, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
return real_FSGetPosFile(client, block, handle, pos, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetPosFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t *pos, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSGetPosFileWrapper(handle, pos, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSGetPosFileAsync(client, block, handle, pos, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSIsEof, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSIsEofWrapper(handle, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
return real_FSIsEof(client, block, handle, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSIsEofAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSIsEofWrapper(handle, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
return real_FSIsEofAsync(client, block, handle, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSWriteFile, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSWriteFileWrapper(buffer, size, count, handle, unk1, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSWriteFile(client, block, buffer, size, count, handle, unk1, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSWriteFileAsync, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask,
|
||||
FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSWriteFileWrapper(buffer, size, count, handle, unk1, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSWriteFileAsync(client, block, buffer, size, count, handle, unk1, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSTruncateFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSTruncateFileWrapper(handle, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSTruncateFile(client, block, handle, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSTruncateFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSTruncateFileWrapper(handle, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSTruncateFileAsync(client, block, handle, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRemove, FSClient *client, FSCmdBlock *block, char *path, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSRemoveWrapper(
|
||||
path, errorMask,
|
||||
[client, block, errorMask](char *_path) -> FSStatus {
|
||||
return real_FSRemove(client, block, _path, errorMask);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSRemove(client, block, path, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRemoveAsync, FSClient *client, FSCmdBlock *block, char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSStatus result = FSRemoveWrapper(
|
||||
path, errorMask,
|
||||
[client, block, errorMask, asyncData](char *_path) -> FSStatus {
|
||||
return real_FSRemoveAsync(client, block, _path, errorMask, asyncData);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSRemoveAsync(client, block, path, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRename, FSClient *client, FSCmdBlock *block, char *oldPath, char *newPath, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s %s", oldPath, newPath);
|
||||
FSStatus result = FSRenameWrapper(
|
||||
oldPath, newPath, errorMask,
|
||||
[client, block, errorMask](char *_oldOath, char *_newPath) -> FSStatus {
|
||||
return real_FSRename(client, block, _oldOath, _newPath, errorMask);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSRename(client, block, oldPath, newPath, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRenameAsync, FSClient *client, FSCmdBlock *block, char *oldPath, char *newPath, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s %s", oldPath, newPath);
|
||||
FSStatus result = FSRenameWrapper(
|
||||
oldPath, newPath, errorMask,
|
||||
[client, block, errorMask, asyncData](char *_oldOath, char *_newPath) -> FSStatus {
|
||||
return real_FSRenameAsync(client, block, _oldOath, _newPath, errorMask, asyncData);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSRenameAsync(client, block, oldPath, newPath, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSFlushFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSFlushFileWrapper(handle, errorMask, SYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSFlushFile(client, block, handle, errorMask);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSFlushFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
FSStatus result = FSFlushFileWrapper(handle, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return real_FSFlushFileAsync(client, block, handle, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSChangeModeAsync, FSClient *client, FSCmdBlock *block, char *path, FSMode mode, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("FSChangeModeAsync %s", path);
|
||||
return real_FSChangeModeAsync(client, block, path, mode, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetFreeSpaceSizeAsync, FSClient *client, FSCmdBlock *block, char *path, uint64_t *outSize, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("FSGetFreeSpaceSizeAsync %s", path);
|
||||
return real_FSGetFreeSpaceSizeAsync(client, block, path, outSize, errorMask, asyncData);
|
||||
}
|
||||
|
||||
|
||||
function_replacement_data_t fs_file_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSOpenFile, LIBRARY_COREINIT, FSOpenFile),
|
||||
REPLACE_FUNCTION(FSOpenFileAsync, LIBRARY_COREINIT, FSOpenFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSCloseFile, LIBRARY_COREINIT, FSCloseFile),
|
||||
REPLACE_FUNCTION(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSGetStat, LIBRARY_COREINIT, FSGetStat),
|
||||
REPLACE_FUNCTION(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSGetStatFile, LIBRARY_COREINIT, FSGetStatFile),
|
||||
REPLACE_FUNCTION(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSReadFile, LIBRARY_COREINIT, FSReadFile),
|
||||
REPLACE_FUNCTION(FSReadFileAsync, LIBRARY_COREINIT, FSReadFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSReadFileWithPos, LIBRARY_COREINIT, FSReadFileWithPos),
|
||||
REPLACE_FUNCTION(FSReadFileWithPosAsync, LIBRARY_COREINIT, FSReadFileWithPosAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSSetPosFile, LIBRARY_COREINIT, FSSetPosFile),
|
||||
REPLACE_FUNCTION(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSGetPosFile, LIBRARY_COREINIT, FSGetPosFile),
|
||||
REPLACE_FUNCTION(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSIsEof, LIBRARY_COREINIT, FSIsEof),
|
||||
REPLACE_FUNCTION(FSIsEofAsync, LIBRARY_COREINIT, FSIsEofAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSWriteFile, LIBRARY_COREINIT, FSWriteFile),
|
||||
REPLACE_FUNCTION(FSWriteFileAsync, LIBRARY_COREINIT, FSWriteFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSTruncateFile, LIBRARY_COREINIT, FSTruncateFile),
|
||||
REPLACE_FUNCTION(FSTruncateFileAsync, LIBRARY_COREINIT, FSTruncateFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSRemove, LIBRARY_COREINIT, FSRemove),
|
||||
REPLACE_FUNCTION(FSRemoveAsync, LIBRARY_COREINIT, FSRemoveAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSRename, LIBRARY_COREINIT, FSRename),
|
||||
REPLACE_FUNCTION(FSRenameAsync, LIBRARY_COREINIT, FSRenameAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSFlushFile, LIBRARY_COREINIT, FSFlushFile),
|
||||
REPLACE_FUNCTION(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync),
|
||||
|
||||
//REPLACE_FUNCTION(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync),
|
||||
|
||||
//REPLACE_FUNCTION(FSGetFreeSpaceSizeAsync, LIBRARY_COREINIT, FSGetFreeSpaceSizeAsync),
|
||||
};
|
||||
|
||||
uint32_t fs_file_function_replacements_size = sizeof(fs_file_function_replacements) / sizeof(function_replacement_data_t);
|
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern function_replacement_data_t fs_file_function_replacements[];
|
||||
extern uint32_t fs_file_function_replacements_size;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
1012
src/FSWrapper.cpp
1012
src/FSWrapper.cpp
File diff suppressed because it is too large
Load Diff
160
src/FSWrapper.h
160
src/FSWrapper.h
@ -1,160 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <coreinit/mutex.h>
|
||||
#include <cstdint>
|
||||
#include <dirent.h>
|
||||
#include <functional>
|
||||
|
||||
typedef struct dirMagic {
|
||||
uint32_t handle{};
|
||||
DIR *dir{};
|
||||
bool in_use{};
|
||||
char path[256]{};
|
||||
|
||||
OSMutex *mutex{};
|
||||
|
||||
FSDirectoryEntry *readResult = nullptr;
|
||||
int readResultCapacity = 0;
|
||||
int readResultNumberOfEntries = 0;
|
||||
|
||||
FSDirectoryHandle realDirHandle = 0;
|
||||
} dirMagic_t;
|
||||
|
||||
typedef struct fileMagic {
|
||||
uint32_t handle;
|
||||
bool in_use;
|
||||
int fd;
|
||||
OSMutex *mutex;
|
||||
} fileMagic_t;
|
||||
|
||||
|
||||
#define ERROR_FLAG_MASK (0xFFFF0000)
|
||||
#define FORCE_REAL_FUNC_MAGIC (0x42420000)
|
||||
#define FORCE_REAL_FUNC_WITH_FULL_ERRORS (FORCE_REAL_FUNC_MAGIC | 0x0000FFFF)
|
||||
|
||||
#define HANDLE_INDICATOR_MASK 0xFFFFFF00
|
||||
#define HANDLE_INDICATOR_MASK 0xFFFFFF00
|
||||
#define HANDLE_MASK (0x000000FF)
|
||||
#define DIR_HANDLE_MAGIC 0x30000000
|
||||
#define FILE_HANDLE_MAGIC 0x30000100
|
||||
|
||||
#define FILE_HANDLES_LENGTH 64
|
||||
#define DIR_HANDLES_LENGTH 64
|
||||
|
||||
#define FS_STATUS_USE_REAL_OS (FSStatus) 0xFFFF0000
|
||||
|
||||
extern dirMagic_t dir_handles[DIR_HANDLES_LENGTH];
|
||||
extern fileMagic_t file_handles[FILE_HANDLES_LENGTH];
|
||||
|
||||
FSStatus FSOpenDirWrapper(char *path,
|
||||
FSDirectoryHandle *handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(char *)> &fallback_function,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
FSDirectoryEntry *entry,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSCloseDirWrapper(FSDirectoryHandle handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSRewindDirWrapper(FSDirectoryHandle handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSMakeDirWrapper(char *path,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(char *)> &fallback_function,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSOpenFileWrapper(char *path,
|
||||
const char *mode,
|
||||
FSFileHandle *handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(char *)> &fallback_function,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSCloseFileWrapper(FSFileHandle handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSGetStatWrapper(char *path,
|
||||
FSStat *stats,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(char *)> &fallback_function,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSGetStatFileWrapper(FSFileHandle handle,
|
||||
FSStat *stats,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSReadFileWrapper(void *buffer,
|
||||
uint32_t size,
|
||||
uint32_t count,
|
||||
FSFileHandle handle,
|
||||
uint32_t unk1,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSReadFileWithPosWrapper(void *buffer,
|
||||
uint32_t size,
|
||||
uint32_t count,
|
||||
uint32_t pos,
|
||||
FSFileHandle handle,
|
||||
int32_t unk1,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSSetPosFileWrapper(FSFileHandle handle,
|
||||
uint32_t pos,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSGetPosFileWrapper(FSFileHandle handle,
|
||||
uint32_t *pos,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSIsEofWrapper(FSFileHandle handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSTruncateFileWrapper(FSFileHandle handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSWriteFileWrapper(uint8_t *buffer,
|
||||
uint32_t size,
|
||||
uint32_t count,
|
||||
FSFileHandle handle,
|
||||
uint32_t unk1,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSRemoveWrapper(char *path,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(char *)> &fallback_function,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSRenameWrapper(char *oldPath,
|
||||
char *newPath,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(char *, char *)> &fallback_function,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
FSStatus FSFlushFileWrapper(FSFileHandle handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler);
|
||||
|
||||
int32_t getNewDirHandleIndex();
|
||||
|
||||
int32_t getNewFileHandleIndex();
|
||||
|
||||
bool isValidDirHandle(int32_t handle);
|
||||
|
||||
bool isValidFileHandle(int32_t handle);
|
@ -1,94 +1,7 @@
|
||||
#include "FileUtils.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/utils.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <map>
|
||||
|
||||
extern "C" OSMessageQueue *OSGetDefaultAppIOQueue();
|
||||
|
||||
FSCmdBlockBody *fsCmdBlockGetBody(FSCmdBlock *cmdBlock) {
|
||||
if (!cmdBlock) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto body = (FSCmdBlockBody *) (ROUNDUP((uint32_t) cmdBlock, 0x40));
|
||||
return body;
|
||||
}
|
||||
|
||||
FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus status) {
|
||||
if (asyncData->callback != nullptr) {
|
||||
if (asyncData->ioMsgQueue != nullptr) {
|
||||
//OSFatal("ERROR: callback and ioMsgQueue both set.");
|
||||
return FS_STATUS_FATAL_ERROR;
|
||||
}
|
||||
// userCallbacks are called in the DefaultAppIOQueue.
|
||||
asyncData->ioMsgQueue = OSGetDefaultAppIOQueue();
|
||||
//DEBUG_FUNCTION_LINE("Force to OSGetDefaultAppIOQueue (%08X)", asyncData->ioMsgQueue);
|
||||
}
|
||||
|
||||
if (asyncData->ioMsgQueue != nullptr) {
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
FSAsyncResult *result = &(fsCmdBlockGetBody(block)->asyncResult);
|
||||
//DEBUG_FUNCTION_LINE("Send result %d to ioMsgQueue (%08X)", status, asyncData->ioMsgQueue);
|
||||
result->asyncData.callback = asyncData->callback;
|
||||
result->asyncData.param = asyncData->param;
|
||||
result->asyncData.ioMsgQueue = asyncData->ioMsgQueue;
|
||||
memset(&result->ioMsg, 0, sizeof(result->ioMsg));
|
||||
result->ioMsg.data = result;
|
||||
result->ioMsg.type = OS_FUNCTION_TYPE_FS_CMD_ASYNC;
|
||||
result->client = client;
|
||||
result->block = block;
|
||||
result->status = status;
|
||||
|
||||
while (!OSSendMessage(asyncData->ioMsgQueue, (OSMessage *) &(result->ioMsg), OS_MESSAGE_FLAGS_NONE)) {
|
||||
DEBUG_FUNCTION_LINE("Failed to send message");
|
||||
}
|
||||
}
|
||||
return FS_STATUS_OK;
|
||||
}
|
||||
|
||||
int32_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count) {
|
||||
int32_t sizeToRead = size * count;
|
||||
/*
|
||||
// https://github.com/decaf-emu/decaf-emu/blob/131aeb14fccff8461a5fd9f2aa5c040ba3880ef5/src/libdecaf/src/cafe/libraries/coreinit/coreinit_fs_cmd.cpp#L2346
|
||||
if (sizeToRead > 0x100000) {
|
||||
sizeToRead = 0x100000;
|
||||
}*/
|
||||
void *newBuffer = buffer;
|
||||
int32_t curResult = -1;
|
||||
int32_t totalSize = 0;
|
||||
// int32_t toRead = 0;
|
||||
while (sizeToRead > 0) {
|
||||
curResult = read(handle, newBuffer, sizeToRead);
|
||||
if (curResult < 0) {
|
||||
DEBUG_FUNCTION_LINE("Error: Reading %08X bytes from handle %08X. result %08X errno: %d ", size * count, handle, curResult, errno);
|
||||
return -1;
|
||||
}
|
||||
if (curResult == 0) {
|
||||
//DEBUG_FUNCTION_LINE("EOF");
|
||||
break;
|
||||
}
|
||||
newBuffer = (void *) (((uint32_t) newBuffer) + curResult);
|
||||
totalSize += curResult;
|
||||
sizeToRead -= curResult;
|
||||
if (sizeToRead > 0) {
|
||||
//DEBUG_FUNCTION_LINE("Reading. missing %08X bytes\n", sizeToRead);
|
||||
}
|
||||
}
|
||||
//DEBUG_FUNCTION_LINE("Success: Read %08X bytes from handle %08X. result %08X \n", size * count, handle, totalSize);
|
||||
return totalSize;
|
||||
}
|
||||
#include <sys/stat.h>
|
||||
|
||||
int32_t CheckFile(const char *filepath) {
|
||||
if (!filepath) {
|
||||
@ -165,92 +78,3 @@ int32_t CreateSubfolder(const char *fullpath) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int32_t getRPXInfoForPath(const std::string &path, romfs_fileInfo *info) {
|
||||
if (romfsMount("rcc", path.c_str(), RomfsSource_FileDescriptor_CafeOS) < 0) {
|
||||
return -1;
|
||||
}
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
if (!(dir = opendir("rcc:/code/"))) {
|
||||
romfsUnmount("rcc");
|
||||
return -2;
|
||||
}
|
||||
bool found = false;
|
||||
int res = -3;
|
||||
while ((entry = readdir(dir)) != nullptr) {
|
||||
if (StringTools::EndsWith(entry->d_name, ".rpx")) {
|
||||
if (romfsGetFileInfoPerPath("rcc", (std::string("code/") + entry->d_name).c_str(), info) >= 0) {
|
||||
found = true;
|
||||
res = 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Failed to get info for %s", entry->d_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
romfsUnmount("rcc");
|
||||
|
||||
if (!found) {
|
||||
return -4;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t LoadFileToMem(const char *filepath, uint8_t **inbuffer, uint32_t *size) {
|
||||
//! always initialze input
|
||||
*inbuffer = nullptr;
|
||||
if (size) {
|
||||
*size = 0;
|
||||
}
|
||||
|
||||
int32_t iFd = open(filepath, O_RDONLY);
|
||||
if (iFd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t filesize = lseek(iFd, 0, SEEK_END);
|
||||
lseek(iFd, 0, SEEK_SET);
|
||||
|
||||
auto *buffer = (uint8_t *) memalign(0x40, ROUNDUP(filesize, 0x40));
|
||||
if (buffer == nullptr) {
|
||||
close(iFd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
uint32_t blocksize = 0x20000;
|
||||
uint32_t done = 0;
|
||||
int32_t readBytes;
|
||||
|
||||
while (done < filesize) {
|
||||
if (done + blocksize > filesize) {
|
||||
blocksize = filesize - done;
|
||||
}
|
||||
readBytes = read(iFd, buffer + done, blocksize);
|
||||
if (readBytes <= 0)
|
||||
break;
|
||||
done += readBytes;
|
||||
}
|
||||
|
||||
::close(iFd);
|
||||
|
||||
if (done != filesize) {
|
||||
free(buffer);
|
||||
buffer = nullptr;
|
||||
return -3;
|
||||
}
|
||||
|
||||
*inbuffer = buffer;
|
||||
|
||||
//! sign is optional input
|
||||
if (size) {
|
||||
*size = filesize;
|
||||
}
|
||||
|
||||
return filesize;
|
||||
}
|
@ -1,23 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <functional>
|
||||
#include <romfs_dev.h>
|
||||
#include <string>
|
||||
|
||||
struct WUT_PACKED FSCmdBlockBody { //! FSAsyncResult object used for this command.
|
||||
|
||||
WUT_UNKNOWN_BYTES(0x96C);
|
||||
FSAsyncResult asyncResult;
|
||||
};
|
||||
WUT_CHECK_OFFSET(FSCmdBlockBody, 0x96C, asyncResult);
|
||||
WUT_CHECK_SIZE(FSCmdBlockBody, 0x96C + 0x28);
|
||||
|
||||
FSCmdBlockBody *fsCmdBlockGetBody(FSCmdBlock *cmdBlock);
|
||||
|
||||
FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus result);
|
||||
|
||||
int32_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count);
|
||||
|
||||
int32_t CreateSubfolder(const char *fullpath);
|
||||
|
||||
int32_t getRPXInfoForPath(const std::string &path, romfs_fileInfo *info);
|
||||
|
@ -1,21 +1,30 @@
|
||||
#include "RPXLoading.h"
|
||||
#include "FileUtils.h"
|
||||
#include "globals.h"
|
||||
#include "utils/FileReader.h"
|
||||
#include "utils/FileReaderCompressed.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/ini.h"
|
||||
#include "utils/logger.h"
|
||||
#include <algorithm>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/ios.h>
|
||||
#include <cstring>
|
||||
#include <dirent.h>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <nn/acp/title.h>
|
||||
#include <romfs_dev.h>
|
||||
#include <rpxloader.h>
|
||||
#include <rpxloader/rpxloader.h>
|
||||
#include <string>
|
||||
#include <wuhb_utils/utils.h>
|
||||
|
||||
std::mutex fileReaderListMutex;
|
||||
std::vector<FileReader *> openFileReaders;
|
||||
|
||||
void RPXLoadingCleanUp() {
|
||||
const std::lock_guard<std::mutex> lock(fileReaderListMutex);
|
||||
for (auto &reader : openFileReaders) {
|
||||
delete reader;
|
||||
}
|
||||
openFileReaders.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
* Patch the meta xml for the home menu
|
||||
@ -39,36 +48,54 @@ DECL_FUNCTION(int32_t, HBM_NN_ACP_ACPGetTitleMetaXmlByDevice, uint32_t titleid_u
|
||||
|
||||
DECL_FUNCTION(int, RPX_FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, int *handle, int error) {
|
||||
const char *iconTex = "iconTex.tga";
|
||||
if (StringTools::EndsWith(path, iconTex)) {
|
||||
if (gReplacementInfo.rpxReplacementInfo.isRPXReplaced) {
|
||||
if (StringTools::EndsWith(path, iconTex)) {
|
||||
auto *reader = new FileReader(reinterpret_cast<uint8_t *>(gReplacementInfo.rpxReplacementInfo.iconCache), ICON_SIZE);
|
||||
*handle = (uint32_t) reader;
|
||||
std::string_view pathView = path;
|
||||
if (gReplacementInfo.rpxReplacementInfo.isRPXReplaced && pathView.ends_with(iconTex)) {
|
||||
const std::lock_guard<std::mutex> lock(fileReaderListMutex);
|
||||
auto *reader = new (std::nothrow) FileReader(reinterpret_cast<uint8_t *>(gReplacementInfo.rpxReplacementInfo.iconCache), ICON_SIZE);
|
||||
if (!reader) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for the FileReader");
|
||||
return FS_STATUS_FATAL_ERROR;
|
||||
}
|
||||
openFileReaders.push_back(reader);
|
||||
*handle = reinterpret_cast<int>(reader);
|
||||
return FS_STATUS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
int result = real_RPX_FSOpenFile(client, block, path, mode, handle, error);
|
||||
return result;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, RPX_FSReadFile, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, uint32_t flags) {
|
||||
// We check if the handle is part of our heap (the MemoryMapping Module allocates to 0x80000000)
|
||||
if ((handle & 0xF0000000) == 0x80000000) {
|
||||
auto reader = (FileReader *) handle;
|
||||
return (FSStatus) reader->read(buffer, size * count);
|
||||
if (gReplacementInfo.rpxReplacementInfo.isRPXReplaced) {
|
||||
const std::lock_guard<std::mutex> lock(fileReaderListMutex);
|
||||
for (auto &reader : openFileReaders) {
|
||||
if ((uint32_t) reader == (uint32_t) handle) {
|
||||
return (FSStatus) (reader->read(buffer, size * count) / size);
|
||||
}
|
||||
FSStatus result = real_RPX_FSReadFile(client, block, buffer, size, count, handle, unk1, flags);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return real_RPX_FSReadFile(client, block, buffer, size, count, handle, unk1, flags);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, RPX_FSCloseFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t flags) {
|
||||
// We check if the handle is part of our heap (the MemoryMapping Module allocates to 0x80000000)
|
||||
if ((handle & 0xF0000000) == 0x80000000) {
|
||||
auto reader = (FileReader *) handle;
|
||||
if (gReplacementInfo.rpxReplacementInfo.isRPXReplaced) {
|
||||
const std::lock_guard<std::mutex> lock(fileReaderListMutex);
|
||||
bool found = false;
|
||||
int index = 0;
|
||||
FileReader *reader = nullptr;
|
||||
for (auto &cur : openFileReaders) {
|
||||
if ((uint32_t) cur == (uint32_t) handle) {
|
||||
found = true;
|
||||
reader = cur;
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
if (found) {
|
||||
openFileReaders.erase(openFileReaders.begin() + index);
|
||||
delete reader;
|
||||
return FS_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return real_RPX_FSCloseFile(client, block, handle, flags);
|
||||
}
|
||||
@ -115,63 +142,56 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) {
|
||||
request.filesize = 0; // unknown filesize
|
||||
request.fileoffset = 0; //
|
||||
|
||||
romfs_fileInfo info;
|
||||
WUHBRPXInfo fileInfo;
|
||||
|
||||
bool metaLoaded = false;
|
||||
|
||||
std::string completePath = std::string("/vol/external01/") + bundle_path;
|
||||
int res = getRPXInfoForPath(completePath, &info);
|
||||
bool isBundle = false;
|
||||
if (res >= 0) {
|
||||
isBundle = true;
|
||||
request.filesize = ((uint32_t *) &info.length)[1];
|
||||
request.fileoffset = ((uint32_t *) &info.offset)[1];
|
||||
|
||||
if (romfsMount("rcc", completePath.c_str(), RomfsSource_FileDescriptor_CafeOS) == 0) {
|
||||
uint8_t *buffer = nullptr;
|
||||
uint32_t size = 0;
|
||||
if (LoadFileToMem("rcc:/meta/meta.ini", &buffer, &size) >= 0 && size > 0) {
|
||||
buffer[size - 1] = 0;
|
||||
bool isBundle = false;
|
||||
auto rpxInfo = WUHBUtils_GetRPXInfo(completePath.c_str(), BundleSource_FileDescriptor_CafeOS, &fileInfo);
|
||||
if (rpxInfo == WUHB_UTILS_RESULT_SUCCESS) {
|
||||
isBundle = true;
|
||||
request.filesize = ((uint32_t *) &fileInfo.length)[1];
|
||||
request.fileoffset = ((uint32_t *) &fileInfo.offset)[1];
|
||||
auto res = -1;
|
||||
|
||||
if (WUHBUtils_MountBundle("rcc", completePath.c_str(), BundleSource_FileDescriptor_CafeOS, &res) == WUHB_UTILS_RESULT_SUCCESS && res == 0) {
|
||||
uint8_t *buffer;
|
||||
uint32_t bufferSize;
|
||||
if (WUHBUtils_ReadWholeFile("rcc:/meta/meta.ini", &buffer, &bufferSize) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||
buffer[bufferSize - 1] = '\0';
|
||||
if (ini_parse_string((const char *) buffer, parseINIhandler, &gReplacementInfo.rpxReplacementInfo.metaInformation) < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to load and parse meta.ini");
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load and parse meta.ini");
|
||||
} else {
|
||||
metaLoaded = true;
|
||||
}
|
||||
}
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read whole file meta.ini");
|
||||
}
|
||||
buffer = nullptr;
|
||||
bufferSize = 0;
|
||||
|
||||
if (WUHBUtils_ReadWholeFile("rcc:/meta/iconTex.tga", &buffer, &bufferSize) == WUHB_UTILS_RESULT_SUCCESS) {
|
||||
uint32_t cpySize = ICON_SIZE;
|
||||
if (bufferSize < cpySize) {
|
||||
cpySize = bufferSize;
|
||||
memset(gReplacementInfo.rpxReplacementInfo.iconCache, 0, ICON_SIZE);
|
||||
}
|
||||
memcpy(gReplacementInfo.rpxReplacementInfo.iconCache, buffer, cpySize);
|
||||
free(buffer);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to read iconTex.tga");
|
||||
}
|
||||
|
||||
FileReader *reader = nullptr;
|
||||
|
||||
if (CheckFile("rcc:/meta/iconTex.tga")) {
|
||||
std::string path = "rcc:/meta/iconTex.tga";
|
||||
reader = new FileReader(path);
|
||||
} else if (CheckFile("rcc:/meta/iconTex.tga.gz")) {
|
||||
std::string path = "rcc:/meta/iconTex.tga.gz";
|
||||
reader = new FileReaderCompressed(path);
|
||||
auto outRes = 0;
|
||||
if (WUHBUtils_UnmountBundle("rcc", &outRes) != WUHB_UTILS_RESULT_SUCCESS || outRes != WUHB_UTILS_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to unmount bundle");
|
||||
}
|
||||
if (reader) {
|
||||
uint32_t alreadyRead = 0;
|
||||
uint32_t toRead = ICON_SIZE;
|
||||
do {
|
||||
int read = reader->read(reinterpret_cast<uint8_t *>(&gReplacementInfo.rpxReplacementInfo.iconCache[alreadyRead]), toRead);
|
||||
if (read <= 0) {
|
||||
break;
|
||||
}
|
||||
alreadyRead += read;
|
||||
toRead -= read;
|
||||
} while (alreadyRead < ICON_SIZE);
|
||||
delete reader;
|
||||
} else {
|
||||
memset(gReplacementInfo.rpxReplacementInfo.iconCache, 0, sizeof(gReplacementInfo.rpxReplacementInfo.iconCache));
|
||||
}
|
||||
romfsUnmount("rcc");
|
||||
}
|
||||
} else {
|
||||
if (!(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE &&
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) {
|
||||
if (!gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) {
|
||||
memset(gReplacementInfo.rpxReplacementInfo.iconCache, 0, sizeof(gReplacementInfo.rpxReplacementInfo.iconCache));
|
||||
}
|
||||
}
|
||||
@ -207,7 +227,7 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) {
|
||||
|
||||
if (!success) {
|
||||
gReplacementInfo.rpxReplacementInfo.willRPXBeReplaced = false;
|
||||
DEBUG_FUNCTION_LINE("Failed to load %s on next restart", request.path);
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to load %s on next restart", request.path);
|
||||
return false;
|
||||
} else {
|
||||
gReplacementInfo.rpxReplacementInfo.willRPXBeReplaced = true;
|
||||
@ -215,27 +235,21 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) {
|
||||
|
||||
DEBUG_FUNCTION_LINE("Launch %s on next restart [size: %08X offset: %08X]", request.path, request.filesize, request.fileoffset);
|
||||
|
||||
if (isBundle) {
|
||||
DEBUG_FUNCTION_LINE("Loaded file is a .wuhb bundle");
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath[0] = '\0';
|
||||
if (isBundle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Loaded file is a .wuhb bundle");
|
||||
strncat(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath,
|
||||
completePath.c_str(),
|
||||
sizeof(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath) - 1);
|
||||
gReplacementInfo.contentReplacementInfo.mode = CONTENTREDIRECT_FROM_WUHB_BUNDLE;
|
||||
gReplacementInfo.contentReplacementInfo.replaceSave = true;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Loaded file is no bundle");
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Loaded file is no bundle");
|
||||
gReplacementInfo.rpxReplacementInfo.willRPXBeReplaced = true;
|
||||
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE &&
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) {
|
||||
if (gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) {
|
||||
// keep the old /vol/content mounted, this way you can reload just the rpx via wiiload
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath[0] = '\0';
|
||||
strncat(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath,
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath,
|
||||
sizeof(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath) - 2);
|
||||
} else {
|
||||
gReplacementInfo.contentReplacementInfo.replaceSave = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,99 +258,89 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t RL_MountBundle(const char *name, const char *path, BundleSource source) {
|
||||
return romfsMount(name, path, (RomfsSource) source);
|
||||
std::mutex mutex;
|
||||
|
||||
bool RL_DisableContentRedirection() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (contentLayerHandle != 0) {
|
||||
auto res = ContentRedirection_SetActive(contentLayerHandle, false);
|
||||
if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (saveLayerHandle != 0) {
|
||||
auto res = ContentRedirection_SetActive(saveLayerHandle, false);
|
||||
if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
ContentRedirection_SetActive(contentLayerHandle, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t RL_UnmountBundle(const char *name) {
|
||||
return romfsUnmount(name);
|
||||
bool RL_EnableContentRedirection() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (contentLayerHandle != 0) {
|
||||
auto res = ContentRedirection_SetActive(contentLayerHandle, true);
|
||||
if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (saveLayerHandle != 0) {
|
||||
auto res = ContentRedirection_SetActive(saveLayerHandle, true);
|
||||
if (res != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
ContentRedirection_SetActive(contentLayerHandle, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RL_UnmountCurrentRunningBundle() {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
if (gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted == false) {
|
||||
return true;
|
||||
}
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE) {
|
||||
if (gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) {
|
||||
DEBUG_FUNCTION_LINE("Unmount /vol/content");
|
||||
romfsUnmount("rom");
|
||||
|
||||
int outRes = -1;
|
||||
if (ContentRedirection_RemoveDevice(WUHB_ROMFS_NAME, &outRes) == CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
if (outRes < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("RemoveDevice \"%s\" failed for ContentRedirection Module", WUHB_ROMFS_NAME);
|
||||
OSFatal("RL_UnmountCurrentRunningBundle: RemoveDevice \"" WUHB_ROMFS_NAME "\" failed for ContentRedirection Module");
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("ContentRedirection_RemoveDevice failed");
|
||||
OSFatal("RL_UnmountCurrentRunningBundle: ContentRedirection_RemoveDevice failed");
|
||||
}
|
||||
|
||||
bool res = true;
|
||||
|
||||
if (contentLayerHandle != 0) {
|
||||
if (ContentRedirection_RemoveFSLayer(contentLayerHandle) != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
res = false;
|
||||
}
|
||||
contentLayerHandle = 0;
|
||||
}
|
||||
|
||||
if (saveLayerHandle != 0) {
|
||||
if (ContentRedirection_RemoveFSLayer(saveLayerHandle) != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
res = false;
|
||||
}
|
||||
saveLayerHandle = 0;
|
||||
}
|
||||
|
||||
romfsUnmount(WUHB_ROMFS_NAME);
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = false;
|
||||
OSMemoryBarrier();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
int32_t RL_FileOpen(const char *name, uint32_t *handle) {
|
||||
if (handle == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
FileReader *reader;
|
||||
std::string path = std::string(name);
|
||||
std::string pathGZ = path + ".gz";
|
||||
|
||||
if (CheckFile(path.c_str())) {
|
||||
reader = new FileReader(path);
|
||||
} else if (CheckFile(pathGZ.c_str())) {
|
||||
reader = new FileReaderCompressed(pathGZ);
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
if (reader == nullptr) {
|
||||
return -3;
|
||||
}
|
||||
*handle = (uint32_t) reader;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t RL_FileRead(uint32_t handle, uint8_t *buffer, uint32_t size) {
|
||||
auto reader = (FileReader *) handle;
|
||||
return reader->read(buffer, size);
|
||||
}
|
||||
|
||||
int32_t RL_FileClose(uint32_t handle) {
|
||||
auto reader = (FileReader *) handle;
|
||||
delete reader;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool RL_FileExists(const char *name) {
|
||||
std::string checkgz = std::string(name) + ".gz";
|
||||
return CheckFile(name) || CheckFile(checkgz.c_str());
|
||||
}
|
||||
|
||||
bool RL_RedirectContentWithFallback(const char *newContentPath) {
|
||||
auto dirHandle = opendir(newContentPath);
|
||||
if (dirHandle == nullptr) {
|
||||
return false;
|
||||
}
|
||||
closedir(dirHandle);
|
||||
|
||||
gReplacementInfo.contentReplacementInfo.replacementPath[0] = '\0';
|
||||
strncat(gReplacementInfo.contentReplacementInfo.replacementPath, newContentPath, sizeof(gReplacementInfo.contentReplacementInfo.replacementPath) - 1);
|
||||
gReplacementInfo.contentReplacementInfo.mode = CONTENTREDIRECT_FROM_PATH;
|
||||
gReplacementInfo.contentReplacementInfo.fallbackOnError = true;
|
||||
gReplacementInfo.contentReplacementInfo.replaceSave = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RL_DisableContentRedirection() {
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
gReplacementInfo.contentReplacementInfo.mode = CONTENTREDIRECT_NONE;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
RPXLoaderVersion RL_GetVersion() {
|
||||
return RPX_LOADER_MODULE_VERSION;
|
||||
}
|
||||
|
||||
WUMS_EXPORT_FUNCTION(RL_GetVersion);
|
||||
WUMS_EXPORT_FUNCTION(RL_LoadFromSDOnNextLaunch);
|
||||
WUMS_EXPORT_FUNCTION(RL_MountBundle);
|
||||
WUMS_EXPORT_FUNCTION(RL_UnmountBundle);
|
||||
WUMS_EXPORT_FUNCTION(RL_FileOpen);
|
||||
WUMS_EXPORT_FUNCTION(RL_FileRead);
|
||||
WUMS_EXPORT_FUNCTION(RL_FileClose);
|
||||
WUMS_EXPORT_FUNCTION(RL_FileExists);
|
||||
WUMS_EXPORT_FUNCTION(RL_RedirectContentWithFallback);
|
||||
WUMS_EXPORT_FUNCTION(RL_EnableContentRedirection);
|
||||
WUMS_EXPORT_FUNCTION(RL_DisableContentRedirection);
|
||||
WUMS_EXPORT_FUNCTION(RL_UnmountCurrentRunningBundle);
|
@ -18,6 +18,9 @@ typedef struct __attribute((packed)) {
|
||||
extern function_replacement_data_t rpx_utils_function_replacements[];
|
||||
extern uint32_t rpx_utils_function_replacements_size;
|
||||
|
||||
void RPXLoadingCleanUp();
|
||||
bool RL_UnmountCurrentRunningBundle();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
4
src/contentredirection.def
Normal file
4
src/contentredirection.def
Normal file
@ -0,0 +1,4 @@
|
||||
:NAME homebrew_content_redirection
|
||||
|
||||
:TEXT
|
||||
CRGetVersion
|
@ -1,7 +1,5 @@
|
||||
#include "globals.h"
|
||||
#include <coreinit/filesystem.h>
|
||||
|
||||
RPXLoader_ReplacementInformation gReplacementInfo __attribute__((section(".data")));
|
||||
|
||||
FSClient *gFSClient __attribute__((section(".data"))) = nullptr;
|
||||
FSCmdBlock *gFSCmd __attribute__((section(".data"))) = nullptr;
|
||||
CRLayerHandle contentLayerHandle __attribute__((section(".data"))) = 0;
|
||||
CRLayerHandle saveLayerHandle __attribute__((section(".data"))) = 0;
|
@ -1,9 +1,14 @@
|
||||
#include "utils/utils.h"
|
||||
#include <content_redirection/redirection.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <coreinit/mutex.h>
|
||||
#include <wums.h>
|
||||
#include <wut.h>
|
||||
|
||||
#define WUHB_ROMFS_NAME "wuhbrom"
|
||||
#define WUHB_ROMFS_PATH WUHB_ROMFS_NAME ":"
|
||||
#define WUHB_ROMFS_CONTENT_PATH WUHB_ROMFS_PATH "/content"
|
||||
|
||||
typedef struct WUT_PACKED MetaInformation_t {
|
||||
char shortname[64];
|
||||
char longname[64];
|
||||
@ -11,7 +16,7 @@ typedef struct WUT_PACKED MetaInformation_t {
|
||||
} MetaInformation;
|
||||
WUT_CHECK_SIZE(MetaInformation_t, 0xC0);
|
||||
|
||||
typedef struct BundleMountInformation_t {
|
||||
typedef struct ContentRedirectionInformation_t {
|
||||
bool isMounted;
|
||||
char toMountPath[255];
|
||||
char mountedPath[255];
|
||||
@ -29,35 +34,22 @@ typedef struct WUT_PACKED RPXReplacementInfo_t {
|
||||
// make sure the iconCache is aligned to 0x40
|
||||
WUT_CHECK_OFFSET(RPXReplacementInfo, 0x100, iconCache);
|
||||
|
||||
|
||||
typedef enum ContentRedirect_Mode {
|
||||
CONTENTREDIRECT_NONE,
|
||||
CONTENTREDIRECT_FROM_WUHB_BUNDLE,
|
||||
CONTENTREDIRECT_FROM_PATH,
|
||||
} ContentRedirect_Mode;
|
||||
|
||||
typedef struct ContentReplacementInfo_t {
|
||||
ContentRedirect_Mode mode;
|
||||
|
||||
BundleMountInformation bundleMountInformation;
|
||||
|
||||
char workingDir[255];
|
||||
|
||||
char replacementPath[255];
|
||||
|
||||
bool replaceSave;
|
||||
|
||||
char savePath[255];
|
||||
|
||||
bool fallbackOnError;
|
||||
char replacementPath[0x280];
|
||||
} ContentReplacementInfo;
|
||||
|
||||
typedef struct ContentReplacementWithFallback_t {
|
||||
char replacementPath[0x280];
|
||||
} ContentReplacementWithFallback;
|
||||
|
||||
typedef struct RPXLoader_ReplacementInformation_t {
|
||||
RPXReplacementInfo rpxReplacementInfo;
|
||||
ContentReplacementInfo contentReplacementInfo;
|
||||
ContentReplacementWithFallback contentReplacementWithFallbackInfo;
|
||||
} RPXLoader_ReplacementInformation;
|
||||
|
||||
|
||||
extern RPXLoader_ReplacementInformation gReplacementInfo;
|
||||
extern FSClient *gFSClient;
|
||||
extern FSCmdBlock *gFSCmd;
|
||||
|
||||
extern CRLayerHandle contentLayerHandle;
|
||||
extern CRLayerHandle saveLayerHandle;
|
171
src/main.cpp
171
src/main.cpp
@ -1,60 +1,62 @@
|
||||
#include <cstring>
|
||||
#include <malloc.h>
|
||||
#include <wums.h>
|
||||
|
||||
#include "FSDirReplacements.h"
|
||||
#include "FSFileReplacements.h"
|
||||
#include "FileUtils.h"
|
||||
#include "RPXLoading.h"
|
||||
#include "globals.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/logger.h"
|
||||
#include <content_redirection/redirection.h>
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/debug.h>
|
||||
#include <coreinit/title.h>
|
||||
#include <string>
|
||||
#include <sysapp/title.h>
|
||||
|
||||
#include <coreinit/cache.h>
|
||||
#include <nn/act.h>
|
||||
#include <romfs_dev.h>
|
||||
#include <string>
|
||||
#include <sysapp/title.h>
|
||||
#include <wuhb_utils/utils.h>
|
||||
#include <wums.h>
|
||||
|
||||
WUMS_MODULE_EXPORT_NAME("homebrew_rpx_loader");
|
||||
WUMS_USE_WUT_DEVOPTAB();
|
||||
|
||||
extern "C" bool CRGetVersion();
|
||||
extern "C" bool WUU_GetVersion();
|
||||
|
||||
WUMS_INITIALIZE() {
|
||||
initLogging();
|
||||
DEBUG_FUNCTION_LINE("Patch functions");
|
||||
// we only patch static functions, we don't need re-patch them at every launch
|
||||
FunctionPatcherPatchFunction(fs_file_function_replacements, fs_file_function_replacements_size);
|
||||
FunctionPatcherPatchFunction(fs_dir_function_replacements, fs_dir_function_replacements_size);
|
||||
FunctionPatcherPatchFunction(rpx_utils_function_replacements, rpx_utils_function_replacements_size);
|
||||
DEBUG_FUNCTION_LINE("Patch functions finished");
|
||||
gReplacementInfo = {};
|
||||
|
||||
// Call this function to make sure the Content Redirection will be loaded before this module is module.
|
||||
CRGetVersion();
|
||||
|
||||
// Call this function to make sure the WUHBUtils will be loaded before this module is module.
|
||||
WUU_GetVersion();
|
||||
|
||||
// But then use libcontentredirection instead.
|
||||
ContentRedirectionStatus error;
|
||||
if ((error = ContentRedirection_Init()) != CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to init ContentRedirection. Error %d", error);
|
||||
OSFatal("Failed to init ContentRedirection.");
|
||||
}
|
||||
|
||||
// But then use libwuhbutils instead.
|
||||
WUHBUtilsStatus error2;
|
||||
if ((error2 = WUHBUtils_Init()) != WUHB_UTILS_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_ERR("RPXLoadingModule: Failed to init WUHBUtils. Error %d", error2);
|
||||
OSFatal("Failed to init WUHBUtils.");
|
||||
}
|
||||
|
||||
deinitLogging();
|
||||
}
|
||||
|
||||
|
||||
WUMS_APPLICATION_ENDS() {
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
gReplacementInfo.contentReplacementInfo.mode = CONTENTREDIRECT_NONE;
|
||||
}
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE) {
|
||||
if (gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) {
|
||||
DEBUG_FUNCTION_LINE("Unmount /vol/content");
|
||||
romfsUnmount("rom");
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = false;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
}
|
||||
RL_UnmountCurrentRunningBundle();
|
||||
|
||||
gReplacementInfo.rpxReplacementInfo.isRPXReplaced = false;
|
||||
if (gFSClient) {
|
||||
FSDelClient(gFSClient, FS_ERROR_FLAG_ALL);
|
||||
free(gFSClient);
|
||||
gFSClient = nullptr;
|
||||
}
|
||||
free(gFSCmd);
|
||||
gFSCmd = nullptr;
|
||||
|
||||
RPXLoadingCleanUp();
|
||||
|
||||
deinitLogging();
|
||||
}
|
||||
@ -70,74 +72,75 @@ WUMS_APPLICATION_STARTS() {
|
||||
gReplacementInfo.rpxReplacementInfo.isRPXReplaced = true;
|
||||
}
|
||||
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
auto fsClient = (FSClient *) memalign(0x20, sizeof(FSClient));
|
||||
auto fsCmd = (FSCmdBlock *) memalign(0x20, sizeof(FSCmdBlock));
|
||||
|
||||
if (fsClient == nullptr || fsCmd == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc memory for fsclient or fsCmd");
|
||||
free(fsClient);
|
||||
free(fsCmd);
|
||||
} else {
|
||||
auto rc = FSAddClient(fsClient, FS_ERROR_FLAG_ALL);
|
||||
if (rc < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to add FSClient");
|
||||
} else {
|
||||
FSInitCmdBlock(fsCmd);
|
||||
gFSClient = fsClient;
|
||||
gFSCmd = fsCmd;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_HEALTH_AND_SAFETY) != OSGetTitleID()) {
|
||||
DEBUG_FUNCTION_LINE("Set mode to CONTENTREDIRECT_NONE and replaceSave to false");
|
||||
gReplacementInfo.contentReplacementInfo.mode = CONTENTREDIRECT_NONE;
|
||||
gReplacementInfo.contentReplacementInfo.replaceSave = false;
|
||||
OSMemoryBarrier();
|
||||
} else {
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE) {
|
||||
if (_SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_HEALTH_AND_SAFETY) == OSGetTitleID() &&
|
||||
strlen(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath) > 0) {
|
||||
uint32_t currentHash = StringTools::hash(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath);
|
||||
|
||||
nn::act::Initialize();
|
||||
nn::act::PersistentId persistentId = nn::act::GetPersistentId();
|
||||
nn::act::Finalize();
|
||||
|
||||
std::string basePath = StringTools::strfmt("/vol/external01/wiiu/apps/save/%08X", currentHash);
|
||||
std::string common = StringTools::strfmt("fs:/vol/external01/wiiu/apps/save/%08X/common", currentHash);
|
||||
std::string user = StringTools::strfmt("fs:/vol/external01/wiiu/apps/save/%08X/%08X", currentHash, 0x80000000 | persistentId);
|
||||
|
||||
gReplacementInfo.contentReplacementInfo.savePath[0] = '\0';
|
||||
strncat(gReplacementInfo.contentReplacementInfo.savePath,
|
||||
basePath.c_str(),
|
||||
sizeof(gReplacementInfo.contentReplacementInfo.savePath) - 1);
|
||||
|
||||
memset(gReplacementInfo.contentReplacementInfo.workingDir, 0, sizeof(gReplacementInfo.contentReplacementInfo.workingDir));
|
||||
std::string basePath = string_format("/vol/external01/wiiu/apps/save/%08X", currentHash);
|
||||
std::string common = string_format("fs:/vol/external01/wiiu/apps/save/%08X/common", currentHash);
|
||||
std::string user = string_format("fs:/vol/external01/wiiu/apps/save/%08X/%08X", currentHash, 0x80000000 | persistentId);
|
||||
|
||||
CreateSubfolder(common.c_str());
|
||||
CreateSubfolder(user.c_str());
|
||||
DEBUG_FUNCTION_LINE("Created %s and %s", common.c_str(), user.c_str());
|
||||
if (romfsMount("rom", gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath, RomfsSource_FileDescriptor_CafeOS) == 0) {
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath[0] = '\0';
|
||||
strncat(gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath,
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath,
|
||||
sizeof(gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath) - 1);
|
||||
|
||||
|
||||
gReplacementInfo.contentReplacementInfo.replacementPath[0] = '\0';
|
||||
strncat(gReplacementInfo.contentReplacementInfo.replacementPath,
|
||||
"rom:/content",
|
||||
sizeof(gReplacementInfo.contentReplacementInfo.replacementPath) - 1);
|
||||
|
||||
DEBUG_FUNCTION_LINE("Mounted %s to /vol/content", gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath);
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = true;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Failed to mount %s", gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath);
|
||||
if (romfsMount(WUHB_ROMFS_NAME, gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath, RomfsSource_FileDescriptor_CafeOS) == 0) {
|
||||
auto device = GetDeviceOpTab(WUHB_ROMFS_PATH);
|
||||
if (device == nullptr || strcmp(device->name, WUHB_ROMFS_NAME) != 0) {
|
||||
romfsUnmount(WUHB_ROMFS_NAME);
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = false;
|
||||
DEBUG_FUNCTION_LINE_ERR("DeviceOpTab for %s not found.", WUHB_ROMFS_PATH);
|
||||
return;
|
||||
}
|
||||
int outRes = -1;
|
||||
if (ContentRedirection_AddDevice(device, &outRes) != CONTENT_REDIRECTION_RESULT_SUCCESS || outRes < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to AddDevice to ContentRedirection");
|
||||
romfsUnmount(WUHB_ROMFS_NAME);
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = false;
|
||||
return;
|
||||
}
|
||||
auto res = ContentRedirection_AddFSLayer(&contentLayerHandle,
|
||||
"WUHB Content",
|
||||
WUHB_ROMFS_CONTENT_PATH,
|
||||
FS_LAYER_TYPE_CONTENT_REPLACE);
|
||||
if (res == CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
res = ContentRedirection_AddFSLayer(&saveLayerHandle,
|
||||
"WUHB Save",
|
||||
basePath.c_str(),
|
||||
FS_LAYER_TYPE_SAVE_REPLACE);
|
||||
if (res == CONTENT_REDIRECTION_RESULT_SUCCESS) {
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath[0] = '\0';
|
||||
strncpy(gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath,
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath,
|
||||
sizeof(gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath));
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Mounted %s to /vol/content", gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath);
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = true;
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath[0] = '\0';
|
||||
|
||||
OSMemoryBarrier();
|
||||
return;
|
||||
} else {
|
||||
if (contentLayerHandle != 0) {
|
||||
ContentRedirection_RemoveFSLayer(contentLayerHandle);
|
||||
contentLayerHandle = 0;
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("ContentRedirection_AddFSLayer had failed for save");
|
||||
}
|
||||
} else {
|
||||
int outRes = -1;
|
||||
if (ContentRedirection_RemoveDevice(WUHB_ROMFS_PATH, &outRes) != CONTENT_REDIRECTION_RESULT_SUCCESS || res < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to remove device");
|
||||
}
|
||||
romfsUnmount(WUHB_ROMFS_PATH);
|
||||
DEBUG_FUNCTION_LINE_ERR("ContentRedirection_AddFSLayer had failed for content");
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to mount %s", gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath);
|
||||
gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = false;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "logger.h"
|
||||
#include <cstring>
|
||||
|
||||
int FileReader::read(uint8_t *buffer, uint32_t size) {
|
||||
int64_t FileReader::read(uint8_t *buffer, uint32_t size) {
|
||||
if (isReadFromBuffer) {
|
||||
if (input_buffer == nullptr) {
|
||||
return -1;
|
||||
@ -31,7 +31,7 @@ FileReader::FileReader(std::string &path) {
|
||||
this->isReadFromBuffer = false;
|
||||
this->file_fd = fd;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Failed to open file %s", path.c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to open file %s", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ public:
|
||||
|
||||
virtual ~FileReader();
|
||||
|
||||
virtual int read(uint8_t *buffer, uint32_t size);
|
||||
virtual int64_t read(uint8_t *buffer, uint32_t size);
|
||||
|
||||
private:
|
||||
bool isReadFromBuffer = false;
|
||||
@ -24,5 +24,5 @@ private:
|
||||
uint32_t input_pos = 0;
|
||||
|
||||
bool isReadFromFile = false;
|
||||
int file_fd = 0;
|
||||
int file_fd = -1;
|
||||
};
|
||||
|
@ -1,89 +0,0 @@
|
||||
#include "FileReaderCompressed.h"
|
||||
|
||||
int FileReaderCompressed::read(uint8_t *buffer, uint32_t size) {
|
||||
if (!initDone) {
|
||||
return -11;
|
||||
}
|
||||
int startValue = this->strm.total_out;
|
||||
uint32_t newSize = 0;
|
||||
int ret = 0;
|
||||
do {
|
||||
uint32_t nextOut = BUFFER_SIZE;
|
||||
if (nextOut > size) {
|
||||
nextOut = size;
|
||||
}
|
||||
if (this->strm.avail_in == 0) {
|
||||
int read_res = FileReader::read(this->zlib_in_buf, BUFFER_SIZE);
|
||||
if (read_res <= 0) {
|
||||
break;
|
||||
}
|
||||
this->strm.avail_in = read_res;
|
||||
this->strm.next_in = this->zlib_in_buf;
|
||||
}
|
||||
/* run inflate() on input until output buffer not full */
|
||||
do {
|
||||
if (nextOut > size - newSize) {
|
||||
nextOut = size - newSize;
|
||||
}
|
||||
|
||||
this->strm.avail_out = nextOut;
|
||||
this->strm.next_out = buffer + newSize;
|
||||
ret = inflate(&this->strm, Z_NO_FLUSH);
|
||||
|
||||
if (ret == Z_STREAM_ERROR) {
|
||||
DEBUG_FUNCTION_LINE("Z_STREAM_ERROR");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ret) {
|
||||
case Z_NEED_DICT:
|
||||
DEBUG_FUNCTION_LINE("Z_NEED_DICT");
|
||||
ret = Z_DATA_ERROR;
|
||||
[[fallthrough]]; /* and fall through */
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
DEBUG_FUNCTION_LINE("Z_MEM_ERROR or Z_DATA_ERROR");
|
||||
(void) inflateEnd(&this->strm);
|
||||
return ret;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
newSize = this->strm.total_out - startValue;
|
||||
if (newSize == size) {
|
||||
break;
|
||||
}
|
||||
nextOut = BUFFER_SIZE;
|
||||
if (newSize + nextOut >= (size)) {
|
||||
nextOut = (size) -newSize;
|
||||
}
|
||||
} while (this->strm.avail_out == 0 && newSize < (size));
|
||||
|
||||
/* done when inflate() says it's done */
|
||||
} while (ret != Z_STREAM_END && newSize < size);
|
||||
|
||||
return newSize;
|
||||
}
|
||||
|
||||
FileReaderCompressed::FileReaderCompressed(std::string &file) : FileReader(file) {
|
||||
this->initCompressedData();
|
||||
}
|
||||
|
||||
void FileReaderCompressed::initCompressedData() {
|
||||
/* allocate inflate state */
|
||||
this->strm.zalloc = Z_NULL;
|
||||
this->strm.zfree = Z_NULL;
|
||||
this->strm.opaque = Z_NULL;
|
||||
this->strm.avail_in = 0;
|
||||
this->strm.next_in = Z_NULL;
|
||||
int ret = inflateInit2(&this->strm, MAX_WBITS | 16); //gzip
|
||||
if (ret != Z_OK) {
|
||||
DEBUG_FUNCTION_LINE("inflateInit2 failed");
|
||||
return;
|
||||
}
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
FileReaderCompressed::FileReaderCompressed(uint8_t *buffer, uint32_t size) : FileReader(buffer, size) {
|
||||
this->initCompressedData();
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "FileReader.h"
|
||||
#include "logger.h"
|
||||
#include <zlib.h>
|
||||
|
||||
#define BUFFER_SIZE 0x20000
|
||||
|
||||
class FileReaderCompressed : public FileReader {
|
||||
public:
|
||||
FileReaderCompressed(uint8_t *buffer, uint32_t size);
|
||||
|
||||
explicit FileReaderCompressed(std::string &file);
|
||||
|
||||
~FileReaderCompressed() override = default;
|
||||
|
||||
int read(uint8_t *buffer, uint32_t size) override;
|
||||
|
||||
private:
|
||||
bool initDone = false;
|
||||
alignas(0x40) uint8_t zlib_in_buf[BUFFER_SIZE]{};
|
||||
z_stream strm{};
|
||||
|
||||
void initCompressedData();
|
||||
};
|
@ -1,294 +1,5 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <strings.h>
|
||||
#include <stdint.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;
|
||||
|
||||
char TokCopy[512];
|
||||
strncpy(TokCopy, compare, sizeof(TokCopy));
|
||||
TokCopy[511] = '\0';
|
||||
|
||||
char *strTok = strtok(TokCopy, separator);
|
||||
|
||||
while (strTok != NULL) {
|
||||
if (strcasecmp(string, strTok) == 0) {
|
||||
return 0;
|
||||
}
|
||||
strTok = strtok(NULL, 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;
|
||||
|
||||
const char *ptr = path;
|
||||
const char *Filename = ptr;
|
||||
|
||||
while (*ptr != '\0') {
|
||||
if (ptr[0] == '/' && ptr[1] != '\0')
|
||||
Filename = ptr + 1;
|
||||
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return Filename;
|
||||
}
|
||||
|
||||
void StringTools::RemoveDoubleSlashs(std::string &str) {
|
||||
uint32_t length = str.size();
|
||||
|
||||
//! clear path of double slashes
|
||||
for (uint32_t i = 1; i < length; ++i) {
|
||||
if (str[i - 1] == '/' && str[i] == '/') {
|
||||
str.erase(i, 1);
|
||||
i--;
|
||||
length--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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 nullptr;
|
||||
len_rep = strlen(rep);
|
||||
if (len_rep == 0)
|
||||
return nullptr; // empty rep causes infinite loop during count
|
||||
if (!with)
|
||||
with = (char *) "";
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/* hash: compute hash value of string */
|
||||
uint32_t StringTools::hash(char *str) {
|
||||
|
@ -1,66 +1,21 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010
|
||||
* by Dimok
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any
|
||||
* damages arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any
|
||||
* purpose, including commercial applications, and to alter it and
|
||||
* redistribute it freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you
|
||||
* must not claim that you wrote the original software. If you use
|
||||
* this software in a product, an acknowledgment in the product
|
||||
* documentation would be appreciated but is not required.
|
||||
*
|
||||
* 2. Altered source versions must be plainly marked as such, and
|
||||
* must not be misrepresented as being the original software.
|
||||
*
|
||||
* 3. This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*
|
||||
* for WiiXplorer 2010
|
||||
***************************************************************************/
|
||||
#ifndef __STRING_TOOLS_H
|
||||
#define __STRING_TOOLS_H
|
||||
#pragma once
|
||||
|
||||
#include "logger.h"
|
||||
#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);
|
||||
|
||||
static uint32_t hash(char *str);
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
// #define VERBOSE_DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
#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();
|
||||
|
4
src/wuhbutils.def
Normal file
4
src/wuhbutils.def
Normal file
@ -0,0 +1,4 @@
|
||||
:NAME homebrew_wuhb_utils
|
||||
|
||||
:TEXT
|
||||
WUU_GetVersion
|
Loading…
Reference in New Issue
Block a user