Index: source/common/wintz.c |
diff --git a/source/common/wintz.c b/source/common/wintz.c |
index 32e2df8ea162a59a3e06065a7220e8cee56f59eb..1b645ee9be42c4a6129eb2f2a9f4e0a9eec6e78f 100644 |
--- a/source/common/wintz.c |
+++ b/source/common/wintz.c |
@@ -1,6 +1,6 @@ |
/* |
******************************************************************************** |
-* Copyright (C) 2005-2013, International Business Machines |
+* Copyright (C) 2005-2014, International Business Machines |
* Corporation and others. All Rights Reserved. |
******************************************************************************** |
* |
@@ -17,8 +17,8 @@ |
#include "cmemory.h" |
#include "cstring.h" |
-#include "unicode/ustring.h" |
#include "unicode/ures.h" |
+#include "unicode/ustring.h" |
# define WIN32_LEAN_AND_MEAN |
# define VC_EXTRALEAN |
@@ -193,6 +193,30 @@ static LONG getSTDName(const char *winid, char *regStdName, int32_t length) { |
return result; |
} |
+static LONG getTZKeyName(char* tzKeyName, int32_t length) { |
+ HKEY hkey; |
+ LONG result = FALSE; |
+ DWORD cbData = length; |
+ |
+ if(ERROR_SUCCESS == RegOpenKeyExA( |
+ HKEY_LOCAL_MACHINE, |
+ CURRENT_ZONE_REGKEY, |
+ 0, |
+ KEY_QUERY_VALUE, |
+ &hkey)) |
+ { |
+ result = RegQueryValueExA( |
+ hkey, |
+ "TimeZoneKeyName", |
+ NULL, |
+ NULL, |
+ (LPBYTE)tzKeyName, |
+ &cbData); |
+ } |
+ |
+ return result; |
+} |
+ |
/* |
This code attempts to detect the Windows time zone, as set in the |
Windows Date and Time control panel. It attempts to work on |
@@ -250,20 +274,24 @@ uprv_detectWindowsTimeZone() { |
UErrorCode status = U_ZERO_ERROR; |
UResourceBundle* bundle = NULL; |
char* icuid = NULL; |
- UChar apiStd[MAX_LENGTH_ID]; |
char apiStdName[MAX_LENGTH_ID]; |
char regStdName[MAX_LENGTH_ID]; |
char tmpid[MAX_LENGTH_ID]; |
int32_t len; |
int id; |
int errorCode; |
- char ISOcode[3]; /* 2 letter iso code */ |
+ UChar ISOcodeW[3]; /* 2 letter iso code in UTF-16*/ |
+ char ISOcodeA[3]; /* 2 letter iso code in ansi */ |
LONG result; |
TZI tziKey; |
TZI tziReg; |
TIME_ZONE_INFORMATION apiTZI; |
+ BOOL isVistaOrHigher; |
+ BOOL tryPreVistaFallback; |
+ OSVERSIONINFO osVerInfo; |
+ |
/* Obtain TIME_ZONE_INFORMATION from the API, and then convert it |
to TZI. We could also interrogate the registry directly; we do |
this below if needed. */ |
@@ -279,39 +307,35 @@ uprv_detectWindowsTimeZone() { |
/* Convert the wchar_t* standard name to char* */ |
uprv_memset(apiStdName, 0, sizeof(apiStdName)); |
- u_strFromWCS(apiStd, MAX_LENGTH_ID, NULL, apiTZI.StandardName, -1, &status); |
- u_austrncpy(apiStdName, apiStd, sizeof(apiStdName) - 1); |
+ wcstombs(apiStdName, apiTZI.StandardName, MAX_LENGTH_ID); |
tmpid[0] = 0; |
id = GetUserGeoID(GEOCLASS_NATION); |
- errorCode = GetGeoInfoA(id,GEO_ISO2,ISOcode,3,0); |
+ errorCode = GetGeoInfoW(id,GEO_ISO2,ISOcodeW,3,0); |
+ u_strToUTF8(ISOcodeA, 3, NULL, ISOcodeW, 3, &status); |
bundle = ures_openDirect(NULL, "windowsZones", &status); |
ures_getByKey(bundle, "mapTimezones", bundle, &status); |
- /* Note: We get the winid not from static tables but from resource bundle. */ |
- while (U_SUCCESS(status) && ures_hasNext(bundle)) { |
- UBool idFound = FALSE; |
- const char* winid; |
- UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status); |
- if (U_FAILURE(status)) { |
- break; |
- } |
- winid = ures_getKey(winTZ); |
- result = getTZI(winid, &tziReg); |
- |
- if (result == ERROR_SUCCESS) { |
- /* Windows alters the DaylightBias in some situations. |
- Using the bias and the rules suffices, so overwrite |
- these unreliable fields. */ |
- tziKey.standardBias = tziReg.standardBias; |
- tziKey.daylightBias = tziReg.daylightBias; |
- |
- if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) { |
+ /* |
+ Windows Vista+ provides us with a "TimeZoneKeyName" that is not localized |
+ and can be used to directly map a name in our bundle. Try to use that first |
+ if we're on Vista or higher |
+ */ |
+ uprv_memset(&osVerInfo, 0, sizeof(osVerInfo)); |
+ osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo); |
+ GetVersionEx(&osVerInfo); |
+ isVistaOrHigher = osVerInfo.dwMajorVersion >= 6; /* actually includes Windows Server 2008 as well, but don't worry about it */ |
+ tryPreVistaFallback = TRUE; |
+ if(isVistaOrHigher) { |
+ result = getTZKeyName(regStdName, sizeof(regStdName)); |
+ if(ERROR_SUCCESS == result) { |
+ UResourceBundle* winTZ = ures_getByKey(bundle, regStdName, NULL, &status); |
+ if(U_SUCCESS(status)) { |
const UChar* icuTZ = NULL; |
if (errorCode != 0) { |
- icuTZ = ures_getStringByKey(winTZ, ISOcode, &len, &status); |
+ icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status); |
} |
if (errorCode==0 || icuTZ==NULL) { |
/* fallback to default "001" and reset status */ |
@@ -319,35 +343,79 @@ uprv_detectWindowsTimeZone() { |
icuTZ = ures_getStringByKey(winTZ, "001", &len, &status); |
} |
- if (U_SUCCESS(status)) { |
- /* Get the standard name from the registry key to compare with |
- the one from Windows API call. */ |
- uprv_memset(regStdName, 0, sizeof(regStdName)); |
- result = getSTDName(winid, regStdName, sizeof(regStdName)); |
- if (result == ERROR_SUCCESS) { |
- if (uprv_strcmp(apiStdName, regStdName) == 0) { |
- idFound = TRUE; |
- } |
+ if(U_SUCCESS(status)) { |
+ int index=0; |
+ while (! (*icuTZ == '\0' || *icuTZ ==' ')) { |
+ tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */ |
+ } |
+ tmpid[index]='\0'; |
+ tryPreVistaFallback = FALSE; |
+ } |
+ } |
+ } |
+ } |
+ |
+ if(tryPreVistaFallback) { |
+ |
+ /* Note: We get the winid not from static tables but from resource bundle. */ |
+ while (U_SUCCESS(status) && ures_hasNext(bundle)) { |
+ UBool idFound = FALSE; |
+ const char* winid; |
+ UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status); |
+ if (U_FAILURE(status)) { |
+ break; |
+ } |
+ winid = ures_getKey(winTZ); |
+ result = getTZI(winid, &tziReg); |
+ |
+ if (result == ERROR_SUCCESS) { |
+ /* Windows alters the DaylightBias in some situations. |
+ Using the bias and the rules suffices, so overwrite |
+ these unreliable fields. */ |
+ tziKey.standardBias = tziReg.standardBias; |
+ tziKey.daylightBias = tziReg.daylightBias; |
+ |
+ if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) { |
+ const UChar* icuTZ = NULL; |
+ if (errorCode != 0) { |
+ icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status); |
} |
+ if (errorCode==0 || icuTZ==NULL) { |
+ /* fallback to default "001" and reset status */ |
+ status = U_ZERO_ERROR; |
+ icuTZ = ures_getStringByKey(winTZ, "001", &len, &status); |
+ } |
+ |
+ if (U_SUCCESS(status)) { |
+ /* Get the standard name from the registry key to compare with |
+ the one from Windows API call. */ |
+ uprv_memset(regStdName, 0, sizeof(regStdName)); |
+ result = getSTDName(winid, regStdName, sizeof(regStdName)); |
+ if (result == ERROR_SUCCESS) { |
+ if (uprv_strcmp(apiStdName, regStdName) == 0) { |
+ idFound = TRUE; |
+ } |
+ } |
- /* tmpid buffer holds the ICU timezone ID corresponding to the timezone ID from Windows. |
- * If none is found, tmpid buffer will contain a fallback ID (i.e. the time zone ID matching |
- * the current time zone information) |
- */ |
- if (idFound || tmpid[0] == 0) { |
- /* if icuTZ has more than one city, take only the first (i.e. terminate icuTZ at first space) */ |
- int index=0; |
- while (! (*icuTZ == '\0' || *icuTZ ==' ')) { |
- tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */ |
+ /* tmpid buffer holds the ICU timezone ID corresponding to the timezone ID from Windows. |
+ * If none is found, tmpid buffer will contain a fallback ID (i.e. the time zone ID matching |
+ * the current time zone information) |
+ */ |
+ if (idFound || tmpid[0] == 0) { |
+ /* if icuTZ has more than one city, take only the first (i.e. terminate icuTZ at first space) */ |
+ int index=0; |
+ while (! (*icuTZ == '\0' || *icuTZ ==' ')) { |
+ tmpid[index++]=(char)(*icuTZ++); /* safe to assume 'char' is ASCII compatible on windows */ |
+ } |
+ tmpid[index]='\0'; |
} |
- tmpid[index]='\0'; |
} |
} |
} |
- } |
- ures_close(winTZ); |
- if (idFound) { |
- break; |
+ ures_close(winTZ); |
+ if (idFound) { |
+ break; |
+ } |
} |
} |