1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5
6#include <assert.h>
7#include <string.h>
8#include <vector>
9
10#include "icushim.h"
11#include "locale.hpp"
12#include "holders.h"
13
14// Enum that corresponds to managed enum CultureData.LocaleStringData.
15// The numeric values of the enum members match their Win32 counterparts.
16enum LocaleStringData : int32_t
17{
18 LocalizedDisplayName = 0x00000002,
19 EnglishDisplayName = 0x00000072,
20 NativeDisplayName = 0x00000073,
21 LocalizedLanguageName = 0x0000006f,
22 EnglishLanguageName = 0x00001001,
23 NativeLanguageName = 0x00000004,
24 EnglishCountryName = 0x00001002,
25 NativeCountryName = 0x00000008,
26 ListSeparator = 0x0000000C,
27 DecimalSeparator = 0x0000000E,
28 ThousandSeparator = 0x0000000F,
29 Digits = 0x00000013,
30 MonetarySymbol = 0x00000014,
31 CurrencyEnglishName = 0x00001007,
32 CurrencyNativeName = 0x00001008,
33 Iso4217MonetarySymbol = 0x00000015,
34 MonetaryDecimalSeparator = 0x00000016,
35 MonetaryThousandSeparator = 0x00000017,
36 AMDesignator = 0x00000028,
37 PMDesignator = 0x00000029,
38 PositiveSign = 0x00000050,
39 NegativeSign = 0x00000051,
40 Iso639LanguageTwoLetterName = 0x00000059,
41 Iso639LanguageThreeLetterName = 0x00000067,
42 Iso3166CountryName = 0x0000005A,
43 Iso3166CountryName2= 0x00000068,
44 NaNSymbol = 0x00000069,
45 PositiveInfinitySymbol = 0x0000006a,
46 ParentName = 0x0000006d,
47 PercentSymbol = 0x00000076,
48 PerMilleSymbol = 0x00000077
49};
50
51/*
52Function:
53GetLocaleInfoDecimalFormatSymbol
54
55Obtains the value of a DecimalFormatSymbols
56*/
57UErrorCode
58GetLocaleInfoDecimalFormatSymbol(const char* locale, UNumberFormatSymbol symbol, UChar* value, int32_t valueLength)
59{
60 UErrorCode status = U_ZERO_ERROR;
61 UNumberFormat* pFormat = unum_open(UNUM_DECIMAL, nullptr, 0, locale, nullptr, &status);
62 UNumberFormatHolder formatHolder(pFormat, status);
63
64 if (U_FAILURE(status))
65 {
66 return status;
67 }
68
69 unum_getSymbol(pFormat, symbol, value, valueLength, &status);
70
71 return status;
72}
73
74/*
75Function:
76GetDigitSymbol
77
78Obtains the value of a Digit DecimalFormatSymbols
79*/
80UErrorCode GetDigitSymbol(const char* locale,
81 UErrorCode previousStatus,
82 UNumberFormatSymbol symbol,
83 int digit,
84 UChar* value,
85 int32_t valueLength)
86{
87 if (U_FAILURE(previousStatus))
88 {
89 return previousStatus;
90 }
91
92 return GetLocaleInfoDecimalFormatSymbol(locale, symbol, value + digit, valueLength - digit);
93}
94
95/*
96Function:
97GetLocaleInfoAmPm
98
99Obtains the value of the AM or PM string for a locale.
100*/
101UErrorCode GetLocaleInfoAmPm(const char* locale, bool am, UChar* value, int32_t valueLength)
102{
103 UErrorCode status = U_ZERO_ERROR;
104 UDateFormat* pFormat = udat_open(UDAT_DEFAULT, UDAT_DEFAULT, locale, nullptr, 0, nullptr, 0, &status);
105 UDateFormatHolder formatHolder(pFormat, status);
106
107 if (U_FAILURE(status))
108 {
109 return status;
110 }
111
112 udat_getSymbols(pFormat, UDAT_AM_PMS, am ? 0 : 1, value, valueLength, &status);
113
114 return status;
115}
116
117/*
118Function:
119GetLocaleIso639LanguageTwoLetterName
120
121Gets the language name for a locale (via uloc_getLanguage) and converts the result to UChars
122*/
123UErrorCode GetLocaleIso639LanguageTwoLetterName(const char* locale, UChar* value, int32_t valueLength)
124{
125 UErrorCode status = U_ZERO_ERROR;
126 int32_t length = uloc_getLanguage(locale, nullptr, 0, &status);
127
128 std::vector<char> buf(length + 1, '\0');
129 status = U_ZERO_ERROR;
130
131 uloc_getLanguage(locale, buf.data(), length + 1, &status);
132
133 if (U_SUCCESS(status))
134 {
135 status = u_charsToUChars_safe(buf.data(), value, valueLength);
136 }
137
138 return status;
139}
140
141/*
142Function:
143GetLocaleIso639LanguageThreeLetterName
144
145Gets the language name for a locale (via uloc_getISO3Language) and converts the result to UChars
146*/
147UErrorCode GetLocaleIso639LanguageThreeLetterName(const char* locale, UChar* value, int32_t valueLength)
148{
149 const char *isoLanguage = uloc_getISO3Language(locale);
150 if (isoLanguage[0] == 0)
151 {
152 return U_ILLEGAL_ARGUMENT_ERROR;
153 }
154
155 return u_charsToUChars_safe(isoLanguage, value, valueLength);
156}
157
158/*
159Function:
160GetLocaleIso3166CountryName
161
162Gets the country name for a locale (via uloc_getCountry) and converts the result to UChars
163*/
164UErrorCode GetLocaleIso3166CountryName(const char* locale, UChar* value, int32_t valueLength)
165{
166 UErrorCode status = U_ZERO_ERROR;
167 int32_t length = uloc_getCountry(locale, nullptr, 0, &status);
168
169 std::vector<char> buf(length + 1, '\0');
170 status = U_ZERO_ERROR;
171
172 uloc_getCountry(locale, buf.data(), length + 1, &status);
173
174 if (U_SUCCESS(status))
175 {
176 status = u_charsToUChars_safe(buf.data(), value, valueLength);
177 }
178
179 return status;
180}
181
182/*
183Function:
184GetLocaleIso3166CountryCode
185
186Gets the 3 letter country code for a locale (via uloc_getISO3Country) and converts the result to UChars
187*/
188UErrorCode GetLocaleIso3166CountryCode(const char* locale, UChar* value, int32_t valueLength)
189{
190 const char *pIsoCountryName = uloc_getISO3Country(locale);
191 int len = strlen(pIsoCountryName);
192
193 if (len == 0)
194 {
195 return U_ILLEGAL_ARGUMENT_ERROR;
196 }
197
198 return u_charsToUChars_safe(pIsoCountryName, value, valueLength);
199}
200
201/*
202Function:
203GetLocaleCurrencyName
204
205Gets the locale currency English or native name and convert the result to UChars
206*/
207UErrorCode GetLocaleCurrencyName(const char* locale, bool nativeName, UChar* value, int32_t valueLength)
208{
209 UErrorCode status = U_ZERO_ERROR;
210
211 UChar currencyThreeLettersName[4]; // 3 letters currency iso name + NULL
212 ucurr_forLocale(locale, currencyThreeLettersName, 4, &status);
213 if (!U_SUCCESS(status))
214 {
215 return status;
216 }
217
218 int32_t len;
219 UBool formatChoice;
220 const UChar *pCurrencyLongName = ucurr_getName(
221 currencyThreeLettersName,
222 nativeName ? locale : ULOC_US,
223 UCURR_LONG_NAME,
224 &formatChoice,
225 &len,
226 &status);
227 if (!U_SUCCESS(status))
228 {
229 return status;
230 }
231
232 if (len >= valueLength) // we need to have room for NULL too
233 {
234 return U_BUFFER_OVERFLOW_ERROR;
235 }
236 u_strncpy(value, pCurrencyLongName, len);
237 value[len] = 0;
238
239 return status;
240}
241
242/*
243PAL Function:
244GetLocaleInfoString
245
246Obtains string locale information.
247Returns 1 for success, 0 otherwise
248*/
249extern "C" int32_t GlobalizationNative_GetLocaleInfoString(
250 const UChar* localeName, LocaleStringData localeStringData, UChar* value, int32_t valueLength)
251{
252 UErrorCode status = U_ZERO_ERROR;
253 char locale[ULOC_FULLNAME_CAPACITY];
254 GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &status);
255
256 if (U_FAILURE(status))
257 {
258 return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
259 }
260
261 switch (localeStringData)
262 {
263 case LocalizedDisplayName:
264 uloc_getDisplayName(locale, DetectDefaultLocaleName(), value, valueLength, &status);
265 break;
266 case EnglishDisplayName:
267 uloc_getDisplayName(locale, ULOC_ENGLISH, value, valueLength, &status);
268 break;
269 case NativeDisplayName:
270 uloc_getDisplayName(locale, locale, value, valueLength, &status);
271 break;
272 case LocalizedLanguageName:
273 uloc_getDisplayLanguage(locale, DetectDefaultLocaleName(), value, valueLength, &status);
274 break;
275 case EnglishLanguageName:
276 uloc_getDisplayLanguage(locale, ULOC_ENGLISH, value, valueLength, &status);
277 break;
278 case NativeLanguageName:
279 uloc_getDisplayLanguage(locale, locale, value, valueLength, &status);
280 break;
281 case EnglishCountryName:
282 uloc_getDisplayCountry(locale, ULOC_ENGLISH, value, valueLength, &status);
283 break;
284 case NativeCountryName:
285 uloc_getDisplayCountry(locale, locale, value, valueLength, &status);
286 break;
287 case ListSeparator:
288 // fall through
289 case ThousandSeparator:
290 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength);
291 break;
292 case DecimalSeparator:
293 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_DECIMAL_SEPARATOR_SYMBOL, value, valueLength);
294 break;
295 case Digits:
296 status = GetDigitSymbol(locale, status, UNUM_ZERO_DIGIT_SYMBOL, 0, value, valueLength);
297 // symbols UNUM_ONE_DIGIT to UNUM_NINE_DIGIT are contiguous
298 for (int32_t symbol = UNUM_ONE_DIGIT_SYMBOL; symbol <= UNUM_NINE_DIGIT_SYMBOL; symbol++)
299 {
300 int charIndex = symbol - UNUM_ONE_DIGIT_SYMBOL + 1;
301 status = GetDigitSymbol(
302 locale, status, static_cast<UNumberFormatSymbol>(symbol), charIndex, value, valueLength);
303 }
304 break;
305 case MonetarySymbol:
306 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_CURRENCY_SYMBOL, value, valueLength);
307 break;
308 case Iso4217MonetarySymbol:
309 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INTL_CURRENCY_SYMBOL, value, valueLength);
310 break;
311 case CurrencyEnglishName:
312 status = GetLocaleCurrencyName(locale, false, value, valueLength);
313 break;
314 case CurrencyNativeName:
315 status = GetLocaleCurrencyName(locale, true, value, valueLength);
316 break;
317 case MonetaryDecimalSeparator:
318 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_SEPARATOR_SYMBOL, value, valueLength);
319 break;
320 case MonetaryThousandSeparator:
321 status =
322 GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, value, valueLength);
323 break;
324 case AMDesignator:
325 status = GetLocaleInfoAmPm(locale, true, value, valueLength);
326 break;
327 case PMDesignator:
328 status = GetLocaleInfoAmPm(locale, false, value, valueLength);
329 break;
330 case PositiveSign:
331 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PLUS_SIGN_SYMBOL, value, valueLength);
332 break;
333 case NegativeSign:
334 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_MINUS_SIGN_SYMBOL, value, valueLength);
335 break;
336 case Iso639LanguageTwoLetterName:
337 status = GetLocaleIso639LanguageTwoLetterName(locale, value, valueLength);
338 break;
339 case Iso639LanguageThreeLetterName:
340 status = GetLocaleIso639LanguageThreeLetterName(locale, value, valueLength);
341 break;
342 case Iso3166CountryName:
343 status = GetLocaleIso3166CountryName(locale, value, valueLength);
344 break;
345 case Iso3166CountryName2:
346 status = GetLocaleIso3166CountryCode(locale, value, valueLength);
347 break;
348 case NaNSymbol:
349 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_NAN_SYMBOL, value, valueLength);
350 break;
351 case PositiveInfinitySymbol:
352 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_INFINITY_SYMBOL, value, valueLength);
353 break;
354 case ParentName:
355 {
356 // ICU supports lang[-script][-region][-variant] so up to 4 parents
357 // including invariant locale
358 char localeNameTemp[ULOC_FULLNAME_CAPACITY];
359
360 uloc_getParent(locale, localeNameTemp, ULOC_FULLNAME_CAPACITY, &status);
361 if (U_SUCCESS(status))
362 {
363 status = u_charsToUChars_safe(localeNameTemp, value, valueLength);
364 if (U_SUCCESS(status))
365 {
366 FixupLocaleName(value, valueLength);
367 }
368 }
369 break;
370 }
371 case PercentSymbol:
372 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERCENT_SYMBOL, value, valueLength);
373 break;
374 case PerMilleSymbol:
375 status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_PERMILL_SYMBOL, value, valueLength);
376 break;
377 default:
378 status = U_UNSUPPORTED_ERROR;
379 break;
380 };
381
382 return UErrorCodeToBool(status);
383}
384
385/*
386PAL Function:
387GetLocaleTimeFormat
388
389Obtains time format information (in ICU format, it needs to be coverted to .NET Format).
390Returns 1 for success, 0 otherwise
391*/
392extern "C" int32_t GlobalizationNative_GetLocaleTimeFormat(
393 const UChar* localeName, int shortFormat, UChar* value, int32_t valueLength)
394{
395 UErrorCode err = U_ZERO_ERROR;
396 char locale[ULOC_FULLNAME_CAPACITY];
397 GetLocale(localeName, locale, ULOC_FULLNAME_CAPACITY, false, &err);
398
399 if (U_FAILURE(err))
400 {
401 return UErrorCodeToBool(U_ILLEGAL_ARGUMENT_ERROR);
402 }
403
404 UDateFormatStyle style = (shortFormat != 0) ? UDAT_SHORT : UDAT_MEDIUM;
405 UDateFormat* pFormat = udat_open(style, UDAT_NONE, locale, nullptr, 0, nullptr, 0, &err);
406 UDateFormatHolder formatHolder(pFormat, err);
407
408 if (U_FAILURE(err))
409 return UErrorCodeToBool(err);
410
411 udat_toPattern(pFormat, false, value, valueLength, &err);
412
413 return UErrorCodeToBool(err);
414}
415