summaryrefslogtreecommitdiff
path: root/src/corefx/System.Globalization.Native
diff options
context:
space:
mode:
Diffstat (limited to 'src/corefx/System.Globalization.Native')
-rw-r--r--src/corefx/System.Globalization.Native/CMakeLists.txt40
-rw-r--r--src/corefx/System.Globalization.Native/calendarData.cpp2
-rw-r--r--src/corefx/System.Globalization.Native/casing.cpp3
-rw-r--r--src/corefx/System.Globalization.Native/collation.cpp44
-rw-r--r--src/corefx/System.Globalization.Native/errors.h8
-rw-r--r--src/corefx/System.Globalization.Native/holders.h8
-rw-r--r--src/corefx/System.Globalization.Native/icushim.cpp226
-rw-r--r--src/corefx/System.Globalization.Native/icushim.h243
-rw-r--r--src/corefx/System.Globalization.Native/idna.cpp2
-rw-r--r--src/corefx/System.Globalization.Native/locale.cpp51
-rw-r--r--src/corefx/System.Globalization.Native/locale.hpp2
-rw-r--r--src/corefx/System.Globalization.Native/localeNumberData.cpp3
-rw-r--r--src/corefx/System.Globalization.Native/localeStringData.cpp104
-rw-r--r--src/corefx/System.Globalization.Native/normalization.cpp2
-rw-r--r--src/corefx/System.Globalization.Native/timeZoneInfo.cpp2
15 files changed, 691 insertions, 49 deletions
diff --git a/src/corefx/System.Globalization.Native/CMakeLists.txt b/src/corefx/System.Globalization.Native/CMakeLists.txt
index 3d9e392132..90f50671cd 100644
--- a/src/corefx/System.Globalization.Native/CMakeLists.txt
+++ b/src/corefx/System.Globalization.Native/CMakeLists.txt
@@ -14,7 +14,7 @@ if(UTYPES_H STREQUAL UTYPES_H-NOTFOUND)
return()
endif()
-if(NOT CLR_CMAKE_PLATFORM_DARWIN)
+if (FEATURE_FIXED_ICU_VERSION AND NOT CLR_CMAKE_PLATFORM_DARWIN)
find_library(ICUUC icuuc)
if(ICUUC STREQUAL ICUUC-NOTFOUND)
message(FATAL_ERROR "Cannot find libicuuc, try installing libicu-dev (or the appropriate package for your platform)")
@@ -26,12 +26,16 @@ if(NOT CLR_CMAKE_PLATFORM_DARWIN)
message(FATAL_ERROR "Cannot find libicui18n, try installing libicu-dev (or the appropriate package for your platform)")
return()
endif()
-else()
+endif()
+
+if(CLR_CMAKE_PLATFORM_DARWIN)
find_library(ICUCORE icucore)
if(ICUI18N STREQUAL ICUCORE-NOTFOUND)
message(FATAL_ERROR "Cannot find libicucore, skipping build for System.Globalization.Native. .NET globalization is not expected to function.")
return()
endif()
+ # On Darwin, we always use the OS provided ICU
+ SET(FEATURE_FIXED_ICU_VERSION 1)
endif()
include(configure.cmake)
@@ -50,6 +54,12 @@ set(NATIVEGLOBALIZATION_SOURCES
timeZoneInfo.cpp
)
+if (NOT FEATURE_FIXED_ICU_VERSION)
+ list(APPEND NATIVEGLOBALIZATION_SOURCES
+ icushim.cpp
+ )
+endif()
+
include_directories(${UTYPES_H})
_add_library(System.Globalization.Native
@@ -60,11 +70,21 @@ _add_library(System.Globalization.Native
# Disable the "lib" prefix.
set_target_properties(System.Globalization.Native PROPERTIES PREFIX "")
+if (FEATURE_FIXED_ICU_VERSION)
+ add_definitions(-DFEATURE_FIXED_ICU_VERSION)
+endif()
+
if(NOT CLR_CMAKE_PLATFORM_DARWIN)
- target_link_libraries(System.Globalization.Native
- ${ICUUC}
- ${ICUI18N}
- )
+ if (FEATURE_FIXED_ICU_VERSION)
+ target_link_libraries(System.Globalization.Native
+ ${ICUUC}
+ ${ICUI18N}
+ )
+ elseif(NOT CMAKE_SYSTEM_NAME STREQUAL FreeBSD AND NOT CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+ target_link_libraries(System.Globalization.Native
+ dl
+ )
+ endif()
else()
target_link_libraries(System.Globalization.Native
${ICUCORE}
@@ -73,5 +93,11 @@ else()
add_definitions(-DU_DISABLE_RENAMING=1)
endif()
+verify_dependencies(
+ System.Globalization.Native
+ "Verification failed. System.Globalization.Native.so has undefined dependencies. These are likely ICU APIs that need to be added to icushim.h."
+)
+
# add the install targets
-install_clr(System.Globalization.Native) \ No newline at end of file
+install_clr(System.Globalization.Native)
+
diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp
index f91cc0cb57..49436078d8 100644
--- a/src/corefx/System.Globalization.Native/calendarData.cpp
+++ b/src/corefx/System.Globalization.Native/calendarData.cpp
@@ -6,7 +6,7 @@
#include <string.h>
#include <vector>
-#include "config.h"
+#include "icushim.h"
#include "locale.hpp"
#include "holders.h"
#include "errors.h"
diff --git a/src/corefx/System.Globalization.Native/casing.cpp b/src/corefx/System.Globalization.Native/casing.cpp
index 58b47fc810..918b8fe6ed 100644
--- a/src/corefx/System.Globalization.Native/casing.cpp
+++ b/src/corefx/System.Globalization.Native/casing.cpp
@@ -5,8 +5,7 @@
#include <assert.h>
#include <stdint.h>
-#include <unicode/uchar.h>
-#include <unicode/utf16.h>
+#include "icushim.h"
/*
Function:
diff --git a/src/corefx/System.Globalization.Native/collation.cpp b/src/corefx/System.Globalization.Native/collation.cpp
index 6039a9ef39..f37211208e 100644
--- a/src/corefx/System.Globalization.Native/collation.cpp
+++ b/src/corefx/System.Globalization.Native/collation.cpp
@@ -8,12 +8,10 @@
#include <stdint.h>
#include <vector>
#include <map>
-#include <unicode/uchar.h>
-#include <unicode/ucol.h>
-#include <unicode/usearch.h>
-#include <unicode/utf16.h>
-#include "config.h"
+#include "icushim.h"
+#include "locale.hpp"
+#include "errors.h"
const int32_t CompareOptionsIgnoreCase = 0x1;
const int32_t CompareOptionsIgnoreNonSpace = 0x2;
@@ -298,7 +296,7 @@ UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t options,
// Returns TRUE if all the collation elements in str are completely ignorable
bool CanIgnoreAllCollationElements(const UCollator* pColl, const UChar* lpStr, int32_t length)
{
- bool result = FALSE;
+ bool result = false;
UErrorCode err = U_ZERO_ERROR;
UCollationElements* pCollElem = ucol_openElements(pColl, lpStr, length, &err);
@@ -306,20 +304,20 @@ bool CanIgnoreAllCollationElements(const UCollator* pColl, const UChar* lpStr, i
{
int32_t curCollElem = UCOL_NULLORDER;
- result = TRUE;
+ result = true;
while ((curCollElem = ucol_next(pCollElem, &err)) != UCOL_NULLORDER)
{
if (curCollElem != 0)
{
- result = FALSE;
+ result = false;
break;
}
}
if (U_FAILURE(err))
{
- result = FALSE;
+ result = false;
}
ucol_closeElements(pCollElem);
@@ -329,24 +327,36 @@ bool CanIgnoreAllCollationElements(const UCollator* pColl, const UChar* lpStr, i
}
-extern "C" SortHandle* GlobalizationNative_GetSortHandle(const char* lpLocaleName)
+extern "C" int32_t GlobalizationNative_GetSortVersion()
{
- SortHandle* pSortHandle = new SortHandle();
+ // we didn't use UCOL_TAILORINGS_VERSION because it is deprecated in ICU v5
+ return UCOL_RUNTIME_VERSION << 16 | UCOL_BUILDER_VERSION;
+}
+
+extern "C" ResultCode GlobalizationNative_GetSortHandle(const char* lpLocaleName, SortHandle** ppSortHandle)
+{
+ assert(ppSortHandle != nullptr);
+
+ *ppSortHandle = new (std::nothrow) SortHandle();
+ if ((*ppSortHandle) == nullptr)
+ {
+ return GetResultCode(U_MEMORY_ALLOCATION_ERROR);
+ }
UErrorCode err = U_ZERO_ERROR;
- pSortHandle->regular = ucol_open(lpLocaleName, &err);
+ (*ppSortHandle)->regular = ucol_open(lpLocaleName, &err);
if (U_FAILURE(err))
{
- if (pSortHandle->regular != nullptr)
- ucol_close(pSortHandle->regular);
+ if ((*ppSortHandle)->regular != nullptr)
+ ucol_close((*ppSortHandle)->regular);
- delete pSortHandle;
- pSortHandle = nullptr;
+ delete (*ppSortHandle);
+ (*ppSortHandle) = nullptr;
}
- return pSortHandle;
+ return GetResultCode(err);
}
extern "C" void GlobalizationNative_CloseSortHandle(SortHandle* pSortHandle)
diff --git a/src/corefx/System.Globalization.Native/errors.h b/src/corefx/System.Globalization.Native/errors.h
index 2bfbdb2ba1..b23a0dacd5 100644
--- a/src/corefx/System.Globalization.Native/errors.h
+++ b/src/corefx/System.Globalization.Native/errors.h
@@ -4,8 +4,6 @@
#pragma once
-#include <unicode/utypes.h>
-
/*
* These values should be kept in sync with
* Interop.GlobalizationInterop.ResultCode
@@ -15,6 +13,7 @@ enum ResultCode : int32_t
Success = 0,
UnknownError = 1,
InsufficentBuffer = 2,
+ OutOfMemory = 3
};
/*
@@ -26,6 +25,11 @@ static ResultCode GetResultCode(UErrorCode err)
{
return InsufficentBuffer;
}
+
+ if (err == U_MEMORY_ALLOCATION_ERROR)
+ {
+ return OutOfMemory;
+ }
if (U_SUCCESS(err))
{
diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h
index 529451f77c..83e253d297 100644
--- a/src/corefx/System.Globalization.Native/holders.h
+++ b/src/corefx/System.Globalization.Native/holders.h
@@ -2,14 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#include <unicode/ucal.h>
-#include <unicode/uenum.h>
-#include <unicode/udatpg.h>
-#include <unicode/udat.h>
-#include <unicode/unum.h>
-#include <unicode/uldnames.h>
-#include <unicode/ures.h>
-
// IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct
// time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the
// pointer and UErrorCode to manage the lifetime. When the holder goes out of scope, the coresponding close method is
diff --git a/src/corefx/System.Globalization.Native/icushim.cpp b/src/corefx/System.Globalization.Native/icushim.cpp
new file mode 100644
index 0000000000..63f111b8b1
--- /dev/null
+++ b/src/corefx/System.Globalization.Native/icushim.cpp
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "icushim.h"
+
+// Define pointers to all the used ICU functions
+#define PER_FUNCTION_BLOCK(fn, lib) decltype(fn)* fn##_ptr;
+FOR_ALL_ICU_FUNCTIONS
+#undef PER_FUNCTION_BLOCK
+
+static void* libicuuc = nullptr;
+static void* libicui18n = nullptr;
+
+// Version ranges to search for each of the three version components
+// The rationale for major version range is that we support versions higher or
+// equal to the version we are built against and less or equal to that version
+// plus 20 to give us enough headspace. The ICU seems to version about twice
+// a year.
+static const int MinICUVersion = U_ICU_VERSION_MAJOR_NUM;
+static const int MaxICUVersion = MinICUVersion + 20;
+static const int MinMinorICUVersion = 1;
+static const int MaxMinorICUVersion = 5;
+static const int MinSubICUVersion = 1;
+static const int MaxSubICUVersion = 5;
+
+// .x.x.x, considering the max number of decimal digits for each component
+static const int MaxICUVersionStringLength = 33;
+
+// Get filename of an ICU library with the requested version in the name
+// There are three possible cases of the version components values:
+// 1. Only majorVer is not equal to -1 => result is baseFileName.majorver
+// 2. Only majorVer and minorVer are not equal to -1 => result is baseFileName.majorver.minorVer
+// 3. All components are not equal to -1 => result is baseFileName.majorver.minorVer.subver
+void GetVersionedLibFileName(const char* baseFileName, int majorVer, int minorVer, int subVer, char* result)
+{
+ assert(majorVer != -1);
+
+ int nameLen = sprintf(result, "%s.%d", baseFileName, majorVer);
+
+ if (minorVer != -1)
+ {
+ nameLen += sprintf(result + nameLen, ".%d", minorVer);
+ if (subVer != -1)
+ {
+ sprintf(result + nameLen, ".%d", subVer);
+ }
+ }
+}
+
+// Try to open the necessary ICU libraries
+bool OpenICULibraries(int majorVer, int minorVer, int subVer)
+{
+ char libicuucName[64];
+ char libicui18nName[64];
+
+ static_assert(sizeof("libicuuc.so") + MaxICUVersionStringLength <= sizeof(libicuucName), "The libicuucName is too small");
+ GetVersionedLibFileName("libicuuc.so", majorVer, minorVer, subVer, libicuucName);
+
+ static_assert(sizeof("libicui18n.so") + MaxICUVersionStringLength <= sizeof(libicui18nName), "The libicui18nName is too small");
+ GetVersionedLibFileName("libicui18n.so", majorVer, minorVer, subVer, libicui18nName);
+
+ libicuuc = dlopen(libicuucName, RTLD_LAZY);
+ if (libicuuc != nullptr)
+ {
+ libicui18n = dlopen(libicui18nName, RTLD_LAZY);
+ if (libicui18n == nullptr)
+ {
+ dlclose(libicuuc);
+ libicuuc = nullptr;
+ }
+ }
+
+ return libicuuc != nullptr;
+}
+
+// Select libraries using the version override specified by the CLR_ICU_VERSION_OVERRIDE
+// environment variable.
+// The format of the string in this variable is majorVer[.minorVer[.subVer]] (the brackets
+// indicate optional parts).
+bool FindLibUsingOverride(int* majorVer, int* minorVer, int* subVer)
+{
+ char* versionOverride = getenv("CLR_ICU_VERSION_OVERRIDE");
+ if (versionOverride != nullptr)
+ {
+ int first = -1;
+ int second = -1;
+ int third = -1;
+
+ int matches = sscanf(versionOverride, "%d.%d.%d", &first, &second, &third);
+ if (matches > 0)
+ {
+ if (OpenICULibraries(first, second, third))
+ {
+ *majorVer = first;
+ *minorVer = second;
+ *subVer = third;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Select the highest supported version of ICU present on the local machine
+// Search for library files with names including the major and minor version.
+bool FindLibWithMajorMinorVersion(int* majorVer, int* minorVer)
+{
+ for (int i = MaxICUVersion; i >= MinICUVersion; i--)
+ {
+ for (int j = MaxMinorICUVersion; j >= MinMinorICUVersion; j--)
+ {
+ if (OpenICULibraries(i, j, -1))
+ {
+ *majorVer = i;
+ *minorVer = j;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Select the highest supported version of ICU present on the local machine
+// Search for library files with names including the major, minor and sub version.
+bool FindLibWithMajorMinorSubVersion(int* majorVer, int* minorVer, int* subVer)
+{
+ for (int i = MaxICUVersion; i >= MinICUVersion; i--)
+ {
+ for (int j = MaxMinorICUVersion; j >= MinMinorICUVersion; j--)
+ {
+ for (int k = MaxSubICUVersion; k >= MinSubICUVersion; k--)
+ {
+ if (OpenICULibraries(i, j, k))
+ {
+ *majorVer = i;
+ *minorVer = j;
+ *subVer = k;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// This function is ran at the end of dlopen for the current shared library
+__attribute__((constructor))
+void InitializeICUShim()
+{
+ int majorVer = -1;
+ int minorVer = -1;
+ int subVer = -1;
+
+ if (!FindLibUsingOverride(&majorVer, &minorVer, &subVer) &&
+ !FindLibWithMajorMinorVersion(&majorVer, &minorVer) &&
+ !FindLibWithMajorMinorSubVersion(&majorVer, &minorVer, &subVer))
+ {
+ // No usable ICU version found
+ fprintf(stderr, "No usable version of the ICU libraries was found\n");
+ abort();
+ }
+
+ char symbolName[128];
+ char symbolVersion[MaxICUVersionStringLength + 1] = "";
+
+ // Find out the format of the version string added to each symbol
+ // First try just the unversioned symbol
+ if (dlsym(libicuuc, "u_strlen") == nullptr)
+ {
+ // Now try just the _majorVer added
+ sprintf(symbolVersion, "_%d", majorVer);
+ sprintf(symbolName, "u_strlen%s", symbolVersion);
+ if (dlsym(libicuuc, symbolName) == nullptr)
+ {
+ // Now try the _majorVer_minorVer added
+ sprintf(symbolVersion, "_%d_%d", majorVer, minorVer);
+ sprintf(symbolName, "u_strlen%s", symbolVersion);
+ if (dlsym(libicuuc, symbolName) == nullptr)
+ {
+ // Finally, try the _majorVer_minorVer_subVer added
+ sprintf(symbolVersion, "_%d_%d_%d", majorVer, minorVer, subVer);
+ sprintf(symbolName, "u_strlen%s", symbolVersion);
+ if (dlsym(libicuuc, symbolName) == nullptr)
+ {
+ fprintf(stderr, "ICU libraries use unknown symbol versioning\n");
+ abort();
+ }
+ }
+ }
+ }
+
+ // Get pointers to all the ICU functions that are needed
+#define PER_FUNCTION_BLOCK(fn, lib) \
+ static_assert((sizeof(#fn) + MaxICUVersionStringLength + 1) <= sizeof(symbolName), "The symbolName is too small for symbol " #fn); \
+ sprintf(symbolName, #fn "%s", symbolVersion); \
+ fn##_ptr = (decltype(fn)*)dlsym(lib, symbolName); \
+ if (fn##_ptr == NULL) { fprintf(stderr, "Cannot get symbol %s from " #lib "\n", symbolName); abort(); }
+
+ FOR_ALL_ICU_FUNCTIONS
+#undef PER_FUNCTION_BLOCK
+}
+
+__attribute__((destructor))
+void ShutdownICUShim()
+{
+ if (libicuuc != nullptr)
+ {
+ dlclose(libicuuc);
+ }
+
+ if (libicui18n != nullptr)
+ {
+ dlclose(libicui18n);
+ }
+}
diff --git a/src/corefx/System.Globalization.Native/icushim.h b/src/corefx/System.Globalization.Native/icushim.h
new file mode 100644
index 0000000000..8ec13d5737
--- /dev/null
+++ b/src/corefx/System.Globalization.Native/icushim.h
@@ -0,0 +1,243 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+// Enable calling ICU functions through shims to enable support for
+// multiple versions of ICU if the FEATURE_FIXED_ICU_VERSION is
+// not defined.
+
+#ifndef __ICUSHIM_H__
+#define __ICUSHIM_H__
+
+#include "config.h"
+
+#ifndef FEATURE_FIXED_ICU_VERSION
+#define U_DISABLE_RENAMING 1
+#endif
+
+// All ICU headers need to be included here so that all function prototypes are
+// available before the function pointers are declared below.
+#include <unicode/locid.h>
+#include <unicode/ucurr.h>
+#include <unicode/ucal.h>
+#include <unicode/uchar.h>
+#include <unicode/ucol.h>
+#include <unicode/udat.h>
+#include <unicode/udatpg.h>
+#include <unicode/uenum.h>
+#include <unicode/uidna.h>
+#include <unicode/uldnames.h>
+#include <unicode/ulocdata.h>
+#include <unicode/unorm2.h>
+#include <unicode/unum.h>
+#include <unicode/ures.h>
+#include <unicode/usearch.h>
+#include <unicode/utf16.h>
+#include <unicode/utypes.h>
+
+#ifndef FEATURE_FIXED_ICU_VERSION
+
+// List of all functions from the ICU libraries that are used in the System.Globalization.Native.so
+#define FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \
+ PER_FUNCTION_BLOCK(u_charsToUChars, libicuuc) \
+ PER_FUNCTION_BLOCK(u_strlen, libicuuc) \
+ PER_FUNCTION_BLOCK(u_strncpy, libicuuc) \
+ PER_FUNCTION_BLOCK(u_tolower, libicuuc) \
+ PER_FUNCTION_BLOCK(u_toupper, libicuuc) \
+ PER_FUNCTION_BLOCK(ucal_add, libicui18n) \
+ PER_FUNCTION_BLOCK(ucal_close, libicui18n) \
+ PER_FUNCTION_BLOCK(ucal_get, libicui18n) \
+ PER_FUNCTION_BLOCK(ucal_getAttribute, libicui18n) \
+ PER_FUNCTION_BLOCK(ucal_getKeywordValuesForLocale, libicui18n) \
+ PER_FUNCTION_BLOCK(ucal_getLimit, libicui18n) \
+ PER_FUNCTION_BLOCK(ucal_getTimeZoneDisplayName, libicui18n) \
+ PER_FUNCTION_BLOCK(ucal_open, libicui18n) \
+ PER_FUNCTION_BLOCK(ucal_set, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_close, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_closeElements, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_getRules, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_getSortKey, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_getStrength, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_next, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_open, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_openElements, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_openRules, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_safeClone, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_setAttribute, libicui18n) \
+ PER_FUNCTION_BLOCK(ucol_strcoll, libicui18n) \
+ PER_FUNCTION_BLOCK(ucurr_forLocale, libicui18n) \
+ PER_FUNCTION_BLOCK(ucurr_getName, libicui18n) \
+ PER_FUNCTION_BLOCK(udat_close, libicui18n) \
+ PER_FUNCTION_BLOCK(udat_countSymbols, libicui18n) \
+ PER_FUNCTION_BLOCK(udat_getSymbols, libicui18n) \
+ PER_FUNCTION_BLOCK(udat_open, libicui18n) \
+ PER_FUNCTION_BLOCK(udat_setCalendar, libicui18n) \
+ PER_FUNCTION_BLOCK(udat_toPattern, libicui18n) \
+ PER_FUNCTION_BLOCK(udatpg_close, libicui18n) \
+ PER_FUNCTION_BLOCK(udatpg_getBestPattern, libicui18n) \
+ PER_FUNCTION_BLOCK(udatpg_open, libicui18n) \
+ PER_FUNCTION_BLOCK(uenum_close, libicuuc) \
+ PER_FUNCTION_BLOCK(uenum_count, libicuuc) \
+ PER_FUNCTION_BLOCK(uenum_next, libicuuc) \
+ PER_FUNCTION_BLOCK(uidna_close, libicuuc) \
+ PER_FUNCTION_BLOCK(uidna_nameToASCII, libicuuc) \
+ PER_FUNCTION_BLOCK(uidna_nameToUnicode, libicuuc) \
+ PER_FUNCTION_BLOCK(uidna_openUTS46, libicuuc) \
+ PER_FUNCTION_BLOCK(uldn_close, libicui18n) \
+ PER_FUNCTION_BLOCK(uldn_keyValueDisplayName, libicui18n) \
+ PER_FUNCTION_BLOCK(uldn_open, libicui18n) \
+ PER_FUNCTION_BLOCK(uloc_canonicalize, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_countAvailable, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getAvailable, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getBaseName, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getCharacterOrientation, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getCountry, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getDefault, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getDisplayCountry, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getDisplayLanguage, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getDisplayName, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getISO3Country, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getISO3Language, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getKeywordValue, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getLanguage, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getLCID, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getName, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_getParent, libicuuc) \
+ PER_FUNCTION_BLOCK(uloc_setKeywordValue, libicuuc) \
+ PER_FUNCTION_BLOCK(ulocdata_getMeasurementSystem, libicui18n) \
+ PER_FUNCTION_BLOCK(unorm2_getNFCInstance, libicuuc) \
+ PER_FUNCTION_BLOCK(unorm2_getNFDInstance, libicuuc) \
+ PER_FUNCTION_BLOCK(unorm2_getNFKCInstance, libicuuc) \
+ PER_FUNCTION_BLOCK(unorm2_getNFKDInstance, libicuuc) \
+ PER_FUNCTION_BLOCK(unorm2_isNormalized, libicuuc) \
+ PER_FUNCTION_BLOCK(unorm2_normalize, libicuuc) \
+ PER_FUNCTION_BLOCK(unum_close, libicui18n) \
+ PER_FUNCTION_BLOCK(unum_getAttribute, libicui18n) \
+ PER_FUNCTION_BLOCK(unum_getSymbol, libicui18n) \
+ PER_FUNCTION_BLOCK(unum_open, libicui18n) \
+ PER_FUNCTION_BLOCK(unum_toPattern, libicui18n) \
+ PER_FUNCTION_BLOCK(ures_close, libicuuc) \
+ PER_FUNCTION_BLOCK(ures_getByKey, libicuuc) \
+ PER_FUNCTION_BLOCK(ures_getSize, libicuuc) \
+ PER_FUNCTION_BLOCK(ures_getStringByIndex, libicuuc) \
+ PER_FUNCTION_BLOCK(ures_open, libicuuc) \
+ PER_FUNCTION_BLOCK(usearch_close, libicui18n) \
+ PER_FUNCTION_BLOCK(usearch_first, libicui18n) \
+ PER_FUNCTION_BLOCK(usearch_getMatchedLength, libicui18n) \
+ PER_FUNCTION_BLOCK(usearch_last, libicui18n) \
+ PER_FUNCTION_BLOCK(usearch_openFromCollator, libicui18n)
+
+#if HAVE_SET_MAX_VARIABLE
+#define FOR_ALL_ICU_FUNCTIONS \
+ FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \
+ PER_FUNCTION_BLOCK(ucol_setMaxVariable, libicui18n)
+#else
+#define FOR_ALL_ICU_FUNCTIONS \
+ FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \
+ PER_FUNCTION_BLOCK(ucol_setVariableTop, libicui18n)
+#endif
+
+// Declare pointers to all the used ICU functions
+#define PER_FUNCTION_BLOCK(fn, lib) extern decltype(fn)* fn##_ptr;
+FOR_ALL_ICU_FUNCTIONS
+#undef PER_FUNCTION_BLOCK
+
+// Redefine all calls to ICU functions as calls through pointers that are set
+// to the functions of the selected version of ICU in the initialization.
+#define u_charsToUChars(...) u_charsToUChars_ptr(__VA_ARGS__)
+#define u_strlen(...) u_strlen_ptr(__VA_ARGS__)
+#define u_strncpy(...) u_strncpy_ptr(__VA_ARGS__)
+#define u_tolower(...) u_tolower_ptr(__VA_ARGS__)
+#define u_toupper(...) u_toupper_ptr(__VA_ARGS__)
+#define ucal_add(...) ucal_add_ptr(__VA_ARGS__)
+#define ucal_close(...) ucal_close_ptr(__VA_ARGS__)
+#define ucal_get(...) ucal_get_ptr(__VA_ARGS__)
+#define ucal_getAttribute(...) ucal_getAttribute_ptr(__VA_ARGS__)
+#define ucal_getKeywordValuesForLocale(...) ucal_getKeywordValuesForLocale_ptr(__VA_ARGS__)
+#define ucal_getLimit(...) ucal_getLimit_ptr(__VA_ARGS__)
+#define ucal_getTimeZoneDisplayName(...) ucal_getTimeZoneDisplayName_ptr(__VA_ARGS__)
+#define ucal_open(...) ucal_open_ptr(__VA_ARGS__)
+#define ucal_set(...) ucal_set_ptr(__VA_ARGS__)
+#define ucol_close(...) ucol_close_ptr(__VA_ARGS__)
+#define ucol_closeElements(...) ucol_closeElements_ptr(__VA_ARGS__)
+#define ucol_getRules(...) ucol_getRules_ptr(__VA_ARGS__)
+#define ucol_getSortKey(...) ucol_getSortKey_ptr(__VA_ARGS__)
+#define ucol_getStrength(...) ucol_getStrength_ptr(__VA_ARGS__)
+#define ucol_next(...) ucol_next_ptr(__VA_ARGS__)
+#define ucol_open(...) ucol_open_ptr(__VA_ARGS__)
+#define ucol_openElements(...) ucol_openElements_ptr(__VA_ARGS__)
+#define ucol_openRules(...) ucol_openRules_ptr(__VA_ARGS__)
+#define ucol_safeClone(...) ucol_safeClone_ptr(__VA_ARGS__)
+#define ucol_setAttribute(...) ucol_setAttribute_ptr(__VA_ARGS__)
+#if HAVE_SET_MAX_VARIABLE
+#define ucol_setMaxVariable(...) ucol_setMaxVariable_ptr(__VA_ARGS__)
+#else
+#define ucol_setVariableTop(...) ucol_setVariableTop_ptr(__VA_ARGS__)
+#endif
+#define ucol_strcoll(...) ucol_strcoll_ptr(__VA_ARGS__)
+#define ucurr_forLocale(...) ucurr_forLocale_ptr(__VA_ARGS__)
+#define ucurr_getName(...) ucurr_getName_ptr(__VA_ARGS__)
+#define udat_close(...) udat_close_ptr(__VA_ARGS__)
+#define udat_countSymbols(...) udat_countSymbols_ptr(__VA_ARGS__)
+#define udat_getSymbols(...) udat_getSymbols_ptr(__VA_ARGS__)
+#define udat_open(...) udat_open_ptr(__VA_ARGS__)
+#define udat_setCalendar(...) udat_setCalendar_ptr(__VA_ARGS__)
+#define udat_toPattern(...) udat_toPattern_ptr(__VA_ARGS__)
+#define udatpg_close(...) udatpg_close_ptr(__VA_ARGS__)
+#define udatpg_getBestPattern(...) udatpg_getBestPattern_ptr(__VA_ARGS__)
+#define udatpg_open(...) udatpg_open_ptr(__VA_ARGS__)
+#define uenum_close(...) uenum_close_ptr(__VA_ARGS__)
+#define uenum_count(...) uenum_count_ptr(__VA_ARGS__)
+#define uenum_next(...) uenum_next_ptr(__VA_ARGS__)
+#define uidna_close(...) uidna_close_ptr(__VA_ARGS__)
+#define uidna_nameToASCII(...) uidna_nameToASCII_ptr(__VA_ARGS__)
+#define uidna_nameToUnicode(...) uidna_nameToUnicode_ptr(__VA_ARGS__)
+#define uidna_openUTS46(...) uidna_openUTS46_ptr(__VA_ARGS__)
+#define uldn_close(...) uldn_close_ptr(__VA_ARGS__)
+#define uldn_keyValueDisplayName(...) uldn_keyValueDisplayName_ptr(__VA_ARGS__)
+#define uldn_open(...) uldn_open_ptr(__VA_ARGS__)
+#define uloc_canonicalize(...) uloc_canonicalize_ptr(__VA_ARGS__)
+#define uloc_countAvailable(...) uloc_countAvailable_ptr(__VA_ARGS__)
+#define uloc_getAvailable(...) uloc_getAvailable_ptr(__VA_ARGS__)
+#define uloc_getBaseName(...) uloc_getBaseName_ptr(__VA_ARGS__)
+#define uloc_getCharacterOrientation(...) uloc_getCharacterOrientation_ptr(__VA_ARGS__)
+#define uloc_getCountry(...) uloc_getCountry_ptr(__VA_ARGS__)
+#define uloc_getDefault(...) uloc_getDefault_ptr(__VA_ARGS__)
+#define uloc_getDisplayCountry(...) uloc_getDisplayCountry_ptr(__VA_ARGS__)
+#define uloc_getDisplayLanguage(...) uloc_getDisplayLanguage_ptr(__VA_ARGS__)
+#define uloc_getDisplayName(...) uloc_getDisplayName_ptr(__VA_ARGS__)
+#define uloc_getISO3Country(...) uloc_getISO3Country_ptr(__VA_ARGS__)
+#define uloc_getISO3Language(...) uloc_getISO3Language_ptr(__VA_ARGS__)
+#define uloc_getKeywordValue(...) uloc_getKeywordValue_ptr(__VA_ARGS__)
+#define uloc_getLanguage(...) uloc_getLanguage_ptr(__VA_ARGS__)
+#define uloc_getLCID(...) uloc_getLCID_ptr(__VA_ARGS__)
+#define uloc_getName(...) uloc_getName_ptr(__VA_ARGS__)
+#define uloc_getParent(...) uloc_getParent_ptr(__VA_ARGS__)
+#define uloc_setKeywordValue(...) uloc_setKeywordValue_ptr(__VA_ARGS__)
+#define ulocdata_getMeasurementSystem(...) ulocdata_getMeasurementSystem_ptr(__VA_ARGS__)
+#define unorm2_getNFCInstance(...) unorm2_getNFCInstance_ptr(__VA_ARGS__)
+#define unorm2_getNFDInstance(...) unorm2_getNFDInstance_ptr(__VA_ARGS__)
+#define unorm2_getNFKCInstance(...) unorm2_getNFKCInstance_ptr(__VA_ARGS__)
+#define unorm2_getNFKDInstance(...) unorm2_getNFKDInstance_ptr(__VA_ARGS__)
+#define unorm2_isNormalized(...) unorm2_isNormalized_ptr(__VA_ARGS__)
+#define unorm2_normalize(...) unorm2_normalize_ptr(__VA_ARGS__)
+#define unum_close(...) unum_close_ptr(__VA_ARGS__)
+#define unum_getAttribute(...) unum_getAttribute_ptr(__VA_ARGS__)
+#define unum_getSymbol(...) unum_getSymbol_ptr(__VA_ARGS__)
+#define unum_open(...) unum_open_ptr(__VA_ARGS__)
+#define unum_toPattern(...) unum_toPattern_ptr(__VA_ARGS__)
+#define ures_close(...) ures_close_ptr(__VA_ARGS__)
+#define ures_getByKey(...) ures_getByKey_ptr(__VA_ARGS__)
+#define ures_getSize(...) ures_getSize_ptr(__VA_ARGS__)
+#define ures_getStringByIndex(...) ures_getStringByIndex_ptr(__VA_ARGS__)
+#define ures_open(...) ures_open_ptr(__VA_ARGS__)
+#define usearch_close(...) usearch_close_ptr(__VA_ARGS__)
+#define usearch_first(...) usearch_first_ptr(__VA_ARGS__)
+#define usearch_getMatchedLength(...) usearch_getMatchedLength_ptr(__VA_ARGS__)
+#define usearch_last(...) usearch_last_ptr(__VA_ARGS__)
+#define usearch_openFromCollator(...) usearch_openFromCollator_ptr(__VA_ARGS__)
+
+#endif // !FEATURE_ICU_VERSION_RESILIENT
+
+#endif // __ICUSHIM_H__
diff --git a/src/corefx/System.Globalization.Native/idna.cpp b/src/corefx/System.Globalization.Native/idna.cpp
index 4820d2c3f2..23942b3a68 100644
--- a/src/corefx/System.Globalization.Native/idna.cpp
+++ b/src/corefx/System.Globalization.Native/idna.cpp
@@ -4,7 +4,7 @@
//
#include <stdint.h>
-#include <unicode/uidna.h>
+#include "icushim.h"
const uint32_t AllowUnassigned = 0x1;
const uint32_t UseStd3AsciiRules = 0x2;
diff --git a/src/corefx/System.Globalization.Native/locale.cpp b/src/corefx/System.Globalization.Native/locale.cpp
index 1cb564a45a..951179d321 100644
--- a/src/corefx/System.Globalization.Native/locale.cpp
+++ b/src/corefx/System.Globalization.Native/locale.cpp
@@ -9,6 +9,7 @@
#include <stdlib.h>
#include <locale.h>
+#include "icushim.h"
#include "locale.hpp"
int32_t UErrorCodeToBool(UErrorCode status)
@@ -147,6 +148,56 @@ const char* DetectDefaultLocaleName()
return uloc_getDefault();
}
+// GlobalizationNative_GetLocales gets all locale names and store it in the value buffer
+// in case of success, it returns the count of the characters stored in value buffer
+// in case of failure, it returns negative number.
+// if the input value buffer is null, it returns the length needed to store the
+// locale names list.
+// if the value is not null, it fills the value with locale names separated by the length
+// of each name.
+extern "C" int32_t GlobalizationNative_GetLocales(UChar *value, int32_t valueLength)
+{
+ int32_t totalLength = 0;
+ int32_t index = 0;
+ int32_t localeCount = uloc_countAvailable();
+
+ if (localeCount <= 0)
+ return -1; // failed
+
+ for (int32_t i = 0; i < localeCount; i++)
+ {
+ const char *pLocaleName = uloc_getAvailable(i);
+ if (pLocaleName[0] == 0) // unexpected empty name
+ return -2;
+
+ int32_t localeNameLength = strlen(pLocaleName);
+
+ totalLength += localeNameLength + 1; // add 1 for the name length
+
+ if (value != nullptr)
+ {
+ if (totalLength > valueLength)
+ return -3;
+
+ value[index++] = (UChar) localeNameLength;
+
+ for (int j=0; j<localeNameLength; j++)
+ {
+ if (pLocaleName[j] == '_') // fix the locale name
+ {
+ value[index++] = (UChar) '-';
+ }
+ else
+ {
+ value[index++] = (UChar) pLocaleName[j];
+ }
+ }
+ }
+ }
+
+ return totalLength;
+}
+
extern "C" int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength)
{
UErrorCode status = U_ZERO_ERROR;
diff --git a/src/corefx/System.Globalization.Native/locale.hpp b/src/corefx/System.Globalization.Native/locale.hpp
index 4845859960..79328f3b19 100644
--- a/src/corefx/System.Globalization.Native/locale.hpp
+++ b/src/corefx/System.Globalization.Native/locale.hpp
@@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-#include "unicode/locid.h"
-
/*
Function:
UErrorCodeToBool
diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/localeNumberData.cpp
index 595cb130b2..a3586b568f 100644
--- a/src/corefx/System.Globalization.Native/localeNumberData.cpp
+++ b/src/corefx/System.Globalization.Native/localeNumberData.cpp
@@ -7,8 +7,7 @@
#include <string.h>
#include <vector>
-#include <unicode/ulocdata.h>
-
+#include "icushim.h"
#include "locale.hpp"
#include "holders.h"
diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp
index 927da67095..b8eaa307c7 100644
--- a/src/corefx/System.Globalization.Native/localeStringData.cpp
+++ b/src/corefx/System.Globalization.Native/localeStringData.cpp
@@ -7,6 +7,7 @@
#include <string.h>
#include <vector>
+#include "icushim.h"
#include "locale.hpp"
#include "holders.h"
@@ -27,6 +28,8 @@ enum LocaleStringData : int32_t
ThousandSeparator = 0x0000000F,
Digits = 0x00000013,
MonetarySymbol = 0x00000014,
+ CurrencyEnglishName = 0x00001007,
+ CurrencyNativeName = 0x00001008,
Iso4217MonetarySymbol = 0x00000015,
MonetaryDecimalSeparator = 0x00000016,
MonetaryThousandSeparator = 0x00000017,
@@ -34,8 +37,10 @@ enum LocaleStringData : int32_t
PMDesignator = 0x00000029,
PositiveSign = 0x00000050,
NegativeSign = 0x00000051,
- Iso639LanguageName = 0x00000059,
+ Iso639LanguageTwoLetterName = 0x00000059,
+ Iso639LanguageThreeLetterName = 0x00000067,
Iso3166CountryName = 0x0000005A,
+ Iso3166CountryName2= 0x00000068,
NaNSymbol = 0x00000069,
PositiveInfinitySymbol = 0x0000006a,
ParentName = 0x0000006d,
@@ -111,11 +116,11 @@ UErrorCode GetLocaleInfoAmPm(const char* locale, bool am, UChar* value, int32_t
/*
Function:
-GetLocaleIso639LanguageName
+GetLocaleIso639LanguageTwoLetterName
Gets the language name for a locale (via uloc_getLanguage) and converts the result to UChars
*/
-UErrorCode GetLocaleIso639LanguageName(const char* locale, UChar* value, int32_t valueLength)
+UErrorCode GetLocaleIso639LanguageTwoLetterName(const char* locale, UChar* value, int32_t valueLength)
{
UErrorCode status = U_ZERO_ERROR;
int32_t length = uloc_getLanguage(locale, nullptr, 0, &status);
@@ -135,6 +140,23 @@ UErrorCode GetLocaleIso639LanguageName(const char* locale, UChar* value, int32_t
/*
Function:
+GetLocaleIso639LanguageThreeLetterName
+
+Gets the language name for a locale (via uloc_getISO3Language) and converts the result to UChars
+*/
+UErrorCode GetLocaleIso639LanguageThreeLetterName(const char* locale, UChar* value, int32_t valueLength)
+{
+ const char *isoLanguage = uloc_getISO3Language(locale);
+ if (isoLanguage[0] == 0)
+ {
+ return U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ return u_charsToUChars_safe(isoLanguage, value, valueLength);
+}
+
+/*
+Function:
GetLocaleIso3166CountryName
Gets the country name for a locale (via uloc_getCountry) and converts the result to UChars
@@ -158,6 +180,66 @@ UErrorCode GetLocaleIso3166CountryName(const char* locale, UChar* value, int32_t
}
/*
+Function:
+GetLocaleIso3166CountryCode
+
+Gets the 3 letter country code for a locale (via uloc_getISO3Country) and converts the result to UChars
+*/
+UErrorCode GetLocaleIso3166CountryCode(const char* locale, UChar* value, int32_t valueLength)
+{
+ const char *pIsoCountryName = uloc_getISO3Country(locale);
+ int len = strlen(pIsoCountryName);
+
+ if (len == 0)
+ {
+ return U_ILLEGAL_ARGUMENT_ERROR;
+ }
+
+ return u_charsToUChars_safe(pIsoCountryName, value, valueLength);
+}
+
+/*
+Function:
+GetLocaleCurrencyName
+
+Gets the locale currency English or native name and convert the result to UChars
+*/
+UErrorCode GetLocaleCurrencyName(const char* locale, bool nativeName, UChar* value, int32_t valueLength)
+{
+ UErrorCode status = U_ZERO_ERROR;
+
+ UChar currencyThreeLettersName[4]; // 3 letters currency iso name + NULL
+ ucurr_forLocale(locale, currencyThreeLettersName, 4, &status);
+ if (!U_SUCCESS(status))
+ {
+ return status;
+ }
+
+ int32_t len;
+ UBool formatChoice;
+ const UChar *pCurrencyLongName = ucurr_getName(
+ currencyThreeLettersName,
+ nativeName ? locale : ULOC_US,
+ UCURR_LONG_NAME,
+ &formatChoice,
+ &len,
+ &status);
+ if (!U_SUCCESS(status))
+ {
+ return status;
+ }
+
+ if (len >= valueLength) // we need to have room for NULL too
+ {
+ return U_BUFFER_OVERFLOW_ERROR;
+ }
+ u_strncpy(value, pCurrencyLongName, len);
+ value[len] = 0;
+
+ return status;
+}
+
+/*
PAL Function:
GetLocaleInfoString
@@ -226,6 +308,12 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoString(
case Iso4217MonetarySymbol:
status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength);
break;
+ case CurrencyEnglishName:
+ status = GetLocaleCurrencyName(locale, false, value, valueLength);
+ break;
+ case CurrencyNativeName:
+ status = GetLocaleCurrencyName(locale, true, value, valueLength);
+ break;
case MonetaryDecimalSeparator:
status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength);
break;
@@ -245,12 +333,18 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoString(
case NegativeSign:
status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength);
break;
- case Iso639LanguageName:
- status = GetLocaleIso639LanguageName(locale, value, valueLength);
+ case Iso639LanguageTwoLetterName:
+ status = GetLocaleIso639LanguageTwoLetterName(locale, value, valueLength);
+ break;
+ case Iso639LanguageThreeLetterName:
+ status = GetLocaleIso639LanguageThreeLetterName(locale, value, valueLength);
break;
case Iso3166CountryName:
status = GetLocaleIso3166CountryName(locale, value, valueLength);
break;
+ case Iso3166CountryName2:
+ status = GetLocaleIso3166CountryCode(locale, value, valueLength);
+ break;
case NaNSymbol:
status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength);
break;
diff --git a/src/corefx/System.Globalization.Native/normalization.cpp b/src/corefx/System.Globalization.Native/normalization.cpp
index f96f5ee315..014894a5ed 100644
--- a/src/corefx/System.Globalization.Native/normalization.cpp
+++ b/src/corefx/System.Globalization.Native/normalization.cpp
@@ -4,7 +4,7 @@
//
#include <stdint.h>
-#include <unicode/unorm2.h>
+#include "icushim.h"
/*
* These values should be kept in sync with System.Text.NormalizationForm
diff --git a/src/corefx/System.Globalization.Native/timeZoneInfo.cpp b/src/corefx/System.Globalization.Native/timeZoneInfo.cpp
index d0e01e5ce6..0dd28b4b70 100644
--- a/src/corefx/System.Globalization.Native/timeZoneInfo.cpp
+++ b/src/corefx/System.Globalization.Native/timeZoneInfo.cpp
@@ -5,8 +5,8 @@
#include <stdint.h>
#include <unistd.h>
-#include <unicode/ucal.h>
+#include "icushim.h"
#include "locale.hpp"
#include "holders.h"
#include "errors.h"