From f1536a801a0ebcd81f308fa53986b4850067f60d Mon Sep 17 00:00:00 2001 From: kichikuou Date: Thu, 6 Nov 2025 11:05:23 +0900 Subject: [PATCH] QE/LE: Handle backslashes in filenames Rance 5D uses filename `Save\\Rance5dSystem.asd`. This caused issues: - On Windows, saving would fail if the `Save` directory did not exist. - On other platforms, files were created with literal backslashes in their names. This change addresses these problems by: - In commandQE, normalizing backslashes to forward slashes in the path and ensuring that the target directory exists by calling mkdir_p(). - In commandLE, first attempting to load files with normalized forward slashes. If that fails, it retries with the original path (containing backslashes) for compatibility with older saves. --- src/cmdl.c | 20 ++++++++++++++++++-- src/cmdq.c | 17 +++++++++++++++-- src/filecheck.c | 16 ++++++++-------- src/filecheck.h | 1 + 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/cmdl.c b/src/cmdl.c index eac76f0..43c7c8e 100644 --- a/src/cmdl.c +++ b/src/cmdl.c @@ -110,21 +110,35 @@ void commandLT() { void commandLE(char terminator) { int type = sl_getc(); const char *filename = sl_getString(terminator); + char *fname_utf8 = toUTF8(filename); + char *fallback_fname = NULL; + if (strchr(fname_utf8, '\\')) { + fallback_fname = strdup(fname_utf8); + for (char *p = fname_utf8; *p; p++) { + if (*p == '\\') + *p = '/'; + } + } + int var, cnt; struct VarRef vref; - - char *fname_utf8 = toUTF8(filename); switch (type) { case 0: getCaliArray(&vref); var = vref.var; cnt = getCaliValue(); sysVar[0] = load_vars_from_file(fname_utf8, &vref, cnt); + // For compatibility; the QE command in v2.16.1 and earlier did not + // convert backslashes to slashes. + if (sysVar[0] == SAVE_LOADERR && fallback_fname) + sysVar[0] = load_vars_from_file(fallback_fname, &vref, cnt); break; case 1: var = getCaliValue(); cnt = getCaliValue(); sysVar[0] = load_strs_from_file(fname_utf8, var, cnt); + if (sysVar[0] == SAVE_LOADERR && fallback_fname) + sysVar[0] = load_strs_from_file(fallback_fname, var, cnt); break; default: var = getCaliValue(); @@ -132,6 +146,8 @@ void commandLE(char terminator) { WARNING("Unknown LE command %d", type); break; } + if (fallback_fname) + free(fallback_fname); free(fname_utf8); TRACE("LE %d,%s,%d,%d:",type, filename, var, cnt); diff --git a/src/cmdq.c b/src/cmdq.c index f7c69b7..d3a0a15 100644 --- a/src/cmdq.c +++ b/src/cmdq.c @@ -29,6 +29,7 @@ #include "scenario.h" #include "savedata.h" #include "utfsjis.h" +#include "filecheck.h" #include "cmd_check.h" void commandQD() { @@ -83,10 +84,22 @@ void commandQC() { void commandQE(char terminator) { int type = sl_getc(); const char *filename = sl_getString(terminator); + char *fname_utf8 = toUTF8(filename); + char *last_slash = NULL; + for (char *p = fname_utf8; *p; p++) { + if (*p == '\\') { + *p = '/'; + last_slash = p; + } + } + if (last_slash) { + *last_slash = '\0'; + mkdir_p(fname_utf8); + *last_slash = '/'; + } + int var, cnt; struct VarRef vref; - - char *fname_utf8 = toUTF8(filename); switch (type) { case 0: getCaliArray(&vref); diff --git a/src/filecheck.c b/src/filecheck.c index 9c5bba7..6da3025 100644 --- a/src/filecheck.c +++ b/src/filecheck.c @@ -67,28 +67,28 @@ static int make_dir(const char *path) #endif // Adapted from http://stackoverflow.com/a/2336245/119527 -static int mkdir_p(const char *path) +int mkdir_p(const char *path_utf8) { - const size_t len = strlen(path); - char _path[PATH_MAX]; + const size_t len = strlen(path_utf8); + char path[PATH_MAX]; char *p; errno = 0; // Copy string so its mutable - if (len > sizeof(_path)-1) { + if (len > sizeof(path)-1) { errno = ENAMETOOLONG; return -1; } - strcpy(_path, path); + strcpy(path, path_utf8); // Iterate the string - for (p = _path + 1; *p; p++) { + for (p = path + 1; *p; p++) { if (*p == '/') { // Temporarily truncate *p = '\0'; - if (make_dir(_path) != 0) { + if (make_dir(path) != 0) { if (errno != EEXIST) return -1; } @@ -97,7 +97,7 @@ static int mkdir_p(const char *path) } } - if (make_dir(_path) != 0) { + if (make_dir(path) != 0) { if (errno != EEXIST) return -1; } diff --git a/src/filecheck.h b/src/filecheck.h index 85e3d2d..76a6eb4 100644 --- a/src/filecheck.h +++ b/src/filecheck.h @@ -31,5 +31,6 @@ char *fc_get_path(const char *fname_utf8); bool fc_exists(const char *fname_utf8); FILE *fc_open(const char *fname_utf8, char type); void fc_backup_oldfile(const char *filename); +int mkdir_p(const char *path_utf8); #endif /* !__FILECHECK_H__ */