summaryrefslogtreecommitdiff
path: root/src/corefx
diff options
context:
space:
mode:
authorMatt Ellis <matell@microsoft.com>2015-10-25 17:29:03 -0700
committerMatt Ellis <matell@microsoft.com>2015-10-25 17:29:03 -0700
commite93beb1f04fd028cd373bf601acbe7803a444cca (patch)
tree9934d3b05dbf7dd42f56479833d9be5d5d422563 /src/corefx
parentf7ea5660a87e491841c1e49bf799d00898e728ca (diff)
parent392f5f43475843a8dc417ef84b88e855e91f909e (diff)
downloadcoreclr-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.txt71
-rw-r--r--src/corefx/System.Globalization.Native/calendarData.cpp408
-rw-r--r--src/corefx/System.Globalization.Native/holders.h103
-rw-r--r--src/corefx/System.Globalization.Native/locale.cpp123
-rw-r--r--src/corefx/System.Globalization.Native/locale.hpp8
-rw-r--r--src/corefx/System.Globalization.Native/localeNumberData.cpp203
-rw-r--r--src/corefx/System.Globalization.Native/localeStringData.cpp262
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);
}