code/windows.c: add method for converting from utf16 to utf8

Modify the funcion system_default_path_append() to
both receive and return wchar_t types.

Remove fallback in system_default_path_append()
as this is now redundant.

Add a function utf16_to_utf8() and use that
in places where system_default_path_append() needs
to be converted to utf8.

Move both utf16_to_utf8*() and utf8_to_utf16*()
near the top of the file.

Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
This commit is contained in:
Lubomir I. Ivanov 2018-09-03 21:58:42 +03:00 committed by Dirk Hohndel
parent 0ef145337a
commit c47b6b672f

View file

@ -41,11 +41,60 @@ bool subsurface_ignore_font(const char *font)
return false; return false;
} }
/* this function converts a win32's utf-16 2 byte string to utf-8.
* the caller function should manage the allocated memory.
*/
static char *utf16_to_utf8_fl(const wchar_t *utf16, char *file, int line)
{
assert(utf16 != NULL);
assert(file != NULL);
assert(line);
/* estimate buffer size */
const int sz = wcslen(utf16) + 1;
char *utf8 = (char *)malloc(sz);
if (!utf8) {
fprintf(stderr, "%s:%d: %s %d.", file, line, "cannot allocate buffer of size", sz);
return NULL;
}
if (WideCharToMultiByte(CP_UTF8, 0, utf16, -1, utf8, sz, NULL, NULL)) {
return utf8;
}
fprintf(stderr, "%s:%d: %s", file, line, "cannot convert string.");
free((void *)utf8);
return NULL;
}
#define utf16_to_utf8(s) utf16_to_utf8_fl(s, __FILE__, __LINE__)
/* this function converts a utf-8 string to win32's utf-16 2 byte string.
* the caller function should manage the allocated memory.
*/
static wchar_t *utf8_to_utf16_fl(const char *utf8, char *file, int line)
{
assert(utf8 != NULL);
assert(file != NULL);
assert(line);
/* estimate buffer size */
const int sz = strlen(utf8) + 1;
wchar_t *utf16 = (wchar_t *)malloc(sizeof(wchar_t) * sz);
if (!utf16) {
fprintf(stderr, "%s:%d: %s %d.", file, line, "cannot allocate buffer of size", sz);
return NULL;
}
if (MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, sz))
return utf16;
fprintf(stderr, "%s:%d: %s", file, line, "cannot convert string.");
free((void *)utf16);
return NULL;
}
#define utf8_to_utf16(s) utf8_to_utf16_fl(s, __FILE__, __LINE__)
/* this function returns the Win32 Roaming path for the current user as UTF-8. /* this function returns the Win32 Roaming path for the current user as UTF-8.
* it never returns NULL but fallsback to .\ instead! * it never returns NULL but fallsback to .\ instead!
* the append argument will append a wchar_t string to the end of the path. * the append argument will append a wchar_t string to the end of the path.
*/ */
static const char *system_default_path_append(const wchar_t *append) static wchar_t *system_default_path_append(const wchar_t *append)
{ {
wchar_t wpath[MAX_PATH] = { 0 }; wchar_t wpath[MAX_PATH] = { 0 };
const char *fname = "system_default_path_append()"; const char *fname = "system_default_path_append()";
@ -66,27 +115,10 @@ static const char *system_default_path_append(const wchar_t *append)
wcscat(wpath, append); wcscat(wpath, append);
} }
/* attempt to convert the UTF-16 string to UTF-8. wchar_t *result = wcsdup(wpath);
* resize the buffer and fallback to .\Subsurface if it fails. if (!result)
*/ fprintf(stderr, "%s: cannot allocate memory for path!\n", fname);
const int wsz = wcslen(wpath); return result;
const int sz = WideCharToMultiByte(CP_UTF8, 0, wpath, wsz, NULL, 0, NULL, NULL);
char *path = (char *)malloc(sz + 1);
if (!sz)
goto fallback;
if (WideCharToMultiByte(CP_UTF8, 0, wpath, wsz, path, sz, NULL, NULL)) {
path[sz] = '\0';
return path;
}
fallback:
fprintf(stderr, "%s: cannot obtain path as UTF-8!\n", fname);
const char *local = ".\\Subsurface";
const int len = strlen(local) + 1;
path = (char *)realloc(path, len);
memset(path, 0, len);
strcat(path, local);
return path;
} }
/* by passing NULL to system_default_path_append() we obtain the pure path. /* by passing NULL to system_default_path_append() we obtain the pure path.
@ -95,8 +127,11 @@ fallback:
const char *system_default_directory(void) const char *system_default_directory(void)
{ {
static const char *path = NULL; static const char *path = NULL;
if (!path) if (!path) {
path = system_default_path_append(NULL); wchar_t *wpath = system_default_path_append(NULL);
path = utf16_to_utf8(wpath);
free((void *)wpath);
}
return path; return path;
} }
@ -112,7 +147,9 @@ const char *system_default_filename(void)
wchar_t filename[UNLEN + 5] = { 0 }; wchar_t filename[UNLEN + 5] = { 0 };
wcscat(filename, username); wcscat(filename, username);
wcscat(filename, L".xml"); wcscat(filename, L".xml");
path = system_default_path_append(filename); wchar_t *wpath = system_default_path_append(filename);
path = utf16_to_utf8(wpath);
free((void *)wpath);
} }
return path; return path;
} }
@ -205,30 +242,6 @@ int enumerate_devices(device_callback_t callback, void *userdata, unsigned int t
return index; return index;
} }
/* this function converts a utf-8 string to win32's utf-16 2 byte string.
* the caller function should manage the allocated memory.
*/
static wchar_t *utf8_to_utf16_fl(const char *utf8, char *file, int line)
{
assert(utf8 != NULL);
assert(file != NULL);
assert(line);
/* estimate buffer size */
const int sz = strlen(utf8) + 1;
wchar_t *utf16 = (wchar_t *)malloc(sizeof(wchar_t) * sz);
if (!utf16) {
fprintf(stderr, "%s:%d: %s %d.", file, line, "cannot allocate buffer of size", sz);
return NULL;
}
if (MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, sz))
return utf16;
fprintf(stderr, "%s:%d: %s", file, line, "cannot convert string.");
free((void *)utf16);
return NULL;
}
#define utf8_to_utf16(s) utf8_to_utf16_fl(s, __FILE__, __LINE__)
/* bellow we provide a set of wrappers for some I/O functions to use wchar_t. /* bellow we provide a set of wrappers for some I/O functions to use wchar_t.
* on win32 this solves the issue that we need paths to be utf-16 encoded. * on win32 this solves the issue that we need paths to be utf-16 encoded.
*/ */