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.
This commit is contained in:
kichikuou
2025-11-06 11:05:23 +09:00
parent ab372b7873
commit f1536a801a
4 changed files with 42 additions and 12 deletions
+18 -2
View File
@@ -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);
+15 -2
View File
@@ -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);
+8 -8
View File
@@ -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;
}
+1
View File
@@ -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__ */