SDL: Fixed sscanf("026", "%1x%1x%1x", &r, &g, &b) (776f0)

From 776f0a685c6a8fb8afb7050d7e9f4f3bbcdf71aa Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 10 Mar 2025 14:25:11 -0700
Subject: [PATCH] Fixed sscanf("026", "%1x%1x%1x", &r, &g, &b)

Fixes https://github.com/libsdl-org/SDL/issues/12510

(cherry picked from commit be6ed6e9c4c74f1973597214517ac3f8f89feb85)
---
 src/stdlib/SDL_string.c      | 24 ++++++++++--------------
 test/testautomation_stdlib.c | 12 ++++++++++++
 2 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c
index 007719ef796f1..79679a1f44405 100644
--- a/src/stdlib/SDL_string.c
+++ b/src/stdlib/SDL_string.c
@@ -368,14 +368,12 @@ static size_t SDL_ScanUnsignedLongLongInternal(const char *text, int count, int
             negative = *text == '-';
             ++text;
         }
-        if ((radix == 0 || radix == 16) && *text == '0' && text[1] != '\0') {
+        if ((radix == 0 || radix == 16) && *text == '0' && (text[1] == 'x' || text[1] == 'X')) {
+            text += 2;
+            radix = 16;
+        } else if (radix == 0 && *text == '0' && (text[1] >= '0' && text[1] <= '9')) {
             ++text;
-            if (*text == 'x' || *text == 'X') {
-                radix = 16;
-                ++text;
-            } else if (radix == 0) {
-                radix = 8;
-            }
+            radix = 8;
         } else if (radix == 0) {
             radix = 10;
         }
@@ -462,14 +460,12 @@ static size_t SDL_ScanUnsignedLongLongInternalW(const wchar_t *text, int count,
             negative = *text == '-';
             ++text;
         }
-        if ((radix == 0 || radix == 16) && *text == '0') {
+        if ((radix == 0 || radix == 16) && *text == '0' && (text[1] == 'x' || text[1] == 'X')) {
+            text += 2;
+            radix = 16;
+        } else if (radix == 0 && *text == '0' && (text[1] >= '0' && text[1] <= '9')) {
             ++text;
-            if (*text == 'x' || *text == 'X') {
-                radix = 16;
-                ++text;
-            } else if (radix == 0) {
-                radix = 8;
-            }
+            radix = 8;
         } else if (radix == 0) {
             radix = 10;
         }
diff --git a/test/testautomation_stdlib.c b/test/testautomation_stdlib.c
index bd7e17a5a7d04..e3f2d47a75403 100644
--- a/test/testautomation_stdlib.c
+++ b/test/testautomation_stdlib.c
@@ -750,6 +750,7 @@ static int SDLCALL stdlib_sscanf(void *arg)
     size_t size_output, expected_size_output;
     void *ptr_output, *expected_ptr_output;
     char text[128], text2[128];
+    unsigned int r = 0, g = 0, b = 0;
 
     expected_output = output = 123;
     expected_result = -1;
@@ -785,6 +786,17 @@ static int SDLCALL stdlib_sscanf(void *arg)
     SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
     SDLTest_AssertCheck(length == 1, "Check length, expected: 1, got: %i", length);
 
+    expected_result = 3;
+    result = SDL_sscanf("#026", "#%1x%1x%1x", &r, &g, &b);
+    SDLTest_AssertPass("Call to SDL_sscanf(\"#026\", \"#%%1x%%1x%%1x\", &r, &g, &b)");
+    expected_output = 0;
+    SDLTest_AssertCheck(r == expected_output, "Check output for r, expected: %i, got: %i", expected_output, r);
+    expected_output = 2;
+    SDLTest_AssertCheck(g == expected_output, "Check output for g, expected: %i, got: %i", expected_output, g);
+    expected_output = 6;
+    SDLTest_AssertCheck(b == expected_output, "Check output for b, expected: %i, got: %i", expected_output, b);
+    SDLTest_AssertCheck(expected_result == result, "Check return value, expected: %i, got: %i", expected_result, result);
+
 #define SIZED_TEST_CASE(type, var, printf_specifier, scanf_specifier)                                                                                                            \
     var##_output = 123;                                                                                                                                                          \
     var##_length = 0;                                                                                                                                                            \