]> granicus.if.org Git - icu/commitdiff
ICU-13687 ICU4C Enable Windows UWP version to use TZ update/override files. (#31)
authorJeff Genovy <29107334+jefgen@users.noreply.github.com>
Tue, 11 Sep 2018 16:42:49 +0000 (09:42 -0700)
committerShane Carr <shane@unicode.org>
Thu, 27 Sep 2018 21:27:39 +0000 (14:27 -0700)
Enable the Windows UWP version of ICU4C to use TZ update/override files (.res files) for out-of-band timezone data updates. Also use the *W version of the Windows APIs to avoid code-page conversion.

icu4c/source/common/putil.cpp
icu4c/source/common/umapfile.cpp

index b9bd396c8a89a54d96e04a1e0def49693c228565..bc3fbb9ba6217355b30dd6558780244b1e62e957 100644 (file)
@@ -1325,6 +1325,43 @@ uprv_pathIsAbsolute(const char *path)
 # endif
 #endif
 
+#if U_PLATFORM_HAS_WINUWP_API != 0
+// Helper function to get the ICU Data Directory under the Windows directory location.
+static BOOL U_CALLCONV getIcuDataDirectoryUnderWindowsDirectory(char* directoryBuffer, UINT bufferLength)
+{
+#if defined(ICU_DATA_DIR_WINDOWS)
+    wchar_t windowsPath[MAX_PATH];
+    char windowsPathUtf8[MAX_PATH];
+
+    UINT length = GetSystemWindowsDirectoryW(windowsPath, UPRV_LENGTHOF(windowsPath));
+    if ((length > 0) && (length < (UPRV_LENGTHOF(windowsPath) - 1))) {
+        // Convert UTF-16 to a UTF-8 string.
+        UErrorCode status = U_ZERO_ERROR;
+        int32_t windowsPathUtf8Len = 0;
+        u_strToUTF8(windowsPathUtf8, static_cast<int32_t>(UPRV_LENGTHOF(windowsPathUtf8)),
+            &windowsPathUtf8Len, reinterpret_cast<const UChar*>(windowsPath), -1, &status);
+
+        if (U_SUCCESS(status) && (status != U_STRING_NOT_TERMINATED_WARNING) &&
+            (windowsPathUtf8Len < (UPRV_LENGTHOF(windowsPathUtf8) - 1))) {
+            // Ensure it always has a separator, so we can append the ICU data path.
+            if (windowsPathUtf8[windowsPathUtf8Len - 1] != U_FILE_SEP_CHAR) {
+                windowsPathUtf8[windowsPathUtf8Len++] = U_FILE_SEP_CHAR;
+                windowsPathUtf8[windowsPathUtf8Len] = '\0';
+            }
+            // Check if the concatenated string will fit.
+            if ((windowsPathUtf8Len + UPRV_LENGTHOF(ICU_DATA_DIR_WINDOWS)) < bufferLength) {
+                uprv_strcpy(directoryBuffer, windowsPathUtf8);
+                uprv_strcat(directoryBuffer, ICU_DATA_DIR_WINDOWS);
+                return TRUE;
+            }
+        }
+    }
+#endif
+
+    return FALSE;
+}
+#endif
+
 static void U_CALLCONV dataDirectoryInitFn() {
     /* If we already have the directory, then return immediately. Will happen if user called
      * u_setDataDirectory().
@@ -1384,24 +1421,10 @@ static void U_CALLCONV dataDirectoryInitFn() {
     }
 #endif
 
-#if defined(ICU_DATA_DIR_WINDOWS) && U_PLATFORM_HAS_WINUWP_API != 0
-    // Use data from the %windir%\globalization\icu directory
-    // This is only available if ICU is built as a system component
+#if U_PLATFORM_HAS_WINUWP_API != 0  && defined(ICU_DATA_DIR_WINDOWS)
     char datadir_path_buffer[MAX_PATH];
-    UINT length = GetWindowsDirectoryA(datadir_path_buffer, UPRV_LENGTHOF(datadir_path_buffer));
-    if (length > 0 && length < (UPRV_LENGTHOF(datadir_path_buffer) - sizeof(ICU_DATA_DIR_WINDOWS) - 1))
-    {
-        if (datadir_path_buffer[length - 1] != '\\')
-        {
-            datadir_path_buffer[length++] = '\\';
-            datadir_path_buffer[length] = '\0';
-        }
-
-        if ((length + 1 + sizeof(ICU_DATA_DIR_WINDOWS)) < UPRV_LENGTHOF(datadir_path_buffer))
-        {
-            uprv_strcat(datadir_path_buffer, ICU_DATA_DIR_WINDOWS);
-            path = datadir_path_buffer;
-        }
+    if (getIcuDataDirectoryUnderWindowsDirectory(datadir_path_buffer, UPRV_LENGTHOF(datadir_path_buffer))) {
+        path = datadir_path_buffer;
     }
 #endif
 
@@ -1450,20 +1473,30 @@ static void U_CALLCONV TimeZoneDataDirInitFn(UErrorCode &status) {
         status = U_MEMORY_ALLOCATION_ERROR;
         return;
     }
-#if U_PLATFORM_HAS_WINUWP_API == 0
-    const char *dir = getenv("ICU_TIMEZONE_FILES_DIR");
-#else
-    // TODO: UWP does not support alternate timezone data directories at this time
+
     const char *dir = "";
+
+#if U_PLATFORM_HAS_WINUWP_API != 0
+    // The UWP version does not support the environment variable setting, but can possibly pick them up from the Windows directory.
+    char datadir_path_buffer[MAX_PATH];
+    if (getIcuDataDirectoryUnderWindowsDirectory(datadir_path_buffer, UPRV_LENGTHOF(datadir_path_buffer))) {
+        dir = datadir_path_buffer;
+    }
+#else
+    dir = getenv("ICU_TIMEZONE_FILES_DIR");
 #endif // U_PLATFORM_HAS_WINUWP_API
+
 #if defined(U_TIMEZONE_FILES_DIR)
     if (dir == NULL) {
+        // Build time configuration setting.
         dir = TO_STRING(U_TIMEZONE_FILES_DIR);
     }
 #endif
+
     if (dir == NULL) {
         dir = "";
     }
+
     setTimeZoneFilesDir(dir, status);
 }
 
index ffb18ef152ec30df994621a82c84726bfe1d4864..175e1a93ef3ef16ade48d7bcf553e060431b829b 100644 (file)
@@ -22,6 +22,7 @@
 #include "uposixdefs.h"
 
 #include "unicode/putil.h"
+#include "unicode/ustring.h"
 #include "udatamem.h"
 #include "umapfile.h"
 
             OPEN_EXISTING,
             FILE_ATTRIBUTE_NORMAL|FILE_FLAG_RANDOM_ACCESS, NULL);
 #else
-        // First we need to go from char to UTF-16
-        // u_UCharsToChars could work but it requires length.
-        WCHAR utf16Path[MAX_PATH];
-        int32_t i;
-        for (i = 0; i < UPRV_LENGTHOF(utf16Path); i++)
-        {
-            utf16Path[i] = path[i];
-            if (path[i] == '\0')
-            {
-                break;
-            }
+        // Convert from UTF-8 string to UTF-16 string.
+        wchar_t utf16Path[MAX_PATH];
+        int32_t pathUtf16Len = 0;
+        u_strFromUTF8(reinterpret_cast<UChar*>(utf16Path), static_cast<int32_t>(UPRV_LENGTHOF(utf16Path)), &pathUtf16Len, path, -1, status);
+
+        if (U_FAILURE(*status)) {
+            return FALSE;
         }
-        if (i >= UPRV_LENGTHOF(utf16Path))
-        {
-            // Ran out of room, unlikely but be safe
-            utf16Path[UPRV_LENGTHOF(utf16Path) - 1] = '\0';
+        if (*status == U_STRING_NOT_TERMINATED_WARNING) {
+            // Report back an error instead of a warning.
+            *status = U_BUFFER_OVERFLOW_ERROR;
+            return FALSE;
         }
 
         // TODO: Is it worth setting extended parameters to specify random access?