From 3ae7a54c942da8bd99b58fca5f5bf8706696af6c Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Fri, 14 Nov 2025 19:33:00 -0500
Subject: [PATCH] filesystem: SDL_OpenFileStorage() now deals with relative
paths better.
Fixes #13484.
---
src/storage/generic/SDL_genericstorage.c | 53 +++++++++++++++++-------
1 file changed, 38 insertions(+), 15 deletions(-)
diff --git a/src/storage/generic/SDL_genericstorage.c b/src/storage/generic/SDL_genericstorage.c
index 864e7d9e8d753..f03e7c4739712 100644
--- a/src/storage/generic/SDL_genericstorage.c
+++ b/src/storage/generic/SDL_genericstorage.c
@@ -341,29 +341,52 @@ static const SDL_StorageInterface GENERIC_file_iface = {
SDL_Storage *GENERIC_OpenFileStorage(const char *path)
{
SDL_Storage *result;
- size_t len = 0;
char *basepath = NULL;
+ char *prepend = NULL;
+ bool is_absolute = false;
- if (path) {
- len += SDL_strlen(path);
+ if (path && !*path) {
+ path = NULL; // so we don't end up with str[-1] later due to empty string.
}
- if (len > 0) {
+
+ if (path) {
#ifdef SDL_PLATFORM_WINDOWS
- const bool appended_separator = (path[len-1] == '/') || (path[len-1] == '\\');
+ const char ch = (char) SDL_toupper(path[0]);
+ is_absolute = (ch == '/') || // some sort of absolute Unix-style path.
+ (ch == '\\') || // some sort of absolute Windows-style path.
+ (((ch >= 'A') && (ch <= 'Z')) && (path[1] == ':') && ((path[2] == '\\') || (path[2] == '/'))); // an absolute path with a drive letter.
#else
- const bool appended_separator = (path[len-1] == '/');
+ is_absolute = (path[0] == '/'); // some sort of absolute Unix-style path.
#endif
- if (appended_separator) {
- basepath = SDL_strdup(path);
- if (!basepath) {
- return NULL;
- }
- } else {
- if (SDL_asprintf(&basepath, "%s/", path) < 0) {
- return NULL;
- }
+ }
+
+ if (!is_absolute) {
+ prepend = SDL_GetCurrentDirectory();
+ if (!prepend) {
+ return NULL;
}
}
+
+ const char *finalpath = path ? path : prepend;
+ SDL_assert(finalpath != NULL); // _one_ of these had to be non-NULL...
+ const size_t len = SDL_strlen(finalpath);
+ SDL_assert(len > 0); // _one_ of these had to be non-empty...
+ const char *appended_separator = "";
+ #ifdef SDL_PLATFORM_WINDOWS
+ if ((finalpath[len-1] != '/') && (finalpath[len-1] != '\\')) {
+ appended_separator = "/";
+ }
+ #else
+ if (finalpath[len-1] != '/') {
+ appended_separator = "/";
+ }
+ #endif
+ const int rc = SDL_asprintf(&basepath, "%s%s%s", prepend ? prepend : "", path ? path : "", appended_separator);
+ SDL_free(prepend);
+ if (rc < 0) {
+ return NULL;
+ }
+
result = SDL_OpenStorage(&GENERIC_file_iface, basepath);
if (result == NULL) {
SDL_free(basepath);