[PATCH 2/2] Added unicode support for the configuration entries on Windows

Lubomir I. Ivanov neolit123 at gmail.com
Thu Oct 4 14:48:45 PDT 2012


From: "Lubomir I. Ivanov" <neolit123 at gmail.com>

windows.c:

Windows's registry (which is technically a filesystem) uses UTF-16
for its "keys". This forces us to convert each of our UTF-8 (GLib, GTK)
configuration entries if we want to store special characters. To do that
we use the RegQueryValueExW() and do some conversation around
the function call itself.

The opposite happens when we require a UTF-16 value to be read from the
registry and converted to UTF-8 in subsurface_set_conf().

An addition to this patch is a somehow expandable buffer in
windows.c: subsurface_get_conf(). We increase the size of the buffer
in chunks of 64 bytes, until RegQueryValueExW() is able to write to it
(as suggested by the WINAPI documentation).

Signed-off-by: Lubomir I. Ivanov <neolit123 at gmail.com>
---
 windows.c | 59 ++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 44 insertions(+), 15 deletions(-)

diff --git a/windows.c b/windows.c
index f2f06f9..a4cbd9f 100644
--- a/windows.c
+++ b/windows.c
@@ -40,39 +40,68 @@ void subsurface_set_conf(char *name, pref_type_t type, const void *value)
 	 * calls to RegSetValueEx needs to pass &value (when we want
 	 * to pass the boolean value), the other one passes value (the
 	 * address of the string. */
+	int wlen;
+	wchar_t *wname = NULL, *wstring = NULL;
+
+	wname = (wchar_t *)g_utf8_to_utf16(name, -1, NULL, NULL, NULL);
+	if (!wname)
+		return;
 	switch (type) {
 	case PREF_BOOL:
 		/* we simply store the value as DWORD */
-		RegSetValueEx(hkey, (LPCTSTR)TEXT(name), 0, REG_DWORD, (const BYTE *)&value, 4);
+		RegSetValueExW(hkey, (LPCWSTR)wname, 0, REG_DWORD, (const BYTE *)&value, 4);
 		break;
 	case PREF_STRING:
-		RegSetValueEx(hkey, (LPCTSTR)TEXT(name), 0, REG_SZ, (const BYTE *)value, strlen(value));
+		wlen = g_utf8_strlen((char *)value, -1);
+		if (wlen == -1) { /* we cannot continue. lets free the name string and bail out. */
+			if (wname)
+				free(wname);
+			return;
+		}
+		wstring = (wchar_t *)g_utf8_to_utf16((char *)value, -1, NULL, NULL, NULL);
+		RegSetValueExW(hkey, (LPCWSTR)wname, 0, REG_SZ, (const BYTE *)wstring, wlen * sizeof(wchar_t));
 	}
+	free(wname);
+	free(wstring);
 }
 
 const void *subsurface_get_conf(char *name, pref_type_t type)
 {
-	LONG success;
-	char *string;
-	int len;
+	const int csize = 64;
+	int blen = 0;
+	LONG ret = ERROR_MORE_DATA;
+	wchar_t *wstring = NULL, *wname = NULL;
 
 	switch (type) {
 	case PREF_BOOL:
 		return get_from_registry(hkey, name) ? (void *) 1 : NULL;
 	case PREF_STRING:
-		string = malloc(80);
-		len = 80;
-		success = RegQueryValueEx(hkey, (LPCTSTR)TEXT(name), NULL, NULL,
-					(LPBYTE) string, (LPDWORD)&len );
-		if (success != ERROR_SUCCESS) {
-			/* that's what happens the first time we start - just return NULL */
-			free(string);
+		// if (cstr_to_utf16(name, &wname) == -1) /* convert name to utf-16 */
+			// return NULL;
+		wname = (wchar_t *)g_utf8_to_utf16(name, -1, NULL, NULL, NULL);
+		if (!wname)
+			return NULL;
+		blen = 0;
+		/* lest try to load the string in chunks of 'csize' bytes until it fits */
+		while(ret == ERROR_MORE_DATA) {
+			blen += csize;
+			wstring = (wchar_t *)realloc(wstring, blen * sizeof(wchar_t));
+			ret = RegQueryValueExW(hkey, (LPCWSTR)wname, NULL, NULL,
+			                     (LPBYTE)wstring, (LPDWORD)&blen);
+		}
+		/* that's what happens the first time we start - just return NULL */
+		if (ret != ERROR_SUCCESS) {
+			free(wname);
+			free(wstring);
 			return NULL;
 		}
-		return string;
+		/* convert the returned string into utf-8 */
+		char *utf8_string = g_utf16_to_utf8(wstring, -1, NULL, NULL, NULL);
+		free(wstring);
+		free(wname);
+		return utf8_string;
 	}
-	/* we shouldn't get here */
-	return NULL;
+	return NULL; /* we shouldn't get here */
 }
 
 void subsurface_flush_conf(void)
-- 
1.7.11.msysgit.0



More information about the subsurface mailing list