shithub: choc

Download patch

ref: d2efe0521e570178ffabac2379a12f5dc443aa0f
parent: 88f5ae5be28d3c472c6d4e060304b877d52ec139
author: Roman Fomin <rfomin@gmail.com>
date: Wed Dec 14 18:45:12 EST 2022

Support non-Latin paths in i_glob.c, don't use SDL_iconv_string() (#1557)

* Support non-Latin paths in i_glob.c, don't use SDL_iconv_string()

* Fix gcc build

* Fix memory leak

* Add comments

--- a/src/i_glob.c
+++ b/src/i_glob.c
@@ -102,6 +102,7 @@
     int num_globs;
     glob_t *result;
     va_list args;
+    char *directory_native;
 
     globs = malloc(sizeof(char *));
     if (globs == NULL)
@@ -140,15 +141,18 @@
         return NULL;
     }
 
-    result->dir = opendir(directory);
+    directory_native = M_ConvertUtf8ToSysNativeMB(directory);
+
+    result->dir = opendir(directory_native);
     if (result->dir == NULL)
     {
         FreeStringList(globs, num_globs);
         free(result);
+        free(directory_native);
         return NULL;
     }
 
-    result->directory = M_StringDuplicate(directory);
+    result->directory = directory_native;
     result->globs = globs;
     result->num_globs = num_globs;
     result->flags = flags;
@@ -242,6 +246,7 @@
 static char *NextGlob(glob_t *glob)
 {
     struct dirent *de;
+    char *temp, *ret;
 
     do
     {
@@ -254,7 +259,13 @@
           || !MatchesAnyGlob(de->d_name, glob));
 
     // Return the fully-qualified path, not just the bare filename.
-    return M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL);
+    temp = M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL);
+
+    ret = M_ConvertSysNativeMBToUtf8(temp);
+
+    free(temp);
+
+    return ret;
 }
 
 static void ReadAllFilenames(glob_t *glob)
--- a/src/m_misc.c
+++ b/src/m_misc.c
@@ -28,7 +28,6 @@
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <io.h>
-#include "SDL_stdinc.h" // SDL_iconv_string
 #ifdef _MSC_VER
 #include <direct.h>
 #endif
@@ -49,17 +48,17 @@
 #include "z_zone.h"
 
 #ifdef _WIN32
-wchar_t *M_ConvertUtf8ToWide(const char *str)
+static wchar_t *ConvertMultiByteToWide(const char *str, UINT code_page)
 {
     wchar_t *wstr = NULL;
     int wlen = 0;
 
-    wlen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+    wlen = MultiByteToWideChar(code_page, 0, str, -1, NULL, 0);
 
     if (!wlen)
     {
         errno = EINVAL;
-        printf("M_ConvertUtf8ToWide: Failed to convert path from UTF8\n");
+        printf("ConvertMultiByteToWide: Failed to convert path to wide encoding.\n");
         return NULL;
     }
 
@@ -67,14 +66,14 @@
 
     if (!wstr)
     {
-        I_Error("M_ConvertUtf8ToWide: Failed to allocate new string");
+        I_Error("ConvertMultiByteToWide: Failed to allocate new string.");
         return NULL;
     }
 
-    if (MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, wlen) == 0)
+    if (MultiByteToWideChar(code_page, 0, str, -1, wstr, wlen) == 0)
     {
         errno = EINVAL;
-        printf("M_ConvertUtf8ToWide: Failed to convert path from UTF8\n");
+        printf("ConvertMultiByteToWide: Failed to convert path to wide encoding.\n");
         free(wstr);
         return NULL;
     }
@@ -81,8 +80,116 @@
 
     return wstr;
 }
+
+static char *ConvertWideToMultiByte(const wchar_t *wstr, UINT code_page)
+{
+    char *str = NULL;
+    int len = 0;
+
+    len = WideCharToMultiByte(code_page, 0, wstr, -1, NULL, 0, NULL, NULL);
+
+    if (!len)
+    {
+        errno = EINVAL;
+        printf("ConvertWideToMultiByte: Failed to convert path to multibyte encoding.\n");
+        return NULL;
+    }
+
+    str = malloc(sizeof(char) * len);
+
+    if (!str)
+    {
+        I_Error("ConvertWideToMultiByte: Failed to allocate new string.");
+        return NULL;
+    }
+
+    if (WideCharToMultiByte(code_page, 0, wstr, -1, str, len, NULL, NULL) == 0)
+    {
+        errno = EINVAL;
+        printf("ConvertWideToMultiByte: Failed to convert path to multibyte encoding.\n");
+        free(str);
+        return NULL;
+    }
+
+    return str;
+}
+
+static char *ConvertWideToUtf8(const wchar_t *wstr)
+{
+    return ConvertWideToMultiByte(wstr, CP_UTF8);
+}
+
+static wchar_t *ConvertSysNativeMBToWide(const char *str)
+{
+    return ConvertMultiByteToWide(str, CP_ACP);
+}
+
+static char *ConvertWideToSysNativeMB(const wchar_t *wstr)
+{
+    return ConvertWideToMultiByte(wstr, CP_ACP);
+}
+
+// Convert UTF8 string to a wide string. The result is newly allocated and must
+// be freed by the caller after use.
+
+wchar_t *M_ConvertUtf8ToWide(const char *str)
+{
+    return ConvertMultiByteToWide(str, CP_UTF8);
+}
 #endif
 
+// Convert multibyte string in system encoding to UTF8. The result is newly
+// allocated and must be freed by the caller after use.
+
+char *M_ConvertSysNativeMBToUtf8(const char *str)
+{
+#ifdef _WIN32
+    char *ret = NULL;
+    wchar_t *wstr = NULL;
+
+    wstr = ConvertSysNativeMBToWide(str);
+
+    if (!wstr)
+    {
+        return NULL;
+    }
+
+    ret = ConvertWideToUtf8(wstr);
+
+    free(wstr);
+
+    return ret;
+#else
+    return M_StringDuplicate(str);
+#endif
+}
+
+// Convert UTF8 string to multibyte string in system encoding. The result is
+// newly allocated and must be freed by the caller after use.
+
+char *M_ConvertUtf8ToSysNativeMB(const char *str)
+{
+#ifdef _WIN32
+    char *ret = NULL;
+    wchar_t *wstr = NULL;
+
+    wstr = M_ConvertUtf8ToWide(str);
+
+    if (!wstr)
+    {
+        return NULL;
+    }
+
+    ret = ConvertWideToSysNativeMB(wstr);
+
+    free(wstr);
+
+    return ret;
+#else
+    return M_StringDuplicate(str);
+#endif
+}
+
 FILE *M_fopen(const char *filename, const char *mode)
 {
 #ifdef _WIN32
@@ -221,7 +328,9 @@
     for (i = 0; i < num_vars; ++i)
     {
         if (!strcasecmp(name, env_vars[i].name))
-           return env_vars[i].var;
+        {
+            return env_vars[i].var;
+        }
     }
 
     wname = M_ConvertUtf8ToWide(name);
@@ -237,8 +346,7 @@
 
     if (wenv)
     {
-        env = SDL_iconv_string("UTF-8", "UTF-16LE", (const char *)wenv,
-                               (wcslen(wenv) + 1) * sizeof(wchar_t));
+        env = ConvertWideToUtf8(wenv);
     }
     else
     {
--- a/src/m_misc.h
+++ b/src/m_misc.h
@@ -29,6 +29,8 @@
 #ifdef _WIN32
 wchar_t *M_ConvertUtf8ToWide(const char *str);
 #endif
+char *M_ConvertUtf8ToSysNativeMB(const char *str);
+char *M_ConvertSysNativeMBToUtf8(const char *str);
 
 FILE *M_fopen(const char *filename, const char *mode);
 int M_remove(const char *path);