/*
PAL Function:
GetLocaleInfoGroupingSizes

Obtains grouping sizes for decimal and currency
Returns 1 for success, 0 otherwise
*/
extern "C" int32_t GlobalizationNative_GetLocaleInfoGroupingSizes(
    const UChar* localeName, LocaleNumberData localeGroupingData, int32_t* primaryGroupSize, int32_t* secondaryGroupSize)
{
    UErrorCode status = U_ZERO_ERROR;
    char locale[ULOC_FULLNAME_CAPACITY];
    GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status);

    if (U_FAILURE(status))
    {
        return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
    }

    UNumberFormatStyle style;
    switch (localeGroupingData)
    {
    case Digit:
        style = UNUM_DECIMAL;
        break;
    case Monetary:
        style = UNUM_CURRENCY;
        break;
    default:
        return UErrorCodeToBool(U_UNSUPPORTED_ERROR);
    }

    UNumberFormat* numformat = unum_open(style, NULL, 0, locale, NULL, &status);
    if (U_SUCCESS(status))
    {
        *primaryGroupSize = unum_getAttribute(numformat, UNUM_GROUPING_SIZE);
        *secondaryGroupSize = unum_getAttribute(numformat, UNUM_SECONDARY_GROUPING_SIZE);
        unum_close(numformat);
    }

    return UErrorCodeToBool(status);
}
/*
Function:
InvokeCallbackForDateTimePattern

Gets the DateTime pattern for the specified skeleton and invokes the callback
with the retrieved value.
*/
static int InvokeCallbackForDateTimePattern(const char* locale,
                                            const UChar* patternSkeleton,
                                            EnumCalendarInfoCallback callback,
                                            const void* context)
{
    UErrorCode err = U_ZERO_ERROR;
    UDateTimePatternGenerator* pGenerator = udatpg_open(locale, &err);

    if (U_FAILURE(err))
        return FALSE;

    UErrorCode ignore = U_ZERO_ERROR;
    int32_t patternLen = udatpg_getBestPattern(pGenerator, patternSkeleton, -1, NULL, 0, &ignore) + 1;

    UChar* bestPattern = calloc(patternLen, sizeof(UChar));
    if (bestPattern == NULL)
    {
        udatpg_close(pGenerator);
        return FALSE;
    }

    udatpg_getBestPattern(pGenerator, patternSkeleton, -1, bestPattern, patternLen, &err);
    udatpg_close(pGenerator);

    if (U_SUCCESS(err))
    {
        callback(bestPattern, context);
    }

    free(bestPattern);
    return UErrorCodeToBool(err);
}
/*
Function:
InvokeCallbackForDatePattern

Gets the ICU date pattern for the specified locale and EStyle and invokes the
callback with the result.
*/
static int InvokeCallbackForDatePattern(const char* locale,
                                        UDateFormatStyle style,
                                        EnumCalendarInfoCallback callback,
                                        const void* context)
{
    UErrorCode err = U_ZERO_ERROR;
    UDateFormat* pFormat = udat_open(UDAT_NONE, style, locale, NULL, 0, NULL, 0, &err);

    if (U_FAILURE(err))
        return FALSE;

    UErrorCode ignore = U_ZERO_ERROR;
    int32_t patternLen = udat_toPattern(pFormat, FALSE, NULL, 0, &ignore) + 1;

    UChar* pattern = calloc(patternLen, sizeof(UChar));
    if (pattern == NULL)
    {
        udat_close(pFormat);
        return FALSE;
    }

    udat_toPattern(pFormat, FALSE, pattern, patternLen, &err);
    udat_close(pFormat);

    if (U_SUCCESS(err))
    {
        callback(pattern, context);
    }

    free(pattern);
    return UErrorCodeToBool(err);
}
Exemple #4
0
int32_t GlobalizationNative_GetDefaultLocaleName(UChar* value, int32_t valueLength)
{
    char localeNameBuffer[ULOC_FULLNAME_CAPACITY];
    UErrorCode status = U_ZERO_ERROR;

    const char* defaultLocale = DetectDefaultLocaleName();

    uloc_getBaseName(defaultLocale, localeNameBuffer, ULOC_FULLNAME_CAPACITY, &status);
    u_charsToUChars_safe(localeNameBuffer, value, valueLength, &status);

    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)
        {
            // copy the collation; managed uses a "_" to represent collation (not
            // "@collation=")
            u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen, &status);
            u_charsToUChars_safe(collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1, &status);
        }
    }

    return UErrorCodeToBool(status);
}
Exemple #5
0
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);
	}

	// other validation done on managed side

	UErrorCode status = u_charsToUChars_safe(locale.getName(), value, valueLength);
	if (U_SUCCESS(status))
	{
		FixupLocaleName(value, valueLength);
	}

	return UErrorCodeToBool(status);
}
/*
PAL Function:
GetLocaleTimeFormat

Obtains time format information (in ICU format, it needs to be coverted to .NET Format).
Returns 1 for success, 0 otherwise
*/
extern "C" int32_t GetLocaleTimeFormat(const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength)
{
    UErrorCode err = U_ZERO_ERROR;
    char locale[ULOC_FULLNAME_CAPACITY];
    GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err);

    if (U_FAILURE(err))
    {
        return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
    }

    UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM;
    UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, nullptr, 0, nullptr, 0, &err);
    UDateFormatHolder formatHolder(pFormat, err);

    if (U_FAILURE(err))
        return UErrorCodeToBool(err);

    udat_toPattern(pFormat, false, value, valueLength, &err);

    return UErrorCodeToBool(err);
}
/*
PAL Function:
GetLocaleTimeFormat

Obtains time format information (in ICU format, it needs to be coverted to .NET Format).
Returns 1 for success, 0 otherwise
*/
int32_t GlobalizationNative_GetLocaleTimeFormat(const UChar* localeName,
                                                int shortFormat,
                                                UChar* value,
                                                int32_t valueLength)
{
    UErrorCode err = U_ZERO_ERROR;
    char locale[ULOC_FULLNAME_CAPACITY];
    GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &err);
    UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM;
    UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, NULL, 0, NULL, 0, &err);
    udat_toPattern(pFormat, FALSE, value, valueLength, &err);
    udat_close(pFormat);
    return UErrorCodeToBool(err);
}
Exemple #8
0
int32_t GlobalizationNative_GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength)
{
    UErrorCode status = U_ZERO_ERROR;

    char localeNameBuffer[ULOC_FULLNAME_CAPACITY];
    GetLocale(localeName, localeNameBuffer, ULOC_FULLNAME_CAPACITY, TRUE, &status);
    u_charsToUChars_safe(localeNameBuffer, value, valueLength, &status);

    if (U_SUCCESS(status))
    {
        FixupLocaleName(value, valueLength);
    }

    return UErrorCodeToBool(status);
}
/*
PAL Function:
GetLocaleInfoString

Obtains string locale information.
Returns 1 for success, 0 otherwise
*/
int32_t GlobalizationNative_GetLocaleInfoString(const UChar* localeName,
                                                LocaleStringData localeStringData,
                                                UChar* value,
                                                int32_t valueLength)
{
    UErrorCode status = U_ZERO_ERROR;
    char locale[ULOC_FULLNAME_CAPACITY];
    GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, FALSE, &status);

    if (U_FAILURE(status))
    {
        return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
    }

    switch (localeStringData)
    {
        case LocaleString_LocalizedDisplayName:
            uloc_getDisplayName(locale, DetectDefaultLocaleName(), value, valueLength, &status);
            break;
        case LocaleString_EnglishDisplayName:
            uloc_getDisplayName(locale, ULOC_ENGLISH, value, valueLength, &status);
            break;
        case LocaleString_NativeDisplayName:
            uloc_getDisplayName(locale, locale, value, valueLength, &status);
            break;
        case LocaleString_LocalizedLanguageName:
            uloc_getDisplayLanguage(locale, DetectDefaultLocaleName(), value, valueLength, &status);
            break;
        case LocaleString_EnglishLanguageName:
            uloc_getDisplayLanguage(locale, ULOC_ENGLISH, value, valueLength, &status);
            break;
        case LocaleString_NativeLanguageName:
            uloc_getDisplayLanguage(locale, locale, value, valueLength, &status);
            break;
        case LocaleString_EnglishCountryName:
            uloc_getDisplayCountry(locale, ULOC_ENGLISH, value, valueLength, &status);
            break;
        case LocaleString_NativeCountryName:
            uloc_getDisplayCountry(locale, locale, value, valueLength, &status);
            break;
        case LocaleString_ListSeparator:
        // fall through
        case LocaleString_ThousandSeparator:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength);
            break;
        case LocaleString_DecimalSeparator:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength);
            break;
        case LocaleString_Digits:
            status = GetDigitSymbol(locale, status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength);
            // symbols UNUM_ONE_DIGIT to UNUM_NINE_DIGIT are contiguous
            for (int32_t symbol = UNUM_ONE_DIGIT_SYMBOL; symbol <= UNUM_NINE_DIGIT_SYMBOL; symbol++)
            {
                int charIndex = symbol - UNUM_ONE_DIGIT_SYMBOL + 1;
                status = GetDigitSymbol(
                    locale, status, (UNumberFormatSymbol)symbol, charIndex, value, valueLength);
            }
            break;
        case LocaleString_MonetarySymbol:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_CURRENCY_SYMBOL, value, valueLength);
            break;
        case LocaleString_Iso4217MonetarySymbol:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength);
            break;
        case LocaleString_CurrencyEnglishName:
            status = GetLocaleCurrencyName(locale, FALSE, value, valueLength);
            break;
        case LocaleString_CurrencyNativeName:
            status = GetLocaleCurrencyName(locale, TRUE, value, valueLength);
            break;
        case LocaleString_MonetaryDecimalSeparator:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength);
            break;
        case LocaleString_MonetaryThousandSeparator:
            status =
                GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength);
            break;
        case LocaleString_AMDesignator:
            status = GetLocaleInfoAmPm(locale, TRUE, value, valueLength);
            break;
        case LocaleString_PMDesignator:
            status = GetLocaleInfoAmPm(locale, FALSE, value, valueLength);
            break;
        case LocaleString_PositiveSign:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PLUS_SIGN_SYMBOL, value, valueLength);
            break;
        case LocaleString_NegativeSign:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength);
            break;
        case LocaleString_Iso639LanguageTwoLetterName:
            status = GetLocaleIso639LanguageTwoLetterName(locale, value, valueLength);
            break;
        case LocaleString_Iso639LanguageThreeLetterName:
            status = GetLocaleIso639LanguageThreeLetterName(locale, value, valueLength);
            break;
        case LocaleString_Iso3166CountryName:
            status = GetLocaleIso3166CountryName(locale, value, valueLength);
            break;
        case LocaleString_Iso3166CountryName2:
            status = GetLocaleIso3166CountryCode(locale, value, valueLength);
            break;
        case LocaleString_NaNSymbol:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength);
            break;
        case LocaleString_PositiveInfinitySymbol:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INFINITY_SYMBOL, value, valueLength);
            break;
        case LocaleString_ParentName:
        {
            // ICU supports lang[-script][-region][-variant] so up to 4 parents
            // including invariant locale
            char localeNameTemp[ULOC_FULLNAME_CAPACITY];

            uloc_getParent(locale, localeNameTemp, ULOC_FULLNAME_CAPACITY, &status);
            u_charsToUChars_safe(localeNameTemp, value, valueLength, &status);
            if (U_SUCCESS(status))
            {
                FixupLocaleName(value, valueLength);
            }
            break;
        }
        case LocaleString_PercentSymbol:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERCENT_SYMBOL, value, valueLength);
            break;
        case LocaleString_PerMilleSymbol:
            status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERMILL_SYMBOL, value, valueLength);
            break;
        default:
            status = U_UNSUPPORTED_ERROR;
            break;
    };

    return UErrorCodeToBool(status);
}
/*
Function:
GetJapaneseEraInfo

Gets the starting Gregorian date of the specified Japanese Era.
*/
int32_t GlobalizationNative_GetJapaneseEraStartDate(int32_t era,
                                                    int32_t* startYear,
                                                    int32_t* startMonth,
                                                    int32_t* startDay)
{
    *startYear = -1;
    *startMonth = -1;
    *startDay = -1;

    UErrorCode err = U_ZERO_ERROR;
    UCalendar* pCal = ucal_open(NULL, 0, JAPANESE_LOCALE_AND_CALENDAR, UCAL_TRADITIONAL, &err);

    if (U_FAILURE(err))
        return FALSE;

    ucal_set(pCal, UCAL_ERA, era);
    ucal_set(pCal, UCAL_YEAR, 1);

    // UCAL_EXTENDED_YEAR is the gregorian year for the JapaneseCalendar
    *startYear = ucal_get(pCal, UCAL_EXTENDED_YEAR, &err);
    if (U_FAILURE(err))
    {
        ucal_close(pCal);
        return FALSE;
    }

    // set the date to Jan 1
    ucal_set(pCal, UCAL_MONTH, 0);
    ucal_set(pCal, UCAL_DATE, 1);

    int32_t currentEra;
    for (int i = 0; U_SUCCESS(err) && i <= 12; i++)
    {
        currentEra = ucal_get(pCal, UCAL_ERA, &err);
        if (currentEra == era)
        {
            for (int i = 0; U_SUCCESS(err) && i < 31; i++)
            {
                // subtract 1 day at a time until we get out of the specified Era
                ucal_add(pCal, UCAL_DATE, -1, &err);
                currentEra = ucal_get(pCal, UCAL_ERA, &err);
                if (U_SUCCESS(err) && currentEra != era)
                {
                    // add back 1 day to get back into the specified Era
                    ucal_add(pCal, UCAL_DATE, 1, &err);
                    *startMonth =
                        ucal_get(pCal, UCAL_MONTH, &err) + 1; // ICU Calendar months are 0-based, but .NET is 1-based
                    *startDay = ucal_get(pCal, UCAL_DATE, &err);
                    ucal_close(pCal);

                    return UErrorCodeToBool(err);
                }
            }
        }

        // add 1 month at a time until we get into the specified Era
        ucal_add(pCal, UCAL_MONTH, 1, &err);
    }

    ucal_close(pCal);
    return FALSE;
}
/*
Function:
EnumSymbols

Enumerates all of the symbols of a type for a locale and calendar and invokes a callback
for each value.
*/
static int32_t EnumSymbols(const char* locale,
                           CalendarId calendarId,
                           UDateFormatSymbolType type,
                           int32_t startIndex,
                           EnumCalendarInfoCallback callback,
                           const void* context)
{
    UErrorCode err = U_ZERO_ERROR;
    UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, NULL, 0, NULL, 0, &err);

    if (U_FAILURE(err))
        return FALSE;

    char localeWithCalendarName[ULOC_FULLNAME_CAPACITY];
    strncpy(localeWithCalendarName, locale, ULOC_FULLNAME_CAPACITY);
    uloc_setKeywordValue("calendar", GetCalendarName(calendarId), localeWithCalendarName, ULOC_FULLNAME_CAPACITY, &err);

    UCalendar* pCalendar = ucal_open(NULL, 0, localeWithCalendarName, UCAL_DEFAULT, &err);

    if (U_FAILURE(err))
    {
        udat_close(pFormat);
        return FALSE;
    }

    udat_setCalendar(pFormat, pCalendar);

    int32_t symbolCount = udat_countSymbols(pFormat, type);
    UChar stackSymbolBuf[100];
    UChar* symbolBuf;

    for (int32_t i = startIndex; U_SUCCESS(err) && i < symbolCount; i++)
    {
        UErrorCode ignore = U_ZERO_ERROR;
        int symbolLen = udat_getSymbols(pFormat, type, i, NULL, 0, &ignore) + 1;

        if (symbolLen <= sizeof(stackSymbolBuf) / sizeof(stackSymbolBuf[0]))
        {
            symbolBuf = stackSymbolBuf;
        }
        else
        {
            symbolBuf = calloc(symbolLen, sizeof(UChar));
            if (symbolBuf == NULL)
            {
                err = U_MEMORY_ALLOCATION_ERROR;
                break;
            }
        }

        udat_getSymbols(pFormat, type, i, symbolBuf, symbolLen, &err);

        if (U_SUCCESS(err))
        {
            callback(symbolBuf, context);
        }

        if (symbolBuf != stackSymbolBuf)
        {
            free(symbolBuf);
        }
    }

    udat_close(pFormat);
    ucal_close(pCalendar);
    return UErrorCodeToBool(err);
}
/*
PAL Function:
GetLocaleInfoInt

Obtains integer locale information
Returns 1 for success, 0 otherwise
*/
extern "C" int32_t GlobalizationNative_GetLocaleInfoInt(
    const UChar* localeName, LocaleNumberData localeNumberData, int32_t* value)
{
    UErrorCode status = U_ZERO_ERROR;
    char locale[ULOC_FULLNAME_CAPACITY];
    GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status);

    if (U_FAILURE(status))
    {
        return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
    }

    switch (localeNumberData)
    {
    case LanguageId:
        *value = uloc_getLCID(locale);
        break;
    case MeasurementSystem:
        status = GetMeasurementSystem(locale, value);
        break;
    case FractionalDigitsCount:
    {
        UNumberFormat* numformat = unum_open(UNUM_DECIMAL, NULL, 0, locale, NULL, &status);
        if (U_SUCCESS(status))
        {
            *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS);
            unum_close(numformat);
        }
        break;
    }
    case NegativeNumberFormat:
        *value = GetNumberNegativePattern(locale);
        break;
    case MonetaryFractionalDigitsCount:
    {
        UNumberFormat* numformat = unum_open(UNUM_CURRENCY, NULL, 0, locale, NULL, &status);
        if (U_SUCCESS(status))
        {
            *value = unum_getAttribute(numformat, UNUM_MAX_FRACTION_DIGITS);
            unum_close(numformat);
        }
        break;
    }
    case PositiveMonetaryNumberFormat:
        *value = GetCurrencyPositivePattern(locale);
        break;
    case NegativeMonetaryNumberFormat:
        *value = GetCurrencyNegativePattern(locale);
        break;
    case FirstWeekOfYear:
    {
        // corresponds to DateTimeFormat.CalendarWeekRule
        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 = ucal_getAttribute(pCal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK);
            if (minDaysInWeek == 1)
            {
                *value = CalendarWeekRule::FirstDay;
            }
            else if (minDaysInWeek == 7)
            {
                *value = CalendarWeekRule::FirstFullWeek;
            }
            else if (minDaysInWeek >= 4)
            {
                *value = CalendarWeekRule::FirstFourDayWeek;
            }
            else
            {
                status = U_UNSUPPORTED_ERROR;
            }
        }
        break;
    }
    case ReadingLayout:
    {
        // coresponds to values 0 and 1 in LOCALE_IREADINGLAYOUT (values 2 and 3 not
        // used in coreclr)
        //  0 - Left to right (such as en-US)
        //  1 - Right to left (such as arabic locales)
        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))
        {
            *value = (orientation == ULOC_LAYOUT_RTL) ? 1 : 0;
        }
        break;
    }
    case FirstDayofWeek:
    {
        UCalendar* pCal = ucal_open(nullptr, 0, locale, UCAL_TRADITIONAL, &status);
        UCalendarHolder calHolder(pCal, status);

        if (U_SUCCESS(status))
        {
            *value = ucal_getAttribute(pCal, UCAL_FIRST_DAY_OF_WEEK) - 1; // .NET is 0-based and ICU is 1-based
        }
        break;
    }
    case NegativePercentFormat:
        *value = GetPercentNegativePattern(locale);
        break;
    case PositivePercentFormat:
        *value = GetPercentPositivePattern(locale);
        break;
    default:
        status = U_UNSUPPORTED_ERROR;
        assert(false);
        break;
    }

    return UErrorCodeToBool(status);
}