From 6a74ade73dd3c7f91bd6331fedcbdce574e92062 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Fri, 19 Jul 2024 11:42:53 -0400 Subject: [PATCH] Make SDL_URIToLocal available to multiple platforms Moves the functions out of core/unix into SDL_utils.c --- src/SDL_utils.c | 114 ++++++++++++++++++++++++ src/SDL_utils_c.h | 13 +++ src/core/unix/SDL_uri_decode.c | 123 -------------------------- src/core/unix/SDL_uri_decode.h | 56 ------------ src/dialog/unix/SDL_portaldialog.c | 1 - src/video/wayland/SDL_waylandevents.c | 1 - src/video/x11/SDL_x11events.c | 1 - 7 files changed, 127 insertions(+), 182 deletions(-) delete mode 100644 src/core/unix/SDL_uri_decode.c delete mode 100644 src/core/unix/SDL_uri_decode.h diff --git a/src/SDL_utils.c b/src/SDL_utils.c index 222cf49a3e..26b838258d 100644 --- a/src/SDL_utils.c +++ b/src/SDL_utils.c @@ -22,6 +22,10 @@ #include "SDL_hashtable.h" +#if defined(SDL_PLATFORM_UNIX) || defined(SDL_PLATFORM_APPLE) +#include +#endif + /* Common utility functions that aren't in the public API */ int SDL_powerof2(int x) @@ -206,3 +210,113 @@ void SDL_SetObjectsInvalid(void) SDL_objects = NULL; } } + +static int SDL_URIDecode(const char *src, char *dst, int len) +{ + int ri, wi, di; + char decode = '\0'; + if (!src || !dst || len < 0) { + return -1; + } + if (len == 0) { + len = SDL_strlen(src); + } + for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) { + if (di == 0) { + /* start decoding */ + if (src[ri] == '%') { + decode = '\0'; + di += 1; + continue; + } + /* normal write */ + dst[wi] = src[ri]; + wi += 1; + } else if (di == 1 || di == 2) { + char off = '\0'; + char isa = src[ri] >= 'a' && src[ri] <= 'f'; + char isA = src[ri] >= 'A' && src[ri] <= 'F'; + char isn = src[ri] >= '0' && src[ri] <= '9'; + if (!(isa || isA || isn)) { + /* not a hexadecimal */ + int sri; + for (sri = ri - di; sri <= ri; sri += 1) { + dst[wi] = src[sri]; + wi += 1; + } + di = 0; + continue; + } + /* itsy bitsy magicsy */ + if (isn) { + off = 0 - '0'; + } else if (isa) { + off = 10 - 'a'; + } else if (isA) { + off = 10 - 'A'; + } + decode |= (src[ri] + off) << (2 - di) * 4; + if (di == 2) { + dst[wi] = decode; + wi += 1; + di = 0; + } else { + di += 1; + } + } + } + dst[wi] = '\0'; + return wi; +} + +int SDL_URIToLocal(const char *src, char *dst) +{ + if (SDL_memcmp(src, "file:/", 6) == 0) { + src += 6; /* local file? */ + } else if (SDL_strstr(src, ":/") != NULL) { + return -1; /* wrong scheme */ + } + + SDL_bool local = src[0] != '/' || (src[0] != '\0' && src[1] == '/'); + + /* Check the hostname, if present. RFC 3986 states that the hostname component of a URI is not case-sensitive. */ + if (!local && src[0] == '/' && src[2] != '/') { + char *hostname_end = SDL_strchr(src + 1, '/'); + if (hostname_end) { + const size_t src_len = hostname_end - (src + 1); + size_t hostname_len; + +#if defined(SDL_PLATFORM_UNIX) || defined(SDL_PLATFORM_APPLE) + char hostname[257]; + if (gethostname(hostname, 255) == 0) { + hostname[256] = '\0'; + hostname_len = SDL_strlen(hostname); + if (hostname_len == src_len && SDL_strncasecmp(src + 1, hostname, src_len) == 0) { + src = hostname_end + 1; + local = SDL_TRUE; + } + } +#endif + + if (!local) { + static const char *localhost = "localhost"; + hostname_len = SDL_strlen(localhost); + if (hostname_len == src_len && SDL_strncasecmp(src + 1, localhost, src_len) == 0) { + src = hostname_end + 1; + local = SDL_TRUE; + } + } + } + } + + if (local) { + /* Convert URI escape sequences to real characters */ + if (src[0] == '/') { + src++; + } else { + src--; + } + return SDL_URIDecode(src, dst, 0); + } + return -1; +} diff --git a/src/SDL_utils_c.h b/src/SDL_utils_c.h index 35d8543e8a..5e41da3e7a 100644 --- a/src/SDL_utils_c.h +++ b/src/SDL_utils_c.h @@ -32,6 +32,19 @@ extern void SDL_CalculateFraction(float x, int *numerator, int *denominator); extern SDL_bool SDL_endswith(const char *string, const char *suffix); +/** Convert URI to a local filename, stripping the "file://" + * preamble and hostname if present, and writes the result + * to the dst buffer. Since URI-encoded characters take + * three times the space of normal characters, src and dst + * can safely point to the same buffer for in situ conversion. + * + * Returns the number of decoded bytes that wound up in + * the destination buffer, excluding the terminating NULL byte. + * + * On error, -1 is returned. + */ +extern int SDL_URIToLocal(const char *src, char *dst); + typedef enum { SDL_OBJECT_TYPE_UNKNOWN, diff --git a/src/core/unix/SDL_uri_decode.c b/src/core/unix/SDL_uri_decode.c deleted file mode 100644 index dd60595864..0000000000 --- a/src/core/unix/SDL_uri_decode.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2024 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "SDL_internal.h" - -#include "SDL_uri_decode.h" -#include -#include - -int SDL_URIDecode(const char *src, char *dst, int len) -{ - int ri, wi, di; - char decode = '\0'; - if (!src || !dst || len < 0) { - errno = EINVAL; - return -1; - } - if (len == 0) { - len = SDL_strlen(src); - } - for (ri = 0, wi = 0, di = 0; ri < len && wi < len; ri += 1) { - if (di == 0) { - /* start decoding */ - if (src[ri] == '%') { - decode = '\0'; - di += 1; - continue; - } - /* normal write */ - dst[wi] = src[ri]; - wi += 1; - continue; - } else if (di == 1 || di == 2) { - char off = '\0'; - char isa = src[ri] >= 'a' && src[ri] <= 'f'; - char isA = src[ri] >= 'A' && src[ri] <= 'F'; - char isn = src[ri] >= '0' && src[ri] <= '9'; - if (!(isa || isA || isn)) { - /* not a hexadecimal */ - int sri; - for (sri = ri - di; sri <= ri; sri += 1) { - dst[wi] = src[sri]; - wi += 1; - } - di = 0; - continue; - } - /* itsy bitsy magicsy */ - if (isn) { - off = 0 - '0'; - } else if (isa) { - off = 10 - 'a'; - } else if (isA) { - off = 10 - 'A'; - } - decode |= (src[ri] + off) << (2 - di) * 4; - if (di == 2) { - dst[wi] = decode; - wi += 1; - di = 0; - } else { - di += 1; - } - continue; - } - } - dst[wi] = '\0'; - return wi; -} - -int SDL_URIToLocal(const char *src, char *dst) -{ - if (SDL_memcmp(src, "file:/", 6) == 0) { - src += 6; /* local file? */ - } else if (SDL_strstr(src, ":/") != NULL) { - return -1; /* wrong scheme */ - } - - SDL_bool local = src[0] != '/' || (src[0] != '\0' && src[1] == '/'); - - /* got a hostname? */ - if (!local && src[0] == '/' && src[2] != '/') { - char *hostname_end = SDL_strchr(src + 1, '/'); - if (hostname_end) { - char hostname[257]; - if (gethostname(hostname, 255) == 0) { - hostname[256] = '\0'; - if (SDL_memcmp(src + 1, hostname, hostname_end - (src + 1)) == 0) { - src = hostname_end + 1; - local = SDL_TRUE; - } - } - } - } - if (local) { - /* Convert URI escape sequences to real characters */ - if (src[0] == '/') { - src++; - } else { - src--; - } - return SDL_URIDecode(src, dst, 0); - } - return -1; -} diff --git a/src/core/unix/SDL_uri_decode.h b/src/core/unix/SDL_uri_decode.h deleted file mode 100644 index fbe33f12b8..0000000000 --- a/src/core/unix/SDL_uri_decode.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - Simple DirectMedia Layer - Copyright (C) 1997-2024 Sam Lantinga - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. -*/ - -#include "SDL_internal.h" - -#ifndef SDL_uri_decode_h_ -#define SDL_uri_decode_h_ - -/* Decodes URI escape sequences in string src of len bytes - * (excluding the terminating NULL byte) into the dst buffer. - * Since URI-encoded characters take three times the space of - * normal characters, src and dst can safely point to the same - * buffer for in situ conversion. - * - * The buffer is guaranteed to be NULL-terminated, but - * may contain embedded NULL bytes. - * - * Returns the number of decoded bytes that wound up in - * the destination buffer, excluding the terminating NULL byte. - * - * On error, -1 is returned. - */ -int SDL_URIDecode(const char *src, char *dst, int len); - -/* Convert URI to a local filename, stripping the "file://" - * preamble and hostname if present, and writes the result - * to the dst buffer. Since URI-encoded characters take - * three times the space of normal characters, src and dst - * can safely point to the same buffer for in situ conversion. - * - * Returns the number of decoded bytes that wound up in - * the destination buffer, excluding the terminating NULL byte. - * - * On error, -1 is returned; - */ -int SDL_URIToLocal(const char *src, char *dst); - -#endif /* SDL_uri_decode_h_ */ diff --git a/src/dialog/unix/SDL_portaldialog.c b/src/dialog/unix/SDL_portaldialog.c index de75719eb8..b5e7348c20 100644 --- a/src/dialog/unix/SDL_portaldialog.c +++ b/src/dialog/unix/SDL_portaldialog.c @@ -22,7 +22,6 @@ #include "../SDL_dialog_utils.h" #include "../../core/linux/SDL_dbus.h" -#include "../../core/unix/SDL_uri_decode.h" #ifdef SDL_USE_LIBDBUS diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 7ce9b7cb32..7c77bee7e0 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -24,7 +24,6 @@ #ifdef SDL_VIDEO_DRIVER_WAYLAND #include "../../core/unix/SDL_poll.h" -#include "../../core/unix/SDL_uri_decode.h" #include "../../events/SDL_events_c.h" #include "../../events/SDL_scancode_tables_c.h" #include "../../core/linux/SDL_system_theme.h" diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 7f62f37e84..e4650c32c8 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -36,7 +36,6 @@ #include "SDL_x11settings.h" #include "../SDL_clipboard_c.h" #include "../../core/unix/SDL_poll.h" -#include "../../core/unix/SDL_uri_decode.h" #include "../../events/SDL_events_c.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_touch_c.h"