From b8e8caf7c57df1d6b86eaa9c70c854a3caaa1603 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Mon, 6 Apr 2026 19:22:13 -0400
Subject: [PATCH] dbus: Better handle local URI paths
Decode file URIs before trying to open them, and properly handle non-URI local paths.
---
src/SDL_utils.c | 33 +++++++++++++++++++++++++++++++++
src/SDL_utils_c.h | 3 +++
src/core/linux/SDL_dbus.c | 29 ++++++++++++++++++++++++-----
3 files changed, 60 insertions(+), 5 deletions(-)
diff --git a/src/SDL_utils.c b/src/SDL_utils.c
index 66b043796e538..2667390ac627d 100644
--- a/src/SDL_utils.c
+++ b/src/SDL_utils.c
@@ -384,6 +384,39 @@ int SDL_URIToLocal(const char *src, char *dst)
return -1;
}
+bool SDL_IsURI(const char *uri)
+{
+ /* A valid URI begins with a letter and is followed by any sequence of
+ * letters, digits, '+', '.', or '-'.
+ */
+ if (!uri) {
+ return false;
+ }
+
+ // The first character of the scheme must be a letter.
+ if (!((*uri >= 'a' && *uri <= 'z') || (*uri >= 'A' && *uri <= 'Z'))) {
+ return false;
+ }
+
+ /* If the colon is found before encountering the end of the string or
+ * any invalid characters, the scheme can be considered valid.
+ */
+ while (*uri) {
+ if (!((*uri >= 'a' && *uri <= 'z') ||
+ (*uri >= 'A' && *uri <= 'Z') ||
+ (*uri >= '0' && *uri <= '9') ||
+ *uri == '+' || *uri == '-' || *uri == '.')) {
+ return false;
+ }
+
+ if (*++uri == ':') {
+ return true;
+ }
+ }
+
+ return false;
+}
+
// This is a set of per-thread persistent strings that we can return from the SDL API.
// This is used for short strings that might persist past the lifetime of the object
// they are related to.
diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h
index 266eb09249f47..a49eaa11b663e 100644
--- a/src/SDL_utils_c.h
+++ b/src/SDL_utils_c.h
@@ -48,6 +48,9 @@ extern bool SDL_endswith(const char *string, const char *suffix);
*/
extern int SDL_URIToLocal(const char *src, char *dst);
+/// Determine if a URI is valid by validating the scheme.
+extern bool SDL_IsURI(const char *uri);
+
typedef enum
{
SDL_OBJECT_TYPE_UNKNOWN,
diff --git a/src/core/linux/SDL_dbus.c b/src/core/linux/SDL_dbus.c
index 3b1f095a23c0b..9a2bef87e1e04 100644
--- a/src/core/linux/SDL_dbus.c
+++ b/src/core/linux/SDL_dbus.c
@@ -487,14 +487,31 @@ bool SDL_DBus_OpenURI(const char *uri, const char *window_id, const char *activa
return false;
}
- // The OpenURI method can't open local 'file://' URIs, so OpenFile must be used instead.
DBusMessageIter iterInit;
DBusMessage *msg = NULL;
int fd = -1;
bool ret = false;
-
- if (SDL_strncasecmp(uri, "file://", 7) == 0) {
- fd = open(uri + 7, O_RDWR | O_CLOEXEC);
+ const bool has_file_scheme = SDL_strncasecmp(uri, "file:/", 6) == 0;
+
+ // The OpenURI method can't open 'file://' URIs or local paths, so OpenFile must be used instead.
+ if (has_file_scheme || !SDL_IsURI(uri)) {
+ char *decoded_path = NULL;
+
+ // Decode the path if it is a URI.
+ if (has_file_scheme) {
+ const size_t len = SDL_strlen(uri) + 1;
+ decoded_path = SDL_malloc(len);
+ if (!decoded_path) {
+ goto done;
+ }
+ if (SDL_URIToLocal(uri, decoded_path) < 0) {
+ SDL_free(decoded_path);
+ goto done;
+ }
+ uri = decoded_path;
+ }
+ fd = open(uri, O_RDWR | O_CLOEXEC);
+ SDL_free(decoded_path);
if (fd >= 0) {
msg = dbus.message_new_method_call(bus_name, path, interface, "OpenFile");
}
@@ -548,7 +565,9 @@ bool SDL_DBus_OpenURI(const char *uri, const char *window_id, const char *activa
}
done:
- dbus.message_unref(msg);
+ if (msg) {
+ dbus.message_unref(msg);
+ }
// The file descriptor is duplicated by D-Bus, so it can be closed on this end.
if (fd >= 0) {