diff --git a/CMakeLists.txt b/CMakeLists.txt index 31b814f118d8..a9649e642dd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ set(CLR_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(VM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vm) set(GENERATED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/src/inc) set(GENERATED_EVENTING_DIR ${CMAKE_CURRENT_BINARY_DIR}/eventing) -set(VERSION_FILE_PATH "${CMAKE_BINARY_DIR}/version.cpp") +set(VERSION_FILE_PATH "${CMAKE_BINARY_DIR}/version.c") set(PAL_REDEFINES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/src/dlls/mscordac/palredefines.S) set(CORECLR_SET_RPATH ON) diff --git a/build-test.sh b/build-test.sh index a0ba5da53ca0..86472d1d7376 100755 --- a/build-test.sh +++ b/build-test.sh @@ -472,8 +472,8 @@ build_native_projects() if [ $__SkipConfigure == 0 ]; then # if msbuild is not supported, then set __SkipGenerateVersion to 1 if [ $__isMSBuildOnNETCoreSupported == 0 ]; then __SkipGenerateVersion=1; fi - # Drop version.cpp file - __versionSourceFile="$intermediatesForBuild/version.cpp" + # Drop version.c file + __versionSourceFile="$intermediatesForBuild/version.c" if [ $__SkipGenerateVersion == 0 ]; then pwd $__ProjectRoot/dotnet.sh msbuild /nologo /verbosity:minimal /clp:Summary \ @@ -484,7 +484,7 @@ build_native_projects() /l:BinClashLogger,Tools/Microsoft.DotNet.Build.Tasks.dll\;LogFile=binclash.log \ $__CommonMSBuildArgs $__UnprocessedBuildArgs else - # Generate the dummy version.cpp, but only if it didn't exist to make sure we don't trigger unnecessary rebuild + # Generate the dummy version.c, but only if it didn't exist to make sure we don't trigger unnecessary rebuild __versionSourceLine="static char sccsid[] __attribute__((used)) = \"@(#)No version information produced\";" if [ -e $__versionSourceFile ]; then read existingVersionSourceLine < $__versionSourceFile diff --git a/build.sh b/build.sh index 72d0456db2d3..536dbe8f5bb3 100755 --- a/build.sh +++ b/build.sh @@ -293,8 +293,8 @@ build_native() if [ $__SkipConfigure == 0 ]; then # if msbuild is not supported, then set __SkipGenerateVersion to 1 if [ $__isMSBuildOnNETCoreSupported == 0 ]; then __SkipGenerateVersion=1; fi - # Drop version.cpp file - __versionSourceFile="$intermediatesForBuild/version.cpp" + # Drop version.c file + __versionSourceFile="$intermediatesForBuild/version.c" if [ $__SkipGenerateVersion == 0 ]; then pwd "$__ProjectRoot/dotnet.sh" msbuild /nologo /verbosity:minimal /clp:Summary \ @@ -304,7 +304,7 @@ build_native() "$__ProjectDir/build.proj" /p:GenerateVersionSourceFile=true /t:GenerateVersionSourceFile /p:NativeVersionSourceFile=$__versionSourceFile \ $__CommonMSBuildArgs $__UnprocessedBuildArgs else - # Generate the dummy version.cpp, but only if it didn't exist to make sure we don't trigger unnecessary rebuild + # Generate the dummy version.c, but only if it didn't exist to make sure we don't trigger unnecessary rebuild __versionSourceLine="static char sccsid[] __attribute__((used)) = \"@(#)No version information produced\";" if [ -e $__versionSourceFile ]; then read existingVersionSourceLine < $__versionSourceFile diff --git a/src/corefx/System.Globalization.Native/CMakeLists.txt b/src/corefx/System.Globalization.Native/CMakeLists.txt index d3280db8ba90..026e5bb1e291 100644 --- a/src/corefx/System.Globalization.Native/CMakeLists.txt +++ b/src/corefx/System.Globalization.Native/CMakeLists.txt @@ -1,5 +1,4 @@ - -project(System.Globalization.Native) +project(System.Globalization.Native C) set(CMAKE_INCLUDE_CURRENT_DIR ON) @@ -8,6 +7,9 @@ add_definitions(-DBIT64=1) set(ICU_HOMEBREW_INC_PATH "/usr/local/opt/icu4c/include") +# We mark the function which needs exporting with DLLEXPORT +add_compile_options(-fvisibility=hidden) + find_path(UTYPES_H "unicode/utypes.h" PATHS ${ICU_HOMEBREW_INC_PATH}) if(UTYPES_H STREQUAL UTYPES_H-NOTFOUND) message(FATAL_ERROR "Cannot find utypes.h, try installing libicu-dev (or the appropriate package for your platform)") @@ -39,18 +41,19 @@ endif() include(configure.cmake) add_compile_options(-fPIC) +add_compile_options(-Wno-incompatible-pointer-types-discards-qualifiers) set(NATIVEGLOBALIZATION_SOURCES - calendarData.cpp - casing.cpp - collation.cpp - idna.cpp - locale.cpp - localeNumberData.cpp - localeStringData.cpp - normalization.cpp - timeZoneInfo.cpp - icushim.cpp + pal_calendarData.c + pal_casing.c + pal_collation.c + pal_idna.c + pal_locale.c + pal_localeNumberData.c + pal_localeStringData.c + pal_normalization.c + pal_timeZoneInfo.c + pal_icushim.c ) include_directories(${UTYPES_H}) @@ -97,4 +100,3 @@ verify_dependencies( # add the install targets install_clr(System.Globalization.Native) install(TARGETS System.Globalization.Native_Static DESTINATION .) - diff --git a/src/corefx/System.Globalization.Native/configure.cmake b/src/corefx/System.Globalization.Native/configure.cmake index 87992509a696..6fd506dbe25a 100644 --- a/src/corefx/System.Globalization.Native/configure.cmake +++ b/src/corefx/System.Globalization.Native/configure.cmake @@ -1,11 +1,11 @@ -include(CheckCXXSourceCompiles) -include(CheckCXXSymbolExists) +include(CheckCSourceCompiles) +include(CheckSymbolExists) set(CMAKE_REQUIRED_INCLUDES ${UTYPES_H} ${ICU_HOMEBREW_INC_PATH}) -CHECK_CXX_SOURCE_COMPILES(" +CHECK_C_SOURCE_COMPILES(" #include - int main() { UDateFormatSymbolType e = UDAT_STANDALONE_SHORTER_WEEKDAYS; } + int main(void) { enum UDateFormatSymbolType e = UDAT_STANDALONE_SHORTER_WEEKDAYS; } " HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS) if(NOT CLR_CMAKE_PLATFORM_DARWIN) @@ -14,7 +14,7 @@ else() set(CMAKE_REQUIRED_LIBRARIES ${ICUCORE}) endif() -check_cxx_symbol_exists( +check_symbol_exists( ucol_setMaxVariable "unicode/ucol.h" HAVE_SET_MAX_VARIABLE) diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h deleted file mode 100644 index 83e253d29768..000000000000 --- a/src/corefx/System.Globalization.Native/holders.h +++ /dev/null @@ -1,94 +0,0 @@ -// 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. - -// 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 -// called on the pointer. -template -class IcuHolder -{ - public: - IcuHolder(T* p, UErrorCode err) - { - m_p = U_SUCCESS(err) ? p : nullptr; - } - - ~IcuHolder() - { - if (m_p != nullptr) - { - Closer()(m_p); - } - } - - private: - T* m_p; - IcuHolder(const IcuHolder&) = delete; - IcuHolder operator=(const IcuHolder&) = delete; -}; - -struct UCalendarCloser -{ - void operator()(UCalendar* pCal) const - { - ucal_close(pCal); - } -}; - -struct UEnumerationCloser -{ - void operator()(UEnumeration* pEnum) const - { - uenum_close(pEnum); - } -}; - -struct UDateTimePatternGeneratorCloser -{ - void operator()(UDateTimePatternGenerator* pGenerator) const - { - udatpg_close(pGenerator); - } -}; - -struct UDateFormatCloser -{ - void operator()(UDateFormat* pDateFormat) const - { - udat_close(pDateFormat); - } -}; - -struct UNumberFormatCloser -{ - void operator()(UNumberFormat* pNumberFormat) const - { - unum_close(pNumberFormat); - } -}; - -struct ULocaleDisplayNamesCloser -{ - void operator()(ULocaleDisplayNames* pLocaleDisplayNames) const - { - uldn_close(pLocaleDisplayNames); - } -}; - -struct UResourceBundleCloser -{ - void operator()(UResourceBundle* pResourceBundle) const - { - ures_close(pResourceBundle); - } -}; - -typedef IcuHolder UCalendarHolder; -typedef IcuHolder UEnumerationHolder; -typedef IcuHolder UDateTimePatternGeneratorHolder; -typedef IcuHolder UDateFormatHolder; -typedef IcuHolder UNumberFormatHolder; -typedef IcuHolder ULocaleDisplayNamesHolder; -typedef IcuHolder UResourceBundleHolder; diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/pal_calendarData.c similarity index 61% rename from src/corefx/System.Globalization.Native/calendarData.cpp rename to src/corefx/System.Globalization.Native/pal_calendarData.c index 5a834e7cb113..be0cc9b6b8b7 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/pal_calendarData.c @@ -3,13 +3,11 @@ // See the LICENSE file in the project root for more information. #include +#include #include -#include +#include -#include "icushim.h" -#include "locale.hpp" -#include "holders.h" -#include "errors.h" +#include "pal_calendarData.h" #define GREGORIAN_NAME "gregorian" #define JAPANESE_NAME "japanese" @@ -27,72 +25,13 @@ const UChar UDAT_MONTH_DAY_UCHAR[] = {'M', 'M', 'M', 'M', 'd', '\0'}; const UChar UDAT_YEAR_NUM_MONTH_DAY_UCHAR[] = {'y', 'M', 'd', '\0'}; const UChar UDAT_YEAR_MONTH_UCHAR[] = {'y', 'M', 'M', 'M', 'M', '\0'}; -/* -* These values should be kept in sync with System.Globalization.CalendarId -*/ -enum CalendarId : int16_t -{ - UNINITIALIZED_VALUE = 0, - GREGORIAN = 1, // Gregorian (localized) calendar - GREGORIAN_US = 2, // Gregorian (U.S.) calendar - JAPAN = 3, // Japanese Emperor Era calendar - /* SSS_WARNINGS_OFF */ - TAIWAN = 4, // Taiwan Era calendar /* SSS_WARNINGS_ON */ - KOREA = 5, // Korean Tangun Era calendar - HIJRI = 6, // Hijri (Arabic Lunar) calendar - THAI = 7, // Thai calendar - HEBREW = 8, // Hebrew (Lunar) calendar - GREGORIAN_ME_FRENCH = 9, // Gregorian Middle East French calendar - GREGORIAN_ARABIC = 10, // Gregorian Arabic calendar - GREGORIAN_XLIT_ENGLISH = 11, // Gregorian Transliterated English calendar - GREGORIAN_XLIT_FRENCH = 12, - // Note that all calendars after this point are MANAGED ONLY for now. - JULIAN = 13, - JAPANESELUNISOLAR = 14, - CHINESELUNISOLAR = 15, - SAKA = 16, // reserved to match Office but not implemented in our code - LUNAR_ETO_CHN = 17, // reserved to match Office but not implemented in our code - LUNAR_ETO_KOR = 18, // reserved to match Office but not implemented in our code - LUNAR_ETO_ROKUYOU = 19, // reserved to match Office but not implemented in our code - KOREANLUNISOLAR = 20, - TAIWANLUNISOLAR = 21, - PERSIAN = 22, - UMALQURA = 23, - LAST_CALENDAR = 23 // Last calendar ID -}; - -/* -* These values should be kept in sync with System.Globalization.CalendarDataType -*/ -enum CalendarDataType : int32_t -{ - Uninitialized = 0, - NativeName = 1, - MonthDay = 2, - ShortDates = 3, - LongDates = 4, - YearMonths = 5, - DayNames = 6, - AbbrevDayNames = 7, - MonthNames = 8, - AbbrevMonthNames = 9, - SuperShortDayNames = 10, - MonthGenitiveNames = 11, - AbbrevMonthGenitiveNames = 12, - EraNames = 13, - AbbrevEraNames = 14, -}; - -// the function pointer definition for the callback used in EnumCalendarInfo -typedef void (*EnumCalendarInfoCallback)(const UChar*, const void*); - /* Function: GetCalendarName Gets the associated ICU calendar name for the CalendarId. */ -const char* GetCalendarName(CalendarId calendarId) +static const char* GetCalendarName(CalendarId calendarId) { switch (calendarId) { @@ -140,7 +79,7 @@ GetCalendarId Gets the associated CalendarId for the ICU calendar name. */ -CalendarId GetCalendarId(const char* calendarName) +static CalendarId GetCalendarId(const char* calendarName) { if (strcasecmp(calendarName, GREGORIAN_NAME) == 0) // TODO: what about the other gregorian types? @@ -171,26 +110,14 @@ GetCalendars Returns the list of CalendarIds that are available for the specified locale. */ -extern "C" int32_t GlobalizationNative_GetCalendars( +int32_t GlobalizationNative_GetCalendars( const UChar* localeName, CalendarId* calendars, int32_t calendarsCapacity) { UErrorCode err = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); - - if (U_FAILURE(err)) - return 0; - + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &err); UEnumeration* pEnum = ucal_getKeywordValuesForLocale("calendar", locale, TRUE, &err); - UEnumerationHolder enumHolder(pEnum, err); - - if (U_FAILURE(err)) - return 0; - int stringEnumeratorCount = uenum_count(pEnum, &err); - if (U_FAILURE(err)) - return 0; - int calendarsReturned = 0; for (int i = 0; i < stringEnumeratorCount && calendarsReturned < calendarsCapacity; i++) { @@ -206,7 +133,7 @@ extern "C" int32_t GlobalizationNative_GetCalendars( } } } - + uenum_close(pEnum); return calendarsReturned; } @@ -216,17 +143,14 @@ GetMonthDayPattern Gets the Month-Day DateTime pattern for the specified locale. */ -ResultCode GetMonthDayPattern(const char* locale, UChar* sMonthDay, int32_t stringCapacity) +static ResultCode GetMonthDayPattern(const char* locale, + UChar* sMonthDay, + int32_t stringCapacity) { UErrorCode err = U_ZERO_ERROR; UDateTimePatternGenerator* pGenerator = udatpg_open(locale, &err); - UDateTimePatternGeneratorHolder generatorHolder(pGenerator, err); - - if (U_FAILURE(err)) - return GetResultCode(err); - udatpg_getBestPattern(pGenerator, UDAT_MONTH_DAY_UCHAR, -1, sMonthDay, stringCapacity, &err); - + udatpg_close(pGenerator); return GetResultCode(err); } @@ -236,14 +160,17 @@ GetNativeCalendarName Gets the native calendar name. */ -ResultCode GetNativeCalendarName(const char* locale, CalendarId calendarId, UChar* nativeName, int32_t stringCapacity) +static ResultCode GetNativeCalendarName(const char* locale, + CalendarId calendarId, + UChar* nativeName, + int32_t stringCapacity) { UErrorCode err = U_ZERO_ERROR; ULocaleDisplayNames* pDisplayNames = uldn_open(locale, ULDN_STANDARD_NAMES, &err); - ULocaleDisplayNamesHolder displayNamesHolder(pDisplayNames, err); uldn_keyValueDisplayName(pDisplayNames, "calendar", GetCalendarName(calendarId), nativeName, stringCapacity, &err); + uldn_close(pDisplayNames); return GetResultCode(err); } @@ -254,24 +181,24 @@ GetCalendarInfo Gets a single string of calendar information by filling the result parameter with the requested value. */ -extern "C" ResultCode GlobalizationNative_GetCalendarInfo( +ResultCode GlobalizationNative_GetCalendarInfo( const UChar* localeName, CalendarId calendarId, CalendarDataType dataType, UChar* result, int32_t resultCapacity) { UErrorCode err = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &err); if (U_FAILURE(err)) return UnknownError; switch (dataType) { - case NativeName: + case CalendarData_NativeName: return GetNativeCalendarName(locale, calendarId, result, resultCapacity); - case MonthDay: + case CalendarData_MonthDay: return GetMonthDayPattern(locale, result, resultCapacity); default: - assert(false); + assert(FALSE); return UnknownError; } } @@ -283,31 +210,37 @@ InvokeCallbackForDatePattern Gets the ICU date pattern for the specified locale and EStyle and invokes the callback with the result. */ -bool InvokeCallbackForDatePattern(const char* locale, - UDateFormatStyle style, - EnumCalendarInfoCallback callback, - const void* context) +static int InvokeCallbackForDatePattern(const char* locale, + UDateFormatStyle style, + EnumCalendarInfoCallback callback, + const void* context) { UErrorCode err = U_ZERO_ERROR; - UDateFormat* pFormat = udat_open(UDAT_NONE, style, locale, nullptr, 0, nullptr, 0, &err); - UDateFormatHolder formatHolder(pFormat, err); + UDateFormat* pFormat = udat_open(UDAT_NONE, style, locale, NULL, 0, NULL, 0, &err); if (U_FAILURE(err)) - return false; + return FALSE; UErrorCode ignore = U_ZERO_ERROR; - int32_t patternLen = udat_toPattern(pFormat, false, nullptr, 0, &ignore); + int32_t patternLen = udat_toPattern(pFormat, FALSE, NULL, 0, &ignore) + 1; - std::vector pattern(patternLen + 1, '\0'); + UChar* pattern = calloc(patternLen, sizeof(UChar)); + if (pattern == NULL) + { + udat_close(pFormat); + return FALSE; + } - udat_toPattern(pFormat, false, pattern.data(), patternLen + 1, &err); + udat_toPattern(pFormat, FALSE, pattern, patternLen, &err); + udat_close(pFormat); if (U_SUCCESS(err)) { - callback(pattern.data(), context); + callback(pattern, context); } - return U_SUCCESS(err); + free(pattern); + return UErrorCodeToBool(err); } /* @@ -317,31 +250,37 @@ InvokeCallbackForDateTimePattern Gets the DateTime pattern for the specified skeleton and invokes the callback with the retrieved value. */ -bool InvokeCallbackForDateTimePattern(const char* locale, - const UChar* patternSkeleton, - EnumCalendarInfoCallback callback, - const void* context) +static int InvokeCallbackForDateTimePattern(const char* locale, + const UChar* patternSkeleton, + EnumCalendarInfoCallback callback, + const void* context) { UErrorCode err = U_ZERO_ERROR; UDateTimePatternGenerator* pGenerator = udatpg_open(locale, &err); - UDateTimePatternGeneratorHolder generatorHolder(pGenerator, err); if (U_FAILURE(err)) - return false; + return FALSE; UErrorCode ignore = U_ZERO_ERROR; - int32_t patternLen = udatpg_getBestPattern(pGenerator, patternSkeleton, -1, nullptr, 0, &ignore); + int32_t patternLen = udatpg_getBestPattern(pGenerator, patternSkeleton, -1, NULL, 0, &ignore) + 1; - std::vector bestPattern(patternLen + 1, '\0'); + UChar* bestPattern = calloc(patternLen, sizeof(UChar)); + if (bestPattern == NULL) + { + udatpg_close(pGenerator); + return FALSE; + } - udatpg_getBestPattern(pGenerator, patternSkeleton, -1, bestPattern.data(), patternLen + 1, &err); + udatpg_getBestPattern(pGenerator, patternSkeleton, -1, bestPattern, patternLen, &err); + udatpg_close(pGenerator); if (U_SUCCESS(err)) { - callback(bestPattern.data(), context); + callback(bestPattern, context); } - return U_SUCCESS(err); + free(bestPattern); + return UErrorCodeToBool(err); } /* @@ -351,58 +290,77 @@ EnumSymbols Enumerates all of the symbols of a type for a locale and calendar and invokes a callback for each value. */ -bool EnumSymbols(const char* locale, - CalendarId calendarId, - UDateFormatSymbolType type, - int32_t startIndex, - EnumCalendarInfoCallback callback, - const void* context) +static int32_t EnumSymbols(const char* locale, + CalendarId calendarId, + UDateFormatSymbolType type, + int32_t startIndex, + EnumCalendarInfoCallback callback, + const void* context) { UErrorCode err = U_ZERO_ERROR; - UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, nullptr, 0, nullptr, 0, &err); - UDateFormatHolder formatHolder(pFormat, err); + UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, NULL, 0, NULL, 0, &err); if (U_FAILURE(err)) - return false; + return FALSE; char localeWithCalendarName[ULOC_FULLNAME_CAPACITY]; strncpy(localeWithCalendarName, locale, ULOC_FULLNAME_CAPACITY); uloc_setKeywordValue("calendar", GetCalendarName(calendarId), localeWithCalendarName, ULOC_FULLNAME_CAPACITY, &err); - if (U_FAILURE(err)) - return false; - - UCalendar* pCalendar = ucal_open(nullptr, 0, localeWithCalendarName, UCAL_DEFAULT, &err); - UCalendarHolder calendarHolder(pCalendar, err); + UCalendar* pCalendar = ucal_open(NULL, 0, localeWithCalendarName, UCAL_DEFAULT, &err); if (U_FAILURE(err)) - return false; + { + udat_close(pFormat); + return FALSE; + } udat_setCalendar(pFormat, pCalendar); int32_t symbolCount = udat_countSymbols(pFormat, type); + UChar stackSymbolBuf[100]; + UChar* symbolBuf; - for (int32_t i = startIndex; i < symbolCount; i++) + for (int32_t i = startIndex; U_SUCCESS(err) && i < symbolCount; i++) { UErrorCode ignore = U_ZERO_ERROR; - int symbolLen = udat_getSymbols(pFormat, type, i, nullptr, 0, &ignore); - - std::vector symbolBuf(symbolLen + 1, '\0'); + int symbolLen = udat_getSymbols(pFormat, type, i, NULL, 0, &ignore) + 1; - udat_getSymbols(pFormat, type, i, symbolBuf.data(), symbolBuf.size(), &err); + if (symbolLen <= sizeof(stackSymbolBuf) / sizeof(stackSymbolBuf[0])) + { + symbolBuf = stackSymbolBuf; + } + else + { + symbolBuf = calloc(symbolLen, sizeof(UChar)); + if (symbolBuf == NULL) + { + err = U_MEMORY_ALLOCATION_ERROR; + break; + } + } - assert(U_SUCCESS(err)); + udat_getSymbols(pFormat, type, i, symbolBuf, symbolLen, &err); - if (U_FAILURE(err)) - return false; + if (U_SUCCESS(err)) + { + callback(symbolBuf, context); + } - callback(symbolBuf.data(), context); + if (symbolBuf != stackSymbolBuf) + { + free(symbolBuf); + } } - return true; + udat_close(pFormat); + ucal_close(pCalendar); + return UErrorCodeToBool(err); } -bool EnumUResourceBundle(const UResourceBundle* bundle, EnumCalendarInfoCallback callback, const void* context) +static void EnumUResourceBundle(const UResourceBundle* bundle, + EnumCalendarInfoCallback callback, + const void* context) { int32_t eraNameCount = ures_getSize(bundle); @@ -417,8 +375,19 @@ bool EnumUResourceBundle(const UResourceBundle* bundle, EnumCalendarInfoCallback callback(eraName, context); } } +} - return true; +static void CloseResBundle(const UResourceBundle* rootResBundle, + const UResourceBundle* calResBundle, + const UResourceBundle* targetCalResBundle, + const UResourceBundle* erasColResBundle, + const UResourceBundle* erasResBundle) +{ + ures_close(rootResBundle); + ures_close(calResBundle); + ures_close(targetCalResBundle); + ures_close(erasColResBundle); + ures_close(erasResBundle); } /* @@ -428,10 +397,10 @@ EnumAbbrevEraNames Enumerates all the abbreviated era names of the specified locale and calendar, invoking the callback function for each era name. */ -bool EnumAbbrevEraNames(const char* locale, - CalendarId calendarId, - EnumCalendarInfoCallback callback, - const void* context) +static int32_t EnumAbbrevEraNames(const char* locale, + CalendarId calendarId, + EnumCalendarInfoCallback callback, + const void* context) { // The C-API for ICU provides no way to get at the abbreviated era names for a calendar (so we can't use EnumSymbols // here). Instead we will try to walk the ICU resource tables directly and fall back to regular era names if can't @@ -444,35 +413,28 @@ bool EnumAbbrevEraNames(const char* locale, strncpy(localeNamePtr, locale, ULOC_FULLNAME_CAPACITY); - while (true) + while (TRUE) { UErrorCode status = U_ZERO_ERROR; + char* name = GetCalendarName(calendarId); - UResourceBundle* rootResBundle = ures_open(nullptr, localeNamePtr, &status); - UResourceBundleHolder rootResBundleHolder(rootResBundle, status); - - UResourceBundle* calResBundle = ures_getByKey(rootResBundle, "calendar", nullptr, &status); - UResourceBundleHolder calResBundleHolder(calResBundle, status); - - UResourceBundle* targetCalResBundle = - ures_getByKey(calResBundle, GetCalendarName(calendarId), nullptr, &status); - UResourceBundleHolder targetCalResBundleHolder(targetCalResBundle, status); - - UResourceBundle* erasColResBundle = ures_getByKey(targetCalResBundle, "eras", nullptr, &status); - UResourceBundleHolder erasColResBundleHolder(erasColResBundle, status); - - UResourceBundle* erasResBundle = ures_getByKey(erasColResBundle, "narrow", nullptr, &status); - UResourceBundleHolder erasResBundleHolder(erasResBundle, status); + UResourceBundle* rootResBundle = ures_open(NULL, localeNamePtr, &status); + UResourceBundle* calResBundle = ures_getByKey(rootResBundle, "calendar", NULL, &status); + UResourceBundle* targetCalResBundle = ures_getByKey(calResBundle, name, NULL, &status); + UResourceBundle* erasColResBundle = ures_getByKey(targetCalResBundle, "eras", NULL, &status); + UResourceBundle* erasResBundle = ures_getByKey(erasColResBundle, "narrow", NULL, &status); if (U_SUCCESS(status)) { EnumUResourceBundle(erasResBundle, callback, context); - return true; + CloseResBundle(rootResBundle, calResBundle, targetCalResBundle, erasColResBundle, erasResBundle); + return TRUE; } // Couldn't find the data we need for this locale, we should fallback. if (localeNameBuf[0] == 0x0) { + CloseResBundle(rootResBundle, calResBundle, targetCalResBundle, erasColResBundle, erasResBundle); // We are already at the root locale so there is nothing to fall back to, just use the regular eras. break; } @@ -481,6 +443,7 @@ bool EnumAbbrevEraNames(const char* locale, if (U_FAILURE(status)) { + CloseResBundle(rootResBundle, calResBundle, targetCalResBundle, erasColResBundle, erasResBundle); // Something bad happened getting the parent name, bail out. break; } @@ -492,6 +455,8 @@ bool EnumAbbrevEraNames(const char* locale, char* temp = localeNamePtr; localeNamePtr = parentNamePtr; parentNamePtr = temp; + + CloseResBundle(rootResBundle, calResBundle, targetCalResBundle, erasColResBundle, erasResBundle); } // Walking the resource bundles didn't work, just use the regular eras. @@ -508,43 +473,42 @@ Allows for a collection of calendar string data to be retrieved by invoking the callback for each value in the collection. The context parameter is passed through to the callback along with each string. */ -extern "C" int32_t GlobalizationNative_EnumCalendarInfo( - EnumCalendarInfoCallback callback, - const UChar* localeName, - CalendarId calendarId, - CalendarDataType dataType, - const void* context) +int32_t GlobalizationNative_EnumCalendarInfo(EnumCalendarInfoCallback callback, + const UChar* localeName, + CalendarId calendarId, + CalendarDataType dataType, + const void* context) { UErrorCode err = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &err); if (U_FAILURE(err)) - return false; + return FALSE; switch (dataType) { - case ShortDates: + case CalendarData_ShortDates: // ShortDates to map kShort and kMedium in ICU, but also adding the "yMd" // skeleton as well, as this closely matches what is used on Windows return InvokeCallbackForDatePattern(locale, UDAT_SHORT, callback, context) && InvokeCallbackForDatePattern(locale, UDAT_MEDIUM, callback, context) && InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_NUM_MONTH_DAY_UCHAR, callback, context); - case LongDates: + case CalendarData_LongDates: // LongDates map to kFull and kLong in ICU. return InvokeCallbackForDatePattern(locale, UDAT_FULL, callback, context) && InvokeCallbackForDatePattern(locale, UDAT_LONG, callback, context); - case YearMonths: + case CalendarData_YearMonths: return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH_UCHAR, callback, context); - case DayNames: + case CalendarData_DayNames: return EnumSymbols(locale, calendarId, UDAT_STANDALONE_WEEKDAYS, 1, callback, context); - case AbbrevDayNames: + case CalendarData_AbbrevDayNames: return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_WEEKDAYS, 1, callback, context); - case MonthNames: + case CalendarData_MonthNames: return EnumSymbols(locale, calendarId, UDAT_STANDALONE_MONTHS, 0, callback, context); - case AbbrevMonthNames: + case CalendarData_AbbrevMonthNames: return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_MONTHS, 0, callback, context); - case SuperShortDayNames: + case CalendarData_SuperShortDayNames: // UDAT_STANDALONE_SHORTER_WEEKDAYS was added in ICU 51, and CentOS 7 currently uses ICU 50. // fallback to UDAT_STANDALONE_NARROW_WEEKDAYS in that case. #if HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS @@ -552,17 +516,17 @@ extern "C" int32_t GlobalizationNative_EnumCalendarInfo( #else return EnumSymbols(locale, calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context); #endif - case MonthGenitiveNames: + case CalendarData_MonthGenitiveNames: return EnumSymbols(locale, calendarId, UDAT_MONTHS, 0, callback, context); - case AbbrevMonthGenitiveNames: + case CalendarData_AbbrevMonthGenitiveNames: return EnumSymbols(locale, calendarId, UDAT_SHORT_MONTHS, 0, callback, context); - case EraNames: + case CalendarData_EraNames: return EnumSymbols(locale, calendarId, UDAT_ERAS, 0, callback, context); - case AbbrevEraNames: + case CalendarData_AbbrevEraNames: return EnumAbbrevEraNames(locale, calendarId, callback, context); default: - assert(false); - return false; + assert(FALSE); + return FALSE; } } @@ -572,11 +536,10 @@ GetLatestJapaneseEra Gets the latest era in the Japanese calendar. */ -extern "C" int32_t GlobalizationNative_GetLatestJapaneseEra() +int32_t GlobalizationNative_GetLatestJapaneseEra() { UErrorCode err = U_ZERO_ERROR; - UCalendar* pCal = ucal_open(nullptr, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); - UCalendarHolder calHolder(pCal, err); + UCalendar* pCal = ucal_open(NULL, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); if (U_FAILURE(err)) return 0; @@ -584,6 +547,7 @@ extern "C" int32_t GlobalizationNative_GetLatestJapaneseEra() ucal_set(pCal, UCAL_EXTENDED_YEAR, 9999); int32_t ret = ucal_get(pCal, UCAL_ERA, &err); + ucal_close(pCal); return U_SUCCESS(err) ? ret : 0; } @@ -593,19 +557,20 @@ GetJapaneseEraInfo Gets the starting Gregorian date of the specified Japanese Era. */ -extern "C" int32_t GlobalizationNative_GetJapaneseEraStartDate( - int32_t era, int32_t* startYear, int32_t* startMonth, int32_t* startDay) +int32_t GlobalizationNative_GetJapaneseEraStartDate(int32_t era, + int32_t* startYear, + int32_t* startMonth, + int32_t* startDay) { *startYear = -1; *startMonth = -1; *startDay = -1; UErrorCode err = U_ZERO_ERROR; - UCalendar* pCal = ucal_open(nullptr, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); - UCalendarHolder calHolder(pCal, err); + UCalendar* pCal = ucal_open(NULL, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); if (U_FAILURE(err)) - return false; + return FALSE; ucal_set(pCal, UCAL_ERA, era); ucal_set(pCal, UCAL_YEAR, 1); @@ -613,58 +578,44 @@ extern "C" int32_t GlobalizationNative_GetJapaneseEraStartDate( // UCAL_EXTENDED_YEAR is the gregorian year for the JapaneseCalendar *startYear = ucal_get(pCal, UCAL_EXTENDED_YEAR, &err); if (U_FAILURE(err)) - return false; + { + ucal_close(pCal); + return FALSE; + } // set the date to Jan 1 ucal_set(pCal, UCAL_MONTH, 0); ucal_set(pCal, UCAL_DATE, 1); int32_t currentEra; - for (int i = 0; i <= 12; i++) + for (int i = 0; U_SUCCESS(err) && i <= 12; i++) { currentEra = ucal_get(pCal, UCAL_ERA, &err); - if (U_FAILURE(err)) - return false; - if (currentEra == era) { - for (int i = 0; i < 31; i++) + for (int i = 0; U_SUCCESS(err) && i < 31; i++) { // subtract 1 day at a time until we get out of the specified Era ucal_add(pCal, UCAL_DATE, -1, &err); - if (U_FAILURE(err)) - return false; - currentEra = ucal_get(pCal, UCAL_ERA, &err); - if (U_FAILURE(err)) - return false; - - if (currentEra != era) + if (U_SUCCESS(err) && currentEra != era) { // add back 1 day to get back into the specified Era ucal_add(pCal, UCAL_DATE, 1, &err); - if (U_FAILURE(err)) - return false; - *startMonth = ucal_get(pCal, UCAL_MONTH, &err) + 1; // ICU Calendar months are 0-based, but .NET is 1-based - if (U_FAILURE(err)) - return false; - *startDay = ucal_get(pCal, UCAL_DATE, &err); - if (U_FAILURE(err)) - return false; + ucal_close(pCal); - return true; + return UErrorCodeToBool(err); } } } // add 1 month at a time until we get into the specified Era ucal_add(pCal, UCAL_MONTH, 1, &err); - if (U_FAILURE(err)) - return false; } - return false; + ucal_close(pCal); + return FALSE; } diff --git a/src/corefx/System.Globalization.Native/pal_calendarData.h b/src/corefx/System.Globalization.Native/pal_calendarData.h new file mode 100644 index 000000000000..e0d5ac5f4672 --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_calendarData.h @@ -0,0 +1,92 @@ +// 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 + +#include "pal_compiler.h" +#include "pal_locale.h" +#include "pal_errors.h" + +/* +* These values should be kept in sync with System.Globalization.CalendarId +*/ +enum +{ + UNINITIALIZED_VALUE = 0, + GREGORIAN = 1, // Gregorian (localized) calendar + GREGORIAN_US = 2, // Gregorian (U.S.) calendar + JAPAN = 3, // Japanese Emperor Era calendar + /* SSS_WARNINGS_OFF */ + TAIWAN = 4, // Taiwan Era calendar /* SSS_WARNINGS_ON */ + KOREA = 5, // Korean Tangun Era calendar + HIJRI = 6, // Hijri (Arabic Lunar) calendar + THAI = 7, // Thai calendar + HEBREW = 8, // Hebrew (Lunar) calendar + GREGORIAN_ME_FRENCH = 9, // Gregorian Middle East French calendar + GREGORIAN_ARABIC = 10, // Gregorian Arabic calendar + GREGORIAN_XLIT_ENGLISH = 11, // Gregorian Transliterated English calendar + GREGORIAN_XLIT_FRENCH = 12, + // Note that all calendars after this point are MANAGED ONLY for now. + JULIAN = 13, + JAPANESELUNISOLAR = 14, + CHINESELUNISOLAR = 15, + SAKA = 16, // reserved to match Office but not implemented in our code + LUNAR_ETO_CHN = 17, // reserved to match Office but not implemented in our code + LUNAR_ETO_KOR = 18, // reserved to match Office but not implemented in our code + LUNAR_ETO_ROKUYOU = 19, // reserved to match Office but not implemented in our code + KOREANLUNISOLAR = 20, + TAIWANLUNISOLAR = 21, + PERSIAN = 22, + UMALQURA = 23, + LAST_CALENDAR = 23 // Last calendar ID +}; +typedef uint16_t CalendarId; + +/* +* These values should be kept in sync with System.Globalization.CalendarDataType +*/ +typedef enum +{ + CalendarData_Uninitialized = 0, + CalendarData_NativeName = 1, + CalendarData_MonthDay = 2, + CalendarData_ShortDates = 3, + CalendarData_LongDates = 4, + CalendarData_YearMonths = 5, + CalendarData_DayNames = 6, + CalendarData_AbbrevDayNames = 7, + CalendarData_MonthNames = 8, + CalendarData_AbbrevMonthNames = 9, + CalendarData_SuperShortDayNames = 10, + CalendarData_MonthGenitiveNames = 11, + CalendarData_AbbrevMonthGenitiveNames = 12, + CalendarData_EraNames = 13, + CalendarData_AbbrevEraNames = 14, +} CalendarDataType; + +// the function pointer definition for the callback used in EnumCalendarInfo +typedef void (*EnumCalendarInfoCallback)(const UChar*, const void*); + +DLLEXPORT int32_t GlobalizationNative_GetCalendars(const UChar* localeName, + CalendarId* calendars, + int32_t calendarsCapacity); + +DLLEXPORT ResultCode GlobalizationNative_GetCalendarInfo(const UChar* localeName, + CalendarId calendarId, + CalendarDataType dataType, + UChar* result, + int32_t resultCapacity); + +DLLEXPORT int32_t GlobalizationNative_EnumCalendarInfo(EnumCalendarInfoCallback callback, + const UChar* localeName, + CalendarId calendarId, + CalendarDataType dataType, + const void* context); + +DLLEXPORT int32_t GlobalizationNative_GetLatestJapaneseEra(void); + +DLLEXPORT int32_t GlobalizationNative_GetJapaneseEraStartDate(int32_t era, + int32_t* startYear, + int32_t* startMonth, + int32_t* startDay); diff --git a/src/corefx/System.Globalization.Native/casing.cpp b/src/corefx/System.Globalization.Native/pal_casing.c similarity index 94% rename from src/corefx/System.Globalization.Native/casing.cpp rename to src/corefx/System.Globalization.Native/pal_casing.c index 918b8fe6ed2b..e6b27d3eb8a1 100644 --- a/src/corefx/System.Globalization.Native/casing.cpp +++ b/src/corefx/System.Globalization.Native/pal_casing.c @@ -5,7 +5,9 @@ #include #include -#include "icushim.h" + +#include "pal_casing.h" +#include "pal_icushim.h" /* Function: @@ -14,16 +16,16 @@ ChangeCase Performs upper or lower casing of a string into a new buffer. No special casing is performed beyond that provided by ICU. */ -extern "C" void GlobalizationNative_ChangeCase( +void GlobalizationNative_ChangeCase( const UChar* lpSrc, int32_t cwSrcLength, UChar* lpDst, int32_t cwDstLength, int32_t bToUpper) { // Iterate through the string, decoding the next one or two UTF-16 code units - // into a codepoint and updating srcIdx to point to the next UTF-16 code unit - // to decode. Then upper or lower case it, write dstCodepoint into lpDst at + // into a codepoint and updating srcIdx to point to the next UTF-16 code unit + // to decode. Then upper or lower case it, write dstCodepoint into lpDst at // offset dstIdx, and update dstIdx. // (The loop here has been manually cloned for each of the four cases, rather - // than having a single loop that internally branched based on bToUpper as the + // than having a single loop that internally branched based on bToUpper as the // compiler wasn't doing that optimization, and it results in an ~15-20% perf // improvement on longer strings.) @@ -58,10 +60,10 @@ extern "C" void GlobalizationNative_ChangeCase( ChangeCaseInvariant Performs upper or lower casing of a string into a new buffer. -Special casing is performed to ensure that invariant casing +Special casing is performed to ensure that invariant casing matches that of Windows in certain situations, e.g. Turkish i's. */ -extern "C" void GlobalizationNative_ChangeCaseInvariant( +void GlobalizationNative_ChangeCaseInvariant( const UChar* lpSrc, int32_t cwSrcLength, UChar* lpDst, int32_t cwDstLength, int32_t bToUpper) { // See algorithmic comment in ChangeCase. @@ -105,7 +107,7 @@ ChangeCaseTurkish Performs upper or lower casing of a string into a new buffer, performing special casing for Turkish. */ -extern "C" void GlobalizationNative_ChangeCaseTurkish( +void GlobalizationNative_ChangeCaseTurkish( const UChar* lpSrc, int32_t cwSrcLength, UChar* lpDst, int32_t cwDstLength, int32_t bToUpper) { // See algorithmic comment in ChangeCase. diff --git a/src/corefx/System.Globalization.Native/pal_casing.h b/src/corefx/System.Globalization.Native/pal_casing.h new file mode 100644 index 000000000000..3ea29dd73b4e --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_casing.h @@ -0,0 +1,24 @@ +// 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 "pal_compiler.h" +#include "pal_locale.h" + +DLLEXPORT void GlobalizationNative_ChangeCase(const UChar* lpSrc, + int32_t cwSrcLength, + UChar* lpDst, + int32_t cwDstLength, + int32_t bToUpper); + +DLLEXPORT void GlobalizationNative_ChangeCaseInvariant(const UChar* lpSrc, + int32_t cwSrcLength, + UChar* lpDst, + int32_t cwDstLength, + int32_t bToUpper); + +DLLEXPORT void GlobalizationNative_ChangeCaseTurkish(const UChar* lpSrc, + int32_t cwSrcLength, + UChar* lpDst, + int32_t cwDstLength, + int32_t bToUpper); diff --git a/src/corefx/System.Globalization.Native/collation.cpp b/src/corefx/System.Globalization.Native/pal_collation.c similarity index 64% rename from src/corefx/System.Globalization.Native/collation.cpp rename to src/corefx/System.Globalization.Native/pal_collation.c index 3aefae2a6aa3..a0ce96d1fd4b 100644 --- a/src/corefx/System.Globalization.Native/collation.cpp +++ b/src/corefx/System.Globalization.Native/pal_collation.c @@ -5,13 +5,17 @@ #include #include +#include #include -#include -#include +#include +#include -#include "icushim.h" -#include "locale.hpp" -#include "errors.h" +#include "pal_collation.h" + +c_static_assert_msg(UCOL_EQUAL == 0, "managed side requires 0 for equal strings"); +c_static_assert_msg(UCOL_LESS < 0, "managed side requires less than zero for a < b"); +c_static_assert_msg(UCOL_GREATER > 0, "managed side requires greater than zero for a > b"); +c_static_assert_msg(USEARCH_DONE == -1, "managed side requires -1 for not found"); const int32_t CompareOptionsIgnoreCase = 0x1; const int32_t CompareOptionsIgnoreNonSpace = 0x2; @@ -24,34 +28,35 @@ const int32_t CompareOptionsIgnoreWidth = 0x10; // Windows and Unix platforms. The nonalphanumeric symbols will come after alphanumeric // characters on Windows, but before on Unix. // Since locale - specific string sort order can change from one version of Windows to the next, -// there is no reason to guarantee string sort order between Windows and ICU. Thus trying to +// there is no reason to guarantee string sort order between Windows and ICU. Thus trying to // change ICU's default behavior here isn't really justified unless someone has a strong reason // for !StringSort to behave differently. -typedef std::map TCollatorMap; -typedef std::pair TCollatorMapPair; +typedef struct { int32_t key; UCollator* UCollator; } TCollatorMap; /* * For increased performance, we cache the UCollator objects for a locale and * share them across threads. This is safe (and supported in ICU) if we ensure * multiple threads are only ever dealing with const UCollators. */ -typedef struct _sort_handle +struct SortHandle { UCollator* regular; - TCollatorMap collatorsPerOption; + TCollatorMap* collatorsPerOption; pthread_mutex_t collatorsLockObject; + void* pRoot; +}; - _sort_handle() : regular(nullptr) - { - int result = pthread_mutex_init(&collatorsLockObject, NULL); - if (result != 0) - { - assert(false && "Unexpected pthread_mutex_init return value."); - } - } +typedef struct { UChar* items; size_t capacity; size_t size; } UCharList; -} SortHandle; +static int TreeComparer(const void* left, const void* right) +{ + const TCollatorMap* leftMap = left; + const TCollatorMap* rightMap = right; + if (leftMap->key < rightMap->key) return -1; + if (leftMap->key > rightMap->key) return 1; + return 0; +} // Hiragana character range const UChar hiraganaStart = 0x3041; @@ -109,7 +114,7 @@ Thus, to use these characters in a rule, they need to be escaped. This rule was taken from http://www.unicode.org/reports/tr35/tr35-collation.html#Rules. */ -bool NeedsEscape(UChar character) +static int NeedsEscape(UChar character) { return ((0x21 <= character && character <= 0x2f) || (0x3a <= character && character <= 0x40) @@ -127,85 +132,121 @@ This is done so we can use range checks instead of comparing individual characte These ranges were obtained by running the above characters through .NET CompareInfo.Compare with CompareOptions.IgnoreSymbols on Windows. */ -bool IsHalfFullHigherSymbol(UChar character) +static int IsHalfFullHigherSymbol(UChar character) { return (0xffe0 <= character && character <= 0xffe6) || (0xff61 <= character && character <= 0xff65); } +static int AddItem(UCharList* list, const UChar item) +{ + size_t size = list->size++; + if (size >= list->capacity) + { + list->capacity *= 2; + UChar* ptr = (UChar*)realloc(list->items, list->capacity * sizeof(UChar*)); + if (ptr == NULL) + { + return FALSE; + } + list->items = ptr; + } + + list->items[size] = item; + return TRUE; +} + /* Gets a string of custom collation rules, if necessary. Since the CompareOptions flags don't map 1:1 with ICU default functionality, we need to fall back to using custom rules in order to support IgnoreKanaType and IgnoreWidth CompareOptions correctly. */ -std::vector GetCustomRules(int32_t options, UColAttributeValue strength, bool isIgnoreSymbols) +static UCharList* GetCustomRules(int32_t options, UColAttributeValue strength, int isIgnoreSymbols) { - bool isIgnoreKanaType = (options & CompareOptionsIgnoreKanaType) == CompareOptionsIgnoreKanaType; - bool isIgnoreWidth = (options & CompareOptionsIgnoreWidth) == CompareOptionsIgnoreWidth; + int isIgnoreKanaType = (options & CompareOptionsIgnoreKanaType) == CompareOptionsIgnoreKanaType; + int isIgnoreWidth = (options & CompareOptionsIgnoreWidth) == CompareOptionsIgnoreWidth; // kana differs at the tertiary level - bool needsIgnoreKanaTypeCustomRule = isIgnoreKanaType && strength >= UCOL_TERTIARY; - bool needsNotIgnoreKanaTypeCustomRule = !isIgnoreKanaType && strength < UCOL_TERTIARY; + int needsIgnoreKanaTypeCustomRule = isIgnoreKanaType && strength >= UCOL_TERTIARY; + int needsNotIgnoreKanaTypeCustomRule = !isIgnoreKanaType && strength < UCOL_TERTIARY; // character width differs at the tertiary level - bool needsIgnoreWidthCustomRule = isIgnoreWidth && strength >= UCOL_TERTIARY; - bool needsNotIgnoreWidthCustomRule = !isIgnoreWidth && strength < UCOL_TERTIARY; + int needsIgnoreWidthCustomRule = isIgnoreWidth && strength >= UCOL_TERTIARY; + int needsNotIgnoreWidthCustomRule = !isIgnoreWidth && strength < UCOL_TERTIARY; + + if (!(needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule || needsIgnoreWidthCustomRule || needsNotIgnoreWidthCustomRule)) + return NULL; - std::vector customRules; - if (needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule || needsIgnoreWidthCustomRule || needsNotIgnoreWidthCustomRule) + UCharList* customRules = (UCharList*)malloc(sizeof(UCharList)); + if (customRules == NULL) { - // If we need to create customRules, the KanaType custom rule will be 88 kana characters * 4 = 352 chars long - // and the Width custom rule will be at least 215 halfwidth characters * 4 = 860 chars long. - // Use 512 as the starting size, so the customRules won't have to grow if we are just - // doing the KanaType custom rule. - customRules.reserve(512); + return NULL; + } - if (needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule) - { - UChar compareChar = needsIgnoreKanaTypeCustomRule ? '=' : '<'; + // If we need to create customRules, the KanaType custom rule will be 88 kana characters * 4 = 352 chars long + // and the Width custom rule will be at least 215 halfwidth characters * 4 = 860 chars long. + // Use 512 as the starting size, so the customRules won't have to grow if we are just + // doing the KanaType custom rule. + customRules->capacity = 512; + customRules->items = calloc(customRules->capacity, sizeof(UChar)); + if (customRules->items == NULL) + { + free(customRules); + return NULL; + } + + customRules->size = 0; + + if (needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule) + { + UChar compareChar = needsIgnoreKanaTypeCustomRule ? '=' : '<'; - for (UChar hiraganaChar = hiraganaStart; hiraganaChar <= hiraganaEnd; hiraganaChar++) + for (UChar hiraganaChar = hiraganaStart; hiraganaChar <= hiraganaEnd; hiraganaChar++) + { + // Hiragana is the range 3041 to 3096 & 309D & 309E + if (hiraganaChar <= 0x3096 || hiraganaChar >= 0x309D) // characters between 3096 and 309D are not mapped to katakana { - // Hiragana is the range 3041 to 3096 & 309D & 309E - if (hiraganaChar <= 0x3096 || hiraganaChar >= 0x309D) // characters between 3096 and 309D are not mapped to katakana + if(!(AddItem(customRules, '&') && + AddItem(customRules, hiraganaChar) && + AddItem(customRules, compareChar) && + AddItem(customRules, hiraganaChar + hiraganaToKatakanaOffset))) { - customRules.push_back('&'); - customRules.push_back(hiraganaChar); - customRules.push_back(compareChar); - customRules.push_back(hiraganaChar + hiraganaToKatakanaOffset); + free(customRules->items); + free(customRules); + return NULL; } } } + } - if (needsIgnoreWidthCustomRule || needsNotIgnoreWidthCustomRule) - { - UChar compareChar = needsIgnoreWidthCustomRule ? '=' : '<'; + if (needsIgnoreWidthCustomRule || needsNotIgnoreWidthCustomRule) + { + UChar compareChar = needsIgnoreWidthCustomRule ? '=' : '<'; - UChar lowerChar; - UChar higherChar; - bool needsEscape; - for (int i = 0; i < g_HalfFullCharsLength; i++) + UChar lowerChar; + UChar higherChar; + int needsEscape; + for (int i = 0; i < g_HalfFullCharsLength; i++) + { + lowerChar = g_HalfFullLowerChars[i]; + higherChar = g_HalfFullHigherChars[i]; + // the lower chars need to be checked for escaping since they contain ASCII punctuation + needsEscape = NeedsEscape(lowerChar); + + // when isIgnoreSymbols is true and we are not ignoring width, check to see if + // this character is a symbol, and if so skip it + if (!(isIgnoreSymbols && needsNotIgnoreWidthCustomRule && (needsEscape || IsHalfFullHigherSymbol(higherChar)))) { - lowerChar = g_HalfFullLowerChars[i]; - higherChar = g_HalfFullHigherChars[i]; - // the lower chars need to be checked for escaping since they contain ASCII punctuation - needsEscape = NeedsEscape(lowerChar); - - // when isIgnoreSymbols is true and we are not ignoring width, check to see if - // this character is a symbol, and if so skip it - if (!(isIgnoreSymbols && needsNotIgnoreWidthCustomRule && (needsEscape || IsHalfFullHigherSymbol(higherChar)))) + if(!(AddItem(customRules, '&') && + (!needsEscape || AddItem(customRules, '\\')) && + AddItem(customRules, lowerChar) && + AddItem(customRules, compareChar) && + AddItem(customRules, higherChar))) { - customRules.push_back('&'); - - if (needsEscape) - { - customRules.push_back('\\'); - } - customRules.push_back(lowerChar); - - customRules.push_back(compareChar); - customRules.push_back(higherChar); + free(customRules->items); + free(customRules); + return NULL; } } } @@ -224,9 +265,9 @@ UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t options, { UColAttributeValue strength = ucol_getStrength(pCollator); - bool isIgnoreCase = (options & CompareOptionsIgnoreCase) == CompareOptionsIgnoreCase; - bool isIgnoreNonSpace = (options & CompareOptionsIgnoreNonSpace) == CompareOptionsIgnoreNonSpace; - bool isIgnoreSymbols = (options & CompareOptionsIgnoreSymbols) == CompareOptionsIgnoreSymbols; + int isIgnoreCase = (options & CompareOptionsIgnoreCase) == CompareOptionsIgnoreCase; + int isIgnoreNonSpace = (options & CompareOptionsIgnoreNonSpace) == CompareOptionsIgnoreNonSpace; + int isIgnoreSymbols = (options & CompareOptionsIgnoreSymbols) == CompareOptionsIgnoreSymbols; if (isIgnoreCase) { @@ -239,29 +280,33 @@ UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t options, } UCollator* pClonedCollator; - std::vector customRules = GetCustomRules(options, strength, isIgnoreSymbols); - if (customRules.empty()) + UCharList* customRules = GetCustomRules(options, strength, isIgnoreSymbols); + if (customRules == NULL) { - pClonedCollator = ucol_safeClone(pCollator, nullptr, nullptr, pErr); + pClonedCollator = ucol_safeClone(pCollator, NULL, NULL, pErr); } else { - int32_t customRuleLength = customRules.size(); + int32_t customRuleLength = customRules->size; int32_t localeRulesLength; const UChar* localeRules = ucol_getRules(pCollator, &localeRulesLength); + int32_t completeRulesLength = localeRulesLength + customRuleLength + 1; + + UChar* completeRules = calloc(completeRulesLength, sizeof(UChar)); - std::vector completeRules(localeRulesLength + customRuleLength + 1, '\0'); for (int i = 0; i < localeRulesLength; i++) { completeRules[i] = localeRules[i]; } for (int i = 0; i < customRuleLength; i++) { - completeRules[localeRulesLength + i] = customRules[i]; + completeRules[localeRulesLength + i] = customRules->items[i]; } - pClonedCollator = ucol_openRules(completeRules.data(), completeRules.size(), UCOL_DEFAULT, strength, NULL, pErr); + pClonedCollator = ucol_openRules(completeRules, completeRulesLength, UCOL_DEFAULT, strength, NULL, pErr); + free(completeRules); + free(customRules); } if (isIgnoreSymbols) @@ -294,45 +339,54 @@ 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) +static int CanIgnoreAllCollationElements(const UCollator* pColl, const UChar* lpStr, int32_t length) { - bool result = false; + int result = TRUE; UErrorCode err = U_ZERO_ERROR; UCollationElements* pCollElem = ucol_openElements(pColl, lpStr, length, &err); if (U_SUCCESS(err)) { int32_t curCollElem = UCOL_NULLORDER; - - result = true; - while ((curCollElem = ucol_next(pCollElem, &err)) != UCOL_NULLORDER) { if (curCollElem != 0) { - result = false; + result = FALSE; break; } } - if (U_FAILURE(err)) - { - result = false; - } - ucol_closeElements(pCollElem); } - return result; + return U_SUCCESS(err) ? result : FALSE; } -extern "C" ResultCode GlobalizationNative_GetSortHandle(const char* lpLocaleName, SortHandle** ppSortHandle) +void CreateSortHandle(SortHandle** ppSortHandle) { - assert(ppSortHandle != nullptr); - - *ppSortHandle = new (std::nothrow) SortHandle(); - if ((*ppSortHandle) == nullptr) + *ppSortHandle = (SortHandle*)malloc(sizeof(SortHandle)); + if ((*ppSortHandle) == NULL) + { + return; + } + + (*ppSortHandle)->pRoot = NULL; + int result = pthread_mutex_init(&(*ppSortHandle)->collatorsLockObject, NULL); + + if (result != 0) + { + assert(FALSE && "Unexpected pthread_mutex_init return value."); + } +} + +ResultCode GlobalizationNative_GetSortHandle(const char* lpLocaleName, SortHandle** ppSortHandle) +{ + assert(ppSortHandle != NULL); + + CreateSortHandle(ppSortHandle); + if ((*ppSortHandle) == NULL) { return GetResultCode(U_MEMORY_ALLOCATION_ERROR); } @@ -343,30 +397,30 @@ extern "C" ResultCode GlobalizationNative_GetSortHandle(const char* lpLocaleName if (U_FAILURE(err)) { - if ((*ppSortHandle)->regular != nullptr) - ucol_close((*ppSortHandle)->regular); - - delete (*ppSortHandle); - (*ppSortHandle) = nullptr; + pthread_mutex_destroy(&(*ppSortHandle)->collatorsLockObject); + free(*ppSortHandle); + (*ppSortHandle) = NULL; } return GetResultCode(err); } -extern "C" void GlobalizationNative_CloseSortHandle(SortHandle* pSortHandle) +void GlobalizationNative_CloseSortHandle(SortHandle* pSortHandle) { ucol_close(pSortHandle->regular); - pSortHandle->regular = nullptr; + pSortHandle->regular = NULL; - TCollatorMap::iterator it; - for (it = pSortHandle->collatorsPerOption.begin(); it != pSortHandle->collatorsPerOption.end(); it++) + while (pSortHandle->pRoot != NULL) { - ucol_close(it->second); + TCollatorMap* data = *(TCollatorMap **)pSortHandle->pRoot; + tdelete(data, &pSortHandle->pRoot, TreeComparer); + ucol_close(data->UCollator); + free(data); } pthread_mutex_destroy(&pSortHandle->collatorsLockObject); - delete pSortHandle; + free(pSortHandle); } const UCollator* GetCollatorFromSortHandle(SortHandle* pSortHandle, int32_t options, UErrorCode* pErr) @@ -381,18 +435,22 @@ const UCollator* GetCollatorFromSortHandle(SortHandle* pSortHandle, int32_t opti int lockResult = pthread_mutex_lock(&pSortHandle->collatorsLockObject); if (lockResult != 0) { - assert(false && "Unexpected pthread_mutex_lock return value."); + assert(FALSE && "Unexpected pthread_mutex_lock return value."); } - TCollatorMap::iterator entry = pSortHandle->collatorsPerOption.find(options); - if (entry == pSortHandle->collatorsPerOption.end()) + TCollatorMap* map = (TCollatorMap*)malloc(sizeof(TCollatorMap)); + map->key = options; + void* entry = tfind(map, &pSortHandle->pRoot, TreeComparer); + if (entry == NULL) { pCollator = CloneCollatorWithOptions(pSortHandle->regular, options, pErr); - pSortHandle->collatorsPerOption[options] = pCollator; + map->UCollator = pCollator; + tsearch(map, &pSortHandle->pRoot, TreeComparer); } else { - pCollator = entry->second; + free(map); + pCollator = (*(TCollatorMap**)entry)->UCollator; } pthread_mutex_unlock(&pSortHandle->collatorsLockObject); @@ -401,7 +459,7 @@ const UCollator* GetCollatorFromSortHandle(SortHandle* pSortHandle, int32_t opti return pCollator; } -extern "C" int32_t GlobalizationNative_GetSortVersion(SortHandle* pSortHandle) +int32_t GlobalizationNative_GetSortVersion(SortHandle* pSortHandle) { UErrorCode err = U_ZERO_ERROR; const UCollator* pColl = GetCollatorFromSortHandle(pSortHandle, 0, &err); @@ -413,7 +471,7 @@ extern "C" int32_t GlobalizationNative_GetSortVersion(SortHandle* pSortHandle) } else { - assert(false && "Unexpected ucol_getVersion to fail."); + assert(FALSE && "Unexpected ucol_getVersion to fail."); // we didn't use UCOL_TAILORINGS_VERSION because it is deprecated in ICU v5 result = UCOL_RUNTIME_VERSION << 16 | UCOL_BUILDER_VERSION; @@ -425,13 +483,9 @@ extern "C" int32_t GlobalizationNative_GetSortVersion(SortHandle* pSortHandle) Function: CompareString */ -extern "C" int32_t GlobalizationNative_CompareString( +int32_t GlobalizationNative_CompareString( SortHandle* pSortHandle, const UChar* lpStr1, int32_t cwStr1Length, const UChar* lpStr2, int32_t cwStr2Length, int32_t options) { - static_assert(UCOL_EQUAL == 0, "managed side requires 0 for equal strings"); - static_assert(UCOL_LESS < 0, "managed side requires less than zero for a < b"); - static_assert(UCOL_GREATER > 0, "managed side requires greater than zero for a > b"); - UCollationResult result = UCOL_EQUAL; UErrorCode err = U_ZERO_ERROR; const UCollator* pColl = GetCollatorFromSortHandle(pSortHandle, options, &err); @@ -448,24 +502,22 @@ extern "C" int32_t GlobalizationNative_CompareString( Function: IndexOf */ -extern "C" int32_t GlobalizationNative_IndexOf( - SortHandle* pSortHandle, - const UChar* lpTarget, - int32_t cwTargetLength, - const UChar* lpSource, - int32_t cwSourceLength, +int32_t GlobalizationNative_IndexOf( + SortHandle* pSortHandle, + const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, int32_t options, int32_t* pMatchedLength) { - static_assert(USEARCH_DONE == -1, "managed side requires -1 for not found"); - int32_t result = USEARCH_DONE; UErrorCode err = U_ZERO_ERROR; const UCollator* pColl = GetCollatorFromSortHandle(pSortHandle, options, &err); if (U_SUCCESS(err)) { - UStringSearch* pSearch = usearch_openFromCollator(lpTarget, cwTargetLength, lpSource, cwSourceLength, pColl, nullptr, &err); + UStringSearch* pSearch = usearch_openFromCollator(lpTarget, cwTargetLength, lpSource, cwSourceLength, pColl, NULL, &err); if (U_SUCCESS(err)) { @@ -474,8 +526,8 @@ extern "C" int32_t GlobalizationNative_IndexOf( // if the search was successful, // we'll try to get the matched string length. if(result != USEARCH_DONE && pMatchedLength != NULL) - { - *pMatchedLength = usearch_getMatchedLength(pSearch); + { + *pMatchedLength = usearch_getMatchedLength(pSearch); } usearch_close(pSearch); } @@ -488,23 +540,21 @@ extern "C" int32_t GlobalizationNative_IndexOf( Function: LastIndexOf */ -extern "C" int32_t GlobalizationNative_LastIndexOf( - SortHandle* pSortHandle, - const UChar* lpTarget, - int32_t cwTargetLength, - const UChar* lpSource, - int32_t cwSourceLength, +int32_t GlobalizationNative_LastIndexOf( + SortHandle* pSortHandle, + const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, int32_t options) { - static_assert(USEARCH_DONE == -1, "managed side requires -1 for not found"); - int32_t result = USEARCH_DONE; UErrorCode err = U_ZERO_ERROR; const UCollator* pColl = GetCollatorFromSortHandle(pSortHandle, options, &err); if (U_SUCCESS(err)) { - UStringSearch* pSearch = usearch_openFromCollator(lpTarget, cwTargetLength, lpSource, cwSourceLength, pColl, nullptr, &err); + UStringSearch* pSearch = usearch_openFromCollator(lpTarget, cwTargetLength, lpSource, cwSourceLength, pColl, NULL, &err); if (U_SUCCESS(err)) { @@ -520,13 +570,13 @@ extern "C" int32_t GlobalizationNative_LastIndexOf( Static Function: AreEqualOrdinalIgnoreCase */ -static bool AreEqualOrdinalIgnoreCase(UChar32 one, UChar32 two) +static int AreEqualOrdinalIgnoreCase(UChar32 one, UChar32 two) { // Return whether the two characters are identical or would be identical if they were upper-cased. if (one == two) { - return true; + return TRUE; } if (one == 0x0131 || two == 0x0131) @@ -534,7 +584,7 @@ static bool AreEqualOrdinalIgnoreCase(UChar32 one, UChar32 two) // On Windows with InvariantCulture, the LATIN SMALL LETTER DOTLESS I (U+0131) // capitalizes to itself, whereas with ICU it capitalizes to LATIN CAPITAL LETTER I (U+0049). // We special case it to match the Windows invariant behavior. - return false; + return FALSE; } return u_toupper(one) == u_toupper(two); @@ -544,7 +594,7 @@ static bool AreEqualOrdinalIgnoreCase(UChar32 one, UChar32 two) Function: IndexOfOrdinalIgnoreCase */ -extern "C" int32_t GlobalizationNative_IndexOfOrdinalIgnoreCase( +int32_t GlobalizationNative_IndexOfOrdinalIgnoreCase( const UChar* lpTarget, int32_t cwTargetLength, const UChar* lpSource, int32_t cwSourceLength, int32_t findLast) { int32_t result = -1; @@ -559,14 +609,14 @@ extern "C" int32_t GlobalizationNative_IndexOfOrdinalIgnoreCase( const UChar *src = lpSource, *trg = lpTarget; UChar32 srcCodepoint, trgCodepoint; - bool match = true; + int32_t match = TRUE; while (trgIdx < cwTargetLength) { U16_NEXT(src, srcIdx, cwSourceLength, srcCodepoint); U16_NEXT(trg, trgIdx, cwTargetLength, trgCodepoint); if (!AreEqualOrdinalIgnoreCase(srcCodepoint, trgCodepoint)) { - match = false; + match = FALSE; break; } } @@ -589,12 +639,12 @@ extern "C" int32_t GlobalizationNative_IndexOfOrdinalIgnoreCase( /* Return value is a "Win32 BOOL" (1 = true, 0 = false) */ -extern "C" int32_t GlobalizationNative_StartsWith( - SortHandle* pSortHandle, - const UChar* lpTarget, - int32_t cwTargetLength, - const UChar* lpSource, - int32_t cwSourceLength, +int32_t GlobalizationNative_StartsWith( + SortHandle* pSortHandle, + const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, int32_t options) { int32_t result = FALSE; @@ -603,7 +653,7 @@ extern "C" int32_t GlobalizationNative_StartsWith( if (U_SUCCESS(err)) { - UStringSearch* pSearch = usearch_openFromCollator(lpTarget, cwTargetLength, lpSource, cwSourceLength, pColl, nullptr, &err); + UStringSearch* pSearch = usearch_openFromCollator(lpTarget, cwTargetLength, lpSource, cwSourceLength, pColl, NULL, &err); int32_t idx = USEARCH_DONE; if (U_SUCCESS(err)) @@ -631,12 +681,12 @@ extern "C" int32_t GlobalizationNative_StartsWith( /* Return value is a "Win32 BOOL" (1 = true, 0 = false) */ -extern "C" int32_t GlobalizationNative_EndsWith( - SortHandle* pSortHandle, - const UChar* lpTarget, - int32_t cwTargetLength, - const UChar* lpSource, - int32_t cwSourceLength, +int32_t GlobalizationNative_EndsWith( + SortHandle* pSortHandle, + const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, int32_t options) { int32_t result = FALSE; @@ -645,7 +695,7 @@ extern "C" int32_t GlobalizationNative_EndsWith( if (U_SUCCESS(err)) { - UStringSearch* pSearch = usearch_openFromCollator(lpTarget, cwTargetLength, lpSource, cwSourceLength, pColl, nullptr, &err); + UStringSearch* pSearch = usearch_openFromCollator(lpTarget, cwTargetLength, lpSource, cwSourceLength, pColl, NULL, &err); int32_t idx = USEARCH_DONE; if (U_SUCCESS(err)) @@ -674,12 +724,12 @@ extern "C" int32_t GlobalizationNative_EndsWith( return result; } -extern "C" int32_t GlobalizationNative_GetSortKey( - SortHandle* pSortHandle, - const UChar* lpStr, - int32_t cwStrLength, - uint8_t* sortKey, - int32_t cbSortKeyLength, +int32_t GlobalizationNative_GetSortKey( + SortHandle* pSortHandle, + const UChar* lpStr, + int32_t cwStrLength, + uint8_t* sortKey, + int32_t cbSortKeyLength, int32_t options) { UErrorCode err = U_ZERO_ERROR; @@ -694,12 +744,12 @@ extern "C" int32_t GlobalizationNative_GetSortKey( return result; } -extern "C" int32_t GlobalizationNative_CompareStringOrdinalIgnoreCase( +int32_t GlobalizationNative_CompareStringOrdinalIgnoreCase( const UChar* lpStr1, int32_t cwStr1Length, const UChar* lpStr2, int32_t cwStr2Length) { - assert(lpStr1 != nullptr); + assert(lpStr1 != NULL); assert(cwStr1Length >= 0); - assert(lpStr2 != nullptr); + assert(lpStr2 != NULL); assert(cwStr2Length >= 0); int32_t str1Idx = 0; diff --git a/src/corefx/System.Globalization.Native/pal_collation.h b/src/corefx/System.Globalization.Native/pal_collation.h new file mode 100644 index 000000000000..482a59a7eca2 --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_collation.h @@ -0,0 +1,69 @@ +// 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 "pal_compiler.h" +#include "pal_locale.h" +#include "pal_errors.h" + +typedef struct SortHandle SortHandle; + +DLLEXPORT ResultCode GlobalizationNative_GetSortHandle(const char* lpLocaleName, SortHandle** ppSortHandle); + +DLLEXPORT void GlobalizationNative_CloseSortHandle(SortHandle* pSortHandle); + +DLLEXPORT int32_t GlobalizationNative_GetSortVersion(SortHandle* pSortHandle); + +DLLEXPORT int32_t GlobalizationNative_CompareString(SortHandle* pSortHandle, + const UChar* lpStr1, + int32_t cwStr1Length, + const UChar* lpStr2, + int32_t cwStr2Length, + int32_t options); + +DLLEXPORT int32_t GlobalizationNative_IndexOf(SortHandle* pSortHandle, + const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, + int32_t options, + int32_t* pMatchedLength); + +DLLEXPORT int32_t GlobalizationNative_LastIndexOf(SortHandle* pSortHandle, + const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, + int32_t options); + +DLLEXPORT int32_t GlobalizationNative_IndexOfOrdinalIgnoreCase(const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, + int32_t findLast); + +DLLEXPORT int32_t GlobalizationNative_StartsWith(SortHandle* pSortHandle, + const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, + int32_t options); + +DLLEXPORT int32_t GlobalizationNative_EndsWith(SortHandle* pSortHandle, + const UChar* lpTarget, + int32_t cwTargetLength, + const UChar* lpSource, + int32_t cwSourceLength, + int32_t options); + +DLLEXPORT int32_t GlobalizationNative_GetSortKey(SortHandle* pSortHandle, + const UChar* lpStr, + int32_t cwStrLength, + uint8_t* sortKey, + int32_t cbSortKeyLength, + int32_t options); + +DLLEXPORT int32_t GlobalizationNative_CompareStringOrdinalIgnoreCase(const UChar* lpStr1, + int32_t cwStr1Length, + const UChar* lpStr2, + int32_t cwStr2Length); diff --git a/src/corefx/System.Globalization.Native/pal_compiler.h b/src/corefx/System.Globalization.Native/pal_compiler.h new file mode 100644 index 000000000000..01ba72ad9771 --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_compiler.h @@ -0,0 +1,19 @@ +// 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. + +#pragma once + +#ifndef __has_extension +#define __has_extension(...) 0 +#endif + +#ifdef static_assert +#define c_static_assert_msg(e, msg) static_assert((e), msg) +#elif __has_extension(c_static_assert) +#define c_static_assert_msg(e, msg) _Static_assert((e), msg) +#else +#define c_static_assert_msg(e, msg) typedef char __c_static_assert__[(e)?1:-1] +#endif + +#define DLLEXPORT __attribute__ ((__visibility__ ("default"))) diff --git a/src/corefx/System.Globalization.Native/errors.h b/src/corefx/System.Globalization.Native/pal_errors.h similarity index 93% rename from src/corefx/System.Globalization.Native/errors.h rename to src/corefx/System.Globalization.Native/pal_errors.h index b23a0dacd518..55d9ca026b94 100644 --- a/src/corefx/System.Globalization.Native/errors.h +++ b/src/corefx/System.Globalization.Native/pal_errors.h @@ -4,17 +4,19 @@ #pragma once +#include "pal_compiler.h" + /* * These values should be kept in sync with * Interop.GlobalizationInterop.ResultCode */ -enum ResultCode : int32_t +typedef enum { Success = 0, UnknownError = 1, InsufficentBuffer = 2, OutOfMemory = 3 -}; +} ResultCode; /* Converts a UErrorCode to a ResultCode. @@ -25,7 +27,7 @@ static ResultCode GetResultCode(UErrorCode err) { return InsufficentBuffer; } - + if (err == U_MEMORY_ALLOCATION_ERROR) { return OutOfMemory; diff --git a/src/corefx/System.Globalization.Native/icushim.cpp b/src/corefx/System.Globalization.Native/pal_icushim.c similarity index 72% rename from src/corefx/System.Globalization.Native/icushim.cpp rename to src/corefx/System.Globalization.Native/pal_icushim.c index e250238fe9c3..ce42af642fcd 100644 --- a/src/corefx/System.Globalization.Native/icushim.cpp +++ b/src/corefx/System.Globalization.Native/pal_icushim.c @@ -9,42 +9,42 @@ #include #include -#include "icushim.h" +#include "pal_icushim.h" // Define pointers to all the used ICU functions -#define PER_FUNCTION_BLOCK(fn, lib) decltype(fn)* fn##_ptr; +#define PER_FUNCTION_BLOCK(fn, lib) __typeof(fn)* fn##_ptr; FOR_ALL_ICU_FUNCTIONS #undef PER_FUNCTION_BLOCK -static void* libicuuc = nullptr; -static void* libicui18n = nullptr; +static void* libicuuc = NULL; +static void* libicui18n = NULL; #define VERSION_PREFIX_NONE "" #define VERSION_PREFIX_SUSE "suse" // .[suse]x.x.x, considering the max number of decimal digits for each component -static const int MaxICUVersionStringLength = sizeof(VERSION_PREFIX_SUSE) + 33; +#define MaxICUVersionStringLength (sizeof(VERSION_PREFIX_SUSE) + 33) #ifdef __APPLE__ -bool FindICULibs(const char* versionPrefix, char* symbolName, char* symbolVersion) +static int FindICULibs(const char* versionPrefix, char* symbolName, char* symbolVersion) { #ifndef OSX_ICU_LIBRARY_PATH - static_assert(false, "The ICU Library path is not defined"); + c_static_assert_msg(false, "The ICU Library path is not defined"); #endif // OSX_ICU_LIBRARY_PATH // Usually OSX_ICU_LIBRARY_PATH is "/usr/lib/libicucore.dylib" libicuuc = dlopen(OSX_ICU_LIBRARY_PATH, RTLD_LAZY); - - if (libicuuc == nullptr) + + if (libicuuc == NULL) { - return false; + return FALSE; } - // in OSX all ICU APIs exist in the same library libicucore.A.dylib + // in OSX all ICU APIs exist in the same library libicucore.A.dylib libicui18n = libicuuc; - return true; + return TRUE; } #else // __APPLE__ @@ -66,7 +66,7 @@ static const int MaxSubICUVersion = 5; // 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, const char* versionPrefix, char* result) +static void GetVersionedLibFileName(const char* baseFileName, int majorVer, int minorVer, int subVer, const char* versionPrefix, char* result) { assert(majorVer != -1); @@ -78,77 +78,77 @@ void GetVersionedLibFileName(const char* baseFileName, int majorVer, int minorVe if (subVer != -1) { sprintf(result + nameLen, ".%d", subVer); - } + } } } -bool FindSymbolVersion(int majorVer, int minorVer, int subVer, char* symbolName, char* symbolVersion) +static int FindSymbolVersion(int majorVer, int minorVer, int subVer, char* symbolName, char* symbolVersion) { // Find out the format of the version string added to each symbol // First try just the unversioned symbol - if (dlsym(libicuuc, "u_strlen") == nullptr) + if (dlsym(libicuuc, "u_strlen") == NULL) { // Now try just the _majorVer added sprintf(symbolVersion, "_%d", majorVer); sprintf(symbolName, "u_strlen%s", symbolVersion); - if ((dlsym(libicuuc, symbolName) == nullptr) && (minorVer != -1)) + if ((dlsym(libicuuc, symbolName) == NULL) && (minorVer != -1)) { // Now try the _majorVer_minorVer added sprintf(symbolVersion, "_%d_%d", majorVer, minorVer); sprintf(symbolName, "u_strlen%s", symbolVersion); - if ((dlsym(libicuuc, symbolName) == nullptr) && (subVer != -1)) + if ((dlsym(libicuuc, symbolName) == NULL) && (subVer != -1)) { // 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) + if (dlsym(libicuuc, symbolName) == NULL) { - return false; + return FALSE; } } } } - return true; + return TRUE; } // Try to open the necessary ICU libraries -bool OpenICULibraries(int majorVer, int minorVer, int subVer, const char* versionPrefix, char* symbolName, char* symbolVersion) +static int OpenICULibraries(int majorVer, int minorVer, int subVer, const char* versionPrefix, char* symbolName, char* symbolVersion) { char libicuucName[64]; char libicui18nName[64]; - static_assert(sizeof("libicuuc.so") + MaxICUVersionStringLength <= sizeof(libicuucName), "The libicuucName is too small"); + c_static_assert_msg(sizeof("libicuuc.so") + MaxICUVersionStringLength <= sizeof(libicuucName), "The libicuucName is too small"); GetVersionedLibFileName("libicuuc.so", majorVer, minorVer, subVer, versionPrefix, libicuucName); - static_assert(sizeof("libicui18n.so") + MaxICUVersionStringLength <= sizeof(libicui18nName), "The libicui18nName is too small"); + c_static_assert_msg(sizeof("libicui18n.so") + MaxICUVersionStringLength <= sizeof(libicui18nName), "The libicui18nName is too small"); GetVersionedLibFileName("libicui18n.so", majorVer, minorVer, subVer, versionPrefix, libicui18nName); libicuuc = dlopen(libicuucName, RTLD_LAZY); - if (libicuuc != nullptr) + if (libicuuc != NULL) { if (FindSymbolVersion(majorVer, minorVer, subVer, symbolName, symbolVersion)) { libicui18n = dlopen(libicui18nName, RTLD_LAZY); } - if (libicui18n == nullptr) + if (libicui18n == NULL) { dlclose(libicuuc); - libicuuc = nullptr; + libicuuc = NULL; } } - return libicuuc != nullptr; + return libicuuc != NULL; } // 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(const char* versionPrefix, char* symbolName, char* symbolVersion) +static int FindLibUsingOverride(const char* versionPrefix, char* symbolName, char* symbolVersion) { char* versionOverride = getenv("CLR_ICU_VERSION_OVERRIDE"); - if (versionOverride != nullptr) + if (versionOverride != NULL) { int first = -1; int second = -1; @@ -159,16 +159,16 @@ bool FindLibUsingOverride(const char* versionPrefix, char* symbolName, char* sym { if (OpenICULibraries(first, second, third, versionPrefix, symbolName, symbolVersion)) { - return true; + return TRUE; } } } - return false; + return FALSE; } // Search for library files with names including the major version. -bool FindLibWithMajorVersion(const char* versionPrefix, char* symbolName, char* symbolVersion) +static int FindLibWithMajorVersion(const char* versionPrefix, char* symbolName, char* symbolVersion) { // ICU packaging documentation (http://userguide.icu-project.org/packaging) // describes applications link against the major (e.g. libicuuc.so.54). @@ -176,7 +176,7 @@ bool FindLibWithMajorVersion(const char* versionPrefix, char* symbolName, char* // Select the version of ICU present at build time. if (OpenICULibraries(MinICUVersion, -1, -1, versionPrefix, symbolName, symbolVersion)) { - return true; + return TRUE; } // Select the highest supported version of ICU present on the local machine @@ -184,16 +184,16 @@ bool FindLibWithMajorVersion(const char* versionPrefix, char* symbolName, char* { if (OpenICULibraries(i, -1, -1, versionPrefix, symbolName, symbolVersion)) { - return true; + return TRUE; } } - return false; + 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(const char* versionPrefix, char* symbolName, char* symbolVersion) +static int FindLibWithMajorMinorVersion(const char* versionPrefix, char* symbolName, char* symbolVersion) { for (int i = MaxICUVersion; i >= MinICUVersion; i--) { @@ -201,17 +201,17 @@ bool FindLibWithMajorMinorVersion(const char* versionPrefix, char* symbolName, c { if (OpenICULibraries(i, j, -1, versionPrefix, symbolName, symbolVersion)) { - return true; + return TRUE; } } } - return false; + 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(const char* versionPrefix, char* symbolName, char* symbolVersion) +static int FindLibWithMajorMinorSubVersion(const char* versionPrefix, char* symbolName, char* symbolVersion) { for (int i = MaxICUVersion; i >= MinICUVersion; i--) { @@ -221,17 +221,17 @@ bool FindLibWithMajorMinorSubVersion(const char* versionPrefix, char* symbolName { if (OpenICULibraries(i, j, k, versionPrefix, symbolName, symbolVersion)) { - return true; + return TRUE; } } } } - return false; + return FALSE; } -bool FindICULibs(const char* versionPrefix, char* symbolName, char* symbolVersion) +static int FindICULibs(const char* versionPrefix, char* symbolName, char* symbolVersion) { return FindLibUsingOverride(versionPrefix, symbolName, symbolVersion) || FindLibWithMajorVersion(versionPrefix, symbolName, symbolVersion) || @@ -242,10 +242,10 @@ bool FindICULibs(const char* versionPrefix, char* symbolName, char* symbolVersio #endif // __APPLE__ // GlobalizationNative_LoadICU -// This method get called from the managed side during the globalization initialization. +// 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 // return 0 if failed to load ICU and 1 otherwise -extern "C" int32_t GlobalizationNative_LoadICU() +int32_t GlobalizationNative_LoadICU() { char symbolName[128]; char symbolVersion[MaxICUVersionStringLength + 1] = ""; @@ -256,49 +256,49 @@ extern "C" int32_t GlobalizationNative_LoadICU() if (!FindICULibs(VERSION_PREFIX_SUSE, symbolName, symbolVersion)) #endif { - return 0; + return FALSE; } } // 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); \ + c_static_assert_msg((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); \ + fn##_ptr = (__typeof(fn)*)dlsym(lib, symbolName); \ if (fn##_ptr == NULL) { fprintf(stderr, "Cannot get symbol %s from " #lib "\nError: %s\n", symbolName, dlerror()); abort(); } FOR_ALL_ICU_FUNCTIONS #undef PER_FUNCTION_BLOCK #ifdef __APPLE__ - // libicui18n initialized with libicuuc so we null it to avoid double closing same handle - libicui18n = nullptr; + // libicui18n initialized with libicuuc so we null it to avoid double closing same handle + libicui18n = NULL; #endif // __APPLE__ - return 1; + return TRUE; } // GlobalizationNative_GetICUVersion // return the current loaded ICU version -extern "C" int32_t GlobalizationNative_GetICUVersion() +int32_t GlobalizationNative_GetICUVersion() { int32_t version; u_getVersion((uint8_t *) &version); - return version; + return version; } __attribute__((destructor)) void ShutdownICUShim() { - if (libicuuc != nullptr) + if (libicuuc != NULL) { dlclose(libicuuc); - libicuuc = nullptr; + libicuuc = NULL; } - if (libicui18n != nullptr) + if (libicui18n != NULL) { dlclose(libicui18n); - libicui18n = nullptr; + libicui18n = NULL; } } diff --git a/src/corefx/System.Globalization.Native/icushim.h b/src/corefx/System.Globalization.Native/pal_icushim.h similarity index 98% rename from src/corefx/System.Globalization.Native/icushim.h rename to src/corefx/System.Globalization.Native/pal_icushim.h index d7ec2fb05ccd..4ada6b97f517 100644 --- a/src/corefx/System.Globalization.Native/icushim.h +++ b/src/corefx/System.Globalization.Native/pal_icushim.h @@ -3,19 +3,19 @@ // See the LICENSE file in the project root for more information. // -// Enable calling ICU functions through shims to enable support for +// Enable calling ICU functions through shims to enable support for // multiple versions of ICU. #ifndef __ICUSHIM_H__ #define __ICUSHIM_H__ #include "config.h" +#include "pal_compiler.h" #define U_DISABLE_RENAMING 1 // All ICU headers need to be included here so that all function prototypes are // available before the function pointers are declared below. -#include #include #include #include @@ -138,7 +138,7 @@ #endif // Declare pointers to all the used ICU functions -#define PER_FUNCTION_BLOCK(fn, lib) extern decltype(fn)* fn##_ptr; +#define PER_FUNCTION_BLOCK(fn, lib) extern __typeof(fn)* fn##_ptr; FOR_ALL_ICU_FUNCTIONS #undef PER_FUNCTION_BLOCK @@ -240,3 +240,7 @@ FOR_ALL_ICU_FUNCTIONS #define usearch_openFromCollator(...) usearch_openFromCollator_ptr(__VA_ARGS__) #endif // __ICUSHIM_H__ + +DLLEXPORT int32_t GlobalizationNative_LoadICU(void); + +DLLEXPORT int32_t GlobalizationNative_GetICUVersion(void); diff --git a/src/corefx/System.Globalization.Native/idna.cpp b/src/corefx/System.Globalization.Native/pal_idna.c similarity index 94% rename from src/corefx/System.Globalization.Native/idna.cpp rename to src/corefx/System.Globalization.Native/pal_idna.c index 23942b3a6849..1d8786cca0eb 100644 --- a/src/corefx/System.Globalization.Native/idna.cpp +++ b/src/corefx/System.Globalization.Native/pal_idna.c @@ -4,7 +4,9 @@ // #include -#include "icushim.h" + +#include "pal_icushim.h" +#include "pal_idna.h" const uint32_t AllowUnassigned = 0x1; const uint32_t UseStd3AsciiRules = 0x2; @@ -38,7 +40,7 @@ Return values: 0: internal error during conversion. >0: the length of the converted string (not including the null terminator). */ -extern "C" int32_t GlobalizationNative_ToAscii( +int32_t GlobalizationNative_ToAscii( uint32_t flags, const UChar* lpSrc, int32_t cwSrcLength, UChar* lpDst, int32_t cwDstLength) { UErrorCode err = U_ZERO_ERROR; @@ -64,7 +66,7 @@ Return values: 0: internal error during conversion. >0: the length of the converted string (not including the null terminator). */ -extern "C" int32_t GlobalizationNative_ToUnicode( +int32_t GlobalizationNative_ToUnicode( int32_t flags, const UChar* lpSrc, int32_t cwSrcLength, UChar* lpDst, int32_t cwDstLength) { UErrorCode err = U_ZERO_ERROR; diff --git a/src/corefx/System.Globalization.Native/pal_idna.h b/src/corefx/System.Globalization.Native/pal_idna.h new file mode 100644 index 000000000000..f9ff5e477088 --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_idna.h @@ -0,0 +1,19 @@ +// 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 "pal_compiler.h" +#include "pal_locale.h" + +DLLEXPORT int32_t GlobalizationNative_ToAscii(uint32_t flags, + const UChar* lpSrc, + int32_t cwSrcLength, + UChar* lpDst, + int32_t cwDstLength); + +DLLEXPORT int32_t GlobalizationNative_ToUnicode(int32_t flags, + const UChar* lpSrc, + int32_t cwSrcLength, + UChar* lpDst, + int32_t cwDstLength); diff --git a/src/corefx/System.Globalization.Native/locale.cpp b/src/corefx/System.Globalization.Native/pal_locale.c similarity index 73% rename from src/corefx/System.Globalization.Native/locale.cpp rename to src/corefx/System.Globalization.Native/pal_locale.c index 951179d32159..b7465df2768b 100644 --- a/src/corefx/System.Globalization.Native/locale.cpp +++ b/src/corefx/System.Globalization.Native/pal_locale.c @@ -9,14 +9,13 @@ #include #include -#include "icushim.h" -#include "locale.hpp" +#include "pal_locale.h" int32_t UErrorCodeToBool(UErrorCode status) { if (U_SUCCESS(status)) { - return 1; + return TRUE; } // assert errors that should never occur @@ -25,15 +24,23 @@ int32_t UErrorCodeToBool(UErrorCode status) // add possible SetLastError support here - return 0; + return FALSE; } -int32_t GetLocale( - const UChar* localeName, char* localeNameResult, int32_t localeNameResultLength, bool canonicalize, UErrorCode* err) +int32_t GetLocale(const UChar* localeName, + char* localeNameResult, + int32_t localeNameResultLength, + UBool canonicalize, + UErrorCode* err) { char localeNameTemp[ULOC_FULLNAME_CAPACITY] = {0}; int32_t localeLength; + if (U_FAILURE(*err)) + { + return 0; + } + // Convert ourselves instead of doing u_UCharsToChars as that function considers '@' a variant and stops. for (int i = 0; i < ULOC_FULLNAME_CAPACITY - 1; i++) { @@ -82,17 +89,21 @@ int32_t GetLocale( return localeLength; } -UErrorCode u_charsToUChars_safe(const char* str, UChar* value, int32_t valueLength) +void u_charsToUChars_safe(const char* str, UChar* value, int32_t valueLength, UErrorCode* err) { - int len = strlen(str); + if (U_FAILURE(*err)) + { + return; + } + int len = strlen(str); if (len >= valueLength) { - return U_BUFFER_OVERFLOW_ERROR; + *err = U_BUFFER_OVERFLOW_ERROR; + return; } u_charsToUChars(str, value, len + 1); - return U_ZERO_ERROR; } int32_t FixupLocaleName(UChar* value, int32_t valueLength) @@ -113,11 +124,11 @@ int32_t FixupLocaleName(UChar* value, int32_t valueLength) return i; } -bool IsEnvVarSet(const char* name) +static int IsEnvVarSet(const char* name) { const char* value = getenv(name); - return (value != nullptr) && (strcmp("", value) != 0); + return (value != NULL) && (strcmp("", value) != 0); } // The behavior of uloc_getDefault() on POSIX systems is to query @@ -135,9 +146,9 @@ bool IsEnvVarSet(const char* name) // normalization it would do. const char* DetectDefaultLocaleName() { - char* loc = setlocale(LC_MESSAGES, nullptr); + char* loc = setlocale(LC_MESSAGES, NULL); - if (loc != nullptr && (strcmp("C", loc) == 0 || strcmp("POSIX", loc) == 0)) + if (loc != NULL && (strcmp("C", loc) == 0 || strcmp("POSIX", loc) == 0)) { if (!IsEnvVarSet("LC_ALL") && !IsEnvVarSet("LC_MESSAGES") && !IsEnvVarSet("LANG")) { @@ -155,7 +166,7 @@ const char* DetectDefaultLocaleName() // 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 GlobalizationNative_GetLocales(UChar *value, int32_t valueLength) { int32_t totalLength = 0; int32_t index = 0; @@ -174,7 +185,7 @@ extern "C" int32_t GlobalizationNative_GetLocales(UChar *value, int32_t valueLen totalLength += localeNameLength + 1; // add 1 for the name length - if (value != nullptr) + if (value != NULL) { if (totalLength > valueLength) return -3; @@ -198,27 +209,23 @@ extern "C" int32_t GlobalizationNative_GetLocales(UChar *value, int32_t valueLen return totalLength; } -extern "C" int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength) +int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, localeNameBuffer, ULOC_FULLNAME_CAPACITY, true, &status); + GetLocale(localeName, localeNameBuffer, ULOC_FULLNAME_CAPACITY, TRUE, &status); + u_charsToUChars_safe(localeNameBuffer, value, valueLength, &status); if (U_SUCCESS(status)) { - status = u_charsToUChars_safe(localeNameBuffer, value, valueLength); - - if (U_SUCCESS(status)) - { - FixupLocaleName(value, valueLength); - } + FixupLocaleName(value, valueLength); } return UErrorCodeToBool(status); } -extern "C" int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLength) +int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLength) { char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; UErrorCode status = U_ZERO_ERROR; @@ -226,30 +233,22 @@ extern "C" int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_ const char* defaultLocale = DetectDefaultLocaleName(); uloc_getBaseName(defaultLocale, localeNameBuffer, ULOC_FULLNAME_CAPACITY, &status); + u_charsToUChars_safe(localeNameBuffer, value, valueLength, &status); if (U_SUCCESS(status)) { - status = u_charsToUChars_safe(localeNameBuffer, value, valueLength); - - if (U_SUCCESS(status)) - { - int localeNameLen = FixupLocaleName(value, valueLength); + int localeNameLen = FixupLocaleName(value, valueLength); - char collationValueTemp[ULOC_KEYWORDS_CAPACITY]; - int32_t collationLen = - uloc_getKeywordValue(defaultLocale, "collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, &status); + char collationValueTemp[ULOC_KEYWORDS_CAPACITY]; + int32_t collationLen = + uloc_getKeywordValue(defaultLocale, "collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, &status); - if (U_SUCCESS(status) && collationLen > 0) - { - // copy the collation; managed uses a "_" to represent collation (not - // "@collation=") - status = u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen); - if (U_SUCCESS(status)) - { - status = u_charsToUChars_safe( - collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1); - } - } + if (U_SUCCESS(status) && collationLen > 0) + { + // copy the collation; managed uses a "_" to represent collation (not + // "@collation=") + u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen, &status); + u_charsToUChars_safe(collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1, &status); } } diff --git a/src/corefx/System.Globalization.Native/locale.hpp b/src/corefx/System.Globalization.Native/pal_locale.h similarity index 70% rename from src/corefx/System.Globalization.Native/locale.hpp rename to src/corefx/System.Globalization.Native/pal_locale.h index 79328f3b19b7..134291e4d457 100644 --- a/src/corefx/System.Globalization.Native/locale.hpp +++ b/src/corefx/System.Globalization.Native/pal_locale.h @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#include "pal_icushim.h" + /* Function: UErrorCodeToBool @@ -20,7 +22,7 @@ Converts a managed localeName into something ICU understands and can use as a lo int32_t GetLocale(const UChar* localeName, char* localeNameResult, int32_t localeNameResultLength, - bool canonicalize, + UBool canonicalize, UErrorCode* err); /* @@ -29,7 +31,7 @@ u_charsToUChars_safe Copies the given null terminated char* to UChar with error checking. Replacement for ICU u_charsToUChars */ -UErrorCode u_charsToUChars_safe(const char* str, UChar* value, int32_t valueLength); +void u_charsToUChars_safe(const char* str, UChar* value, int32_t valueLength, UErrorCode* err); /* Function: @@ -38,7 +40,7 @@ FixupLocaleName Replace underscores with hyphens to interop with existing .NET code. Returns the length of the string. */ -int FixupLocaleName(UChar* value, int32_t valueLength); +int32_t FixupLocaleName(UChar* value, int32_t valueLength); /* Function: @@ -48,3 +50,9 @@ Detect the default locale for the machine, defaulting to Invaraint if we can't compute one (different from uloc_getDefault()) would do. */ const char* DetectDefaultLocaleName(); + +DLLEXPORT int32_t GlobalizationNative_GetLocales(UChar *value, int32_t valueLength); + +DLLEXPORT int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength); + +DLLEXPORT int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLength); diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/pal_localeNumberData.c similarity index 68% rename from src/corefx/System.Globalization.Native/localeNumberData.cpp rename to src/corefx/System.Globalization.Native/pal_localeNumberData.c index a3586b568fc3..5663c63d8251 100644 --- a/src/corefx/System.Globalization.Native/localeNumberData.cpp +++ b/src/corefx/System.Globalization.Native/pal_localeNumberData.c @@ -4,12 +4,10 @@ // #include +#include #include -#include -#include "icushim.h" -#include "locale.hpp" -#include "holders.h" +#include "pal_localeNumberData.h" // invariant character definitions used by ICU #define UCHAR_CURRENCY ((UChar)0x00A4) // international currency @@ -24,34 +22,6 @@ #define ARRAY_LENGTH(array) (sizeof(array) / sizeof(array[0])) -// Enum that corresponds to managed enum CultureData.LocaleNumberData. -// The numeric values of the enum members match their Win32 counterparts. -enum LocaleNumberData : int32_t -{ - LanguageId = 0x00000001, - MeasurementSystem = 0x0000000D, - FractionalDigitsCount = 0x00000011, - NegativeNumberFormat = 0x00001010, - MonetaryFractionalDigitsCount = 0x00000019, - PositiveMonetaryNumberFormat = 0x0000001B, - NegativeMonetaryNumberFormat = 0x0000001C, - FirstDayofWeek = 0x0000100C, - FirstWeekOfYear = 0x0000100D, - ReadingLayout = 0x00000070, - NegativePercentFormat = 0x00000074, - PositivePercentFormat = 0x00000075, - Digit = 0x00000010, - Monetary = 0x00000018 -}; - -// Enum that corresponds to managed enum System.Globalization.CalendarWeekRule -enum CalendarWeekRule : int32_t -{ - FirstDay = 0, - FirstFullWeek = 1, - FirstFourDayWeek = 2 -}; - /* Function: NormalizeNumericPattern @@ -59,16 +29,8 @@ NormalizeNumericPattern Returns a numeric string pattern in a format that we can match against the appropriate managed pattern. */ -std::string NormalizeNumericPattern(const UChar* srcPattern, bool isNegative) +static char* NormalizeNumericPattern(const UChar* srcPattern, int isNegative) { - // A srcPattern example: "#,##0.00 C;(#,##0.00 C)" but where C is the - // international currency symbol (UCHAR_CURRENCY) - // The positive pattern comes first, then an optional negative pattern - // separated by a semicolon - // A destPattern example: "(C n)" where C represents the currency symbol, and - // n is the number - std::string destPattern; - int iStart = 0; int iEnd = u_strlen(srcPattern); int32_t iNegativePatternStart = -1; @@ -93,10 +55,45 @@ std::string NormalizeNumericPattern(const UChar* srcPattern, bool isNegative) } } - bool minusAdded = false; - bool digitAdded = false; - bool currencyAdded = false; - bool spaceAdded = false; + int index = 0; + int minusAdded = FALSE; + int digitAdded = FALSE; + int currencyAdded = FALSE; + int spaceAdded = FALSE; + + for (int i = iStart; i <= iEnd; i++) + { + UChar ch = srcPattern[i]; + switch (ch) + { + case UCHAR_MINUS: + case UCHAR_OPENPAREN: + case UCHAR_CLOSEPAREN: + minusAdded = TRUE; + break; + } + } + + // international currency symbol (UCHAR_CURRENCY) + // The positive pattern comes first, then an optional negative pattern + // separated by a semicolon + // A destPattern example: "(C n)" where C represents the currency symbol, and + // n is the number + char* destPattern; + + // if there is no negative subpattern, the ICU convention is to prefix the + // minus sign + if (isNegative && !minusAdded) + { + size_t length = (iEnd - iStart) + 2; + destPattern = calloc(length, sizeof(char)); + destPattern[index++] = '-'; + } + else + { + size_t length = (iEnd - iStart) + 1; + destPattern = calloc(length, sizeof(char)); + } for (int i = iStart; i <= iEnd; i++) { @@ -106,16 +103,16 @@ std::string NormalizeNumericPattern(const UChar* srcPattern, bool isNegative) case UCHAR_DIGIT: if (!digitAdded) { - digitAdded = true; - destPattern.push_back('n'); + digitAdded = TRUE; + destPattern[index++] = 'n'; } break; case UCHAR_CURRENCY: if (!currencyAdded) { - currencyAdded = true; - destPattern.push_back('C'); + currencyAdded = TRUE; + destPattern[index++] = 'C'; } break; @@ -123,35 +120,28 @@ std::string NormalizeNumericPattern(const UChar* srcPattern, bool isNegative) case UCHAR_NBSPACE: if (!spaceAdded) { - spaceAdded = true; - destPattern.push_back(' '); + spaceAdded = TRUE; + destPattern[index++] = ' '; } else { - assert(false); + assert(FALSE); } break; case UCHAR_MINUS: case UCHAR_OPENPAREN: case UCHAR_CLOSEPAREN: - minusAdded = true; - destPattern.push_back(static_cast(ch)); + minusAdded = TRUE; + destPattern[index++] = (char)ch; break; case UCHAR_PERCENT: - destPattern.push_back('%'); + destPattern[index++] = '%'; break; } } - // if there is no negative subpattern, the ICU convention is to prefix the - // minus sign - if (isNegative && !minusAdded) - { - destPattern.insert(destPattern.begin(), '-'); - } - return destPattern; } @@ -163,41 +153,55 @@ Determines the pattern from the decimalFormat and returns the matching pattern's index from patterns[]. Returns index -1 if no pattern is found. */ -int GetNumericPattern(const UNumberFormat* pNumberFormat, const char* patterns[], int patternsCount, bool isNegative) +static int GetNumericPattern(const UNumberFormat* pNumberFormat, + const char* patterns[], + int patternsCount, + int isNegative) { const int INVALID_FORMAT = -1; const int MAX_DOTNET_NUMERIC_PATTERN_LENGTH = 6; // example: "(C n)" plus terminator UErrorCode ignore = U_ZERO_ERROR; - int32_t icuPatternLength = unum_toPattern(pNumberFormat, false, nullptr, 0, &ignore); + int32_t icuPatternLength = unum_toPattern(pNumberFormat, FALSE, NULL, 0, &ignore) + 1; - std::vector icuPattern(icuPatternLength + 1, '\0'); + UChar* icuPattern = calloc(icuPatternLength, sizeof(UChar)); + if (icuPattern == NULL) + { + return U_MEMORY_ALLOCATION_ERROR; + } UErrorCode err = U_ZERO_ERROR; - unum_toPattern(pNumberFormat, false, icuPattern.data(), icuPattern.size(), &err); + unum_toPattern(pNumberFormat, FALSE, icuPattern, icuPatternLength, &err); assert(U_SUCCESS(err)); - std::string normalizedPattern = NormalizeNumericPattern(icuPattern.data(), isNegative); + char* normalizedPattern = NormalizeNumericPattern(icuPattern, isNegative); + + free(icuPattern); + + size_t normalizedPatternLength = strlen(normalizedPattern); - assert(normalizedPattern.length() > 0); - assert(normalizedPattern.length() < MAX_DOTNET_NUMERIC_PATTERN_LENGTH); + assert(normalizedPatternLength > 0); + assert(normalizedPatternLength < MAX_DOTNET_NUMERIC_PATTERN_LENGTH); - if (normalizedPattern.length() == 0 || normalizedPattern.length() >= MAX_DOTNET_NUMERIC_PATTERN_LENGTH) + if (normalizedPatternLength == 0 || normalizedPatternLength >= MAX_DOTNET_NUMERIC_PATTERN_LENGTH) { + free(normalizedPattern); return INVALID_FORMAT; } for (int i = 0; i < patternsCount; i++) { - if (strcmp(normalizedPattern.c_str(), patterns[i]) == 0) + if (strcmp(normalizedPattern, patterns[i]) == 0) { + free(normalizedPattern); return i; } - }; + } - assert(false); // should have found a valid pattern + assert(FALSE); // should have found a valid pattern + free(normalizedPattern); return INVALID_FORMAT; } @@ -208,7 +212,7 @@ GetCurrencyNegativePattern Implementation of NumberFormatInfo.CurrencyNegativePattern. Returns the pattern index. */ -int GetCurrencyNegativePattern(const char* locale) +static int GetCurrencyNegativePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"(Cn)", @@ -229,20 +233,21 @@ int GetCurrencyNegativePattern(const char* locale) "(n C)"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale, nullptr, &status); - UNumberFormatHolder formatHolder(pFormat, status); + UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status); assert(U_SUCCESS(status)); if (U_SUCCESS(status)) { - int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), TRUE); if (value >= 0) { + unum_close(pFormat); return value; } } + unum_close(pFormat); return DEFAULT_VALUE; } @@ -253,26 +258,27 @@ GetCurrencyPositivePattern Implementation of NumberFormatInfo.CurrencyPositivePattern. Returns the pattern index. */ -int GetCurrencyPositivePattern(const char* locale) +static int GetCurrencyPositivePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"Cn", "nC", "C n", "n C"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale, nullptr, &status); - UNumberFormatHolder formatHolder(pFormat, status); + UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status); assert(U_SUCCESS(status)); if (U_SUCCESS(status)) { - int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), FALSE); if (value >= 0) { + unum_close(pFormat); return value; } } + unum_close(pFormat); return DEFAULT_VALUE; } @@ -283,26 +289,27 @@ GetNumberNegativePattern Implementation of NumberFormatInfo.NumberNegativePattern. Returns the pattern index. */ -int GetNumberNegativePattern(const char* locale) +static int GetNumberNegativePattern(const char* locale) { const int DEFAULT_VALUE = 1; static const char* Patterns[] = {"(n)", "-n", "- n", "n-", "n -"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); - UNumberFormatHolder formatHolder(pFormat, status); + UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status); assert(U_SUCCESS(status)); if (U_SUCCESS(status)) { - int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), TRUE); if (value >= 0) { + unum_close(pFormat); return value; } } + unum_close(pFormat); return DEFAULT_VALUE; } @@ -313,27 +320,28 @@ GetPercentNegativePattern Implementation of NumberFormatInfo.PercentNegativePattern. Returns the pattern index. */ -int GetPercentNegativePattern(const char* locale) +static int GetPercentNegativePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = { "-n %", "-n%", "-%n", "%-n", "%n-", "n-%", "n%-", "-% n", "n %-", "% n-", "% -n", "n- %"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); - UNumberFormatHolder formatHolder(pFormat, status); + UNumberFormat* pFormat = unum_open(UNUM_PERCENT, NULL, 0, locale, NULL, &status); assert(U_SUCCESS(status)); if (U_SUCCESS(status)) { - int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), TRUE); if (value >= 0) { + unum_close(pFormat); return value; } } + unum_close(pFormat); return DEFAULT_VALUE; } @@ -344,26 +352,27 @@ GetPercentPositivePattern Implementation of NumberFormatInfo.PercentPositivePattern. Returns the pattern index. */ -int GetPercentPositivePattern(const char* locale) +static int GetPercentPositivePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"n %", "n%", "%n", "% n"}; UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); - UNumberFormatHolder formatHolder(pFormat, status); + UNumberFormat* pFormat = unum_open(UNUM_PERCENT, NULL, 0, locale, NULL, &status); assert(U_SUCCESS(status)); if (U_SUCCESS(status)) { - int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), FALSE); if (value >= 0) { + unum_close(pFormat); return value; } } + unum_close(pFormat); return DEFAULT_VALUE; } @@ -374,14 +383,14 @@ GetMeasurementSystem Obtains the measurement system for the local, determining if US or metric. Returns 1 for US, 0 otherwise. */ -UErrorCode GetMeasurementSystem(const char* locale, int32_t* value) +static UErrorCode GetMeasurementSystem(const char* locale, int32_t* value) { UErrorCode status = U_ZERO_ERROR; UMeasurementSystem measurementSystem = ulocdata_getMeasurementSystem(locale, &status); if (U_SUCCESS(status)) { - *value = (measurementSystem == UMeasurementSystem::UMS_US) ? 1 : 0; + *value = (measurementSystem == UMS_US) ? 1 : 0; } return status; @@ -394,27 +403,27 @@ GetLocaleInfoInt Obtains integer locale information Returns 1 for success, 0 otherwise */ -extern "C" int32_t GlobalizationNative_GetLocaleInfoInt( +int32_t GlobalizationNative_GetLocaleInfoInt( const UChar* localeName, LocaleNumberData localeNumberData, int32_t* value) { UErrorCode status = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &status); if (U_FAILURE(status)) { - return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); + return FALSE; } switch (localeNumberData) { - case LanguageId: + case LocaleNumber_LanguageId: *value = uloc_getLCID(locale); break; - case MeasurementSystem: + case LocaleNumber_MeasurementSystem: status = GetMeasurementSystem(locale, value); break; - case FractionalDigitsCount: + case LocaleNumber_FractionalDigitsCount: { UNumberFormat* numformat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) @@ -424,10 +433,10 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoInt( } break; } - case NegativeNumberFormat: + case LocaleNumber_NegativeNumberFormat: *value = GetNumberNegativePattern(locale); break; - case MonetaryFractionalDigitsCount: + case LocaleNumber_MonetaryFractionalDigitsCount: { UNumberFormat* numformat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) @@ -437,17 +446,16 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoInt( } break; } - case PositiveMonetaryNumberFormat: + case LocaleNumber_PositiveMonetaryNumberFormat: *value = GetCurrencyPositivePattern(locale); break; - case NegativeMonetaryNumberFormat: + case LocaleNumber_NegativeMonetaryNumberFormat: *value = GetCurrencyNegativePattern(locale); break; - case FirstWeekOfYear: + case LocaleNumber_FirstWeekOfYear: { // corresponds to DateTimeFormat.CalendarWeekRule - UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); - UCalendarHolder calHolder(pCal, status); + UCalendar* pCal = ucal_open(NULL, 0, locale, UCAL_TRADITIONAL, &status); if (U_SUCCESS(status)) { @@ -455,24 +463,25 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoInt( int minDaysInWeek = ucal_getAttribute(pCal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK); if (minDaysInWeek == 1) { - *value = CalendarWeekRule::FirstDay; + *value = WeekRule_FirstDay; } else if (minDaysInWeek == 7) { - *value = CalendarWeekRule::FirstFullWeek; + *value = WeekRule_FirstFullWeek; } else if (minDaysInWeek >= 4) { - *value = CalendarWeekRule::FirstFourDayWeek; + *value = WeekRule_FirstFourDayWeek; } else { status = U_UNSUPPORTED_ERROR; } } + ucal_close(pCal); break; } - case ReadingLayout: + case LocaleNumber_ReadingLayout: { // coresponds to values 0 and 1 in LOCALE_IREADINGLAYOUT (values 2 and 3 not // used in coreclr) @@ -487,26 +496,26 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoInt( } break; } - case FirstDayofWeek: + case LocaleNumber_FirstDayofWeek: { - UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); - UCalendarHolder calHolder(pCal, status); + UCalendar* pCal = ucal_open(NULL, 0, locale, UCAL_TRADITIONAL, &status); if (U_SUCCESS(status)) { *value = ucal_getAttribute(pCal, UCAL_FIRST_DAY_OF_WEEK) - 1; // .NET is 0-based and ICU is 1-based } + ucal_close(pCal); break; } - case NegativePercentFormat: + case LocaleNumber_NegativePercentFormat: *value = GetPercentNegativePattern(locale); break; - case PositivePercentFormat: + case LocaleNumber_PositivePercentFormat: *value = GetPercentPositivePattern(locale); break; default: status = U_UNSUPPORTED_ERROR; - assert(false); + assert(FALSE); break; } @@ -520,12 +529,12 @@ GetLocaleInfoGroupingSizes Obtains grouping sizes for decimal and currency Returns 1 for success, 0 otherwise */ -extern "C" int32_t GlobalizationNative_GetLocaleInfoGroupingSizes( +int32_t GlobalizationNative_GetLocaleInfoGroupingSizes( const UChar* localeName, LocaleNumberData localeGroupingData, int32_t* primaryGroupSize, int32_t* secondaryGroupSize) { UErrorCode status = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &status); if (U_FAILURE(status)) { @@ -535,10 +544,10 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoGroupingSizes( UNumberFormatStyle style; switch (localeGroupingData) { - case Digit: + case LocaleNumber_Digit: style = UNUM_DECIMAL; break; - case Monetary: + case LocaleNumber_Monetary: style = UNUM_CURRENCY; break; default: diff --git a/src/corefx/System.Globalization.Native/pal_localeNumberData.h b/src/corefx/System.Globalization.Native/pal_localeNumberData.h new file mode 100644 index 000000000000..32eb3fd8a079 --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_localeNumberData.h @@ -0,0 +1,44 @@ +// 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 "pal_compiler.h" +#include "pal_locale.h" + +// Enum that corresponds to managed enum CultureData.LocaleNumberData. +// The numeric values of the enum members match their Win32 counterparts. +typedef enum +{ + LocaleNumber_LanguageId = 0x01, + LocaleNumber_MeasurementSystem = 0x0D, + LocaleNumber_FractionalDigitsCount = 0x00000011, + LocaleNumber_NegativeNumberFormat = 0x00001010, + LocaleNumber_MonetaryFractionalDigitsCount = 0x00000019, + LocaleNumber_PositiveMonetaryNumberFormat = 0x0000001B, + LocaleNumber_NegativeMonetaryNumberFormat = 0x0000001C, + LocaleNumber_FirstDayofWeek = 0x0000100C, + LocaleNumber_FirstWeekOfYear = 0x0000100D, + LocaleNumber_ReadingLayout = 0x00000070, + LocaleNumber_NegativePercentFormat = 0x00000074, + LocaleNumber_PositivePercentFormat = 0x00000075, + LocaleNumber_Digit = 0x00000010, + LocaleNumber_Monetary = 0x00000018 +} LocaleNumberData; + +// Enum that corresponds to managed enum System.Globalization.CalendarWeekRule +typedef enum +{ + WeekRule_FirstDay = 0, + WeekRule_FirstFullWeek = 1, + WeekRule_FirstFourDayWeek = 2 +} CalendarWeekRule; + +DLLEXPORT int32_t GlobalizationNative_GetLocaleInfoInt(const UChar* localeName, + LocaleNumberData localeNumberData, + int32_t* value); + +DLLEXPORT int32_t GlobalizationNative_GetLocaleInfoGroupingSizes(const UChar* localeName, + LocaleNumberData localeGroupingData, + int32_t* primaryGroupSize, + int32_t* secondaryGroupSize); diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/pal_localeStringData.c similarity index 57% rename from src/corefx/System.Globalization.Native/localeStringData.cpp rename to src/corefx/System.Globalization.Native/pal_localeStringData.c index b8eaa307c735..a989b57f7946 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/pal_localeStringData.c @@ -4,49 +4,10 @@ // #include +#include #include -#include -#include "icushim.h" -#include "locale.hpp" -#include "holders.h" - -// Enum that corresponds to managed enum CultureData.LocaleStringData. -// The numeric values of the enum members match their Win32 counterparts. -enum LocaleStringData : int32_t -{ - LocalizedDisplayName = 0x00000002, - EnglishDisplayName = 0x00000072, - NativeDisplayName = 0x00000073, - LocalizedLanguageName = 0x0000006f, - EnglishLanguageName = 0x00001001, - NativeLanguageName = 0x00000004, - EnglishCountryName = 0x00001002, - NativeCountryName = 0x00000008, - ListSeparator = 0x0000000C, - DecimalSeparator = 0x0000000E, - ThousandSeparator = 0x0000000F, - Digits = 0x00000013, - MonetarySymbol = 0x00000014, - CurrencyEnglishName = 0x00001007, - CurrencyNativeName = 0x00001008, - Iso4217MonetarySymbol = 0x00000015, - MonetaryDecimalSeparator = 0x00000016, - MonetaryThousandSeparator = 0x00000017, - AMDesignator = 0x00000028, - PMDesignator = 0x00000029, - PositiveSign = 0x00000050, - NegativeSign = 0x00000051, - Iso639LanguageTwoLetterName = 0x00000059, - Iso639LanguageThreeLetterName = 0x00000067, - Iso3166CountryName = 0x0000005A, - Iso3166CountryName2= 0x00000068, - NaNSymbol = 0x00000069, - PositiveInfinitySymbol = 0x0000006a, - ParentName = 0x0000006d, - PercentSymbol = 0x00000076, - PerMilleSymbol = 0x00000077 -}; +#include "pal_localeStringData.h" /* Function: @@ -54,20 +15,15 @@ GetLocaleInfoDecimalFormatSymbol Obtains the value of a DecimalFormatSymbols */ -UErrorCode -GetLocaleInfoDecimalFormatSymbol(const char* locale, UNumberFormatSymbol symbol, UChar* value, int32_t valueLength) +static UErrorCode GetLocaleInfoDecimalFormatSymbol(const char* locale, + UNumberFormatSymbol symbol, + UChar* value, + int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; - UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); - UNumberFormatHolder formatHolder(pFormat, status); - - if (U_FAILURE(status)) - { - return status; - } - + UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status); unum_getSymbol(pFormat, symbol, value, valueLength, &status); - + unum_close(pFormat); return status; } @@ -77,12 +33,12 @@ GetDigitSymbol Obtains the value of a Digit DecimalFormatSymbols */ -UErrorCode GetDigitSymbol(const char* locale, - UErrorCode previousStatus, - UNumberFormatSymbol symbol, - int digit, - UChar* value, - int32_t valueLength) +static UErrorCode GetDigitSymbol(const char* locale, + UErrorCode previousStatus, + UNumberFormatSymbol symbol, + int digit, + UChar* value, + int32_t valueLength) { if (U_FAILURE(previousStatus)) { @@ -98,19 +54,15 @@ GetLocaleInfoAmPm Obtains the value of the AM or PM string for a locale. */ -UErrorCode GetLocaleInfoAmPm(const char* locale, bool am, UChar* value, int32_t valueLength) +static UErrorCode GetLocaleInfoAmPm(const char* locale, + int am, + UChar* value, + int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; - UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, nullptr, 0, nullptr, 0, &status); - UDateFormatHolder formatHolder(pFormat, status); - - if (U_FAILURE(status)) - { - return status; - } - + UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, NULL, 0, NULL, 0, &status); udat_getSymbols(pFormat, UDAT_AM_PMS, am ? 0 : 1, value, valueLength, &status); - + udat_close(pFormat); return status; } @@ -120,21 +72,21 @@ GetLocaleIso639LanguageTwoLetterName Gets the language name for a locale (via uloc_getLanguage) and converts the result to UChars */ -UErrorCode GetLocaleIso639LanguageTwoLetterName(const char* locale, UChar* value, int32_t valueLength) +static UErrorCode GetLocaleIso639LanguageTwoLetterName(const char* locale, UChar* value, int32_t valueLength) { - UErrorCode status = U_ZERO_ERROR; - int32_t length = uloc_getLanguage(locale, nullptr, 0, &status); - - std::vector buf(length + 1, '\0'); - status = U_ZERO_ERROR; - - uloc_getLanguage(locale, buf.data(), length + 1, &status); + UErrorCode status = U_ZERO_ERROR, ignore = U_ZERO_ERROR; + int32_t length = uloc_getLanguage(locale, NULL, 0, &ignore) + 1; - if (U_SUCCESS(status)) + char* buf = calloc(length, sizeof(char)); + if (buf == NULL) { - status = u_charsToUChars_safe(buf.data(), value, valueLength); + return U_MEMORY_ALLOCATION_ERROR; } + uloc_getLanguage(locale, buf, length, &status); + u_charsToUChars_safe(buf, value, valueLength, &status); + free(buf); + return status; } @@ -144,15 +96,17 @@ 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) +static UErrorCode GetLocaleIso639LanguageThreeLetterName(const char* locale, UChar* value, int32_t valueLength) { + UErrorCode status = U_ZERO_ERROR; const char *isoLanguage = uloc_getISO3Language(locale); if (isoLanguage[0] == 0) { return U_ILLEGAL_ARGUMENT_ERROR; } - - return u_charsToUChars_safe(isoLanguage, value, valueLength); + + u_charsToUChars_safe(isoLanguage, value, valueLength, &status); + return status; } /* @@ -161,21 +115,21 @@ GetLocaleIso3166CountryName Gets the country name for a locale (via uloc_getCountry) and converts the result to UChars */ -UErrorCode GetLocaleIso3166CountryName(const char* locale, UChar* value, int32_t valueLength) +static UErrorCode GetLocaleIso3166CountryName(const char* locale, UChar* value, int32_t valueLength) { - UErrorCode status = U_ZERO_ERROR; - int32_t length = uloc_getCountry(locale, nullptr, 0, &status); - - std::vector buf(length + 1, '\0'); - status = U_ZERO_ERROR; + UErrorCode status = U_ZERO_ERROR, ignore = U_ZERO_ERROR; + int32_t length = uloc_getCountry(locale, NULL, 0, &ignore) + 1; - uloc_getCountry(locale, buf.data(), length + 1, &status); - - if (U_SUCCESS(status)) + char* buf = calloc(length, sizeof(char)); + if (buf == NULL) { - status = u_charsToUChars_safe(buf.data(), value, valueLength); + return U_MEMORY_ALLOCATION_ERROR; } + uloc_getCountry(locale, buf, length, &status); + u_charsToUChars_safe(buf, value, valueLength, &status); + free(buf); + return status; } @@ -185,8 +139,9 @@ 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) +static UErrorCode GetLocaleIso3166CountryCode(const char* locale, UChar* value, int32_t valueLength) { + UErrorCode status = U_ZERO_ERROR; const char *pIsoCountryName = uloc_getISO3Country(locale); int len = strlen(pIsoCountryName); @@ -195,7 +150,8 @@ UErrorCode GetLocaleIso3166CountryCode(const char* locale, UChar* value, int32_t return U_ILLEGAL_ARGUMENT_ERROR; } - return u_charsToUChars_safe(pIsoCountryName, value, valueLength); + u_charsToUChars_safe(pIsoCountryName, value, valueLength, &status); + return status; } /* @@ -204,7 +160,7 @@ 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) +static UErrorCode GetLocaleCurrencyName(const char* locale, UBool nativeName, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; @@ -233,9 +189,10 @@ UErrorCode GetLocaleCurrencyName(const char* locale, bool nativeName, UChar* val { return U_BUFFER_OVERFLOW_ERROR; } + u_strncpy(value, pCurrencyLongName, len); value[len] = 0; - + return status; } @@ -246,12 +203,14 @@ GetLocaleInfoString Obtains string locale information. Returns 1 for success, 0 otherwise */ -extern "C" int32_t GlobalizationNative_GetLocaleInfoString( - const UChar* localeName, LocaleStringData localeStringData, UChar* value, int32_t valueLength) +int32_t GlobalizationNative_GetLocaleInfoString(const UChar* localeName, + LocaleStringData localeStringData, + UChar* value, + int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &status); if (U_FAILURE(status)) { @@ -260,118 +219,115 @@ extern "C" int32_t GlobalizationNative_GetLocaleInfoString( switch (localeStringData) { - case LocalizedDisplayName: + case LocaleString_LocalizedDisplayName: uloc_getDisplayName(locale, DetectDefaultLocaleName(), value, valueLength, &status); break; - case EnglishDisplayName: + case LocaleString_EnglishDisplayName: uloc_getDisplayName(locale, ULOC_ENGLISH, value, valueLength, &status); break; - case NativeDisplayName: + case LocaleString_NativeDisplayName: uloc_getDisplayName(locale, locale, value, valueLength, &status); break; - case LocalizedLanguageName: + case LocaleString_LocalizedLanguageName: uloc_getDisplayLanguage(locale, DetectDefaultLocaleName(), value, valueLength, &status); break; - case EnglishLanguageName: + case LocaleString_EnglishLanguageName: uloc_getDisplayLanguage(locale, ULOC_ENGLISH, value, valueLength, &status); break; - case NativeLanguageName: + case LocaleString_NativeLanguageName: uloc_getDisplayLanguage(locale, locale, value, valueLength, &status); break; - case EnglishCountryName: + case LocaleString_EnglishCountryName: uloc_getDisplayCountry(locale, ULOC_ENGLISH, value, valueLength, &status); break; - case NativeCountryName: + case LocaleString_NativeCountryName: uloc_getDisplayCountry(locale, locale, value, valueLength, &status); break; - case ListSeparator: + case LocaleString_ListSeparator: // fall through - case ThousandSeparator: + case LocaleString_ThousandSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; - case DecimalSeparator: + case LocaleString_DecimalSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength); break; - case Digits: + case LocaleString_Digits: status = GetDigitSymbol(locale, status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength); // symbols UNUM_ONE_DIGIT to UNUM_NINE_DIGIT are contiguous for (int32_t symbol = UNUM_ONE_DIGIT_SYMBOL; symbol <= UNUM_NINE_DIGIT_SYMBOL; symbol++) { int charIndex = symbol - UNUM_ONE_DIGIT_SYMBOL + 1; status = GetDigitSymbol( - locale, status, static_cast(symbol), charIndex, value, valueLength); + locale, status, (UNumberFormatSymbol)symbol, charIndex, value, valueLength); } break; - case MonetarySymbol: + case LocaleString_MonetarySymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_CURRENCY_SYMBOL, value, valueLength); break; - case Iso4217MonetarySymbol: + case LocaleString_Iso4217MonetarySymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength); break; - case CurrencyEnglishName: - status = GetLocaleCurrencyName(locale, false, value, valueLength); + case LocaleString_CurrencyEnglishName: + status = GetLocaleCurrencyName(locale, FALSE, value, valueLength); break; - case CurrencyNativeName: - status = GetLocaleCurrencyName(locale, true, value, valueLength); + case LocaleString_CurrencyNativeName: + status = GetLocaleCurrencyName(locale, TRUE, value, valueLength); break; - case MonetaryDecimalSeparator: + case LocaleString_MonetaryDecimalSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength); break; - case MonetaryThousandSeparator: + case LocaleString_MonetaryThousandSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; - case AMDesignator: - status = GetLocaleInfoAmPm(locale, true, value, valueLength); + case LocaleString_AMDesignator: + status = GetLocaleInfoAmPm(locale, TRUE, value, valueLength); break; - case PMDesignator: - status = GetLocaleInfoAmPm(locale, false, value, valueLength); + case LocaleString_PMDesignator: + status = GetLocaleInfoAmPm(locale, FALSE, value, valueLength); break; - case PositiveSign: + case LocaleString_PositiveSign: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PLUS_SIGN_SYMBOL, value, valueLength); break; - case NegativeSign: + case LocaleString_NegativeSign: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength); break; - case Iso639LanguageTwoLetterName: + case LocaleString_Iso639LanguageTwoLetterName: status = GetLocaleIso639LanguageTwoLetterName(locale, value, valueLength); break; - case Iso639LanguageThreeLetterName: + case LocaleString_Iso639LanguageThreeLetterName: status = GetLocaleIso639LanguageThreeLetterName(locale, value, valueLength); break; - case Iso3166CountryName: + case LocaleString_Iso3166CountryName: status = GetLocaleIso3166CountryName(locale, value, valueLength); break; - case Iso3166CountryName2: + case LocaleString_Iso3166CountryName2: status = GetLocaleIso3166CountryCode(locale, value, valueLength); break; - case NaNSymbol: + case LocaleString_NaNSymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength); break; - case PositiveInfinitySymbol: + case LocaleString_PositiveInfinitySymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INFINITY_SYMBOL, value, valueLength); break; - case ParentName: + case LocaleString_ParentName: { // ICU supports lang[-script][-region][-variant] so up to 4 parents // including invariant locale char localeNameTemp[ULOC_FULLNAME_CAPACITY]; uloc_getParent(locale, localeNameTemp, ULOC_FULLNAME_CAPACITY, &status); + u_charsToUChars_safe(localeNameTemp, value, valueLength, &status); if (U_SUCCESS(status)) { - status = u_charsToUChars_safe(localeNameTemp, value, valueLength); - if (U_SUCCESS(status)) - { - FixupLocaleName(value, valueLength); - } + FixupLocaleName(value, valueLength); } break; } - case PercentSymbol: + case LocaleString_PercentSymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERCENT_SYMBOL, value, valueLength); break; - case PerMilleSymbol: + case LocaleString_PerMilleSymbol: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERMILL_SYMBOL, value, valueLength); break; default: @@ -389,26 +345,17 @@ GetLocaleTimeFormat Obtains time format information (in ICU format, it needs to be coverted to .NET Format). Returns 1 for success, 0 otherwise */ -extern "C" int32_t GlobalizationNative_GetLocaleTimeFormat( - const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength) +int32_t GlobalizationNative_GetLocaleTimeFormat(const UChar* localeName, + int shortFormat, + UChar* value, + int32_t valueLength) { UErrorCode err = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); - - if (U_FAILURE(err)) - { - return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); - } - + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &err); UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM; - UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, nullptr, 0, nullptr, 0, &err); - UDateFormatHolder formatHolder(pFormat, err); - - if (U_FAILURE(err)) - return UErrorCodeToBool(err); - - udat_toPattern(pFormat, false, value, valueLength, &err); - + UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, NULL, 0, NULL, 0, &err); + udat_toPattern(pFormat, FALSE, value, valueLength, &err); + udat_close(pFormat); return UErrorCodeToBool(err); } diff --git a/src/corefx/System.Globalization.Native/pal_localeStringData.h b/src/corefx/System.Globalization.Native/pal_localeStringData.h new file mode 100644 index 000000000000..58894284f1ec --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_localeStringData.h @@ -0,0 +1,54 @@ +// 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 "pal_compiler.h" +#include "pal_locale.h" + +// Enum that corresponds to managed enum CultureData.LocaleStringData. +// The numeric values of the enum members match their Win32 counterparts. +typedef enum +{ + LocaleString_LocalizedDisplayName = 0x02, + LocaleString_EnglishDisplayName = 0x00000072, + LocaleString_NativeDisplayName = 0x00000073, + LocaleString_LocalizedLanguageName = 0x0000006f, + LocaleString_EnglishLanguageName = 0x00001001, + LocaleString_NativeLanguageName = 0x04, + LocaleString_EnglishCountryName = 0x00001002, + LocaleString_NativeCountryName = 0x08, + LocaleString_ListSeparator = 0x0C, + LocaleString_DecimalSeparator = 0x0E, + LocaleString_ThousandSeparator = 0x0F, + LocaleString_Digits = 0x00000013, + LocaleString_MonetarySymbol = 0x00000014, + LocaleString_CurrencyEnglishName = 0x00001007, + LocaleString_CurrencyNativeName = 0x00001008, + LocaleString_Iso4217MonetarySymbol = 0x00000015, + LocaleString_MonetaryDecimalSeparator = 0x00000016, + LocaleString_MonetaryThousandSeparator = 0x00000017, + LocaleString_AMDesignator = 0x00000028, + LocaleString_PMDesignator = 0x00000029, + LocaleString_PositiveSign = 0x00000050, + LocaleString_NegativeSign = 0x00000051, + LocaleString_Iso639LanguageTwoLetterName = 0x00000059, + LocaleString_Iso639LanguageThreeLetterName = 0x00000067, + LocaleString_Iso3166CountryName = 0x0000005A, + LocaleString_Iso3166CountryName2= 0x00000068, + LocaleString_NaNSymbol = 0x00000069, + LocaleString_PositiveInfinitySymbol = 0x0000006a, + LocaleString_ParentName = 0x0000006d, + LocaleString_PercentSymbol = 0x00000076, + LocaleString_PerMilleSymbol = 0x00000077 +} LocaleStringData; + +DLLEXPORT int32_t GlobalizationNative_GetLocaleInfoString(const UChar* localeName, + LocaleStringData localeStringData, + UChar* value, + int32_t valueLength); + +DLLEXPORT int32_t GlobalizationNative_GetLocaleTimeFormat(const UChar* localeName, + int shortFormat, UChar* value, + int32_t valueLength); + diff --git a/src/corefx/System.Globalization.Native/normalization.cpp b/src/corefx/System.Globalization.Native/pal_normalization.c similarity index 81% rename from src/corefx/System.Globalization.Native/normalization.cpp rename to src/corefx/System.Globalization.Native/pal_normalization.c index 014894a5edc5..1fc880b6d0d0 100644 --- a/src/corefx/System.Globalization.Native/normalization.cpp +++ b/src/corefx/System.Globalization.Native/pal_normalization.c @@ -4,35 +4,26 @@ // #include -#include "icushim.h" -/* - * These values should be kept in sync with System.Text.NormalizationForm - */ -enum class NormalizationForm : int32_t -{ - C = 0x1, - D = 0x2, - KC = 0x5, - KD = 0x6 -}; +#include "pal_icushim.h" +#include "pal_normalization.h" const UNormalizer2* GetNormalizerForForm(NormalizationForm normalizationForm, UErrorCode* pErrorCode) { switch (normalizationForm) { - case NormalizationForm::C: + case FormC: return unorm2_getNFCInstance(pErrorCode); - case NormalizationForm::D: + case FormD: return unorm2_getNFDInstance(pErrorCode); - case NormalizationForm::KC: + case FormKC: return unorm2_getNFKCInstance(pErrorCode); - case NormalizationForm::KD: + case FormKD: return unorm2_getNFKDInstance(pErrorCode); } *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; - return nullptr; + return NULL; } /* @@ -48,7 +39,7 @@ Return values: 1: lpStr is normalized. -1: internal error during normalization. */ -extern "C" int32_t GlobalizationNative_IsNormalized( +int32_t GlobalizationNative_IsNormalized( NormalizationForm normalizationForm, const UChar* lpStr, int32_t cwStrLength) { UErrorCode err = U_ZERO_ERROR; @@ -77,7 +68,7 @@ Return values: 0: internal error during normalization. >0: the length of the normalized string (not counting the null terminator). */ -extern "C" int32_t GlobalizationNative_NormalizeString( +int32_t GlobalizationNative_NormalizeString( NormalizationForm normalizationForm, const UChar* lpSrc, int32_t cwSrcLength, UChar* lpDst, int32_t cwDstLength) { UErrorCode err = U_ZERO_ERROR; diff --git a/src/corefx/System.Globalization.Native/pal_normalization.h b/src/corefx/System.Globalization.Native/pal_normalization.h new file mode 100644 index 000000000000..993d95678d3d --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_normalization.h @@ -0,0 +1,28 @@ +// 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 "pal_compiler.h" +#include "pal_locale.h" + +/* + * These values should be kept in sync with System.Text.NormalizationForm + */ +typedef enum +{ + FormC = 0x1, + FormD = 0x2, + FormKC = 0x5, + FormKD = 0x6 +} NormalizationForm; + +DLLEXPORT int32_t GlobalizationNative_IsNormalized(NormalizationForm normalizationForm, + const UChar* lpStr, + int32_t cwStrLength); + +DLLEXPORT int32_t GlobalizationNative_NormalizeString(NormalizationForm normalizationForm, + const UChar* lpSrc, + int32_t cwSrcLength, + UChar* lpDst, + int32_t cwDstLength); diff --git a/src/corefx/System.Globalization.Native/timeZoneInfo.cpp b/src/corefx/System.Globalization.Native/pal_timeZoneInfo.c similarity index 56% rename from src/corefx/System.Globalization.Native/timeZoneInfo.cpp rename to src/corefx/System.Globalization.Native/pal_timeZoneInfo.c index d5ab7e094d60..bf2a9dca0f2c 100644 --- a/src/corefx/System.Globalization.Native/timeZoneInfo.cpp +++ b/src/corefx/System.Globalization.Native/pal_timeZoneInfo.c @@ -6,40 +6,35 @@ #include #include -#include "icushim.h" -#include "locale.hpp" -#include "holders.h" -#include "errors.h" - -/* -These values should be kept in sync with the managed Interop.GlobalizationInterop.TimeZoneDisplayNameType enum. -*/ -enum TimeZoneDisplayNameType : int32_t -{ - Generic = 0, - Standard = 1, - DaylightSavings = 2, -}; +#include "pal_timeZoneInfo.h" /* Gets the localized display name for the specified time zone. */ -extern "C" ResultCode GlobalizationNative_GetTimeZoneDisplayName( - const UChar* localeName, const UChar* timeZoneId, TimeZoneDisplayNameType type, UChar* result, int32_t resultLength) +ResultCode GlobalizationNative_GetTimeZoneDisplayName(const UChar* localeName, + const UChar* timeZoneId, + TimeZoneDisplayNameType type, + UChar* result, + int32_t resultLength) { UErrorCode err = U_ZERO_ERROR; char locale[ULOC_FULLNAME_CAPACITY]; - GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &err); int32_t timeZoneIdLength = -1; // timeZoneId is NULL-terminated UCalendar* calendar = ucal_open(timeZoneId, timeZoneIdLength, locale, UCAL_DEFAULT, &err); - UCalendarHolder calendarHolder(calendar, err); // TODO (https://github.com/dotnet/corefx/issues/5741): need to support Generic names, but ICU "C" api // has no public option for this. For now, just use the ICU standard name for both Standard and Generic // (which is the same behavior on Windows with the mincore TIME_ZONE_INFORMATION APIs). ucal_getTimeZoneDisplayName( - calendar, type == DaylightSavings ? UCAL_DST : UCAL_STANDARD, locale, result, resultLength, &err); + calendar, + type == TimeZoneDisplayName_DaylightSavings ? UCAL_DST : UCAL_STANDARD, + locale, + result, + resultLength, + &err); + ucal_close(calendar); return GetResultCode(err); } diff --git a/src/corefx/System.Globalization.Native/pal_timeZoneInfo.h b/src/corefx/System.Globalization.Native/pal_timeZoneInfo.h new file mode 100644 index 000000000000..1c030ca0c3cb --- /dev/null +++ b/src/corefx/System.Globalization.Native/pal_timeZoneInfo.h @@ -0,0 +1,24 @@ +// 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 "pal_compiler.h" +#include "pal_locale.h" +#include "pal_errors.h" + +/* +These values should be kept in sync with the managed Interop.GlobalizationInterop.TimeZoneDisplayNameType enum. +*/ +typedef enum +{ + TimeZoneDisplayName_Generic = 0, + TimeZoneDisplayName_Standard = 1, + TimeZoneDisplayName_DaylightSavings = 2, +} TimeZoneDisplayNameType; + +DLLEXPORT ResultCode GlobalizationNative_GetTimeZoneDisplayName(const UChar* localeName, + const UChar* timeZoneId, + TimeZoneDisplayNameType type, + UChar* result, + int32_t resultLength);