glib/gtimezone.c: Use Unicode versions of Windows Registry API

We are going to use RegLoadMUIStringW() in the next commit, since there
is no real RegLoadMUIStringA() function (it exists as a stub only).
This is done so that we are consistent along the way

Also fix rule_from_windows_time_zone_info() as we can't just do a strncpy()
of tzi->StandardName and tzi->DaylightName directly, as they are wchar_t/
gunichar2 strings, where we must convert to UTF-8 first.

https://bugzilla.gnome.org/show_bug.cgi?id=719344
This commit is contained in:
Chun-wei Fan 2014-02-27 14:19:02 +08:00
parent dc774db608
commit c868123c0a

View File

@ -39,8 +39,10 @@
#include "gdate.h" #include "gdate.h"
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
#define STRICT #define STRICT
#include <windows.h> #include <windows.h>
#include <wchar.h>
#endif #endif
/** /**
@ -602,10 +604,23 @@ copy_windows_systemtime (SYSTEMTIME *s_time, TimeZoneDate *tzdate)
} }
/* UTC = local time + bias while local time = UTC + offset */ /* UTC = local time + bias while local time = UTC + offset */
static void static gboolean
rule_from_windows_time_zone_info (TimeZoneRule *rule, rule_from_windows_time_zone_info (TimeZoneRule *rule,
TIME_ZONE_INFORMATION *tzi) TIME_ZONE_INFORMATION *tzi)
{ {
gchar *std_name, *dlt_name;
std_name = g_utf16_to_utf8 ((gunichar2 *)tzi->StandardName, -1, NULL, NULL, NULL);
if (std_name == NULL)
return FALSE;
dlt_name = g_utf16_to_utf8 ((gunichar2 *)tzi->DaylightName, -1, NULL, NULL, NULL);
if (dlt_name == NULL)
{
g_free (std_name);
return FALSE;
}
/* Set offset */ /* Set offset */
if (tzi->StandardDate.wMonth) if (tzi->StandardDate.wMonth)
{ {
@ -614,7 +629,6 @@ rule_from_windows_time_zone_info (TimeZoneRule *rule,
copy_windows_systemtime (&(tzi->DaylightDate), &(rule->dlt_start)); copy_windows_systemtime (&(tzi->DaylightDate), &(rule->dlt_start));
copy_windows_systemtime (&(tzi->StandardDate), &(rule->dlt_end)); copy_windows_systemtime (&(tzi->StandardDate), &(rule->dlt_end));
} }
else else
@ -622,31 +636,41 @@ rule_from_windows_time_zone_info (TimeZoneRule *rule,
rule->std_offset = -tzi->Bias * 60; rule->std_offset = -tzi->Bias * 60;
rule->dlt_start.mon = 0; rule->dlt_start.mon = 0;
} }
strncpy (rule->std_name, (gchar*)tzi->StandardName, NAME_SIZE - 1); strncpy (rule->std_name, std_name, NAME_SIZE - 1);
strncpy (rule->dlt_name, (gchar*)tzi->DaylightName, NAME_SIZE - 1); strncpy (rule->dlt_name, dlt_name, NAME_SIZE - 1);
g_free (std_name);
g_free (dlt_name);
return TRUE;
} }
static gchar* static gchar*
windows_default_tzname (void) windows_default_tzname (void)
{ {
const gchar *subkey = const gunichar2 *subkey =
"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation"; L"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation";
HKEY key; HKEY key;
gchar *key_name = NULL; gchar *key_name = NULL;
if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey, 0, gunichar2 *key_name_w = NULL;
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, subkey, 0,
KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
{ {
DWORD size = 0; DWORD size = 0;
if (RegQueryValueExA (key, "TimeZoneKeyName", NULL, NULL, if (RegQueryValueExW (key, L"TimeZoneKeyName", NULL, NULL,
NULL, &size) == ERROR_SUCCESS) NULL, &size) == ERROR_SUCCESS)
{ {
key_name = g_malloc ((gint)size); key_name_w = g_malloc ((gint)size);
if (RegQueryValueExA (key, "TimeZoneKeyName", NULL, NULL,
(LPBYTE)key_name, &size) != ERROR_SUCCESS) if (key_name_w == NULL ||
RegQueryValueExW (key, L"TimeZoneKeyName", NULL, NULL,
(LPBYTE)key_name_w, &size) != ERROR_SUCCESS)
{ {
g_free (key_name); g_free (key_name_w);
key_name = NULL; key_name = NULL;
} }
else
key_name = g_utf16_to_utf8 (key_name_w, -1, NULL, NULL, NULL);
} }
RegCloseKey (key); RegCloseKey (key);
} }
@ -696,7 +720,8 @@ rules_from_windows_time_zone (const gchar *identifier,
TimeZoneRule **rules) TimeZoneRule **rules)
{ {
HKEY key; HKEY key;
gchar *subkey, *subkey_dynamic; gchar *subkey = NULL;
gchar *subkey_dynamic = NULL;
gchar *key_name = NULL; gchar *key_name = NULL;
const gchar *reg_key = const gchar *reg_key =
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\"; "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\";
@ -704,6 +729,7 @@ rules_from_windows_time_zone (const gchar *identifier,
DWORD size; DWORD size;
guint rules_num = 0; guint rules_num = 0;
RegTZI regtzi, regtzi_prev; RegTZI regtzi, regtzi_prev;
gunichar2 *subkey_w, *subkey_dynamic_w;
g_assert (out_identifier != NULL); g_assert (out_identifier != NULL);
g_assert (rules != NULL); g_assert (rules != NULL);
@ -721,90 +747,118 @@ rules_from_windows_time_zone (const gchar *identifier,
return 0; return 0;
subkey = g_strconcat (reg_key, key_name, NULL); subkey = g_strconcat (reg_key, key_name, NULL);
subkey_dynamic = g_strconcat (subkey, "\\Dynamic DST", NULL); subkey_w = g_utf8_to_utf16 (subkey, -1, NULL, NULL, NULL);
if (subkey_w == NULL)
goto utf16_conv_failed;
if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey, 0, subkey_dynamic = g_strconcat (subkey, "\\Dynamic DST", NULL);
subkey_dynamic_w = g_utf8_to_utf16 (subkey_dynamic, -1, NULL, NULL, NULL);
if (subkey_dynamic_w == NULL)
goto utf16_conv_failed;
if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, subkey_w, 0,
KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) KEY_QUERY_VALUE, &key) != ERROR_SUCCESS)
return 0; return 0;
size = sizeof tzi.StandardName; size = sizeof tzi.StandardName;
if (RegQueryValueExA (key, "Std", NULL, NULL, if (RegQueryValueExW (key, L"Std", NULL, NULL,
(LPBYTE)&(tzi.StandardName), &size) != ERROR_SUCCESS) (LPBYTE)&(tzi.StandardName), &size) != ERROR_SUCCESS)
goto failed; goto registry_failed;
size = sizeof tzi.DaylightName; size = sizeof tzi.DaylightName;
if (RegQueryValueExA (key, "Dlt", NULL, NULL, if (RegQueryValueExW (key, L"Dlt", NULL, NULL,
(LPBYTE)&(tzi.DaylightName), &size) != ERROR_SUCCESS) (LPBYTE)&(tzi.DaylightName), &size) != ERROR_SUCCESS)
goto failed; goto registry_failed;
RegCloseKey (key); RegCloseKey (key);
if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey_dynamic, 0, if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, subkey_dynamic_w, 0,
KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
{ {
DWORD first, last; DWORD first, last;
int year, i; int year, i;
gchar *s; wchar_t s[12];
size = sizeof first; size = sizeof first;
if (RegQueryValueExA (key, "FirstEntry", NULL, NULL, if (RegQueryValueExW (key, L"FirstEntry", NULL, NULL,
(LPBYTE) &first, &size) != ERROR_SUCCESS) (LPBYTE) &first, &size) != ERROR_SUCCESS)
goto failed; goto registry_failed;
size = sizeof last; size = sizeof last;
if (RegQueryValueExA (key, "LastEntry", NULL, NULL, if (RegQueryValueExW (key, L"LastEntry", NULL, NULL,
(LPBYTE) &last, &size) != ERROR_SUCCESS) (LPBYTE) &last, &size) != ERROR_SUCCESS)
goto failed; goto registry_failed;
rules_num = last - first + 2; rules_num = last - first + 2;
*rules = g_new0 (TimeZoneRule, rules_num); *rules = g_new0 (TimeZoneRule, rules_num);
for (year = first, i = 0; year <= last; year++) for (year = first, i = 0; *rules != NULL && year <= last; year++)
{ {
s = g_strdup_printf ("%d", year); gboolean failed = FALSE;
swprintf_s (s, 11, L"%d", year);
size = sizeof regtzi; if (!failed)
if (RegQueryValueExA (key, s, NULL, NULL, {
(LPBYTE) &regtzi, &size) != ERROR_SUCCESS) size = sizeof regtzi;
if (RegQueryValueExW (key, s, NULL, NULL,
(LPBYTE) &regtzi, &size) != ERROR_SUCCESS)
failed = TRUE;
}
if (failed)
{ {
g_free (*rules); g_free (*rules);
*rules = NULL; *rules = NULL;
break; break;
} }
g_free (s);
if (year > first && memcmp (&regtzi_prev, &regtzi, sizeof regtzi) == 0) if (year > first && memcmp (&regtzi_prev, &regtzi, sizeof regtzi) == 0)
continue; continue;
else else
memcpy (&regtzi_prev, &regtzi, sizeof regtzi); memcpy (&regtzi_prev, &regtzi, sizeof regtzi);
register_tzi_to_tzi (&regtzi, &tzi); register_tzi_to_tzi (&regtzi, &tzi);
rule_from_windows_time_zone_info (&(*rules)[i], &tzi);
if (!rule_from_windows_time_zone_info (&(*rules)[i], &tzi))
{
g_free (*rules);
*rules = NULL;
break;
}
(*rules)[i++].start_year = year; (*rules)[i++].start_year = year;
} }
rules_num = i + 1; rules_num = i + 1;
failed: registry_failed:
RegCloseKey (key); RegCloseKey (key);
} }
else if (RegOpenKeyExA (HKEY_LOCAL_MACHINE, subkey, 0, else if (RegOpenKeyExW (HKEY_LOCAL_MACHINE, subkey_w, 0,
KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) KEY_QUERY_VALUE, &key) == ERROR_SUCCESS)
{ {
size = sizeof regtzi; size = sizeof regtzi;
if (RegQueryValueExA (key, "TZI", NULL, NULL, if (RegQueryValueExW (key, L"TZI", NULL, NULL,
(LPBYTE) &regtzi, &size) == ERROR_SUCCESS) (LPBYTE) &regtzi, &size) == ERROR_SUCCESS)
{ {
rules_num = 2; rules_num = 2;
*rules = g_new0 (TimeZoneRule, 2); *rules = g_new0 (TimeZoneRule, 2);
register_tzi_to_tzi (&regtzi, &tzi); register_tzi_to_tzi (&regtzi, &tzi);
rule_from_windows_time_zone_info (&(*rules)[0], &tzi);
if (!rule_from_windows_time_zone_info (&(*rules)[0], &tzi))
{
g_free (*rules);
*rules = NULL;
}
} }
RegCloseKey (key); RegCloseKey (key);
} }
utf16_conv_failed:
g_free (subkey_dynamic_w);
g_free (subkey_dynamic); g_free (subkey_dynamic);
g_free (subkey_w);
g_free (subkey); g_free (subkey);
if (*rules) if (*rules)
@ -1518,15 +1572,16 @@ g_time_zone_new (const gchar *identifier)
{ {
rules = g_new0 (TimeZoneRule, 2); rules = g_new0 (TimeZoneRule, 2);
rule_from_windows_time_zone_info (&rules[0], &tzi); if (rule_from_windows_time_zone_info (&rules[0], &tzi))
{
memset (rules[0].std_name, 0, NAME_SIZE);
memset (rules[0].dlt_name, 0, NAME_SIZE);
memset (rules[0].std_name, 0, NAME_SIZE); rules[0].start_year = MIN_TZYEAR;
memset (rules[0].dlt_name, 0, NAME_SIZE); rules[1].start_year = MAX_TZYEAR;
rules[0].start_year = MIN_TZYEAR; init_zone_from_rules (tz, rules, 2, windows_default_tzname ());
rules[1].start_year = MAX_TZYEAR; }
init_zone_from_rules (tz, rules, 2, windows_default_tzname ());
g_free (rules); g_free (rules);
} }