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);