* Change compile time dependency of ICU API ucol_setMaxVariable to be runtime instead. (#58485)
* Change compile time dependency of ICU API ucol_setMaxVariable to be runtime instead.
* Fix Android Build Break
* Deprecate ICU ucol_safeClone and support ucol_clone (#68847)
Co-authored-by: Tarek Mahmoud Sayed <tarekms@microsoft.com>
"unicode/ucol.h"
HAVE_SET_MAX_VARIABLE)
+ check_symbol_exists(
+ ucol_clone
+ "unicode/ucol.h"
+ HAVE_UCOL_CLONE)
+
unset(CMAKE_REQUIRED_LIBRARIES)
unset(CMAKE_REQUIRED_INCLUDES)
endif()
if (customRuleLength == 0)
{
+#if !defined(STATIC_ICU)
+ if (ucol_clone_ptr != NULL)
+ {
+ pClonedCollator = ucol_clone(pCollator, pErr);
+ }
+ else
+ {
+ pClonedCollator = ucol_safeClone_ptr(pCollator, NULL, NULL, pErr);
+ }
+#else // !defined(STATIC_ICU)
+
+#if HAVE_UCOL_CLONE
+ pClonedCollator = ucol_clone(pCollator, pErr);
+#else
pClonedCollator = ucol_safeClone(pCollator, NULL, NULL, pErr);
+#endif // HAVE_UCOL_CLONE
+
+#endif // !defined(STATIC_ICU)
}
else
{
{
ucol_setAttribute(pClonedCollator, UCOL_ALTERNATE_HANDLING, UCOL_SHIFTED, pErr);
+#if !defined(STATIC_ICU)
+ if (ucol_setMaxVariable_ptr != NULL)
+ {
+ // by default, ICU alternate shifted handling only ignores punctuation, but
+ // IgnoreSymbols needs symbols and currency as well, so change the "variable top"
+ // to include all symbols and currency
+ ucol_setMaxVariable(pClonedCollator, UCOL_REORDER_CODE_CURRENCY, pErr);
+ }
+ else
+ {
+ assert(ucol_setVariableTop_ptr != NULL);
+ // 0xfdfc is the last currency character before the first digit character
+ // in http://source.icu-project.org/repos/icu/icu/tags/release-52-1/source/data/unidata/FractionalUCA.txt
+ const UChar ignoreSymbolsVariableTop[] = { 0xfdfc };
+ ucol_setVariableTop_ptr(pClonedCollator, ignoreSymbolsVariableTop, 1, pErr);
+ }
+
+#else // !defined(STATIC_ICU)
+
// by default, ICU alternate shifted handling only ignores punctuation, but
// IgnoreSymbols needs symbols and currency as well, so change the "variable top"
// to include all symbols and currency
const UChar ignoreSymbolsVariableTop[] = { 0xfdfc };
ucol_setVariableTop(pClonedCollator, ignoreSymbolsVariableTop, 1, pErr);
#endif
+
+#endif //!defined(STATIC_ICU)
}
ucol_setAttribute(pClonedCollator, UCOL_STRENGTH, strength, pErr);
#define SYMBOL_NAME_SIZE (128 + SYMBOL_CUSTOM_SUFFIX_SIZE)
#define MaxICUVersionStringWithSuffixLength (MaxICUVersionStringLength + SYMBOL_CUSTOM_SUFFIX_SIZE)
-
#if defined(TARGET_WINDOWS) || defined(TARGET_OSX) || defined(TARGET_ANDROID)
#define MaxICUVersionStringLength 33
static void* libicuuc = NULL;
static void* libicui18n = NULL;
+ucol_setVariableTop_func ucol_setVariableTop_ptr = NULL;
+ucol_safeClone_func ucol_safeClone_ptr = NULL;
#if defined (TARGET_UNIX)
}
}
+static void InitializeUColClonePointers(char* symbolVersion)
+{
+ if (ucol_clone_ptr != NULL)
+ {
+ return;
+ }
+
+#if defined(TARGET_WINDOWS)
+ char symbolName[SYMBOL_NAME_SIZE];
+ sprintf_s(symbolName, SYMBOL_NAME_SIZE, "ucol_safeClone%s", symbolVersion);
+ ucol_safeClone_ptr = (ucol_safeClone_func)GetProcAddress((HMODULE)libicui18n, symbolName);
+#else
+ char symbolName[SYMBOL_NAME_SIZE];
+ sprintf(symbolName, "ucol_safeClone%s", symbolVersion);
+ ucol_safeClone_ptr = (ucol_safeClone_func)dlsym(libicui18n, symbolName);
+#endif // defined(TARGET_WINDOWS)
+
+ if (ucol_safeClone_ptr == NULL)
+ {
+ fprintf(stderr, "Cannot get the symbols of ICU APIs ucol_safeClone or ucol_clone.\n");
+ abort();
+ }
+}
+
+static void InitializeVariableMaxAndTopPointers(char* symbolVersion)
+{
+ if (ucol_setMaxVariable_ptr != NULL)
+ {
+ return;
+ }
+
+#if defined(TARGET_OSX) || defined(TARGET_ANDROID)
+ // OSX and Android always run against ICU version which has ucol_setMaxVariable.
+ // We shouldn't come here.
+ assert(false);
+#elif defined(TARGET_WINDOWS)
+ char symbolName[SYMBOL_NAME_SIZE];
+ sprintf_s(symbolName, SYMBOL_NAME_SIZE, "ucol_setVariableTop%s", symbolVersion);
+ ucol_setVariableTop_ptr = (ucol_setVariableTop_func)GetProcAddress((HMODULE)libicui18n, symbolName);
+#else
+ char symbolName[SYMBOL_NAME_SIZE];
+ sprintf(symbolName, "ucol_setVariableTop%s", symbolVersion);
+ ucol_setVariableTop_ptr = (ucol_setVariableTop_func)dlsym(libicui18n, symbolName);
+#endif // defined(TARGET_OSX) || defined(TARGET_ANDROID)
+
+ if (ucol_setVariableTop_ptr == NULL)
+ {
+ fprintf(stderr, "Cannot get the symbols of ICU APIs ucol_setMaxVariable or ucol_setVariableTop.\n");
+ abort();
+ }
+}
+
// GlobalizationNative_LoadICU
// This method get called from the managed side during the globalization initialization.
// This method shouldn't get called at all if we are running in globalization invariant mode
FOR_ALL_ICU_FUNCTIONS
ValidateICUDataCanLoad();
+
+ InitializeVariableMaxAndTopPointers(symbolVersion);
+ InitializeUColClonePointers(symbolVersion);
+
return true;
}
FOR_ALL_ICU_FUNCTIONS
ValidateICUDataCanLoad();
+
+ InitializeVariableMaxAndTopPointers(symbolVersion);
}
#undef PER_FUNCTION_BLOCK
// (U_ICU_VERSION_MAJOR_NUM < 52)
// The following APIs are not supported in the ICU versions less than 52. We need to define them manually.
// We have to do runtime check before using the pointers to these APIs. That is why these are listed in the FOR_ALL_OPTIONAL_ICU_FUNCTIONS list.
+U_CAPI void U_EXPORT2 ucol_setMaxVariable(UCollator* coll, UColReorderCode group, UErrorCode* pErrorCode);
U_CAPI int32_t U_EXPORT2 ucal_getTimeZoneIDForWindowsID(const UChar* winid, int32_t len, const char* region, UChar* id, int32_t idCapacity, UErrorCode* status);
U_CAPI int32_t U_EXPORT2 ucal_getWindowsTimeZoneID(const UChar* id, int32_t len, UChar* winid, int32_t winidCapacity, UErrorCode* status);
-#endif
+
+// (U_ICU_VERSION_MAJOR_NUM < 71)
+// The following API is not supported in the ICU versions less than 71. We need to define it manually.
+// We have to do runtime check before using the pointers to this API. That is why these are listed in the FOR_ALL_OPTIONAL_ICU_FUNCTIONS list.
+U_CAPI UCollator* U_EXPORT2 ucol_clone(const UCollator* coll, UErrorCode* status);
+
+// ucol_setVariableTop is a deprecated function on the newer ICU versions and ucol_setMaxVariable should be used instead.
+// As can run against ICU versions which not supported ucol_setMaxVariable, we'll dynamically try to get the pointer to ucol_setVariableTop
+// when we couldn't get a pointer to ucol_setMaxVariable.
+typedef uint32_t (U_EXPORT2 *ucol_setVariableTop_func)(UCollator* coll, const UChar* varTop, int32_t len, UErrorCode* status);
+
+// ucol_safeClone is deprecated in ICU version 71. We have to handle it manually to avoid getting a build break when referencing it in the code.
+typedef UCollator* (U_EXPORT2 *ucol_safeClone_func)(const UCollator* coll, void* stackBuffer, int32_t* pBufferSize, UErrorCode* status);
+
+#else // !defined(TARGET_ANDROID)
+
+typedef uint32_t (*ucol_setVariableTop_func)(UCollator* coll, const UChar* varTop, int32_t len, UErrorCode* status);
+typedef UCollator* (*ucol_safeClone_func)(const UCollator* coll, void* stackBuffer, int32_t* pBufferSize, UErrorCode* status);
+
+#endif // !defined(TARGET_ANDROID)
+
+extern ucol_setVariableTop_func ucol_setVariableTop_ptr;
+extern ucol_safeClone_func ucol_safeClone_ptr;
// 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(ucol_open, libicui18n, true) \
PER_FUNCTION_BLOCK(ucol_openElements, libicui18n, true) \
PER_FUNCTION_BLOCK(ucol_openRules, libicui18n, true) \
- PER_FUNCTION_BLOCK(ucol_safeClone, libicui18n, true) \
PER_FUNCTION_BLOCK(ucol_setAttribute, libicui18n, true) \
PER_FUNCTION_BLOCK(ucol_strcoll, libicui18n, true) \
PER_FUNCTION_BLOCK(udat_close, libicui18n, true) \
PER_FUNCTION_BLOCK(usearch_setPattern, libicui18n, true) \
PER_FUNCTION_BLOCK(usearch_setText, libicui18n, true)
-#if HAVE_SET_MAX_VARIABLE
-#define FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \
- PER_FUNCTION_BLOCK(ucol_setMaxVariable, libicui18n, true)
-#else
-
-#define FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \
- PER_FUNCTION_BLOCK(ucol_setVariableTop, libicui18n, true)
-#endif
-
#if defined(TARGET_WINDOWS)
#define FOR_ALL_OS_CONDITIONAL_ICU_FUNCTIONS \
PER_FUNCTION_BLOCK(ucurr_forLocale, libicuuc, true) \
// Otherwise, we'll just not provide the functionality to users which needed these APIs.
#define FOR_ALL_OPTIONAL_ICU_FUNCTIONS \
PER_FUNCTION_BLOCK(ucal_getWindowsTimeZoneID, libicui18n, false) \
- PER_FUNCTION_BLOCK(ucal_getTimeZoneIDForWindowsID, libicui18n, false)
+ PER_FUNCTION_BLOCK(ucal_getTimeZoneIDForWindowsID, libicui18n, false) \
+ PER_FUNCTION_BLOCK(ucol_setMaxVariable, libicui18n, false) \
+ PER_FUNCTION_BLOCK(ucol_clone, libicui18n, false)
#define FOR_ALL_ICU_FUNCTIONS \
FOR_ALL_UNCONDITIONAL_ICU_FUNCTIONS \
- FOR_ALL_SET_VARIABLE_ICU_FUNCTIONS \
FOR_ALL_OPTIONAL_ICU_FUNCTIONS \
FOR_ALL_OS_CONDITIONAL_ICU_FUNCTIONS
#define ucal_openTimeZoneIDEnumeration(...) ucal_openTimeZoneIDEnumeration_ptr(__VA_ARGS__)
#define ucal_set(...) ucal_set_ptr(__VA_ARGS__)
#define ucal_setMillis(...) ucal_setMillis_ptr(__VA_ARGS__)
+#define ucol_clone(...) ucol_clone_ptr(__VA_ARGS__)
#define ucol_close(...) ucol_close_ptr(__VA_ARGS__)
#define ucol_closeElements(...) ucol_closeElements_ptr(__VA_ARGS__)
#define ucol_getOffset(...) ucol_getOffset_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__)
UCollator * ucol_open(const char * loc, UErrorCode * status);
UCollationElements * ucol_openElements(const UCollator * coll, const UChar * text, int32_t textLength, UErrorCode * status);
UCollator * ucol_openRules(const UChar * rules, int32_t rulesLength, UColAttributeValue normalizationMode, UCollationStrength strength, UParseError * parseError, UErrorCode * status);
-UCollator * ucol_safeClone(const UCollator * coll, void * stackBuffer, int32_t * pBufferSize, UErrorCode * status);
+UCollator * ucol_clone(const UCollator * coll, UErrorCode * status);
void ucol_setAttribute(UCollator * coll, UColAttribute attr, UColAttributeValue value, UErrorCode * status);
UCollationResult ucol_strcoll(const UCollator * coll, const UChar * source, int32_t sourceLength, const UChar * target, int32_t targetLength);
int32_t ucurr_forLocale(const char * locale, UChar * buff, int32_t buffCapacity, UErrorCode * ec);