]> granicus.if.org Git - icu/commitdiff
ICU-13827 Clean up ICU4C "wintz.cpp" time zone detection code.
authorJeff Genovy <29107334+jefgen@users.noreply.github.com>
Wed, 19 Sep 2018 07:48:16 +0000 (00:48 -0700)
committerShane Carr <shane@unicode.org>
Thu, 27 Sep 2018 21:27:41 +0000 (14:27 -0700)
- Use stack allocated UResouceBundle to reduce number of calls to malloc (in a method that can't report back an error if Out-Of-Memory [OOM] happens).
- Use LocalUResourcePointer for automatic clean-up of UResouceBundle.
- Use uprv_strdup instead of calloc + strcpy.
- Changes comments, formatting, etc.

icu4c/source/common/wintz.cpp

index df4aa061670defd7c67c6a8add91eb154d0c7b53..9cf79d7b4ac427982536bd8326cc736a35830cc4 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "unicode/ures.h"
 #include "unicode/ustring.h"
+#include "uresimp.h"
 
 #ifndef WIN32_LEAN_AND_MEAN
 #   define WIN32_LEAN_AND_MEAN
 #   define NOMCX
 #include <windows.h>
 
+U_NAMESPACE_BEGIN
+
 // The value of MAX_TIMEZONE_ID_LENGTH is 128, which is defined in DYNAMIC_TIME_ZONE_INFORMATION
 #define MAX_TIMEZONE_ID_LENGTH 128
 
 /**
-* Main Windows time zone detection function.  Returns the Windows
-* time zone, translated to an ICU time zone, or nullptr upon failure.
-* It is calling GetDynamicTimeZoneInformation to get the current time zone info.
-* The API returns non-localized time zone name so it can be used for mapping ICU time zone name.
+* Main Windows time zone detection function.
+* Returns the Windows time zone converted to an ICU time zone as a heap-allocated buffer, or nullptr upon failure.
+* Note: We use the Win32 API GetDynamicTimeZoneInformation to get the current time zone info.
+* This API returns a non-localized time zone name, which we can then map to an ICU time zone name.
 */
 U_CFUNC const char* U_EXPORT2
 uprv_detectWindowsTimeZone()
 {
     UErrorCode status = U_ZERO_ERROR;
-    UResourceBundle* bundle = nullptr;
     char* icuid = nullptr;
-    char dynamicTZKeyName[MAX_TIMEZONE_ID_LENGTH] = {};
-    char tmpid[MAX_TIMEZONE_ID_LENGTH] = {};
+    char dynamicTZKeyName[MAX_TIMEZONE_ID_LENGTH];
+    char tmpid[MAX_TIMEZONE_ID_LENGTH];
     int32_t len;
-    int id;
+    int id = GEOID_NOT_AVAILABLE;
     int errorCode;
-    wchar_t ISOcodeW[3] = {}; /* 2 letter iso code in UTF-16*/
-    char  ISOcodeA[3] = {}; /* 2 letter iso code in ansi */
+    wchar_t ISOcodeW[3] = {}; /* 2 letter ISO code in UTF-16 */
+    char ISOcode[3] = {}; /* 2 letter ISO code in UTF-8 */
 
     DYNAMIC_TIME_ZONE_INFORMATION dynamicTZI;
+    uprv_memset(&dynamicTZI, 0, sizeof(dynamicTZI));
+    uprv_memset(dynamicTZKeyName, 0, sizeof(dynamicTZKeyName));
+    uprv_memset(tmpid, 0, sizeof(tmpid));
 
     /* Obtain TIME_ZONE_INFORMATION from the API and get the non-localized time zone name. */
-    uprv_memset(&dynamicTZI, 0, sizeof(dynamicTZI));
-    if (TIME_ZONE_ID_INVALID == GetDynamicTimeZoneInformation(&dynamicTZI))
-    {
+    if (TIME_ZONE_ID_INVALID == GetDynamicTimeZoneInformation(&dynamicTZI)) {
         return nullptr;
     }
 
-    tmpid[0] = 0;
-
     id = GetUserGeoID(GEOCLASS_NATION);
     errorCode = GetGeoInfoW(id, GEO_ISO2, ISOcodeW, 3, 0);
-    u_strToUTF8(ISOcodeA, 3, nullptr, (const UChar *)ISOcodeW, 3, &status);
 
-    bundle = ures_openDirect(nullptr, "windowsZones", &status);
-    ures_getByKey(bundle, "mapTimezones", bundle, &status);
+    // convert from wchar_t* (UTF-16 on Windows) to char* (UTF-8).
+    u_strToUTF8(ISOcode, UPRV_LENGTHOF(ISOcode), nullptr,
+        reinterpret_cast<const UChar*>(ISOcodeW), UPRV_LENGTHOF(ISOcodeW), &status);
 
-    /* Convert the wchar_t* standard name to char* */
-    uprv_memset(dynamicTZKeyName, 0, sizeof(dynamicTZKeyName));
-    u_strToUTF8(dynamicTZKeyName, MAX_TIMEZONE_ID_LENGTH, nullptr, (const UChar *)dynamicTZI.TimeZoneKeyName, MAX_TIMEZONE_ID_LENGTH, &status);
+    LocalUResourceBundlePointer bundle(ures_openDirect(nullptr, "windowsZones", &status));
+    ures_getByKey(bundle.getAlias(), "mapTimezones", bundle.getAlias(), &status);
+
+    // convert from wchar_t* (UTF-16 on Windows) to char* (UTF-8).
+    u_strToUTF8(dynamicTZKeyName, UPRV_LENGTHOF(dynamicTZKeyName), nullptr,
+        reinterpret_cast<const UChar*>(dynamicTZI.TimeZoneKeyName), UPRV_LENGTHOF(dynamicTZI.TimeZoneKeyName), &status);
 
-    if (dynamicTZI.TimeZoneKeyName[0] != 0)
-    {
-        UResourceBundle* winTZ = ures_getByKey(bundle, dynamicTZKeyName, nullptr, &status);
-        if (U_SUCCESS(status))
-        {
+    if (U_FAILURE(status)) {
+        return nullptr;
+    }
+
+    if (dynamicTZI.TimeZoneKeyName[0] != 0) {
+        UResourceBundle winTZ;
+        ures_initStackObject(&winTZ);
+        ures_getByKey(bundle.getAlias(), dynamicTZKeyName, &winTZ, &status);
+        
+        if (U_SUCCESS(status)) {
             const UChar* icuTZ = nullptr;
-            if (errorCode != 0)
-            {
-                icuTZ = ures_getStringByKey(winTZ, ISOcodeA, &len, &status);
+            if (errorCode != 0) {
+                icuTZ = ures_getStringByKey(&winTZ, ISOcode, &len, &status);
             }
-            if (errorCode == 0 || icuTZ == nullptr)
-            {
+            if (errorCode == 0 || icuTZ == nullptr) {
                 /* fallback to default "001" and reset status */
                 status = U_ZERO_ERROR;
-                icuTZ = ures_getStringByKey(winTZ, "001", &len, &status);
+                icuTZ = ures_getStringByKey(&winTZ, "001", &len, &status);
             }
 
-            if (U_SUCCESS(status))
-            {
+            if (U_SUCCESS(status)) {
                 int index = 0;
-                while (!(*icuTZ == '\0' || *icuTZ == ' '))
-                {
-                    tmpid[index++] = (char)(*icuTZ++);  /* safe to assume 'char' is ASCII compatible on windows */
+
+                while (!(*icuTZ == '\0' || *icuTZ == ' ')) {
+                    // time zone IDs only contain ASCII invariant characters.
+                    tmpid[index++] = (char)(*icuTZ++);
                 }
                 tmpid[index] = '\0';
             }
         }
-        ures_close(winTZ);
+        ures_close(&winTZ);
     }
 
-    /*
-    * Copy the timezone ID to icuid to be returned.
-    */
-    if (tmpid[0] != 0)
-    {
-        len = static_cast<int32_t>(uprv_strlen(tmpid));
-        icuid = (char*)uprv_calloc(len + 1, sizeof(char));
-        if (icuid != nullptr)
-        {
-            uprv_strcpy(icuid, tmpid);
-        }
+    // Copy the timezone ID to icuid to be returned.
+    if (tmpid[0] != 0) {
+        icuid = uprv_strdup(tmpid);
     }
 
-    ures_close(bundle);
-
     return icuid;
 }
 
+U_NAMESPACE_END
 #endif /* U_PLATFORM_HAS_WIN32_API  */