ICU-8892 merge into 4.8.x r32038 and r32039 from #9408

X-SVN-Rev: 33454
diff --git a/source/common/wintz.c b/source/common/wintz.c
index bdacef0..c692ef5 100644
--- a/source/common/wintz.c
+++ b/source/common/wintz.c
@@ -1,6 +1,6 @@
 /*
 ********************************************************************************
-*   Copyright (C) 2005-2011, International Business Machines
+*   Copyright (C) 2005-2013, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 ********************************************************************************
 *
@@ -29,6 +29,8 @@
 #   define NOMCX
 #include <windows.h>
 
+#define MAX_LENGTH_ID 40
+
 /* The layout of the Tzi value in the registry */
 typedef struct
 {
@@ -170,6 +172,28 @@
     return result;
 }
 
+static LONG getSTDName(const char *winid, char *regStdName, int32_t length) {
+    DWORD cbData = length;
+    LONG result;
+    HKEY hkey;
+
+    result = openTZRegKey(&hkey, winid);
+
+    if (result == ERROR_SUCCESS) {
+        result = RegQueryValueExA(hkey,
+                                    STD_REGKEY,
+                                    NULL,
+                                    NULL,
+                                    (LPBYTE)regStdName,
+                                    &cbData);
+
+    }
+
+    RegCloseKey(hkey);
+
+    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
@@ -227,6 +251,15 @@
     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 apiStdLength = 0;
+    int32_t len;
+    int id;
+    int errorCode;
+    char ISOcode[3]; /* 2 letter iso code */
 
     LONG result;
     TZI tziKey;
@@ -246,13 +279,23 @@
     uprv_memcpy((char *)&tziKey.daylightDate, (char*)&apiTZI.DaylightDate,
            sizeof(apiTZI.DaylightDate));
 
+    /* Convert the wchar_t* standard name to char* */
+    uprv_memset(apiStdName, 0, sizeof(apiStdName));
+    u_strFromWCS(apiStd, MAX_LENGTH_ID, &apiStdLength, apiTZI.StandardName, -1, &status);
+    u_austrncpy(apiStdName, apiStd, apiStdLength);
+
+    tmpid[0] = 0;
+
+    id = GetUserGeoID(GEOCLASS_NATION);
+    errorCode = GetGeoInfo(id,GEO_ISO2,ISOcode,3,0);
+
     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;
-        int32_t len;
         UResourceBundle* winTZ = ures_getNextResource(bundle, NULL, &status);
         if (U_FAILURE(status)) {
             break;
@@ -268,22 +311,62 @@
             tziKey.daylightBias = tziReg.daylightBias;
 
             if (uprv_memcmp((char *)&tziKey, (char*)&tziReg, sizeof(tziKey)) == 0) {
-                const UChar* icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
+                const UChar* icuTZ = NULL;
+                if (errorCode != 0) {
+                    icuTZ = ures_getStringByKey(winTZ, ISOcode, &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)) {
-                    icuid = (char*)uprv_malloc(sizeof(char) * (len + 1));
-                    uprv_memset(icuid, 0, len + 1);
-                    u_austrncpy(icuid, icuTZ, len);
+                    /* 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';
+                    }
                 }
             }
         }
         ures_close(winTZ);
-        if (icuid != NULL) {
+        if (idFound) {
             break;
         }
     }
 
-    ures_close(bundle);
+    /*
+     * Copy the timezone ID to icuid to be returned.
+     */
+    if (tmpid[0] != 0) {
+        len = uprv_strlen(tmpid);
+        icuid = (char*)uprv_malloc(sizeof(char) * (len + 1));
+        uprv_memset(icuid, 0, len + 1);
+        if (icuid != NULL) {
+            uprv_strcpy(icuid, tmpid);
+        }
+    }
 
+    ures_close(bundle);
+    
     return icuid;
 }