diff --git a/Makefile b/Makefile index dc52e93..d2e277a 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,7 @@ GAME_DOL_LOADER := game_dol_loader TARGET := $(notdir $(CURDIR)) BUILD := build RELEASE := $(BUILD)/release +EXTRA_CFLAGS ?= SOURCES := source source/update source/pngu source/loader DATA := data TEXTURES := textures @@ -38,11 +39,11 @@ INCLUDES := # Find the length of the `patch_dol` function in $(GAME_DOL_LOADER).c and expose it as a macro, which is needed because we memcpy() it. PATCH_DOL_LEN = 0x$(shell $(DEVKITPPC)/bin/powerpc-eabi-objdump $(GAME_DOL_LOADER).o -t | grep ' patch_dol' | awk '{print $$5}') -CFLAGS = -DPATCH_DOL_LEN=$(PATCH_DOL_LEN) -fno-builtin -g -O2 -Wall $(MACHDEP) $(INCLUDE) -CXXFLAGS = $(CFLAGS) +CFLAGS = -DPATCH_DOL_LEN=$(PATCH_DOL_LEN) $(EXTRA_CFLAGS) -fno-builtin -g -O2 -Wall $(MACHDEP) $(INCLUDE) +CXXFLAGS = $(CFLAGS) # compiler flags for the special $(GAME_DOL_LOADER).c file -GAME_DOL_LOADER_CFLAGS = -O2 -fno-builtin -Wall -g $(MACHDEP) $(INCLUDE) +GAME_DOL_LOADER_CFLAGS = $(EXTRA_CFLAGS) -O2 -fno-builtin -Wall -g $(MACHDEP) $(INCLUDE) LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map @@ -116,15 +117,37 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ -L$(LIBOGC_LIB) export OUTPUT := $(CURDIR)/$(TARGET) -.PHONY: $(BUILD) clean +.PHONY: $(BUILD) build debug beta beta-package clean release run #--------------------------------------------------------------------------------- $(BUILD): - make --no-print-directory -C runtime-ext + make --no-print-directory -C runtime-ext EXTRA_CFLAGS="$(EXTRA_CFLAGS)" @[ -d $@ ] || mkdir -p $@ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile #--------------------------------------------------------------------------------- +debug: EXTRA_CFLAGS := -DRRC_DEBUG=1 +debug: export EXTRA_CFLAGS := -DRRC_DEBUG=1 +debug: $(BUILD) debug-package + +debug-package: + # Move files to a debug staging directory instead of the release directory + mkdir -p $(BUILD)/debug/RetroRewindChannel + mkdir -p $(BUILD)/debug/apps/RetroRewind + cp runtime-ext/runtime-ext-* $(BUILD)/debug/RetroRewindChannel + cp $(OUTPUT).dol $(BUILD)/debug/apps/RetroRewind/boot.dol + +beta: EXTRA_CFLAGS := -DRRC_BETA=1 +beta: export EXTRA_CFLAGS := -DRRC_BETA=1 +beta: $(BUILD) beta-package + +beta-package: + # Move files to a beta staging directory instead of the release directory + mkdir -p $(BUILD)/beta/RetroRewindChannelBeta + mkdir -p $(BUILD)/beta/apps/RetroRewindBeta + cp runtime-ext/runtime-ext-* $(BUILD)/beta/RetroRewindChannelBeta + cp $(OUTPUT).dol $(BUILD)/beta/apps/RetroRewindBeta/boot.dol + clean: @echo clean ... make --no-print-directory -C runtime-ext clean diff --git a/runtime-ext/Makefile b/runtime-ext/Makefile index f79e7d0..86a8e4f 100644 --- a/runtime-ext/Makefile +++ b/runtime-ext/Makefile @@ -15,8 +15,11 @@ OFILES := $(addprefix build/,$(CFILES:.c=.o)) # Prevent deletion of .o files, helps with incr rebuilds .SECONDARY: $(OFILES) +.PHONY: all debug beta clean + INCLUDE := -I../shared -Ivendor -Ivendor/bslug_include -CFLAGS := -nostdlib -mno-eabi -O2 -Wall $(MACHDEP) $(INCLUDE) +EXTRA_CFLAGS ?= +CFLAGS := $(EXTRA_CFLAGS) -nostdlib -mno-eabi -O2 -Wall $(MACHDEP) $(INCLUDE) LINKERSCRIPTS := $(wildcard linker-*.ld) # get region characters @@ -33,6 +36,14 @@ LDFLAGS := $(OFILES) $(MACHDEP) -Wl,--section-start=.init=81744260,--section-sta all: $(DOLS) +debug: EXTRA_CFLAGS := -DDEBUG=1 +debug: export EXTRA_CFLAGS := -DDEBUG=1 +debug: all + +beta: EXTRA_CFLAGS := -DRRC_BETA=1 +beta: export EXTRA_CFLAGS := -DRRC_BETA=1 +beta: all + runtime-ext-%.dol: $(ELFS) @echo runtime-ext-$*.elf @elf2dol runtime-ext-$*.elf $@ diff --git a/runtime-ext/source/dvd.c b/runtime-ext/source/dvd.c index 9ae916b..fac0839 100644 --- a/runtime-ext/source/dvd.c +++ b/runtime-ext/source/dvd.c @@ -32,6 +32,7 @@ #include "trampoline.h" #include #include +#include /** * Contains all and replacements. Initialized in the launcher DOL based on the XML. @@ -232,7 +233,7 @@ static bool rte_dvd_resolve_my_stuff_path_to_entry_num(const char *path, s32 *en char my_stuff_path[64]; if (rrc_bitflags & (RRC_BITFLAGS_MY_STUFF_RR | RRC_BITFLAGS_MY_STUFF_RR_MUSIC)) { - snprintf(my_stuff_path, sizeof(my_stuff_path), "/RetroRewind6/MyStuff/%s", filename); + snprintf(my_stuff_path, sizeof(my_stuff_path), "/" RRC_RETRO_REWIND_BASE_DIR "/MyStuff/%s", filename); } else { @@ -242,7 +243,7 @@ static bool rte_dvd_resolve_my_stuff_path_to_entry_num(const char *path, s32 *en bool cached_file_exists = false; for (int i = 0; i < my_stuff_replacement->folder_contents_count; i++) { - if (strcmp(my_stuff_replacement->folder_contents[i], filename) == 0) + if (strcicmp(my_stuff_replacement->folder_contents[i], filename) == 0) { cached_file_exists = true; break; @@ -292,7 +293,7 @@ static bool rte_dvd_resolve_path_to_entry_num(const char *filename, s32 *entry_n { case RRC_RIIVO_FILE_REPLACEMENT: { - RTE_DBG("Checking file replacement: '%s' == '%s'\n", replacement->disc, "strm"); + RTE_DBG("Checking file replacement: '%s' == '%s'\n", replacement->disc, filename); // Trim leading slashes from either path. const char *disc_path = replacement->disc; @@ -306,7 +307,7 @@ static bool rte_dvd_resolve_path_to_entry_num(const char *filename, s32 *entry_n ffilename++; } - if (strcmp(disc_path, ffilename) == 0) + if (strcicmp(disc_path, ffilename) == 0) { // We already checked that the external file exists when we registered the replacement. RTE_DBG("Found a file replacement! %d (%s)\n", i, disc_path); @@ -391,13 +392,7 @@ static bool rte_dvd_resolve_path_to_entry_num(const char *filename, s32 *entry_n bool cached_file_exists = false; for (int i = 0; i < replacement->folder_contents_count; i++) { - // We need to enforce case insensitivity here because FAT is case-insensitive, - // and the folder_contents are populated based on FAT reads. - - to_lowercase((char *)replacement->folder_contents[i]); - to_lowercase(new_path_filename); - - if (strcmp(replacement->folder_contents[i], new_path_filename) == 0) + if (strcicmp(replacement->folder_contents[i], new_path_filename) == 0) { RTE_DBG("Found a cached match for the filename in the folder contents!\n"); cached_file_exists = true; diff --git a/runtime-ext/source/util.c b/runtime-ext/source/util.c index 95a8725..fa9eddb 100644 --- a/runtime-ext/source/util.c +++ b/runtime-ext/source/util.c @@ -19,6 +19,8 @@ #include #include +#include +#include u32 align_down(u32 num, u32 align_as) { @@ -32,8 +34,27 @@ u32 align_up(u32 num, u32 align_as) void to_lowercase(char *str) { - for (int i = 0; str[i]; i++) { + for (int i = 0; str[i]; i++) + { // Cast to unsigned char to avoid undefined behaviour with non-ASCII chars str[i] = tolower((unsigned char)str[i]); } +} + +int strcicmp(const char *a, const char *b) +{ + const unsigned char *p1 = (const unsigned char *)a; + const unsigned char *p2 = (const unsigned char *)b; + int result; + + if (p1 == p2) + return 0; + + while ((result = tolower(*p1) - tolower(*p2++)) == 0) + { + if (*p1++ == '\0') + break; + } + + return result; } \ No newline at end of file diff --git a/runtime-ext/source/util.h b/runtime-ext/source/util.h index b1a27ec..0d7f521 100644 --- a/runtime-ext/source/util.h +++ b/runtime-ext/source/util.h @@ -25,12 +25,10 @@ void OS_Report(const char *, ...); void OS_Fatal(u32 *, u32 *, const char *); -#ifndef DEBUG -#define RTE_DBG(...) -#endif - -#ifdef DEBUG -#define RTE_DBG OS_Report +#if (defined(RRC_DEBUG) && RRC_DEBUG >= 1) || (defined(RRC_BETA) && RRC_BETA >= 1) +# define RTE_DBG OS_Report +#else +# define RTE_DBG(...) #endif #define RTE_FATAL(...) \ @@ -51,4 +49,6 @@ u32 align_up(u32 num, u32 align_as); void to_lowercase(char *str); +int strcicmp(const char *a, const char *b); + #endif diff --git a/shared/dir.h b/shared/dir.h new file mode 100644 index 0000000..8853e39 --- /dev/null +++ b/shared/dir.h @@ -0,0 +1,31 @@ +/* + dir.h - File base directory handling based on macros + + Copyright (C) 2025 Retro Rewind Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef RRC_DIR_H +#define RRC_DIR_H + +#if defined(RRC_BETA) && RRC_BETA >= 1 +# define RRC_RETRO_REWIND_BASE_DIR "RRBeta" +# define RRC_RETRO_REWIND_CHANNEL_DIR "RetroRewindChannelBeta" +#else +# define RRC_RETRO_REWIND_BASE_DIR "RetroRewind6" +# define RRC_RETRO_REWIND_CHANNEL_DIR "RetroRewindChannel" +#endif + +#endif \ No newline at end of file diff --git a/shared/riivo.h b/shared/riivo.h index 02c0ee5..21b0f2d 100644 --- a/shared/riivo.h +++ b/shared/riivo.h @@ -20,9 +20,10 @@ #ifndef RRC_RIIVO_H #define RRC_RIIVO_H +#include #include "types.h" -#define RRC_RIIVO_XML_PATH "RetroRewind6/xml/RetroRewind6.xml" +#define RRC_RIIVO_XML_PATH "/" RRC_RETRO_REWIND_BASE_DIR "/xml/" RRC_RETRO_REWIND_BASE_DIR ".xml" enum rrc_riivo_disc_replacement_type { diff --git a/source/console.c b/source/console.c index 3058e20..8a8aed1 100644 --- a/source/console.c +++ b/source/console.c @@ -96,7 +96,14 @@ void rrc_con_display_version() } char vertext[32]; - snprintf(vertext, 32, "Version: %i.%i.%i", cached_version.major, cached_version.minor, cached_version.patch); + + #if defined(RRC_BETA) && RRC_BETA >= 1 + snprintf(vertext, 32, "Version: %i.%i.%i (RRBETA BUILD)", cached_version.major, cached_version.minor, cached_version.patch); + #else + snprintf(vertext, 32, "Version: %i.%i.%i", cached_version.major, cached_version.minor, cached_version.patch); + #endif + + rrc_con_cursor_seek_to(rrc_con_get_rows() - 2, rrc_con_get_cols() - strlen(vertext)); printf("%s", vertext); } diff --git a/source/crash.c b/source/crash.c index b806b70..958736d 100644 --- a/source/crash.c +++ b/source/crash.c @@ -18,6 +18,7 @@ along with this program. If not, see . */ +#include #include "crash.h" #include "console.h" #include "prompt.h" @@ -59,7 +60,7 @@ void rrc_crash_handle(void *xfb, struct rrc_settingsfile *settings) "instructions found on https://rwfc.net/downloads,", "and do not manually delete any files.", "", - "A crash file was written to sd:/RetroRewind6/Crash.pul.", + "A crash file was written to sd:/" RRC_RETRO_REWIND_BASE_DIR "/Crash.pul.", "If you continue to experience issues, please report it", "along with this file to our Discord server:", "https://discord.gg/retrorewind", diff --git a/source/crash.h b/source/crash.h index fba63ae..55148e9 100644 --- a/source/crash.h +++ b/source/crash.h @@ -22,6 +22,8 @@ #include "settingsfile.h" +// Do not use the channel base dir constant here, as the game is unaware of this. +// It will always write into the "main" folder. Since it's an ephemeral file, it doesn't really matter. #define RRC_CRASH_FILE_PATH "/RetroRewindChannel/.crash" /* diff --git a/source/ephfile.h b/source/ephfile.h index 8460947..986046c 100644 --- a/source/ephfile.h +++ b/source/ephfile.h @@ -20,6 +20,8 @@ #ifndef RRC_EPHFILE_H #define RRC_EPHFILE_H +// Do not use the channel base dir constant here, as the game is unaware of this. +// It will always write into the "main" folder. Since it's an ephemeral file, it doesn't really matter. #define RRC_LAUNCHED_FROM_RR_FILE_PATH "/RetroRewindChannel/.lfrr" bool rrc_launched_from_rr(); diff --git a/source/loader/binary_loader.h b/source/loader/binary_loader.h index a8dbf1d..399a95a 100644 --- a/source/loader/binary_loader.h +++ b/source/loader/binary_loader.h @@ -21,14 +21,15 @@ #define BINARY_LOADER_H #include +#include #include "../result.h" -#define RRC_LOADER_PUL_PATH "RetroRewind6/Binaries/Loader.pul" +#define RRC_LOADER_PUL_PATH "/" RRC_RETRO_REWIND_BASE_DIR "/Binaries/Loader.pul" // We need to load the correct runtime-ext. // This is provided as a base; however, the region and file extension needs // to be appended at runtime. -#define RRC_RUNTIME_EXT_BASE_PATH "RetroRewindChannel/runtime-ext" +#define RRC_RUNTIME_EXT_BASE_PATH "/" RRC_RETRO_REWIND_CHANNEL_DIR "/runtime-ext" // At the moment this file handles Loader.pul and runtime-ext. diff --git a/source/loader/riivo_patch_loader.c b/source/loader/riivo_patch_loader.c index b11925e..ec52674 100644 --- a/source/loader/riivo_patch_loader.c +++ b/source/loader/riivo_patch_loader.c @@ -309,12 +309,12 @@ struct rrc_result rrc_riivo_patch_loader_parse(struct rrc_settingsfile *settings // All current My Stuff music options *do* have this attribute, so it's fine for them to use this (for now, anyway...). // When all is said and done, we MUST be left with only one folder replacement marked as My Stuff, if My Stuff is enabled. // If there are multiple, they will conflict. - bool is_rr_mystuff = strcmp(elem_id, "RRLoad") == 0; - bool is_ctgpr_mystuff = strcmp(elem_id, "RRCTGPLoad") == 0; + bool is_rr_mystuff = strcmp(elem_id, RRC_RR_MY_STUFF_PATCH_ID) == 0; + bool is_ctgpr_mystuff = strcmp(elem_id, RRC_CTGP_MY_STUFF_PATCH_ID) == 0; // Skip music if the My Stuff exclusive option for it is disabled. - bool is_rr_music = strcmp(elem_id, "RRLoadMusic") == 0; - bool is_ctgp_music = strcmp(elem_id, "RRCTGPLoadMusic") == 0; + bool is_rr_music = strcmp(elem_id, RRC_RR_MUSIC_MY_STUFF_PATCH_ID) == 0; + bool is_ctgp_music = strcmp(elem_id, RRC_CTGP_MUSIC_MY_STUFF_PATCH_ID) == 0; mxml_index_t *file_repl_index = mxmlIndexNew(cur, "file", NULL); for (mxml_node_t *file = mxmlIndexEnum(file_repl_index); file != NULL; file = mxmlIndexEnum(file_repl_index)) @@ -450,7 +450,7 @@ struct rrc_result rrc_riivo_patch_loader_parse(struct rrc_settingsfile *settings // where we barely only have access to a single function. if (valuefile_mxml != NULL) { - if (strcmp(valuefile_mxml, "/" RRC_LOADER_PUL_PATH) == 0) + if (strcmp(valuefile_mxml, RRC_LOADER_PUL_PATH) == 0) { // Loader.pul specifically is handled manually elsewhere, so make an exception for this. u32 loader_addr = strtoul(addr_mxml, NULL, 16); @@ -458,7 +458,10 @@ struct rrc_result rrc_riivo_patch_loader_parse(struct rrc_settingsfile *settings continue; } - return rrc_result_create_error_corrupted_rr_xml("Unhandled valuefile memory patch encountered"); + char error[128]; + snprintf(error, 128, "Unsupported valuefile '%s' in memory patch", valuefile_mxml); + + return rrc_result_create_error_corrupted_rr_xml(error); } PARSE_REQUIRED_ATTR(memory, value_mxml, "value"); diff --git a/source/loader/riivo_patch_loader.h b/source/loader/riivo_patch_loader.h index 6c23571..bac4d15 100644 --- a/source/loader/riivo_patch_loader.h +++ b/source/loader/riivo_patch_loader.h @@ -26,6 +26,28 @@ #include "../settingsfile.h" #include "../result.h" +/* + bool is_rr_mystuff = strcmp(elem_id, "RRLoad") == 0; + bool is_ctgpr_mystuff = strcmp(elem_id, "RRCTGPLoad") == 0; + + // Skip music if the My Stuff exclusive option for it is disabled. + bool is_rr_music = strcmp(elem_id, "RRLoadMusic") == 0; + bool is_ctgp_music = strcmp(elem_id, "RRCTGPLoadMusic") == 0; + +*/ + +#if defined(RRC_BETA) && RRC_BETA >= 1 +# define RRC_RR_MY_STUFF_PATCH_ID "RRBetaLoad" +# define RRC_CTGP_MY_STUFF_PATCH_ID "RRBetaCTGPLoad" +# define RRC_RR_MUSIC_MY_STUFF_PATCH_ID "RRBetaLoadMusic" +# define RRC_CTGP_MUSIC_MY_STUFF_PATCH_ID "RRBetaCTGPLoadMusic" +#else +# define RRC_RR_MY_STUFF_PATCH_ID "RRLoad" +# define RRC_CTGP_MY_STUFF_PATCH_ID "RRCTGPLoad" +# define RRC_RR_MUSIC_MY_STUFF_PATCH_ID "RRLoadMusic" +# define RRC_CTGP_MUSIC_MY_STUFF_PATCH_ID "RRCTGPLoadMusic" +#endif + #define MAX_FILE_PATCHES 1000 #define MAX_MEMORY_PATCHES 128 #define MAX_ENABLED_SETTINGS (64) diff --git a/source/main.c b/source/main.c index 1aa128c..2dd852a 100644 --- a/source/main.c +++ b/source/main.c @@ -58,6 +58,10 @@ /* 100ms */ #define DISKCHECK_DELAY 100000 +// When debug is disabled, some variables become unused. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" + int main(int argc, char **argv) { // There are bugs in pulsar with USB/HIDv5 if the IOS version is 59, which HBC commonly boots programs with. @@ -90,7 +94,7 @@ int main(int argc, char **argv) errno = 0; - DIR *dir = opendir("sd:/RetroRewindChannel"); + DIR *dir = opendir("sd:/" RRC_RETRO_REWIND_CHANNEL_DIR); if (dir != NULL) { closedir(dir); @@ -98,7 +102,7 @@ int main(int argc, char **argv) else { // ??? - struct rrc_result err = rrc_result_create_error_errno(errno, "Failed to open sd:/RetroRewindChannel"); + struct rrc_result err = rrc_result_create_error_errno(errno, "Failed to open sd:/" RRC_RETRO_REWIND_CHANNEL_DIR); rrc_result_error_check_error_fatal(err); } @@ -110,7 +114,7 @@ int main(int argc, char **argv) bool first_open = false; - FILE *afd = fopen("sd:/RetroRewindChannel/accept.txt", "r"); + FILE *afd = fopen("sd:/" RRC_RETRO_REWIND_CHANNEL_DIR "/accept.txt", "r"); if (afd == NULL) { char *lines[] = { @@ -138,7 +142,7 @@ int main(int argc, char **argv) rrc_result_error_check_error_normal(err, xfb); } - FILE *afd = fopen("sd:/RetroRewindChannel/accept.txt", "w"); + FILE *afd = fopen("sd:/" RRC_RETRO_REWIND_CHANNEL_DIR "/accept.txt", "w"); if (afd == NULL) { struct rrc_result err = rrc_result_create_error_errno(errno, "Failed to create acceptance file. The SD card may be write locked."); @@ -359,9 +363,12 @@ int main(int argc, char **argv) WPAD_Shutdown(); s64 systime_end = gettime(); + rrc_dbg_printf("time taken: %.3f seconds\n", ((f64)diff_msec(systime_start, systime_end)) / 1000.0); rrc_loader_load(dol, &stored_settings, bi2, mem1_hi, mem2_hi, region); return 0; } + +#pragma GCC diagnostic pop \ No newline at end of file diff --git a/source/settingsfile.c b/source/settingsfile.c index e3f958d..c4d6bcd 100644 --- a/source/settingsfile.c +++ b/source/settingsfile.c @@ -41,10 +41,11 @@ #include #include #include +#include #include "settingsfile.h" #include "util.h" -#define RRC_SETTINGSFILE_PATH "RetroRewindChannel/.settings" +#define RRC_SETTINGSFILE_PATH "/" RRC_RETRO_REWIND_BASE_DIR "/.settings" #define RRC_SETTINGSFILE_MY_STUFF_KEY "My Stuff" #define RRC_SETTINGSFILE_SAVEGAME_KEY "Separate savegame" #define RRC_SETTINGSFILE_AUTOUPDATE_KEY "Auto update" diff --git a/source/update/update.h b/source/update/update.h index cee1f2f..bbe2c34 100644 --- a/source/update/update.h +++ b/source/update/update.h @@ -19,12 +19,13 @@ #ifndef RRC_UPDATE_H #define RRC_UPDATE_H +#include #include #include "../result.h" #include "../version.h" #define RRC_UPDATE_LARGE_THRESHOLD (long)(1000 * 1000 * 100) /* 100MB */ -#define RRC_VERSIONFILE "RetroRewind6/version.txt" +#define RRC_VERSIONFILE "/" RRC_RETRO_REWIND_BASE_DIR "/version.txt" /* Holds all info related to an update or sequence of updates */ struct rrc_update_state diff --git a/source/util.h b/source/util.h index ed59a72..636c80c 100644 --- a/source/util.h +++ b/source/util.h @@ -31,7 +31,12 @@ When this directive is defined and set to a value greater than 0, debug logging and some additional assertions are enabled. */ -#define DEBUG 1 +#if defined(RRC_BETA) && RRC_BETA >= 1 +// beta implies debug +#define RRC_DEBUG 1 +#elif !defined(RRC_DEBUG) +#define RRC_DEBUG 0 +#endif #define _RRC_STRING(s) #s @@ -77,7 +82,7 @@ #define RRC_STRINGIFY(x) #x -#if defined(DEBUG) && DEBUG >= 0 +#if defined(RRC_DEBUG) && RRC_DEBUG >= 1 /* define debug macros */ #define rrc_dbg_printf(...) \