]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/putil.cpp
ICU-62107.0.1.tar.gz
[apple/icu.git] / icuSources / common / putil.cpp
index 71abfdcee08be3f91e4f9eb882f1b0ec2f9baa8b..15265972546d301d39b40fcae7772873d806bacb 100644 (file)
 #   define NOIME
 #   define NOMCX
 #   include <windows.h>
-#   include "unicode\uloc.h"
+#   include "unicode/uloc.h"
 #if U_PLATFORM_HAS_WINUWP_API == 0
 #   include "wintz.h"
 #else // U_PLATFORM_HAS_WINUWP_API
 typedef PVOID LPMSG; // TODO: figure out how to get rid of this typedef
 #include <Windows.Globalization.h>
 #include <windows.system.userprofile.h>
-#include <wrl\wrappers\corewrappers.h>
-#include <wrl\client.h>
+#include <wrl/wrappers/corewrappers.h>
+#include <wrl/client.h>
 
 using namespace ABI::Windows::Foundation;
 using namespace Microsoft::WRL;
@@ -533,6 +533,28 @@ uprv_fmin(double x, double y)
     return (x > y ? y : x);
 }
 
+U_CAPI UBool U_EXPORT2
+uprv_add32_overflow(int32_t a, int32_t b, int32_t* res) {
+    // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_add_overflow.
+    // This function could be optimized by calling one of those primitives.
+    auto a64 = static_cast<int64_t>(a);
+    auto b64 = static_cast<int64_t>(b);
+    int64_t res64 = a64 + b64;
+    *res = static_cast<int32_t>(res64);
+    return res64 != *res;
+}
+
+U_CAPI UBool U_EXPORT2
+uprv_mul32_overflow(int32_t a, int32_t b, int32_t* res) {
+    // NOTE: Some compilers (GCC, Clang) have primitives available, like __builtin_mul_overflow.
+    // This function could be optimized by calling one of those primitives.
+    auto a64 = static_cast<int64_t>(a);
+    auto b64 = static_cast<int64_t>(b);
+    int64_t res64 = a64 * b64;
+    *res = static_cast<int32_t>(res64);
+    return res64 != *res;
+}
+
 /**
  * Truncates the given double.
  * trunc(3.3) = 3.0, trunc (-3.3) = -3.0
@@ -675,6 +697,16 @@ extern U_IMPORT char *U_TZNAME[];
 
 #if !UCONFIG_NO_FILE_IO && ((U_PLATFORM_IS_DARWIN_BASED && (U_PLATFORM != U_PF_IPHONE || defined(U_TIMEZONE))) || U_PLATFORM_IS_LINUX_BASED || U_PLATFORM == U_PF_BSD || U_PLATFORM == U_PF_SOLARIS)
 /* These platforms are likely to use Olson timezone IDs. */
+/* common targets of the symbolic link at TZDEFAULT are:
+ * "/usr/share/zoneinfo/<olsonID>" default, older Linux distros, macOS to 10.12
+ * "../usr/share/zoneinfo/<olsonID>" newer Linux distros: Red Hat Enterprise Linux 7, Ubuntu 16, SuSe Linux 12
+ * "/usr/share/lib/zoneinfo/<olsonID>" Solaris
+ * "../usr/share/lib/zoneinfo/<olsonID>" Solaris
+ * "/var/db/timezone/zoneinfo/<olsonID>" macOS 10.13
+ * To avoid checking lots of paths, just check that the target path
+ * before the <olsonID> ends with "/zoneinfo/", and the <olsonID> is valid.
+ */
+
 #define CHECK_LOCALTIME_LINK 1
 #if U_PLATFORM_IS_DARWIN_BASED
 #include <tzfile.h>
@@ -682,12 +714,12 @@ extern U_IMPORT char *U_TZNAME[];
 #elif U_PLATFORM == U_PF_SOLARIS
 #define TZDEFAULT       "/etc/localtime"
 #define TZZONEINFO      "/usr/share/lib/zoneinfo/"
-#define TZZONEINFO2     "../usr/share/lib/zoneinfo/"
 #define TZ_ENV_CHECK    "localtime"
 #else
 #define TZDEFAULT       "/etc/localtime"
 #define TZZONEINFO      "/usr/share/zoneinfo/"
 #endif
+#define TZZONEINFOTAIL  "/zoneinfo/"
 #if U_HAVE_DIRENT_H
 #define TZFILE_SKIP     "posixrules" /* tz file to skip when searching. */
 /* Some Linux distributions have 'localtime' in /usr/share/zoneinfo
@@ -939,30 +971,30 @@ static CharString *gSearchTZFileResult = NULL;
  * This function is not thread safe - it uses a global, gSearchTZFileResult, to hold its results.
  */
 static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
-    DIR* dirp = opendir(path);
-    DIR* subDirp = NULL;
+    DIR* dirp = NULL;
     struct dirent* dirEntry = NULL;
-
     char* result = NULL;
+    UErrorCode status = U_ZERO_ERROR;
+
+    /* Save the current path */
+    CharString curpath(path, -1, status);
+    if (U_FAILURE(status)) {
+        goto cleanupAndReturn;
+    }
+
+    dirp = opendir(path);
     if (dirp == NULL) {
-        return result;
+        goto cleanupAndReturn;
     }
 
     if (gSearchTZFileResult == NULL) {
         gSearchTZFileResult = new CharString;
         if (gSearchTZFileResult == NULL) {
-            return NULL;
+            goto cleanupAndReturn;
         }
         ucln_common_registerCleanup(UCLN_COMMON_PUTIL, putil_cleanup);
     }
 
-    /* Save the current path */
-    UErrorCode status = U_ZERO_ERROR;
-    CharString curpath(path, -1, status);
-    if (U_FAILURE(status)) {
-        return NULL;
-    }
-
     /* Check each entry in the directory. */
     while((dirEntry = readdir(dirp)) != NULL) {
         const char* dirName = dirEntry->d_name;
@@ -971,15 +1003,16 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
             CharString newpath(curpath, status);
             newpath.append(dirName, -1, status);
             if (U_FAILURE(status)) {
-                return NULL;
+                break;
             }
 
+            DIR* subDirp = NULL;
             if ((subDirp = opendir(newpath.data())) != NULL) {
                 /* If this new path is a directory, make a recursive call with the newpath. */
                 closedir(subDirp);
                 newpath.append('/', status);
                 if (U_FAILURE(status)) {
-                    return NULL;
+                    break;
                 }
                 result = searchForTZFile(newpath.data(), tzInfo);
                 /*
@@ -1003,7 +1036,7 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
                     gSearchTZFileResult->clear();
                     gSearchTZFileResult->append(zoneid, -1, status);
                     if (U_FAILURE(status)) {
-                        return NULL;
+                        break;
                     }
                     result = gSearchTZFileResult->data();
                     /* Get out after the first one found. */
@@ -1012,7 +1045,11 @@ static char* searchForTZFile(const char* path, DefaultTZInfo* tzInfo) {
             }
         }
     }
-    closedir(dirp);
+
+  cleanupAndReturn:
+    if (dirp) {
+        closedir(dirp);
+    }
     return result;
 }
 #endif
@@ -1045,7 +1082,7 @@ uprv_getWindowsTimeZone()
             hr = timezone->GetTimeZone(timezoneString.GetAddressOf());
             if (SUCCEEDED(hr))
             {
-                int32_t length = wcslen(timezoneString.GetRawBuffer(NULL));
+                int32_t length = static_cast<int32_t>(wcslen(timezoneString.GetRawBuffer(NULL)));
                 char* asciiId = (char*)uprv_calloc(length + 1, sizeof(char));
                 if (asciiId != nullptr)
                 {
@@ -1064,6 +1101,7 @@ uprv_getWindowsTimeZone()
 U_CAPI const char* U_EXPORT2
 uprv_tzname(int n)
 {
+    (void)n; // Avoid unreferenced parameter warning.
     const char *tzid = NULL;
 #if U_PLATFORM_USES_ONLY_WIN32_API
 #if U_PLATFORM_HAS_WINUWP_API > 0
@@ -1125,24 +1163,15 @@ uprv_tzname(int n)
         */
         int32_t ret = (int32_t)readlink(TZDEFAULT, gTimeZoneBuffer, sizeof(gTimeZoneBuffer)-1);
         if (0 < ret) {
-            int32_t tzZoneInfoLen = uprv_strlen(TZZONEINFO);
+            int32_t tzZoneInfoTailLen = uprv_strlen(TZZONEINFOTAIL);
             gTimeZoneBuffer[ret] = 0;
-            if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO, tzZoneInfoLen) == 0
-                && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
-            {
-                return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
-            }
-#if U_PLATFORM == U_PF_SOLARIS
-            else
+            char *  tzZoneInfoTailPtr = uprv_strstr(gTimeZoneBuffer, TZZONEINFOTAIL);
+            
+            if (tzZoneInfoTailPtr != NULL
+                && isValidOlsonID(tzZoneInfoTailPtr + tzZoneInfoTailLen))
             {
-                tzZoneInfoLen = uprv_strlen(TZZONEINFO2);
-                if (uprv_strncmp(gTimeZoneBuffer, TZZONEINFO2, tzZoneInfoLen) == 0
-                                && isValidOlsonID(gTimeZoneBuffer + tzZoneInfoLen))
-                {
-                    return (gTimeZoneBufferPtr = gTimeZoneBuffer + tzZoneInfoLen);
-                }
+                return (gTimeZoneBufferPtr = tzZoneInfoTailPtr + tzZoneInfoTailLen);
             }
-#endif
         } else {
 #if defined(SEARCH_TZFILE)
             DefaultTZInfo* tzInfo = (DefaultTZInfo*)uprv_malloc(sizeof(DefaultTZInfo));
@@ -1228,7 +1257,7 @@ UInitOnce gTimeZoneFilesInitOnce = U_INITONCE_INITIALIZER;
 static CharString *gTimeZoneFilesDirectory = NULL;
 
 #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
- static char *gCorrectedPOSIXLocale = NULL; /* Sometimes heap allocated */
+ static const char *gCorrectedPOSIXLocale = NULL; /* Sometimes heap allocated */
  static bool gCorrectedPOSIXLocaleHeapAllocated = false;
 #endif
 
@@ -1251,7 +1280,7 @@ static UBool U_CALLCONV putil_cleanup(void)
 
 #if U_POSIX_LOCALE || U_PLATFORM_USES_ONLY_WIN32_API
     if (gCorrectedPOSIXLocale && gCorrectedPOSIXLocaleHeapAllocated) {
-        uprv_free(gCorrectedPOSIXLocale);
+        uprv_free(const_cast<char *>(gCorrectedPOSIXLocale));
         gCorrectedPOSIXLocale = NULL;
         gCorrectedPOSIXLocaleHeapAllocated = false;
     }
@@ -1287,7 +1316,7 @@ u_setDataDirectory(const char *directory) {
 #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
         {
             char *p;
-            while(p = uprv_strchr(newDataDir, U_FILE_ALT_SEP_CHAR)) {
+            while((p = uprv_strchr(newDataDir, U_FILE_ALT_SEP_CHAR)) != NULL) {
                 *p = U_FILE_SEP_CHAR;
             }
         }
@@ -1445,7 +1474,7 @@ static void setTimeZoneFilesDir(const char *path, UErrorCode &status) {
     gTimeZoneFilesDirectory->append(path, status);
 #if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
     char *p = gTimeZoneFilesDirectory->data();
-    while (p = uprv_strchr(p, U_FILE_ALT_SEP_CHAR)) {
+    while ((p = uprv_strchr(p, U_FILE_ALT_SEP_CHAR)) != NULL) {
         *p = U_FILE_SEP_CHAR;
     }
 #endif
@@ -1846,6 +1875,8 @@ The leftmost codepage (.xxx) wins.
         }
 
         // Now normalize the resulting name
+        correctedPOSIXLocale = static_cast<char *>(uprv_malloc(POSIX_LOCALE_CAPACITY + 1));
+        /* TODO: Should we just exit on memory allocation failure? */
         if (correctedPOSIXLocale)
         {
             int32_t posixLen = uloc_canonicalize(modifiedWindowsLocale, correctedPOSIXLocale, POSIX_LOCALE_CAPACITY, &status);
@@ -2363,19 +2394,16 @@ u_getVersion(UVersionInfo versionArray) {
  * icucfg.h dependent code 
  */
 
-#if U_ENABLE_DYLOAD
-#if HAVE_DLOPEN && !U_PLATFORM_USES_ONLY_WIN32_API
+#if U_ENABLE_DYLOAD && HAVE_DLOPEN && !U_PLATFORM_USES_ONLY_WIN32_API
 
 #if HAVE_DLFCN_H
-
 #ifdef __MVS__
 #ifndef __SUSV3
 #define __SUSV3 1
 #endif
 #endif
 #include <dlfcn.h>
-#endif
+#endif /* HAVE_DLFCN_H */
 
 U_INTERNAL void * U_EXPORT2
 uprv_dl_open(const char *libName, UErrorCode *status) {
@@ -2415,38 +2443,10 @@ uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
   return uret.fp;
 }
 
-#else
-
-/* null (nonexistent) implementation. */
-
-U_INTERNAL void * U_EXPORT2
-uprv_dl_open(const char *libName, UErrorCode *status) {
-  if(U_FAILURE(*status)) return NULL;
-  *status = U_UNSUPPORTED_ERROR;
-  return NULL;
-}
-
-U_INTERNAL void U_EXPORT2
-uprv_dl_close(void *lib, UErrorCode *status) {
-  if(U_FAILURE(*status)) return;
-  *status = U_UNSUPPORTED_ERROR;
-  return;
-}
-
-
-U_INTERNAL UVoidFunction* U_EXPORT2
-uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
-  if(U_SUCCESS(*status)) {
-    *status = U_UNSUPPORTED_ERROR;
-  }
-  return (UVoidFunction*)NULL;
-}
-
+#elif U_ENABLE_DYLOAD && U_PLATFORM_USES_ONLY_WIN32_API && !U_PLATFORM_HAS_WINUWP_API
 
-
-#endif
-
-#elif U_PLATFORM_USES_ONLY_WIN32_API
+/* Windows API implementation. */
+// Note: UWP does not expose/allow these APIs, so the UWP version gets the null implementation. */
 
 U_INTERNAL void * U_EXPORT2
 uprv_dl_open(const char *libName, UErrorCode *status) {
@@ -2473,7 +2473,6 @@ uprv_dl_close(void *lib, UErrorCode *status) {
   return;
 }
 
-
 U_INTERNAL UVoidFunction* U_EXPORT2
 uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
   HMODULE handle = (HMODULE)lib;
@@ -2495,10 +2494,9 @@ uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
   return addr;
 }
 
-
 #else
 
-/* No dynamic loading set. */
+/* No dynamic loading, null (nonexistent) implementation. */
 
 U_INTERNAL void * U_EXPORT2
 uprv_dl_open(const char *libName, UErrorCode *status) {
@@ -2516,7 +2514,6 @@ uprv_dl_close(void *lib, UErrorCode *status) {
     return;
 }
 
-
 U_INTERNAL UVoidFunction* U_EXPORT2
 uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
   (void)lib;
@@ -2527,7 +2524,7 @@ uprv_dlsym_func(void *lib, const char* sym, UErrorCode *status) {
   return (UVoidFunction*)NULL;
 }
 
-#endif /* U_ENABLE_DYLOAD */
+#endif
 
 /*
  * Hey, Emacs, please set the following: