SDL: Trim any extra platform strings from mappings when they're returned to the application

From 6828955ddfab616b40d8b3ebe596c328a5d83167 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 19 Nov 2021 09:58:11 -0800
Subject: [PATCH] Trim any extra platform strings from mappings when they're
 returned to the application

---
 src/joystick/SDL_gamecontroller.c | 84 ++++++++++++++++++++-----------
 1 file changed, 54 insertions(+), 30 deletions(-)

diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 59c510f34f..305139f7ce 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -1515,6 +1515,57 @@ SDL_GameControllerNumMappings(void)
     return num_mappings;
 }
 
+/*
+ * Create a mapping string for a mapping
+ */
+static char *
+CreateMappingString(ControllerMapping_t *mapping, SDL_JoystickGUID guid)
+{
+    char *pMappingString, *pPlatformString;
+    char pchGUID[33];
+    size_t needed;
+    const char *platform = SDL_GetPlatform();
+
+    SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
+
+    /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
+    needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
+
+    if (!SDL_strstr(mapping->mapping, SDL_CONTROLLER_PLATFORM_FIELD)) {
+        /* add memory for ',' + platform:PLATFORM */
+        if (mapping->mapping[SDL_strlen(mapping->mapping) - 1] != ',') {
+            needed += 1;
+        }
+        needed += SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD) + SDL_strlen(platform);
+    }
+
+    pMappingString = SDL_malloc(needed);
+    if (!pMappingString) {
+        SDL_OutOfMemory();
+        return NULL;
+    }
+
+    SDL_snprintf(pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping);
+
+    if (!SDL_strstr(mapping->mapping, SDL_CONTROLLER_PLATFORM_FIELD)) {
+        if (mapping->mapping[SDL_strlen(mapping->mapping) - 1] != ',') {
+            SDL_strlcat(pMappingString, ",", needed);
+        }
+        SDL_strlcat(pMappingString, SDL_CONTROLLER_PLATFORM_FIELD, needed);
+        SDL_strlcat(pMappingString, platform, needed);
+    }
+
+    /* Make sure multiple platform strings haven't made their way into the mapping */
+    pPlatformString = SDL_strstr(pMappingString, SDL_CONTROLLER_PLATFORM_FIELD);
+    if (pPlatformString) {
+        pPlatformString = SDL_strstr(pPlatformString + 1, SDL_CONTROLLER_PLATFORM_FIELD);
+        if (pPlatformString) {
+            *pPlatformString = '\0';
+        }
+    }
+    return pMappingString;
+}
+
 /*
  *  Get the mapping at a particular index.
  */
@@ -1528,21 +1579,7 @@ SDL_GameControllerMappingForIndex(int mapping_index)
             continue;
         }
         if (mapping_index == 0) {
-            char *pMappingString;
-            char pchGUID[33];
-            size_t needed;
-            const char *platform = SDL_GetPlatform();
-
-            SDL_JoystickGetGUIDString(mapping->guid, pchGUID, sizeof(pchGUID));
-            /* allocate enough memory for GUID + ',' + name + ',' + mapping + platform:PLATFORM + \0 */
-            needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD) + SDL_strlen(platform) + 1;
-            pMappingString = SDL_malloc(needed);
-            if (!pMappingString) {
-                SDL_OutOfMemory();
-                return NULL;
-            }
-            SDL_snprintf(pMappingString, needed, "%s,%s,%s%s%s", pchGUID, mapping->name, mapping->mapping, SDL_CONTROLLER_PLATFORM_FIELD, platform);
-            return pMappingString;
+            return CreateMappingString(mapping, mapping->guid);
         }
         --mapping_index;
     }
@@ -1555,24 +1592,11 @@ SDL_GameControllerMappingForIndex(int mapping_index)
 char *
 SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid)
 {
-    char *pMappingString = NULL;
     ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(guid, SDL_FALSE);
     if (mapping) {
-        char pchGUID[33];
-        size_t needed;
-        const char *platform = SDL_GetPlatform();
-
-        SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
-        /* allocate enough memory for GUID + ',' + name + ',' + mapping + platform:PLATFORM + \0 */
-        needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD) + SDL_strlen(platform) + 1;
-        pMappingString = SDL_malloc(needed);
-        if (!pMappingString) {
-            SDL_OutOfMemory();
-            return NULL;
-        }
-        SDL_snprintf(pMappingString, needed, "%s,%s,%s%s%s", pchGUID, mapping->name, mapping->mapping, SDL_CONTROLLER_PLATFORM_FIELD, platform);
+        return CreateMappingString(mapping, guid);
     }
-    return pMappingString;
+    return NULL;
 }
 
 /*