]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/wintz.c
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / common / wintz.c
index 404e7482f8374257048b7b32e9517ce3c41a22d7..89fc35061ea39345114099b382dfcea6d1a58608 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ********************************************************************************
-*   Copyright (C) 2005-2013, International Business Machines
+*   Copyright (C) 2005-2015, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 ********************************************************************************
 *
@@ -18,6 +18,7 @@
 #include "cstring.h"
 
 #include "unicode/ures.h"
+#include "unicode/ustring.h"
 
 #   define WIN32_LEAN_AND_MEAN
 #   define VC_EXTRALEAN
@@ -43,7 +44,7 @@ typedef struct
  * Various registry keys and key fragments.
  */
 static const char CURRENT_ZONE_REGKEY[] = "SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation\\";
-static const char STANDARD_NAME_REGKEY[] = "StandardName";
+/* static const char STANDARD_NAME_REGKEY[] = "StandardName"; Currently unused constant */
 static const char STANDARD_TIME_REGKEY[] = " Standard Time";
 static const char TZI_REGKEY[] = "TZI";
 static const char STD_REGKEY[] = "Std";
@@ -195,6 +196,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
@@ -258,13 +283,18 @@ uprv_detectWindowsTimeZone() {
     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. */
@@ -285,33 +315,30 @@ uprv_detectWindowsTimeZone() {
     tmpid[0] = 0;
 
     id = GetUserGeoID(GEOCLASS_NATION);
-    errorCode = GetGeoInfo(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 +346,80 @@ 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;
+                }
+            }
+            ures_close(winTZ);
+        }
+    }
+
+    if(tryPreVistaFallback) {
 
-                    /* 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 */
+        /* 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[index]='\0';
                         }
-                        tmpid[index]='\0';
                     }
                 }
             }
-        }
-        ures_close(winTZ);
-        if (idFound) {
-            break;
+            ures_close(winTZ);
+            if (idFound) {
+                break;
+            }
         }
     }