changeset 20698:cbef5ef83eb0 draft

-Fix: [Win32] Use the right code page for converting ANSI strings into UTF-8 for non-Unicode builds. And don't crap out on DBCS code pages either.
author Michael Lutz <michi@icosahedron.de>
date Thu, 28 Mar 2013 02:39:54 +0100
parents c3ef81a9b92e
children d198fbc52efc
files src/os/windows/win32.cpp src/os/windows/win32.h src/video/win32_v.cpp
diffstat 3 files changed, 36 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/src/os/windows/win32.cpp
+++ b/src/os/windows/win32.cpp
@@ -428,10 +428,6 @@
 	char *argv[64]; // max 64 command line arguments
 	char *cmdline;
 
-#if !defined(UNICODE)
-	_codepage = GetACP(); // get system codepage as some kind of a default
-#endif /* UNICODE */
-
 	CrashLog::InitialiseCrashLog();
 
 #if defined(UNICODE)
@@ -567,11 +563,11 @@
 		cbuf = GetClipboardData(CF_UNICODETEXT);
 
 		ptr = (const char*)GlobalLock(cbuf);
-		const char *ret = convert_from_fs((const wchar_t*)ptr, buffer, buff_len);
+		int out_len = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)ptr, -1, buffer, (int)buff_len, NULL, NULL);
 		GlobalUnlock(cbuf);
 		CloseClipboard();
 
-		if (*ret == '\0') return false;
+		if (out_len == 0) return false;
 #if !defined(UNICODE)
 	} else if (IsClipboardFormatAvailable(CF_TEXT)) {
 		OpenClipboard(NULL);
@@ -613,26 +609,7 @@
 const char *FS2OTTD(const TCHAR *name)
 {
 	static char utf8_buf[512];
-#if defined(UNICODE)
 	return convert_from_fs(name, utf8_buf, lengthof(utf8_buf));
-#else
-	char *s = utf8_buf;
-
-	for (; *name != '\0'; name++) {
-		wchar_t w;
-		int len = MultiByteToWideChar(_codepage, 0, name, 1, &w, 1);
-		if (len != 1) {
-			DEBUG(misc, 0, "[utf8] M2W error converting '%c'. Errno %lu", *name, GetLastError());
-			continue;
-		}
-
-		if (s + Utf8CharLen(w) >= lastof(utf8_buf)) break;
-		s += Utf8Encode(s, w);
-	}
-
-	*s = '\0';
-	return utf8_buf;
-#endif /* UNICODE */
 }
 
 /**
@@ -645,33 +622,11 @@
  * this function. So if the value is needed for anything else, use convert_from_fs
  * @param name pointer to a valid string that will be converted (UTF8)
  * @return pointer to the converted string; if failed string is of zero-length
- * @see the current code-page comes from video\win32_v.cpp, event-notification
- * WM_INPUTLANGCHANGE
  */
 const TCHAR *OTTD2FS(const char *name)
 {
 	static TCHAR system_buf[512];
-#if defined(UNICODE)
 	return convert_to_fs(name, system_buf, lengthof(system_buf));
-#else
-	char *s = system_buf;
-
-	for (WChar c; (c = Utf8Consume(&name)) != '\0';) {
-		if (s >= lastof(system_buf)) break;
-
-		char mb;
-		int len = WideCharToMultiByte(_codepage, 0, (wchar_t*)&c, 1, &mb, 1, NULL, NULL);
-		if (len != 1) {
-			DEBUG(misc, 0, "[utf8] W2M error converting '0x%X'. Errno %lu", c, GetLastError());
-			continue;
-		}
-
-		*s++ = mb;
-	}
-
-	*s = '\0';
-	return system_buf;
-#endif /* UNICODE */
 }
 
 
@@ -683,14 +638,26 @@
  * @param buflen length in characters of the receiving buffer
  * @return pointer to utf8_buf. If conversion fails the string is of zero-length
  */
-char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
+char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
 {
-	int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, (int)buflen, NULL, NULL);
-	if (len == 0) {
-		DEBUG(misc, 0, "[utf8] W2M error converting wide-string. Errno %lu", GetLastError());
+#if defined(UNICODE)
+	const WCHAR *wide_buf = name;
+#else
+	/* Convert string from the local codepage to UTF-16. */
+	int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
+	if (wide_len == 0) {
 		utf8_buf[0] = '\0';
+		return utf8_buf;
 	}
 
+	WCHAR *wide_buf = AllocaM(WCHAR, wide_len);
+	MultiByteToWideChar(CP_ACP, 0, name, -1, wide_buf, wide_len);
+#endif
+
+	/* Convert UTF-16 string to UTF-8. */
+	int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (int)buflen, NULL, NULL);
+	if (len == 0) utf8_buf[0] = '\0';
+
 	return utf8_buf;
 }
 
@@ -704,15 +671,26 @@
  * @param buflen length in wide characters of the receiving buffer
  * @return pointer to utf16_buf. If conversion fails the string is of zero-length
  */
-wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen)
+TCHAR *convert_to_fs(const char *name, TCHAR *system_buf, size_t buflen)
 {
-	int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, (int)buflen);
+#if defined(UNICODE)
+	int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (int)buflen);
+	if (len == 0) system_buf[0] = '\0';
+#else
+	int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
 	if (len == 0) {
-		DEBUG(misc, 0, "[utf8] M2W error converting '%s'. Errno %lu", name, GetLastError());
-		utf16_buf[0] = '\0';
+		system_buf[0] = '\0';
+		return system_buf;
 	}
 
-	return utf16_buf;
+	WCHAR *wide_buf = AllocaM(WCHAR, len);
+	MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len);
+
+	len = WideCharToMultiByte(CP_ACP, 0, wide_buf, len, system_buf, (int)buflen, NULL, NULL);
+	if (len == 0) system_buf[0] = '\0';
+#endif
+
+	return system_buf;
 }
 
 /**
--- a/src/os/windows/win32.h
+++ b/src/os/windows/win32.h
@@ -18,8 +18,8 @@
 typedef void (*Function)(int);
 bool LoadLibraryList(Function proc[], const char *dll);
 
-char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen);
-wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen);
+char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen);
+TCHAR *convert_to_fs(const char *name, TCHAR *utf16_buf, size_t buflen);
 
 /* Function shortcuts for UTF-8 <> UNICODE conversion. When unicode is not
  * defined these macros return the string passed to them, with UNICODE
--- a/src/video/win32_v.cpp
+++ b/src/video/win32_v.cpp
@@ -45,9 +45,6 @@
 uint _display_hz;
 uint _fullscreen_bpp;
 static Dimension _bck_resolution;
-#if !defined(UNICODE)
-uint _codepage;
-#endif
 
 /** Whether the drawing is/may be done in a separate thread. */
 static bool _draw_threaded;
@@ -600,17 +597,6 @@
 			return 0;
 		}
 
-#if !defined(UNICODE)
-		case WM_INPUTLANGCHANGE: {
-			TCHAR locale[6];
-			LCID lcid = GB(lParam, 0, 16);
-
-			int len = GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, locale, lengthof(locale));
-			if (len != 0) _codepage = _ttoi(locale);
-			return 1;
-		}
-#endif /* UNICODE */
-
 		case WM_DEADCHAR:
 			console = GB(lParam, 16, 8) == 41;
 			return 0;