diff options
author | Matt Ellis <matell@microsoft.com> | 2015-10-25 17:29:03 -0700 |
---|---|---|
committer | Matt Ellis <matell@microsoft.com> | 2015-10-25 17:29:03 -0700 |
commit | e93beb1f04fd028cd373bf601acbe7803a444cca (patch) | |
tree | 9934d3b05dbf7dd42f56479833d9be5d5d422563 /src/corefx | |
parent | f7ea5660a87e491841c1e49bf799d00898e728ca (diff) | |
parent | 392f5f43475843a8dc417ef84b88e855e91f909e (diff) | |
download | coreclr-e93beb1f04fd028cd373bf601acbe7803a444cca.tar.gz coreclr-e93beb1f04fd028cd373bf601acbe7803a444cca.tar.bz2 coreclr-e93beb1f04fd028cd373bf601acbe7803a444cca.zip |
Merge pull request #1851 from ellismg/icu-remove-c-plus-plus
Remove OSX Homebrew ICU dependency
Diffstat (limited to 'src/corefx')
-rw-r--r-- | src/corefx/System.Globalization.Native/CMakeLists.txt | 71 | ||||
-rw-r--r-- | src/corefx/System.Globalization.Native/calendarData.cpp | 408 | ||||
-rw-r--r-- | src/corefx/System.Globalization.Native/holders.h | 103 | ||||
-rw-r--r-- | src/corefx/System.Globalization.Native/locale.cpp | 123 | ||||
-rw-r--r-- | src/corefx/System.Globalization.Native/locale.hpp | 8 | ||||
-rw-r--r-- | src/corefx/System.Globalization.Native/localeNumberData.cpp | 203 | ||||
-rw-r--r-- | src/corefx/System.Globalization.Native/localeStringData.cpp | 262 |
7 files changed, 676 insertions, 502 deletions
diff --git a/src/corefx/System.Globalization.Native/CMakeLists.txt b/src/corefx/System.Globalization.Native/CMakeLists.txt index 04f29fced7..08d35a0053 100644 --- a/src/corefx/System.Globalization.Native/CMakeLists.txt +++ b/src/corefx/System.Globalization.Native/CMakeLists.txt @@ -6,36 +6,49 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) add_definitions(-DPIC=1) add_definitions(-DBIT64=1) -set(ICU_HOMEBREW_LIB_PATH "/usr/local/opt/icu4c/lib") set(ICU_HOMEBREW_INC_PATH "/usr/local/opt/icu4c/include") -find_library(ICUUC NAMES icuuc PATHS ${ICU_HOMEBREW_LIB_PATH}) -if(ICUUC STREQUAL ICUUC-NOTFOUND) - message(FATAL_ERROR "Cannot find libicuuc, try installing libicu-dev (or the appropriate package for your platform)") - return() -endif() - -find_library(ICUI18N NAMES icui18n PATHS ${ICU_HOMEBREW_LIB_PATH}) -if(ICUI18N STREQUAL ICUI18N-NOTFOUND) - message(FATAL_ERROR "Cannot find libicui18n, try installing libicu-dev (or the appropriate package for your platform)") - return() -endif() - find_path(UTYPES_H "unicode/utypes.h" PATHS ${ICU_HOMEBREW_INC_PATH}) if(UTYPES_H STREQUAL UTYPES_H-NOTFOUND) message(FATAL_ERROR "Cannont find utypes.h, try installing libicu-dev (or the appropriate package for your platform)") return() endif() -set(CMAKE_REQUIRED_INCLUDES ${ICU_HOMEBREW_INC_PATH}) -CHECK_CXX_SOURCE_COMPILES(" - #include <unicode/dtfmtsym.h> - int main() { DateFormatSymbols::DtWidthType e = DateFormatSymbols::DtWidthType::SHORT; } -" HAVE_DTWIDTHTYPE_SHORT) +if(NOT CLR_CMAKE_PLATFORM_DARWIN) + find_library(ICUUC icuuc) + if(ICUUC STREQUAL ICUUC-NOTFOUND) + message(FATAL_ERROR "Cannot find libicuuc, try installing libicu-dev (or the appropriate package for your platform)") + return() + endif() + + find_library(ICUI18N icui18n) + if(ICUI18N STREQUAL ICUI18N-NOTFOUND) + message(FATAL_ERROR "Cannot find libicui18n, try installing libicu-dev (or the appropriate package for your platform)") + return() + endif() + + set(CMAKE_REQUIRED_INCLUDES ${ICU_HOMEBREW_INC_PATH}) + CHECK_CXX_SOURCE_COMPILES(" + #include <unicode/udat.h> + int main() { UDateFormatSymbolType e = UDAT_STANDALONE_SHORTER_WEEKDAYS; } + " HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS) -if(HAVE_DTWIDTHTYPE_SHORT) - add_definitions(-DHAVE_DTWIDTHTYPE_SHORT=1) -endif(HAVE_DTWIDTHTYPE_SHORT) + if(HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS) + add_definitions(-DHAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS=1) + endif(HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS) + +else() + + find_library(ICUCORE icucore) + if(ICUI18N STREQUAL ICUCORE-NOTFOUND) + message(FATAL_ERROR "Cannot find libicucore, skipping build for System.Globalization.Native. .NET globalization is not expected to function.") + return() + endif() + + # libicucore supports UDAT_STANDALONE_SHORTER_WEEKDAYS + add_definitions(-DHAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS=1) + +endif() add_compile_options(-fPIC) @@ -61,9 +74,17 @@ add_library(System.Globalization.Native # Disable the "lib" prefix. set_target_properties(System.Globalization.Native PROPERTIES PREFIX "") -target_link_libraries(System.Globalization.Native - ${ICUUC} - ${ICUI18N} -) +if(NOT CLR_CMAKE_PLATFORM_DARWIN) + target_link_libraries(System.Globalization.Native + ${ICUUC} + ${ICUI18N} + ) +else() + target_link_libraries(System.Globalization.Native + ${ICUCORE} + ) + + add_definitions(-DU_DISABLE_RENAMING=1) +endif() install (TARGETS System.Globalization.Native DESTINATION .) diff --git a/src/corefx/System.Globalization.Native/calendarData.cpp b/src/corefx/System.Globalization.Native/calendarData.cpp index 98c3127549..c18bc9de8e 100644 --- a/src/corefx/System.Globalization.Native/calendarData.cpp +++ b/src/corefx/System.Globalization.Native/calendarData.cpp @@ -5,13 +5,10 @@ #include <assert.h> #include <string.h> +#include <vector> #include "locale.hpp" - -#include <unicode/dtfmtsym.h> -#include <unicode/smpdtfmt.h> -#include <unicode/dtptngen.h> -#include <unicode/locdspnm.h> +#include "holders.h" #define GREGORIAN_NAME "gregorian" #define JAPANESE_NAME "japanese" @@ -25,6 +22,10 @@ #define JAPANESE_LOCALE_AND_CALENDAR "ja_JP@calendar=japanese" +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 */ @@ -203,18 +204,20 @@ Returns the list of CalendarIds that are available for the specified locale. */ extern "C" int32_t GetCalendars(const UChar* localeName, CalendarId* calendars, int32_t calendarsCapacity) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + + if (U_FAILURE(err)) return 0; - UErrorCode err = U_ZERO_ERROR; - LocalPointer<StringEnumeration> stringEnumerator( - Calendar::getKeywordValuesForLocale("calendar", locale, TRUE, err)); + UEnumeration* pEnum = ucal_getKeywordValuesForLocale("calendar", locale, TRUE, &err); + UEnumerationHolder enumHolder(pEnum, err); - if (stringEnumerator.isNull() || U_FAILURE(err)) + if (U_FAILURE(err)) return 0; - int stringEnumeratorCount = stringEnumerator->count(err); + int stringEnumeratorCount = uenum_count(pEnum, &err); if (U_FAILURE(err)) return 0; @@ -222,7 +225,7 @@ extern "C" int32_t GetCalendars(const UChar* localeName, CalendarId* calendars, for (int i = 0; i < stringEnumeratorCount && calendarsReturned < calendarsCapacity; i++) { int32_t calendarNameLength = 0; - const char* calendarName = stringEnumerator->next(&calendarNameLength, err); + const char* calendarName = uenum_next(pEnum, &calendarNameLength, &err); if (U_SUCCESS(err)) { CalendarId calendarId = GetCalendarId(calendarName); @@ -243,18 +246,16 @@ GetMonthDayPattern Gets the Month-Day DateTime pattern for the specified locale. */ -CalendarDataResult GetMonthDayPattern(Locale& locale, UChar* sMonthDay, int32_t stringCapacity) +CalendarDataResult GetMonthDayPattern(const char* locale, UChar* sMonthDay, int32_t stringCapacity) { UErrorCode err = U_ZERO_ERROR; - LocalPointer<DateTimePatternGenerator> generator(DateTimePatternGenerator::createInstance(locale, err)); - if (U_FAILURE(err)) - return GetCalendarDataResult(err); + UDateTimePatternGenerator* pGenerator = udatpg_open(locale, &err); + UDateTimePatternGeneratorHolder generatorHolder(pGenerator, err); - UnicodeString monthDayPattern = generator->getBestPattern(UnicodeString(UDAT_MONTH_DAY), err); if (U_FAILURE(err)) return GetCalendarDataResult(err); - monthDayPattern.extract(sMonthDay, stringCapacity, err); + udatpg_getBestPattern(pGenerator, UDAT_MONTH_DAY_UCHAR, -1, sMonthDay, stringCapacity, &err); return GetCalendarDataResult(err); } @@ -266,15 +267,13 @@ GetNativeCalendarName Gets the native calendar name. */ CalendarDataResult -GetNativeCalendarName(Locale& locale, CalendarId calendarId, UChar* nativeName, int32_t stringCapacity) +GetNativeCalendarName(const char* locale, CalendarId calendarId, UChar* nativeName, int32_t stringCapacity) { - LocalPointer<LocaleDisplayNames> displayNames(LocaleDisplayNames::createInstance(locale)); - - UnicodeString calendarName; - displayNames->keyValueDisplayName("calendar", GetCalendarName(calendarId), calendarName); - UErrorCode err = U_ZERO_ERROR; - calendarName.extract(nativeName, stringCapacity, err); + ULocaleDisplayNames* pDisplayNames = uldn_open(locale, ULDN_STANDARD_NAMES, &err); + ULocaleDisplayNamesHolder displayNamesHolder(pDisplayNames, err); + + uldn_keyValueDisplayName(pDisplayNames, "calendar", GetCalendarName(calendarId), nativeName, stringCapacity, &err); return GetCalendarDataResult(err); } @@ -289,8 +288,11 @@ with the requested value. extern "C" CalendarDataResult GetCalendarInfo( const UChar* localeName, CalendarId calendarId, CalendarDataType dataType, UChar* result, int32_t resultCapacity) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + + if (U_FAILURE(err)) return UnknownError; switch (dataType) @@ -312,25 +314,31 @@ InvokeCallbackForDatePattern Gets the ICU date pattern for the specified locale and EStyle and invokes the callback with the result. */ -bool InvokeCallbackForDatePattern(Locale& locale, - DateFormat::EStyle style, +bool InvokeCallbackForDatePattern(const char* locale, + UDateFormatStyle style, EnumCalendarInfoCallback callback, const void* context) { - LocalPointer<DateFormat> dateFormat(DateFormat::createDateInstance(style, locale)); - if (dateFormat.isNull()) - return false; + UErrorCode err = U_ZERO_ERROR; + UDateFormat* pFormat = udat_open(UDAT_NONE, style, locale, nullptr, 0, nullptr, 0, &err); + UDateFormatHolder formatHolder(pFormat, err); - // cast to SimpleDateFormat so we can call toPattern() - SimpleDateFormat* sdf = dynamic_cast<SimpleDateFormat*>(dateFormat.getAlias()); - if (sdf == NULL) + if (U_FAILURE(err)) return false; - UnicodeString pattern; - sdf->toPattern(pattern); + UErrorCode ignore = U_ZERO_ERROR; + int32_t patternLen = udat_toPattern(pFormat, false, nullptr, 0, &ignore); - callback(pattern.getTerminatedBuffer(), context); - return true; + std::vector<UChar> pattern(patternLen + 1, '\0'); + + udat_toPattern(pFormat, false, pattern.data(), patternLen + 1, &err); + + if (U_SUCCESS(err)) + { + callback(pattern.data(), context); + } + + return U_SUCCESS(err); } /* @@ -340,141 +348,185 @@ InvokeCallbackForDateTimePattern Gets the DateTime pattern for the specified skeleton and invokes the callback with the retrieved value. */ -bool InvokeCallbackForDateTimePattern(Locale& locale, - const char* patternSkeleton, +bool InvokeCallbackForDateTimePattern(const char* locale, + const UChar* patternSkeleton, EnumCalendarInfoCallback callback, const void* context) { UErrorCode err = U_ZERO_ERROR; - LocalPointer<DateTimePatternGenerator> generator(DateTimePatternGenerator::createInstance(locale, err)); + UDateTimePatternGenerator* pGenerator = udatpg_open(locale, &err); + UDateTimePatternGeneratorHolder generatorHolder(pGenerator, err); + if (U_FAILURE(err)) return false; - UnicodeString pattern = generator->getBestPattern(UnicodeString(patternSkeleton), err); - if (U_SUCCESS(err)) - { - callback(pattern.getTerminatedBuffer(), context); - return true; - } + UErrorCode ignore = U_ZERO_ERROR; + int32_t patternLen = udatpg_getBestPattern(pGenerator, patternSkeleton, -1, nullptr, 0, &ignore); - return false; -} + std::vector<UChar> bestPattern(patternLen + 1, '\0'); -/* -Function: -EnumCalendarArray + udatpg_getBestPattern(pGenerator, patternSkeleton, -1, bestPattern.data(), patternLen + 1, &err); -Enumerates an array of strings and invokes the callback for each value. -*/ -bool EnumCalendarArray(const UnicodeString* srcArray, - int32_t srcArrayCount, - EnumCalendarInfoCallback callback, - const void* context) -{ - for (int i = 0; i < srcArrayCount; i++) + if (U_SUCCESS(err)) { - UnicodeString src = srcArray[i]; - callback(src.getTerminatedBuffer(), context); + callback(bestPattern.data(), context); } - return true; + return U_SUCCESS(err); } /* Function: -EnumWeekdays +EnumSymbols -Enumerates all the weekday names of the specified context and width, invoking -the callback function -for each weekday name. +Enumerates all of the symbols of a type for a locale and calendar and invokes a callback +for each value. */ -bool EnumWeekdays(Locale& locale, - CalendarId calendarId, - DateFormatSymbols::DtContextType dtContext, - DateFormatSymbols::DtWidthType dtWidth, - EnumCalendarInfoCallback callback, - const void* context) +bool EnumSymbols(const char* locale, + CalendarId calendarId, + UDateFormatSymbolType type, + int32_t startIndex, + EnumCalendarInfoCallback callback, + const void* context) { UErrorCode err = U_ZERO_ERROR; - DateFormatSymbols dateFormatSymbols(locale, GetCalendarName(calendarId), err); + UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, nullptr, 0, nullptr, 0, &err); + UDateFormatHolder formatHolder(pFormat, err); + if (U_FAILURE(err)) return false; - int32_t daysCount; - const UnicodeString* dayNames = dateFormatSymbols.getWeekdays(daysCount, dtContext, dtWidth); - - // ICU returns an empty string for the first/zeroth element in the weekdays - // array. - // So skip the first element. - dayNames++; - daysCount--; + char localeWithCalendarName[ULOC_FULLNAME_CAPACITY]; + strncpy(localeWithCalendarName, locale, ULOC_FULLNAME_CAPACITY); + uloc_setKeywordValue("calendar", GetCalendarName(calendarId), localeWithCalendarName, ULOC_FULLNAME_CAPACITY, &err); - return EnumCalendarArray(dayNames, daysCount, callback, context); -} + if (U_FAILURE(err)) + return false; -/* -Function: -EnumMonths + UCalendar* pCalendar = ucal_open(nullptr, 0, localeWithCalendarName, UCAL_DEFAULT, &err); + UCalendarHolder calendarHolder(pCalendar, err); -Enumerates all the month names of the specified context and width, invoking the -callback function -for each month name. -*/ -bool EnumMonths(Locale& locale, - CalendarId calendarId, - DateFormatSymbols::DtContextType dtContext, - DateFormatSymbols::DtWidthType dtWidth, - EnumCalendarInfoCallback callback, - const void* context) -{ - UErrorCode err = U_ZERO_ERROR; - DateFormatSymbols dateFormatSymbols(locale, GetCalendarName(calendarId), err); if (U_FAILURE(err)) return false; - int32_t monthsCount; - const UnicodeString* monthNames = dateFormatSymbols.getMonths(monthsCount, dtContext, dtWidth); - return EnumCalendarArray(monthNames, monthsCount, callback, context); + udat_setCalendar(pFormat, pCalendar); + + int32_t symbolCount = udat_countSymbols(pFormat, type); + + for (int32_t i = startIndex; i < symbolCount; i++) + { + UErrorCode ignore = U_ZERO_ERROR; + int symbolLen = udat_getSymbols(pFormat, type, i, nullptr, 0, &ignore); + + std::vector<UChar> symbolBuf(symbolLen + 1, '\0'); + + udat_getSymbols(pFormat, type, i, symbolBuf.data(), symbolBuf.size(), &err); + + assert(U_SUCCESS(err)); + + if (U_FAILURE(err)) + return false; + + callback(symbolBuf.data(), context); + } + + return true; +} + +bool EnumUResourceBundle(const UResourceBundle* bundle, EnumCalendarInfoCallback callback, const void* context) +{ + int32_t eraNameCount = ures_getSize(bundle); + + for (int i = 0; i < eraNameCount; i++) + { + UErrorCode status = U_ZERO_ERROR; + int32_t ignore; // We don't care about the length of the string as it is null terminated. + const UChar* eraName = ures_getStringByIndex(bundle, i, &ignore, &status); + + if (U_SUCCESS(status)) + { + callback(eraName, context); + } + } + + return true; } /* Function: -EnumEraNames +EnumAbbrevEraNames -Enumerates all the era names of the specified locale and calendar, invoking the -callback function -for each era name. +Enumerates all the abbreviated era names of the specified locale and calendar, invoking the +callback function for each era name. */ -bool EnumEraNames(Locale& locale, - CalendarId calendarId, - CalendarDataType dataType, - EnumCalendarInfoCallback callback, - const void* context) +bool EnumAbbrevEraNames(const char* locale, + CalendarId calendarId, + EnumCalendarInfoCallback callback, + const void* context) { - UErrorCode err = U_ZERO_ERROR; - const char* calendarName = GetCalendarName(calendarId); - DateFormatSymbols dateFormatSymbols(locale, calendarName, err); - if (U_FAILURE(err)) - return false; + // 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 + // find good data. + char localeNameBuf[ULOC_FULLNAME_CAPACITY]; + char parentNameBuf[ULOC_FULLNAME_CAPACITY]; - int32_t eraNameCount; - const UnicodeString* eraNames; + char* localeNamePtr = localeNameBuf; + char* parentNamePtr = parentNameBuf; - if (dataType == EraNames) - { - eraNames = dateFormatSymbols.getEras(eraNameCount); - } - else if (dataType == AbbrevEraNames) - { - eraNames = dateFormatSymbols.getNarrowEras(eraNameCount); - } - else + strncpy(localeNamePtr, locale, ULOC_FULLNAME_CAPACITY); + + while (true) { - assert(false); - return false; + UErrorCode status = U_ZERO_ERROR; + + 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); + + if (U_SUCCESS(status)) + { + EnumUResourceBundle(erasResBundle, callback, context); + return true; + } + + // Couldn't find the data we need for this locale, we should fallback. + if (localeNameBuf[0] == 0x0) + { + // We are already at the root locale so there is nothing to fall back to, just use the regular eras. + break; + } + + uloc_getParent(localeNamePtr, parentNamePtr, ULOC_FULLNAME_CAPACITY, &status); + + if (U_FAILURE(status)) + { + // Something bad happened getting the parent name, bail out. + break; + } + + // Swap localeNamePtr and parentNamePtr, parentNamePtr is what we want to use on the next iteration + // and we can use the current localeName as scratch space if we have to fall back on that + // iteration. + + char* temp = localeNamePtr; + localeNamePtr = parentNamePtr; + parentNamePtr = temp; } - return EnumCalendarArray(eraNames, eraNameCount, callback, context); + // Walking the resource bundles didn't work, just use the regular eras. + return EnumSymbols(locale, calendarId, UDAT_ERAS, 0, callback, context); } /* @@ -493,8 +545,11 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, CalendarDataType dataType, const void* context) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); + + if (U_FAILURE(err)) return false; switch (dataType) @@ -503,46 +558,40 @@ extern "C" int32_t EnumCalendarInfo(EnumCalendarInfoCallback callback, // 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 InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_NUM_MONTH_DAY, callback, context) && - InvokeCallbackForDatePattern(locale, DateFormat::kShort, callback, context) && - InvokeCallbackForDatePattern(locale, DateFormat::kMedium, callback, context); + return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_NUM_MONTH_DAY_UCHAR, callback, context) && + InvokeCallbackForDatePattern(locale, UDAT_SHORT, callback, context) && + InvokeCallbackForDatePattern(locale, UDAT_MEDIUM, callback, context); case LongDates: // LongDates map to kFull and kLong in ICU. - return InvokeCallbackForDatePattern(locale, DateFormat::kFull, callback, context) && - InvokeCallbackForDatePattern(locale, DateFormat::kLong, callback, context); + return InvokeCallbackForDatePattern(locale, UDAT_FULL, callback, context) && + InvokeCallbackForDatePattern(locale, UDAT_LONG, callback, context); case YearMonths: - return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH, callback, context); + return InvokeCallbackForDateTimePattern(locale, UDAT_YEAR_MONTH_UCHAR, callback, context); case DayNames: - return EnumWeekdays( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_WEEKDAYS, 1, callback, context); case AbbrevDayNames: - return EnumWeekdays( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_WEEKDAYS, 1, callback, context); case MonthNames: - return EnumMonths( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::WIDE, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_MONTHS, 0, callback, context); case AbbrevMonthNames: - return EnumMonths( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::ABBREVIATED, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORT_MONTHS, 0, callback, context); case SuperShortDayNames: -#ifdef HAVE_DTWIDTHTYPE_SHORT - return EnumWeekdays( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::SHORT, callback, context); + // 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. + +#ifdef HAVE_UDAT_STANDALONE_SHORTER_WEEKDAYS + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_SHORTER_WEEKDAYS, 1, callback, context); #else - // Currently CentOS-7 uses ICU-50 and ::SHORT was added in ICU-51, so use - // ::NARROW instead - return EnumWeekdays( - locale, calendarId, DateFormatSymbols::STANDALONE, DateFormatSymbols::NARROW, callback, context); + return EnumSymbols(locale, calendarId, UDAT_STANDALONE_NARROW_WEEKDAYS, 1, callback, context); #endif case MonthGenitiveNames: - return EnumMonths( - locale, calendarId, DateFormatSymbols::FORMAT, DateFormatSymbols::WIDE, callback, context); + return EnumSymbols(locale, calendarId, UDAT_MONTHS, 0, callback, context); case AbbrevMonthGenitiveNames: - return EnumMonths( - locale, calendarId, DateFormatSymbols::FORMAT, DateFormatSymbols::ABBREVIATED, callback, context); + return EnumSymbols(locale, calendarId, UDAT_SHORT_MONTHS, 0, callback, context); case EraNames: + return EnumSymbols(locale, calendarId, UDAT_ERAS, 0, callback, context); case AbbrevEraNames: - return EnumEraNames(locale, calendarId, dataType, callback, context); + return EnumAbbrevEraNames(locale, calendarId, callback, context); default: assert(false); return false; @@ -558,13 +607,15 @@ Gets the latest era in the Japanese calendar. extern "C" int32_t GetLatestJapaneseEra() { UErrorCode err = U_ZERO_ERROR; - Locale japaneseLocale(JAPANESE_LOCALE_AND_CALENDAR); - LocalPointer<Calendar> calendar(Calendar::createInstance(japaneseLocale, err)); + UCalendar* pCal = ucal_open(nullptr, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); + UCalendarHolder calHolder(pCal, err); if (U_FAILURE(err)) return 0; - return calendar->getMaximum(UCAL_ERA); + int32_t ret = ucal_getLimit(pCal, UCAL_ERA, UCAL_MAXIMUM, &err); + + return U_SUCCESS(err) ? ret : 0; } /* @@ -580,27 +631,28 @@ extern "C" int32_t GetJapaneseEraStartDate(int32_t era, int32_t* startYear, int3 *startDay = -1; UErrorCode err = U_ZERO_ERROR; - Locale japaneseLocale(JAPANESE_LOCALE_AND_CALENDAR); - LocalPointer<Calendar> calendar(Calendar::createInstance(japaneseLocale, err)); + UCalendar* pCal = ucal_open(nullptr, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err); + UCalendarHolder calHolder(pCal, err); + if (U_FAILURE(err)) return false; - calendar->set(UCAL_ERA, era); - calendar->set(UCAL_YEAR, 1); + ucal_set(pCal, UCAL_ERA, era); + ucal_set(pCal, UCAL_YEAR, 1); // UCAL_EXTENDED_YEAR is the gregorian year for the JapaneseCalendar - *startYear = calendar->get(UCAL_EXTENDED_YEAR, err); + *startYear = ucal_get(pCal, UCAL_EXTENDED_YEAR, &err); if (U_FAILURE(err)) return false; // set the date to Jan 1 - calendar->set(UCAL_MONTH, 0); - calendar->set(UCAL_DATE, 1); + ucal_set(pCal, UCAL_MONTH, 0); + ucal_set(pCal, UCAL_DATE, 1); int32_t currentEra; for (int i = 0; i <= 12; i++) { - currentEra = calendar->get(UCAL_ERA, err); + currentEra = ucal_get(pCal, UCAL_ERA, &err); if (U_FAILURE(err)) return false; @@ -609,27 +661,27 @@ extern "C" int32_t GetJapaneseEraStartDate(int32_t era, int32_t* startYear, int3 for (int i = 0; i < 31; i++) { // subtract 1 day at a time until we get out of the specified Era - calendar->add(Calendar::DATE, -1, err); + ucal_add(pCal, UCAL_DATE, -1, &err); if (U_FAILURE(err)) return false; - currentEra = calendar->get(UCAL_ERA, err); + currentEra = ucal_get(pCal, UCAL_ERA, &err); if (U_FAILURE(err)) return false; if (currentEra != era) { // add back 1 day to get back into the specified Era - calendar->add(UCAL_DATE, 1, err); + ucal_add(pCal, UCAL_DATE, 1, &err); if (U_FAILURE(err)) return false; *startMonth = - calendar->get(UCAL_MONTH, err) + 1; // ICU Calendar months are 0-based, but .NET is 1-based + 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 = calendar->get(UCAL_DATE, err); + *startDay = ucal_get(pCal, UCAL_DATE, &err); if (U_FAILURE(err)) return false; @@ -639,7 +691,7 @@ extern "C" int32_t GetJapaneseEraStartDate(int32_t era, int32_t* startYear, int3 } // add 1 month at a time until we get into the specified Era - calendar->add(UCAL_MONTH, 1, err); + ucal_add(pCal, UCAL_MONTH, 1, &err); if (U_FAILURE(err)) return false; } diff --git a/src/corefx/System.Globalization.Native/holders.h b/src/corefx/System.Globalization.Native/holders.h new file mode 100644 index 0000000000..4969726ed6 --- /dev/null +++ b/src/corefx/System.Globalization.Native/holders.h @@ -0,0 +1,103 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include <unicode/ucal.h> +#include <unicode/uenum.h> +#include <unicode/udatpg.h> +#include <unicode/udat.h> +#include <unicode/unum.h> +#include <unicode/uldnames.h> +#include <unicode/ures.h> + +// IcuHolder is a template that can manage the lifetime of a raw pointer to ensure that it is cleaned up at the correct +// time. The general usage pattern is to aquire some ICU resource via an _open call, then construct a holder using the +// pointer and UErrorCode to manage the lifetime. When the holder goes out of scope, the coresponding close method is +// called on the pointer. +template <typename T, typename Closer> +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<UCalendar, UCalendarCloser> UCalendarHolder; +typedef IcuHolder<UEnumeration, UEnumerationCloser> UEnumerationHolder; +typedef IcuHolder<UDateTimePatternGenerator, UDateTimePatternGeneratorCloser> UDateTimePatternGeneratorHolder; +typedef IcuHolder<UDateFormat, UDateFormatCloser> UDateFormatHolder; +typedef IcuHolder<UNumberFormat, UNumberFormatCloser> UNumberFormatHolder; +typedef IcuHolder<ULocaleDisplayNames, ULocaleDisplayNamesCloser> ULocaleDisplayNamesHolder; +typedef IcuHolder<UResourceBundle, UResourceBundleCloser> UResourceBundleHolder; diff --git a/src/corefx/System.Globalization.Native/locale.cpp b/src/corefx/System.Globalization.Native/locale.cpp index f71b68d554..6ae699a107 100644 --- a/src/corefx/System.Globalization.Native/locale.cpp +++ b/src/corefx/System.Globalization.Native/locale.cpp @@ -10,11 +10,6 @@ #include "locale.hpp" -#include "unicode/dcfmtsym.h" //decimal -#include "unicode/dtfmtsym.h" //date -#include "unicode/localpointer.h" -#include "unicode/ulocdata.h" - int32_t UErrorCodeToBool(UErrorCode status) { if (U_SUCCESS(status)) @@ -31,45 +26,76 @@ int32_t UErrorCodeToBool(UErrorCode status) return 0; } -Locale GetLocale(const UChar* localeName, bool canonize) +int32_t GetLocale( + const UChar* localeName, char* localeNameResult, int32_t localeNameResultLength, bool canonicalize, UErrorCode* err) { - char localeNameTemp[ULOC_FULLNAME_CAPACITY]; + char localeNameTemp[ULOC_FULLNAME_CAPACITY] = {0}; + int32_t localeLength; - if (localeName != NULL) + // 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++) { - // use UnicodeString.extract instead of u_UCharsToChars; u_UCharsToChars - // considers '@' a variant and stops - UnicodeString str(localeName, -1, ULOC_FULLNAME_CAPACITY); - str.extract(0, str.length(), localeNameTemp); + UChar c = localeName[i]; + + if (c > (UChar)0x7F) + { + *err = U_ILLEGAL_ARGUMENT_ERROR; + return ULOC_FULLNAME_CAPACITY; + } + + localeNameTemp[i] = (char)c; + + if (c == (UChar)0x0) + { + break; + } } - Locale loc; - if (canonize) + if (canonicalize) { - loc = Locale::createCanonical(localeName == NULL ? NULL : localeNameTemp); + localeLength = uloc_canonicalize(localeNameTemp, localeNameResult, localeNameResultLength, err); } else { - loc = Locale::createFromName(localeName == NULL ? NULL : localeNameTemp); + localeLength = uloc_getName(localeNameTemp, localeNameResult, localeNameResultLength, err); } - return loc; + if (U_SUCCESS(*err)) + { + // Make sure the "language" part of the locale is reasonable (i.e. we can fetch it and it is within range). + // This mimics how the C++ ICU API determines if a locale is "bogus" or not. + + char language[ULOC_LANG_CAPACITY]; + uloc_getLanguage(localeNameTemp, language, ULOC_LANG_CAPACITY, err); + + if (*err == U_STRING_NOT_TERMINATED_WARNING) + { + // ULOC_LANG_CAPACITY includes the null terminator, so if we couldn't extract the language with the null + // terminator, the language must be invalid. + + *err = U_ILLEGAL_ARGUMENT_ERROR; + } + } + + return localeLength; } UErrorCode u_charsToUChars_safe(const char* str, UChar* value, int32_t valueLength) { int len = strlen(str); + if (len >= valueLength) { return U_BUFFER_OVERFLOW_ERROR; } + u_charsToUChars(str, value, len + 1); return U_ZERO_ERROR; } -int FixupLocaleName(UChar* value, int32_t valueLength) +int32_t FixupLocaleName(UChar* value, int32_t valueLength) { - int i = 0; + int32_t i = 0; for (; i < valueLength; i++) { if (value[i] == (UChar)'\0') @@ -87,20 +113,19 @@ int FixupLocaleName(UChar* value, int32_t valueLength) extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength) { - Locale locale = GetLocale(localeName, true); - - if (locale.isBogus()) - { - // localeName not properly formatted - return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); - } + UErrorCode status = U_ZERO_ERROR; - // other validation done on managed side + char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, localeNameBuffer, ULOC_FULLNAME_CAPACITY, true, &status); - UErrorCode status = u_charsToUChars_safe(locale.getName(), value, valueLength); if (U_SUCCESS(status)) { - FixupLocaleName(value, valueLength); + status = u_charsToUChars_safe(localeNameBuffer, value, valueLength); + + if (U_SUCCESS(status)) + { + FixupLocaleName(value, valueLength); + } } return UErrorCodeToBool(status); @@ -108,29 +133,35 @@ extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t extern "C" int32_t GetDefaultLocaleName(UChar* value, int32_t valueLength) { - Locale locale = GetLocale(NULL); - if (locale.isBogus()) - { - // ICU should be able to get default locale - return UErrorCodeToBool(U_INTERNAL_PROGRAM_ERROR); - } + char localeNameBuffer[ULOC_FULLNAME_CAPACITY]; + UErrorCode status = U_ZERO_ERROR; + + const char* defaultLocale = uloc_getDefault(); + + uloc_getBaseName(defaultLocale, localeNameBuffer, ULOC_FULLNAME_CAPACITY, &status); - UErrorCode status = u_charsToUChars_safe(locale.getBaseName(), value, valueLength); if (U_SUCCESS(status)) { - int localeNameLen = FixupLocaleName(value, valueLength); + status = u_charsToUChars_safe(localeNameBuffer, value, valueLength); - // if collation is present, return that to managed side - char collationValueTemp[ULOC_KEYWORDS_CAPACITY]; - if (locale.getKeywordValue("collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, status) > 0) + if (U_SUCCESS(status)) { - // copy the collation; managed uses a "_" to represent collation (not - // "@collation=") - status = u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen); - if (U_SUCCESS(status)) + int localeNameLen = FixupLocaleName(value, valueLength); + + char collationValueTemp[ULOC_KEYWORDS_CAPACITY]; + int32_t collationLen = + uloc_getKeywordValue(defaultLocale, "collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, &status); + + if (U_SUCCESS(status) && collationLen > 0) { - status = u_charsToUChars_safe( - collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1); + // 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); + } } } } diff --git a/src/corefx/System.Globalization.Native/locale.hpp b/src/corefx/System.Globalization.Native/locale.hpp index 3ea1707c05..d6b61b7db6 100644 --- a/src/corefx/System.Globalization.Native/locale.hpp +++ b/src/corefx/System.Globalization.Native/locale.hpp @@ -27,9 +27,13 @@ int32_t UErrorCodeToBool(UErrorCode code); Function: GetLocale -Returns a locale given the locale name +Converts a managed localeName into something ICU understands and can use as a localeName. */ -Locale GetLocale(const UChar* localeName, bool canonize = false); +int32_t GetLocale(const UChar* localeName, + char* localeNameResult, + int32_t localeNameResultLength, + bool canonicalize, + UErrorCode* err); /* Function: diff --git a/src/corefx/System.Globalization.Native/localeNumberData.cpp b/src/corefx/System.Globalization.Native/localeNumberData.cpp index 01ace2977c..b7bb95a48c 100644 --- a/src/corefx/System.Globalization.Native/localeNumberData.cpp +++ b/src/corefx/System.Globalization.Native/localeNumberData.cpp @@ -6,14 +6,12 @@ #include <assert.h> #include <string.h> +#include <vector> -#include "locale.hpp" +#include <unicode/ulocdata.h> -#include "unicode/calendar.h" -#include "unicode/decimfmt.h" -#include "unicode/localpointer.h" -#include "unicode/numfmt.h" -#include "unicode/ulocdata.h" +#include "locale.hpp" +#include "holders.h" // invariant character definitions used by ICU #define UCHAR_CURRENCY ((UChar)0x00A4) // international currency @@ -63,7 +61,7 @@ NormalizeNumericPattern Returns a numeric string pattern in a format that we can match against the appropriate managed pattern. */ -void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* destPattern, bool isNegative) +std::string NormalizeNumericPattern(const UChar* srcPattern, bool isNegative) { // A srcPattern example: "#,##0.00 C;(#,##0.00 C)" but where C is the // international currency symbol (UCHAR_CURRENCY) @@ -71,11 +69,20 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des // separated by a semicolon // A destPattern example: "(C n)" where C represents the currency symbol, and // n is the number - destPattern->remove(); + std::string destPattern; int iStart = 0; - int iEnd = srcPattern->length() - 1; - int32_t iNegativePatternStart = srcPattern->indexOf(UCHAR_SEMICOLON); + int iEnd = u_strlen(srcPattern); + int32_t iNegativePatternStart = -1; + + for (int i = iStart; i < iEnd; i++) + { + if (srcPattern[i] == ';') + { + iNegativePatternStart = i; + } + } + if (iNegativePatternStart >= 0) { if (isNegative) @@ -95,14 +102,14 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des for (int i = iStart; i <= iEnd; i++) { - UChar ch = srcPattern->charAt(i); + UChar ch = srcPattern[i]; switch (ch) { case UCHAR_DIGIT: if (!digitAdded) { digitAdded = true; - destPattern->append('n'); + destPattern.push_back('n'); } break; @@ -110,7 +117,7 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des if (!currencyAdded) { currencyAdded = true; - destPattern->append('C'); + destPattern.push_back('C'); } break; @@ -119,7 +126,7 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des if (!spaceAdded) { spaceAdded = true; - destPattern->append(UCHAR_SPACE); + destPattern.push_back(' '); } else { @@ -131,11 +138,11 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des case UCHAR_OPENPAREN: case UCHAR_CLOSEPAREN: minusAdded = true; - destPattern->append(ch); + destPattern.push_back(static_cast<char>(ch)); break; case UCHAR_PERCENT: - destPattern->append(ch); + destPattern.push_back('%'); break; } } @@ -144,8 +151,10 @@ void NormalizeNumericPattern(const UnicodeString* srcPattern, UnicodeString* des // minus sign if (isNegative && !minusAdded) { - destPattern->insert(0, UCHAR_MINUS); + destPattern.insert(destPattern.begin(), '-'); } + + return destPattern; } /* @@ -156,30 +165,35 @@ 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(DecimalFormat* decimalFormat, const char* patterns[], int patternsCount, bool isNegative) +int GetNumericPattern(const UNumberFormat* pNumberFormat, const char* patterns[], int patternsCount, bool isNegative) { const int INVALID_FORMAT = -1; const int MAX_DOTNET_NUMERIC_PATTERN_LENGTH = 6; // example: "(C n)" plus terminator - char charPattern[MAX_DOTNET_NUMERIC_PATTERN_LENGTH] = {0}; - UnicodeString icuPattern; - decimalFormat->toPattern(icuPattern); + UErrorCode ignore = U_ZERO_ERROR; + int32_t icuPatternLength = unum_toPattern(pNumberFormat, false, nullptr, 0, &ignore); + + std::vector<UChar> icuPattern(icuPatternLength + 1, '\0'); + + UErrorCode err = U_ZERO_ERROR; - UnicodeString normalizedPattern; - NormalizeNumericPattern(&icuPattern, &normalizedPattern, isNegative); + unum_toPattern(pNumberFormat, false, icuPattern.data(), icuPattern.size(), &err); + + assert(U_SUCCESS(err)); + + std::string normalizedPattern = NormalizeNumericPattern(icuPattern.data(), isNegative); assert(normalizedPattern.length() > 0); assert(normalizedPattern.length() < MAX_DOTNET_NUMERIC_PATTERN_LENGTH); + if (normalizedPattern.length() == 0 || normalizedPattern.length() >= MAX_DOTNET_NUMERIC_PATTERN_LENGTH) { return INVALID_FORMAT; } - u_UCharsToChars(normalizedPattern.getTerminatedBuffer(), charPattern, normalizedPattern.length() + 1); - for (int i = 0; i < patternsCount; i++) { - if (strcmp(charPattern, patterns[i]) == 0) + if (strcmp(normalizedPattern.c_str(), patterns[i]) == 0) { return i; } @@ -196,7 +210,7 @@ GetCurrencyNegativePattern Implementation of NumberFormatInfo.CurrencyNegativePattern. Returns the pattern index. */ -int GetCurrencyNegativePattern(const Locale& locale) +int GetCurrencyNegativePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"(Cn)", @@ -217,19 +231,17 @@ int GetCurrencyNegativePattern(const Locale& locale) "(n C)"}; UErrorCode status = U_ZERO_ERROR; - LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_CURRENCY, status)); + UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale, nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true); - if (value >= 0) - { - return value; - } + return value; } } @@ -243,25 +255,23 @@ GetCurrencyPositivePattern Implementation of NumberFormatInfo.CurrencyPositivePattern. Returns the pattern index. */ -int GetCurrencyPositivePattern(const Locale& locale) +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; - LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_CURRENCY, status)); + UNumberFormat* pFormat = unum_open(UNUM_CURRENCY, nullptr, 0, locale, nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), false); - if (value >= 0) - { - return value; - } + return value; } } @@ -275,25 +285,23 @@ GetNumberNegativePattern Implementation of NumberFormatInfo.NumberNegativePattern. Returns the pattern index. */ -int GetNumberNegativePattern(const Locale& locale) +int GetNumberNegativePattern(const char* locale) { const int DEFAULT_VALUE = 1; static const char* Patterns[] = {"(n)", "-n", "- n", "n-", "n -"}; UErrorCode status = U_ZERO_ERROR; - LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_DECIMAL, status)); + UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true); - if (value >= 0) - { - return value; - } + return value; } } @@ -307,26 +315,24 @@ GetPercentNegativePattern Implementation of NumberFormatInfo.PercentNegativePattern. Returns the pattern index. */ -int GetPercentNegativePattern(const Locale& locale) +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; - LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_PERCENT, status)); + UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), true); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), true); - if (value >= 0) - { - return value; - } + return value; } } @@ -340,25 +346,23 @@ GetPercentPositivePattern Implementation of NumberFormatInfo.PercentPositivePattern. Returns the pattern index. */ -int GetPercentPositivePattern(const Locale& locale) +int GetPercentPositivePattern(const char* locale) { const int DEFAULT_VALUE = 0; static const char* Patterns[] = {"n %", "n%", "%n", "% n"}; UErrorCode status = U_ZERO_ERROR; - LocalPointer<NumberFormat> format(NumberFormat::createInstance(locale, UNUM_PERCENT, status)); + UNumberFormat* pFormat = unum_open(UNUM_PERCENT, nullptr, 0, locale, nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); + assert(U_SUCCESS(status)); + if (U_SUCCESS(status)) { - DecimalFormat* decimalFormat = dynamic_cast<DecimalFormat*>(format.getAlias()); - assert(decimalFormat != NULL); - if (decimalFormat != NULL) + int value = GetNumericPattern(pFormat, Patterns, ARRAY_LENGTH(Patterns), false); + if (value >= 0) { - int value = GetNumericPattern(decimalFormat, Patterns, ARRAY_LENGTH(Patterns), false); - if (value >= 0) - { - return value; - } + return value; } } @@ -372,11 +376,11 @@ GetMeasurementSystem Obtains the measurement system for the local, determining if US or metric. Returns 1 for US, 0 otherwise. */ -UErrorCode GetMeasurementSystem(const char* localeId, int32_t* value) +UErrorCode GetMeasurementSystem(const char* locale, int32_t* value) { UErrorCode status = U_ZERO_ERROR; - UMeasurementSystem measurementSystem = ulocdata_getMeasurementSystem(localeId, &status); + UMeasurementSystem measurementSystem = ulocdata_getMeasurementSystem(locale, &status); if (U_SUCCESS(status)) { *value = (measurementSystem == UMeasurementSystem::UMS_US) ? 1 : 0; @@ -394,25 +398,26 @@ Returns 1 for success, 0 otherwise */ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData localeNumberData, int32_t* value) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode status = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + + if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } - UErrorCode status = U_ZERO_ERROR; - switch (localeNumberData) { case LanguageId: - *value = locale.getLCID(); + *value = uloc_getLCID(locale); break; case MeasurementSystem: - status = GetMeasurementSystem(locale.getName(), value); + status = GetMeasurementSystem(locale, value); break; case FractionalDigitsCount: { - UNumberFormat* numformat = unum_open(UNUM_DECIMAL, NULL, 0, locale.getName(), NULL, &status); + UNumberFormat* numformat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS); @@ -425,7 +430,7 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo break; case MonetaryFractionalDigitsCount: { - UNumberFormat* numformat = unum_open(UNUM_CURRENCY, NULL, 0, locale.getName(), NULL, &status); + UNumberFormat* numformat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS); @@ -442,11 +447,13 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo case FirstWeekOfYear: { // corresponds to DateTimeFormat.CalendarWeekRule - LocalPointer<Calendar> calendar(Calendar::createInstance(locale, status)); + UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); + UCalendarHolder calHolder(pCal, status); + if (U_SUCCESS(status)) { // values correspond to LOCALE_IFIRSTWEEKOFYEAR - int minDaysInWeek = calendar->getMinimalDaysInFirstWeek(); + int minDaysInWeek = ucal_getAttribute(pCal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK); if (minDaysInWeek == 1) { *value = CalendarWeekRule::FirstDay; @@ -472,8 +479,8 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo // used in coreclr) // 0 - Left to right (such as en-US) // 1 - Right to left (such as arabic locales) - ULayoutType orientation = uloc_getCharacterOrientation(locale.getName(), &status); - // alternative implementation in ICU 54+ is Locale.isRightToLeft() which + ULayoutType orientation = uloc_getCharacterOrientation(locale, &status); + // alternative implementation in ICU 54+ is uloc_isRightToLeft() which // also supports script tags in locale if (U_SUCCESS(status)) { @@ -483,10 +490,12 @@ extern "C" int32_t GetLocaleInfoInt(const UChar* localeName, LocaleNumberData lo } case FirstDayofWeek: { - LocalPointer<Calendar> pcalendar(Calendar::createInstance(locale, status)); + UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status); + UCalendarHolder calHolder(pCal, status); + if (U_SUCCESS(status)) { - *value = pcalendar->getFirstDayOfWeek(status) - 1; // .NET is 0-based and ICU is 1-based + *value = ucal_getAttribute(pCal, UCAL_FIRST_DAY_OF_WEEK) - 1; // .NET is 0-based and ICU is 1-based } break; } @@ -517,8 +526,11 @@ extern "C" int32_t GetLocaleInfoGroupingSizes(const UChar* localeName, int32_t* primaryGroupSize, int32_t* secondaryGroupSize) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode status = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + + if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } @@ -536,8 +548,7 @@ extern "C" int32_t GetLocaleInfoGroupingSizes(const UChar* localeName, return UErrorCodeToBool(U_UNSUPPORTED_ERROR); } - UErrorCode status = U_ZERO_ERROR; - UNumberFormat* numformat = unum_open(style, NULL, 0, locale.getName(), NULL, &status); + UNumberFormat* numformat = unum_open(style, NULL, 0, locale, NULL, &status); if (U_SUCCESS(status)) { *primaryGroupSize = unum_getAttribute(numformat, UNUM_GROUPING_SIZE); diff --git a/src/corefx/System.Globalization.Native/localeStringData.cpp b/src/corefx/System.Globalization.Native/localeStringData.cpp index bfe04697ea..8e115129c2 100644 --- a/src/corefx/System.Globalization.Native/localeStringData.cpp +++ b/src/corefx/System.Globalization.Native/localeStringData.cpp @@ -6,17 +6,10 @@ #include <assert.h> #include <string.h> +#include <vector> #include "locale.hpp" - -#include "unicode/dcfmtsym.h" //decimal symbols -#include "unicode/dtfmtsym.h" //date symbols -#include "unicode/smpdtfmt.h" //date format -#include "unicode/localpointer.h" - -// invariant character definitions used by ICU -#define UCHAR_SPACE ((UChar)0x0020) // space -#define UCHAR_NBSPACE ((UChar)0x00A0) // space +#include "holders.h" // Enum that corresponds to managed enum CultureData.LocaleStringData. // The numeric values of the enum members match their Win32 counterparts. @@ -57,26 +50,20 @@ GetLocaleInfoDecimalFormatSymbol Obtains the value of a DecimalFormatSymbols */ -UErrorCode GetLocaleInfoDecimalFormatSymbol(const Locale& locale, - DecimalFormatSymbols::ENumberFormatSymbol symbol, - UChar* value, - int32_t valueLength) +UErrorCode +GetLocaleInfoDecimalFormatSymbol(const char* locale, UNumberFormatSymbol symbol, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; - LocalPointer<DecimalFormatSymbols> decimalsymbols(new DecimalFormatSymbols(locale, status)); - if (decimalsymbols == NULL) - { - status = U_MEMORY_ALLOCATION_ERROR; - } + UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status); + UNumberFormatHolder formatHolder(pFormat, status); if (U_FAILURE(status)) { return status; } - UnicodeString s = decimalsymbols->getSymbol(symbol); + unum_getSymbol(pFormat, symbol, value, valueLength, &status); - s.extract(value, valueLength, status); return status; } @@ -86,9 +73,9 @@ GetDigitSymbol Obtains the value of a Digit DecimalFormatSymbols */ -UErrorCode GetDigitSymbol(const Locale& locale, +UErrorCode GetDigitSymbol(const char* locale, UErrorCode previousStatus, - DecimalFormatSymbols::ENumberFormatSymbol symbol, + UNumberFormatSymbol symbol, int digit, UChar* value, int32_t valueLength) @@ -105,31 +92,69 @@ UErrorCode GetDigitSymbol(const Locale& locale, Function: GetLocaleInfoAmPm -Obtains the value of a DateFormatSymbols Am or Pm string +Obtains the value of the AM or PM string for a locale. */ -UErrorCode GetLocaleInfoAmPm(const Locale& locale, bool am, UChar* value, int32_t valueLength) +UErrorCode GetLocaleInfoAmPm(const char* locale, bool am, UChar* value, int32_t valueLength) { UErrorCode status = U_ZERO_ERROR; - LocalPointer<DateFormatSymbols> dateFormatSymbols(new DateFormatSymbols(locale, status)); - if (dateFormatSymbols == NULL) - { - status = U_MEMORY_ALLOCATION_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; } - int32_t count = 0; - const UnicodeString* tempStr = dateFormatSymbols->getAmPmStrings(count); - int offset = am ? 0 : 1; - if (offset >= count) + udat_getSymbols(pFormat, UDAT_AM_PMS, am ? 0 : 1, value, valueLength, &status); + + return status; +} + +/* +Function: +GetLocaleIso639LanguageName + +Gets the language name for a locale (via uloc_getLanguage) and converts the result to UChars +*/ +UErrorCode GetLocaleIso639LanguageName(const char* locale, UChar* value, int32_t valueLength) +{ + UErrorCode status = U_ZERO_ERROR; + int32_t length = uloc_getLanguage(locale, nullptr, 0, &status); + + std::vector<char> buf(length + 1, '\0'); + status = U_ZERO_ERROR; + + uloc_getLanguage(locale, buf.data(), length + 1, &status); + + if (U_SUCCESS(status)) + { + status = u_charsToUChars_safe(buf.data(), value, valueLength); + } + + return status; +} + +/* +Function: +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) +{ + UErrorCode status = U_ZERO_ERROR; + int32_t length = uloc_getCountry(locale, nullptr, 0, &status); + + std::vector<char> buf(length + 1, '\0'); + status = U_ZERO_ERROR; + + uloc_getCountry(locale, buf.data(), length + 1, &status); + + if (U_SUCCESS(status)) { - return U_INTERNAL_PROGRAM_ERROR; + status = u_charsToUChars_safe(buf.data(), value, valueLength); } - tempStr[offset].extract(value, valueLength, status); return status; } @@ -143,85 +168,71 @@ Returns 1 for success, 0 otherwise extern "C" int32_t GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, UChar* value, int32_t valueLength) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) + UErrorCode status = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status); + + if (U_FAILURE(status)) { return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } - UnicodeString str; - UErrorCode status = U_ZERO_ERROR; switch (localeStringData) { case LocalizedDisplayName: - locale.getDisplayName(str); - str.extract(value, valueLength, status); + uloc_getDisplayName(locale, uloc_getDefault(), value, valueLength, &status); break; case EnglishDisplayName: - locale.getDisplayName(Locale::getEnglish(), str); - str.extract(value, valueLength, status); + uloc_getDisplayName(locale, ULOC_ENGLISH, value, valueLength, &status); break; case NativeDisplayName: - locale.getDisplayName(locale, str); - str.extract(value, valueLength, status); + uloc_getDisplayName(locale, locale, value, valueLength, &status); break; case LocalizedLanguageName: - locale.getDisplayLanguage(str); - str.extract(value, valueLength, status); + uloc_getDisplayLanguage(locale, uloc_getDefault(), value, valueLength, &status); break; case EnglishLanguageName: - locale.getDisplayLanguage(Locale::getEnglish(), str); - str.extract(value, valueLength, status); + uloc_getDisplayLanguage(locale, ULOC_ENGLISH, value, valueLength, &status); break; case NativeLanguageName: - locale.getDisplayLanguage(locale, str); - str.extract(value, valueLength, status); + uloc_getDisplayLanguage(locale, locale, value, valueLength, &status); break; case EnglishCountryName: - locale.getDisplayCountry(Locale::getEnglish(), str); - str.extract(value, valueLength, status); + uloc_getDisplayCountry(locale, ULOC_ENGLISH, value, valueLength, &status); break; case NativeCountryName: - locale.getDisplayCountry(locale, str); - str.extract(value, valueLength, status); + uloc_getDisplayCountry(locale, locale, value, valueLength, &status); break; case ListSeparator: // fall through case ThousandSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale, DecimalFormatSymbols::kGroupingSeparatorSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case DecimalSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale, DecimalFormatSymbols::kDecimalSeparatorSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength); break; case Digits: - status = GetDigitSymbol(locale, status, DecimalFormatSymbols::kZeroDigitSymbol, 0, value, valueLength); - // symbols kOneDigitSymbol to kNineDigitSymbol are contiguous - for (int32_t symbol = DecimalFormatSymbols::kOneDigitSymbol; - symbol <= DecimalFormatSymbols::kNineDigitSymbol; - symbol++) + 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 - DecimalFormatSymbols::kOneDigitSymbol + 1; + int charIndex = symbol - UNUM_ONE_DIGIT_SYMBOL + 1; status = GetDigitSymbol( - locale, status, (DecimalFormatSymbols::ENumberFormatSymbol)symbol, charIndex, value, valueLength); + locale, status, static_cast<UNumberFormatSymbol>(symbol), charIndex, value, valueLength); } break; case MonetarySymbol: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kCurrencySymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_CURRENCY_SYMBOL, value, valueLength); break; case Iso4217MonetarySymbol: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kIntlCurrencySymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength); break; case MonetaryDecimalSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale, DecimalFormatSymbols::kMonetarySeparatorSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength); break; case MonetaryThousandSeparator: - status = GetLocaleInfoDecimalFormatSymbol( - locale, DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol, value, valueLength); + status = + GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; case AMDesignator: status = GetLocaleInfoAmPm(locale, true, value, valueLength); @@ -230,27 +241,22 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, status = GetLocaleInfoAmPm(locale, false, value, valueLength); break; case PositiveSign: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kPlusSignSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PLUS_SIGN_SYMBOL, value, valueLength); break; case NegativeSign: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kMinusSignSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength); break; case Iso639LanguageName: - status = u_charsToUChars_safe(locale.getLanguage(), value, valueLength); + status = GetLocaleIso639LanguageName(locale, value, valueLength); break; case Iso3166CountryName: - // coreclr expects 2-character version, not 3 (3 would correspond to - // LOCALE_SISO3166CTRYNAME2 and locale.getISO3Country) - status = u_charsToUChars_safe(locale.getCountry(), value, valueLength); + status = GetLocaleIso3166CountryName(locale, value, valueLength); break; case NaNSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kNaNSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength); break; case PositiveInfinitySymbol: - status = - GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kInfinitySymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INFINITY_SYMBOL, value, valueLength); break; case ParentName: { @@ -258,7 +264,7 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, // including invariant locale char localeNameTemp[ULOC_FULLNAME_CAPACITY]; - uloc_getParent(locale.getName(), localeNameTemp, ULOC_FULLNAME_CAPACITY, &status); + uloc_getParent(locale, localeNameTemp, ULOC_FULLNAME_CAPACITY, &status); if (U_SUCCESS(status)) { status = u_charsToUChars_safe(localeNameTemp, value, valueLength); @@ -270,10 +276,10 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, break; } case PercentSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kPercentSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERCENT_SYMBOL, value, valueLength); break; case PerMilleSymbol: - status = GetLocaleInfoDecimalFormatSymbol(locale, DecimalFormatSymbols::kPerMillSymbol, value, valueLength); + status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERMILL_SYMBOL, value, valueLength); break; default: status = U_UNSUPPORTED_ERROR; @@ -284,85 +290,31 @@ GetLocaleInfoString(const UChar* localeName, LocaleStringData localeStringData, } /* -Function: -NormalizeTimePattern - -Convert an ICU non-localized time pattern to .NET format -*/ -void NormalizeTimePattern(const UnicodeString* srcPattern, UnicodeString* destPattern) -{ - // An srcPattern example: "h:mm:ss a" - // A destPattern example: "h:mm:ss tt" - destPattern->remove(); - - bool amPmAdded = false; - for (int i = 0; i <= srcPattern->length() - 1; i++) - { - UChar ch = srcPattern->charAt(i); - switch (ch) - { - case ':': - case '.': - case 'H': - case 'h': - case 'm': - case 's': - destPattern->append(ch); - break; - - case UCHAR_SPACE: - case UCHAR_NBSPACE: - destPattern->append(UCHAR_SPACE); - break; - - case 'a': // AM/PM - if (!amPmAdded) - { - amPmAdded = true; - destPattern->append("tt"); - } - break; - } - } -} - -/* PAL Function: GetLocaleTimeFormat -Obtains time format information. +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 GetLocaleTimeFormat(const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength) { - Locale locale = GetLocale(localeName); - if (locale.isBogus()) - { - return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); - } - - DateFormat::EStyle style = (shortFormat != 0) ? DateFormat::kShort : DateFormat::kMedium; - LocalPointer<DateFormat> dateFormat(DateFormat::createTimeInstance(style, locale)); - if (dateFormat == NULL || !dateFormat.isValid()) - { - return UErrorCodeToBool(U_MEMORY_ALLOCATION_ERROR); - } + UErrorCode err = U_ZERO_ERROR; + char locale[ULOC_FULLNAME_CAPACITY]; + GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err); - // cast to SimpleDateFormat so we can call toPattern() - SimpleDateFormat* sdf = dynamic_cast<SimpleDateFormat*>(dateFormat.getAlias()); - if (sdf == NULL) + if (U_FAILURE(err)) { - return UErrorCodeToBool(U_INTERNAL_PROGRAM_ERROR); + return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR); } - UnicodeString icuPattern; - sdf->toPattern(icuPattern); + 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); - UnicodeString dotnetPattern; - NormalizeTimePattern(&icuPattern, &dotnetPattern); + if (U_FAILURE(err)) + return UErrorCodeToBool(err); - UErrorCode status = U_ZERO_ERROR; - dotnetPattern.extract(value, valueLength, status); + udat_toPattern(pFormat, false, value, valueLength, &err); - return UErrorCodeToBool(status); + return UErrorCodeToBool(err); } |