1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 **********************************************************************
5 * Copyright (C) 1997-2016, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
8 *
9 * File locid.cpp
10 *
11 * Created by: Richard Gillam
12 *
13 * Modification History:
14 *
15 * Date Name Description
16 * 02/11/97 aliu Changed gLocPath to fgDataDirectory and added
17 * methods to get and set it.
18 * 04/02/97 aliu Made operator!= inline; fixed return value
19 * of getName().
20 * 04/15/97 aliu Cleanup for AIX/Win32.
21 * 04/24/97 aliu Numerous changes per code review.
22 * 08/18/98 stephen Changed getDisplayName()
23 * Added SIMPLIFIED_CHINESE, TRADITIONAL_CHINESE
24 * Added getISOCountries(), getISOLanguages(),
25 * getLanguagesForCountry()
26 * 03/16/99 bertrand rehaul.
27 * 07/21/99 stephen Added U_CFUNC setDefault
28 * 11/09/99 weiv Added const char * getName() const;
29 * 04/12/00 srl removing unicodestring api's and cached hash code
30 * 08/10/01 grhoten Change the static Locales to accessor functions
31 ******************************************************************************
32 */
33
34 #include <utility>
35
36 #include "unicode/bytestream.h"
37 #include "unicode/locid.h"
38 #include "unicode/strenum.h"
39 #include "unicode/stringpiece.h"
40 #include "unicode/uloc.h"
41 #include "putilimp.h"
42 #include "mutex.h"
43 #include "umutex.h"
44 #include "uassert.h"
45 #include "cmemory.h"
46 #include "cstring.h"
47 #include "uassert.h"
48 #include "uhash.h"
49 #include "ulocimp.h"
50 #include "ucln_cmn.h"
51 #include "ustr_imp.h"
52 #include "charstr.h"
53 #include "bytesinkutil.h"
54
55 U_CDECL_BEGIN
56 static UBool U_CALLCONV locale_cleanup(void);
57 U_CDECL_END
58
59 U_NAMESPACE_BEGIN
60
61 static Locale *gLocaleCache = NULL;
62 static UInitOnce gLocaleCacheInitOnce = U_INITONCE_INITIALIZER;
63
64 // gDefaultLocaleMutex protects all access to gDefaultLocalesHashT and gDefaultLocale.
65 static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER;
66 static UHashtable *gDefaultLocalesHashT = NULL;
67 static Locale *gDefaultLocale = NULL;
68
69 /**
70 * \def ULOC_STRING_LIMIT
71 * strings beyond this value crash in CharString
72 */
73 #define ULOC_STRING_LIMIT 357913941
74
75 U_NAMESPACE_END
76
77 typedef enum ELocalePos {
78 eENGLISH,
79 eFRENCH,
80 eGERMAN,
81 eITALIAN,
82 eJAPANESE,
83 eKOREAN,
84 eCHINESE,
85
86 eFRANCE,
87 eGERMANY,
88 eITALY,
89 eJAPAN,
90 eKOREA,
91 eCHINA, /* Alias for PRC */
92 eTAIWAN,
93 eUK,
94 eUS,
95 eCANADA,
96 eCANADA_FRENCH,
97 eROOT,
98
99
100 //eDEFAULT,
101 eMAX_LOCALES
102 } ELocalePos;
103
104 U_CFUNC int32_t locale_getKeywords(const char *localeID,
105 char prev,
106 char *keywords, int32_t keywordCapacity,
107 char *values, int32_t valuesCapacity, int32_t *valLen,
108 UBool valuesToo,
109 UErrorCode *status);
110
111 U_CDECL_BEGIN
112 //
113 // Deleter function for Locales owned by the default Locale hash table/
114 //
115 static void U_CALLCONV
deleteLocale(void * obj)116 deleteLocale(void *obj) {
117 delete (icu::Locale *) obj;
118 }
119
locale_cleanup(void)120 static UBool U_CALLCONV locale_cleanup(void)
121 {
122 U_NAMESPACE_USE
123
124 delete [] gLocaleCache;
125 gLocaleCache = NULL;
126 gLocaleCacheInitOnce.reset();
127
128 if (gDefaultLocalesHashT) {
129 uhash_close(gDefaultLocalesHashT); // Automatically deletes all elements, using deleter func.
130 gDefaultLocalesHashT = NULL;
131 }
132 gDefaultLocale = NULL;
133 return TRUE;
134 }
135
136
locale_init(UErrorCode & status)137 static void U_CALLCONV locale_init(UErrorCode &status) {
138 U_NAMESPACE_USE
139
140 U_ASSERT(gLocaleCache == NULL);
141 gLocaleCache = new Locale[(int)eMAX_LOCALES];
142 if (gLocaleCache == NULL) {
143 status = U_MEMORY_ALLOCATION_ERROR;
144 return;
145 }
146 ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
147 gLocaleCache[eROOT] = Locale("");
148 gLocaleCache[eENGLISH] = Locale("en");
149 gLocaleCache[eFRENCH] = Locale("fr");
150 gLocaleCache[eGERMAN] = Locale("de");
151 gLocaleCache[eITALIAN] = Locale("it");
152 gLocaleCache[eJAPANESE] = Locale("ja");
153 gLocaleCache[eKOREAN] = Locale("ko");
154 gLocaleCache[eCHINESE] = Locale("zh");
155 gLocaleCache[eFRANCE] = Locale("fr", "FR");
156 gLocaleCache[eGERMANY] = Locale("de", "DE");
157 gLocaleCache[eITALY] = Locale("it", "IT");
158 gLocaleCache[eJAPAN] = Locale("ja", "JP");
159 gLocaleCache[eKOREA] = Locale("ko", "KR");
160 gLocaleCache[eCHINA] = Locale("zh", "CN");
161 gLocaleCache[eTAIWAN] = Locale("zh", "TW");
162 gLocaleCache[eUK] = Locale("en", "GB");
163 gLocaleCache[eUS] = Locale("en", "US");
164 gLocaleCache[eCANADA] = Locale("en", "CA");
165 gLocaleCache[eCANADA_FRENCH] = Locale("fr", "CA");
166 }
167
168 U_CDECL_END
169
170 U_NAMESPACE_BEGIN
171
locale_set_default_internal(const char * id,UErrorCode & status)172 Locale *locale_set_default_internal(const char *id, UErrorCode& status) {
173 // Synchronize this entire function.
174 Mutex lock(&gDefaultLocaleMutex);
175
176 UBool canonicalize = FALSE;
177
178 // If given a NULL string for the locale id, grab the default
179 // name from the system.
180 // (Different from most other locale APIs, where a null name means use
181 // the current ICU default locale.)
182 if (id == NULL) {
183 id = uprv_getDefaultLocaleID(); // This function not thread safe? TODO: verify.
184 canonicalize = TRUE; // always canonicalize host ID
185 }
186
187 char localeNameBuf[512];
188
189 if (canonicalize) {
190 uloc_canonicalize(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
191 } else {
192 uloc_getName(id, localeNameBuf, sizeof(localeNameBuf)-1, &status);
193 }
194 localeNameBuf[sizeof(localeNameBuf)-1] = 0; // Force null termination in event of
195 // a long name filling the buffer.
196 // (long names are truncated.)
197 //
198 if (U_FAILURE(status)) {
199 return gDefaultLocale;
200 }
201
202 if (gDefaultLocalesHashT == NULL) {
203 gDefaultLocalesHashT = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
204 if (U_FAILURE(status)) {
205 return gDefaultLocale;
206 }
207 uhash_setValueDeleter(gDefaultLocalesHashT, deleteLocale);
208 ucln_common_registerCleanup(UCLN_COMMON_LOCALE, locale_cleanup);
209 }
210
211 Locale *newDefault = (Locale *)uhash_get(gDefaultLocalesHashT, localeNameBuf);
212 if (newDefault == NULL) {
213 newDefault = new Locale(Locale::eBOGUS);
214 if (newDefault == NULL) {
215 status = U_MEMORY_ALLOCATION_ERROR;
216 return gDefaultLocale;
217 }
218 newDefault->init(localeNameBuf, FALSE);
219 uhash_put(gDefaultLocalesHashT, (char*) newDefault->getName(), newDefault, &status);
220 if (U_FAILURE(status)) {
221 return gDefaultLocale;
222 }
223 }
224 gDefaultLocale = newDefault;
225 return gDefaultLocale;
226 }
227
228 U_NAMESPACE_END
229
230 /* sfb 07/21/99 */
231 U_CFUNC void
locale_set_default(const char * id)232 locale_set_default(const char *id)
233 {
234 U_NAMESPACE_USE
235 UErrorCode status = U_ZERO_ERROR;
236 locale_set_default_internal(id, status);
237 }
238 /* end */
239
240 U_CFUNC const char *
locale_get_default(void)241 locale_get_default(void)
242 {
243 U_NAMESPACE_USE
244 return Locale::getDefault().getName();
245 }
246
247
248 U_NAMESPACE_BEGIN
249
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)250 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Locale)
251
252 /*Character separating the posix id fields*/
253 // '_'
254 // In the platform codepage.
255 #define SEP_CHAR '_'
256
257 Locale::~Locale()
258 {
259 if (baseName != fullName) {
260 uprv_free(baseName);
261 }
262 baseName = NULL;
263 /*if fullName is on the heap, we free it*/
264 if (fullName != fullNameBuffer)
265 {
266 uprv_free(fullName);
267 fullName = NULL;
268 }
269 }
270
Locale()271 Locale::Locale()
272 : UObject(), fullName(fullNameBuffer), baseName(NULL)
273 {
274 init(NULL, FALSE);
275 }
276
277 /*
278 * Internal constructor to allow construction of a locale object with
279 * NO side effects. (Default constructor tries to get
280 * the default locale.)
281 */
Locale(Locale::ELocaleType)282 Locale::Locale(Locale::ELocaleType)
283 : UObject(), fullName(fullNameBuffer), baseName(NULL)
284 {
285 setToBogus();
286 }
287
288
Locale(const char * newLanguage,const char * newCountry,const char * newVariant,const char * newKeywords)289 Locale::Locale( const char * newLanguage,
290 const char * newCountry,
291 const char * newVariant,
292 const char * newKeywords)
293 : UObject(), fullName(fullNameBuffer), baseName(NULL)
294 {
295 if( (newLanguage==NULL) && (newCountry == NULL) && (newVariant == NULL) )
296 {
297 init(NULL, FALSE); /* shortcut */
298 }
299 else
300 {
301 UErrorCode status = U_ZERO_ERROR;
302 int32_t size = 0;
303 int32_t lsize = 0;
304 int32_t csize = 0;
305 int32_t vsize = 0;
306 int32_t ksize = 0;
307
308 // Calculate the size of the resulting string.
309
310 // Language
311 if ( newLanguage != NULL )
312 {
313 lsize = (int32_t)uprv_strlen(newLanguage);
314 if ( lsize < 0 || lsize > ULOC_STRING_LIMIT ) { // int32 wrap
315 setToBogus();
316 return;
317 }
318 size = lsize;
319 }
320
321 CharString togo(newLanguage, lsize, status); // start with newLanguage
322
323 // _Country
324 if ( newCountry != NULL )
325 {
326 csize = (int32_t)uprv_strlen(newCountry);
327 if ( csize < 0 || csize > ULOC_STRING_LIMIT ) { // int32 wrap
328 setToBogus();
329 return;
330 }
331 size += csize;
332 }
333
334 // _Variant
335 if ( newVariant != NULL )
336 {
337 // remove leading _'s
338 while(newVariant[0] == SEP_CHAR)
339 {
340 newVariant++;
341 }
342
343 // remove trailing _'s
344 vsize = (int32_t)uprv_strlen(newVariant);
345 if ( vsize < 0 || vsize > ULOC_STRING_LIMIT ) { // int32 wrap
346 setToBogus();
347 return;
348 }
349 while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) )
350 {
351 vsize--;
352 }
353 }
354
355 if( vsize > 0 )
356 {
357 size += vsize;
358 }
359
360 // Separator rules:
361 if ( vsize > 0 )
362 {
363 size += 2; // at least: __v
364 }
365 else if ( csize > 0 )
366 {
367 size += 1; // at least: _v
368 }
369
370 if ( newKeywords != NULL)
371 {
372 ksize = (int32_t)uprv_strlen(newKeywords);
373 if ( ksize < 0 || ksize > ULOC_STRING_LIMIT ) {
374 setToBogus();
375 return;
376 }
377 size += ksize + 1;
378 }
379
380 // NOW we have the full locale string..
381 // Now, copy it back.
382
383 // newLanguage is already copied
384
385 if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v
386 { // ^
387 togo.append(SEP_CHAR, status);
388 }
389
390 if ( csize != 0 )
391 {
392 togo.append(newCountry, status);
393 }
394
395 if ( vsize != 0)
396 {
397 togo.append(SEP_CHAR, status)
398 .append(newVariant, vsize, status);
399 }
400
401 if ( ksize != 0)
402 {
403 if (uprv_strchr(newKeywords, '=')) {
404 togo.append('@', status); /* keyword parsing */
405 }
406 else {
407 togo.append('_', status); /* Variant parsing with a script */
408 if ( vsize == 0) {
409 togo.append('_', status); /* No country found */
410 }
411 }
412 togo.append(newKeywords, status);
413 }
414
415 if (U_FAILURE(status)) {
416 // Something went wrong with appending, etc.
417 setToBogus();
418 return;
419 }
420 // Parse it, because for example 'language' might really be a complete
421 // string.
422 init(togo.data(), FALSE);
423 }
424 }
425
Locale(const Locale & other)426 Locale::Locale(const Locale &other)
427 : UObject(other), fullName(fullNameBuffer), baseName(NULL)
428 {
429 *this = other;
430 }
431
Locale(Locale && other)432 Locale::Locale(Locale&& other) U_NOEXCEPT
433 : UObject(other), fullName(fullNameBuffer), baseName(fullName) {
434 *this = std::move(other);
435 }
436
operator =(const Locale & other)437 Locale& Locale::operator=(const Locale& other) {
438 if (this == &other) {
439 return *this;
440 }
441
442 setToBogus();
443
444 if (other.fullName == other.fullNameBuffer) {
445 uprv_strcpy(fullNameBuffer, other.fullNameBuffer);
446 } else if (other.fullName == nullptr) {
447 fullName = nullptr;
448 } else {
449 fullName = uprv_strdup(other.fullName);
450 if (fullName == nullptr) return *this;
451 }
452
453 if (other.baseName == other.fullName) {
454 baseName = fullName;
455 } else if (other.baseName != nullptr) {
456 baseName = uprv_strdup(other.baseName);
457 if (baseName == nullptr) return *this;
458 }
459
460 uprv_strcpy(language, other.language);
461 uprv_strcpy(script, other.script);
462 uprv_strcpy(country, other.country);
463
464 variantBegin = other.variantBegin;
465 fIsBogus = other.fIsBogus;
466
467 return *this;
468 }
469
operator =(Locale && other)470 Locale& Locale::operator=(Locale&& other) U_NOEXCEPT {
471 if (baseName != fullName) uprv_free(baseName);
472 if (fullName != fullNameBuffer) uprv_free(fullName);
473
474 if (other.fullName == other.fullNameBuffer) {
475 uprv_strcpy(fullNameBuffer, other.fullNameBuffer);
476 fullName = fullNameBuffer;
477 } else {
478 fullName = other.fullName;
479 }
480
481 if (other.baseName == other.fullName) {
482 baseName = fullName;
483 } else {
484 baseName = other.baseName;
485 }
486
487 uprv_strcpy(language, other.language);
488 uprv_strcpy(script, other.script);
489 uprv_strcpy(country, other.country);
490
491 variantBegin = other.variantBegin;
492 fIsBogus = other.fIsBogus;
493
494 other.baseName = other.fullName = other.fullNameBuffer;
495
496 return *this;
497 }
498
499 Locale *
clone() const500 Locale::clone() const {
501 return new Locale(*this);
502 }
503
504 UBool
operator ==(const Locale & other) const505 Locale::operator==( const Locale& other) const
506 {
507 return (uprv_strcmp(other.fullName, fullName) == 0);
508 }
509
510 #define ISASCIIALPHA(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
511
512 /*This function initializes a Locale from a C locale ID*/
init(const char * localeID,UBool canonicalize)513 Locale& Locale::init(const char* localeID, UBool canonicalize)
514 {
515 fIsBogus = FALSE;
516 /* Free our current storage */
517 if (baseName != fullName) {
518 uprv_free(baseName);
519 }
520 baseName = NULL;
521 if(fullName != fullNameBuffer) {
522 uprv_free(fullName);
523 fullName = fullNameBuffer;
524 }
525
526 // not a loop:
527 // just an easy way to have a common error-exit
528 // without goto and without another function
529 do {
530 char *separator;
531 char *field[5] = {0};
532 int32_t fieldLen[5] = {0};
533 int32_t fieldIdx;
534 int32_t variantField;
535 int32_t length;
536 UErrorCode err;
537
538 if(localeID == NULL) {
539 // not an error, just set the default locale
540 return *this = getDefault();
541 }
542
543 /* preset all fields to empty */
544 language[0] = script[0] = country[0] = 0;
545
546 // "canonicalize" the locale ID to ICU/Java format
547 err = U_ZERO_ERROR;
548 length = canonicalize ?
549 uloc_canonicalize(localeID, fullName, sizeof(fullNameBuffer), &err) :
550 uloc_getName(localeID, fullName, sizeof(fullNameBuffer), &err);
551
552 if(err == U_BUFFER_OVERFLOW_ERROR || length >= (int32_t)sizeof(fullNameBuffer)) {
553 /*Go to heap for the fullName if necessary*/
554 fullName = (char *)uprv_malloc(sizeof(char)*(length + 1));
555 if(fullName == 0) {
556 fullName = fullNameBuffer;
557 break; // error: out of memory
558 }
559 err = U_ZERO_ERROR;
560 length = canonicalize ?
561 uloc_canonicalize(localeID, fullName, length+1, &err) :
562 uloc_getName(localeID, fullName, length+1, &err);
563 }
564 if(U_FAILURE(err) || err == U_STRING_NOT_TERMINATED_WARNING) {
565 /* should never occur */
566 break;
567 }
568
569 variantBegin = length;
570
571 /* after uloc_getName/canonicalize() we know that only '_' are separators */
572 separator = field[0] = fullName;
573 fieldIdx = 1;
574 while ((separator = uprv_strchr(field[fieldIdx-1], SEP_CHAR)) != 0 && fieldIdx < UPRV_LENGTHOF(field)-1) {
575 field[fieldIdx] = separator + 1;
576 fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
577 fieldIdx++;
578 }
579 // variant may contain @foo or .foo POSIX cruft; remove it
580 separator = uprv_strchr(field[fieldIdx-1], '@');
581 char* sep2 = uprv_strchr(field[fieldIdx-1], '.');
582 if (separator!=NULL || sep2!=NULL) {
583 if (separator==NULL || (sep2!=NULL && separator > sep2)) {
584 separator = sep2;
585 }
586 fieldLen[fieldIdx-1] = (int32_t)(separator - field[fieldIdx-1]);
587 } else {
588 fieldLen[fieldIdx-1] = length - (int32_t)(field[fieldIdx-1] - fullName);
589 }
590
591 if (fieldLen[0] >= (int32_t)(sizeof(language)))
592 {
593 break; // error: the language field is too long
594 }
595
596 variantField = 1; /* Usually the 2nd one, except when a script or country is also used. */
597 if (fieldLen[0] > 0) {
598 /* We have a language */
599 uprv_memcpy(language, fullName, fieldLen[0]);
600 language[fieldLen[0]] = 0;
601 }
602 if (fieldLen[1] == 4 && ISASCIIALPHA(field[1][0]) &&
603 ISASCIIALPHA(field[1][1]) && ISASCIIALPHA(field[1][2]) &&
604 ISASCIIALPHA(field[1][3])) {
605 /* We have at least a script */
606 uprv_memcpy(script, field[1], fieldLen[1]);
607 script[fieldLen[1]] = 0;
608 variantField++;
609 }
610
611 if (fieldLen[variantField] == 2 || fieldLen[variantField] == 3) {
612 /* We have a country */
613 uprv_memcpy(country, field[variantField], fieldLen[variantField]);
614 country[fieldLen[variantField]] = 0;
615 variantField++;
616 } else if (fieldLen[variantField] == 0) {
617 variantField++; /* script or country empty but variant in next field (i.e. en__POSIX) */
618 }
619
620 if (fieldLen[variantField] > 0) {
621 /* We have a variant */
622 variantBegin = (int32_t)(field[variantField] - fullName);
623 }
624
625 err = U_ZERO_ERROR;
626 initBaseName(err);
627 if (U_FAILURE(err)) {
628 break;
629 }
630
631 // successful end of init()
632 return *this;
633 } while(0); /*loop doesn't iterate*/
634
635 // when an error occurs, then set this object to "bogus" (there is no UErrorCode here)
636 setToBogus();
637
638 return *this;
639 }
640
641 /*
642 * Set up the base name.
643 * If there are no key words, it's exactly the full name.
644 * If key words exist, it's the full name truncated at the '@' character.
645 * Need to set up both at init() and after setting a keyword.
646 */
647 void
initBaseName(UErrorCode & status)648 Locale::initBaseName(UErrorCode &status) {
649 if (U_FAILURE(status)) {
650 return;
651 }
652 U_ASSERT(baseName==NULL || baseName==fullName);
653 const char *atPtr = uprv_strchr(fullName, '@');
654 const char *eqPtr = uprv_strchr(fullName, '=');
655 if (atPtr && eqPtr && atPtr < eqPtr) {
656 // Key words exist.
657 int32_t baseNameLength = (int32_t)(atPtr - fullName);
658 baseName = (char *)uprv_malloc(baseNameLength + 1);
659 if (baseName == NULL) {
660 status = U_MEMORY_ALLOCATION_ERROR;
661 return;
662 }
663 uprv_strncpy(baseName, fullName, baseNameLength);
664 baseName[baseNameLength] = 0;
665
666 // The original computation of variantBegin leaves it equal to the length
667 // of fullName if there is no variant. It should instead be
668 // the length of the baseName.
669 if (variantBegin > baseNameLength) {
670 variantBegin = baseNameLength;
671 }
672 } else {
673 baseName = fullName;
674 }
675 }
676
677
678 int32_t
hashCode() const679 Locale::hashCode() const
680 {
681 return ustr_hashCharsN(fullName, static_cast<int32_t>(uprv_strlen(fullName)));
682 }
683
684 void
setToBogus()685 Locale::setToBogus() {
686 /* Free our current storage */
687 if(baseName != fullName) {
688 uprv_free(baseName);
689 }
690 baseName = NULL;
691 if(fullName != fullNameBuffer) {
692 uprv_free(fullName);
693 fullName = fullNameBuffer;
694 }
695 *fullNameBuffer = 0;
696 *language = 0;
697 *script = 0;
698 *country = 0;
699 fIsBogus = TRUE;
700 variantBegin = 0;
701 }
702
703 const Locale& U_EXPORT2
getDefault()704 Locale::getDefault()
705 {
706 {
707 Mutex lock(&gDefaultLocaleMutex);
708 if (gDefaultLocale != NULL) {
709 return *gDefaultLocale;
710 }
711 }
712 UErrorCode status = U_ZERO_ERROR;
713 return *locale_set_default_internal(NULL, status);
714 }
715
716
717
718 void U_EXPORT2
setDefault(const Locale & newLocale,UErrorCode & status)719 Locale::setDefault( const Locale& newLocale,
720 UErrorCode& status)
721 {
722 if (U_FAILURE(status)) {
723 return;
724 }
725
726 /* Set the default from the full name string of the supplied locale.
727 * This is a convenient way to access the default locale caching mechanisms.
728 */
729 const char *localeID = newLocale.getName();
730 locale_set_default_internal(localeID, status);
731 }
732
733 void
addLikelySubtags(UErrorCode & status)734 Locale::addLikelySubtags(UErrorCode& status) {
735 if (U_FAILURE(status)) {
736 return;
737 }
738
739 // The maximized locale ID string is often longer, but there is no good
740 // heuristic to estimate just how much longer. Leave that to CharString.
741 CharString maximizedLocaleID;
742 int32_t maximizedLocaleIDCapacity = static_cast<int32_t>(uprv_strlen(fullName));
743
744 char* buffer;
745 int32_t reslen;
746
747 for (;;) {
748 buffer = maximizedLocaleID.getAppendBuffer(
749 /*minCapacity=*/maximizedLocaleIDCapacity,
750 /*desiredCapacityHint=*/maximizedLocaleIDCapacity,
751 maximizedLocaleIDCapacity,
752 status);
753
754 if (U_FAILURE(status)) {
755 return;
756 }
757
758 reslen = uloc_addLikelySubtags(
759 fullName,
760 buffer,
761 maximizedLocaleIDCapacity,
762 &status);
763
764 if (status != U_BUFFER_OVERFLOW_ERROR) {
765 break;
766 }
767
768 maximizedLocaleIDCapacity = reslen;
769 status = U_ZERO_ERROR;
770 }
771
772 if (U_FAILURE(status)) {
773 return;
774 }
775
776 maximizedLocaleID.append(buffer, reslen, status);
777 if (status == U_STRING_NOT_TERMINATED_WARNING) {
778 status = U_ZERO_ERROR; // Terminators provided by CharString.
779 }
780
781 if (U_FAILURE(status)) {
782 return;
783 }
784
785 init(maximizedLocaleID.data(), /*canonicalize=*/FALSE);
786 if (isBogus()) {
787 status = U_ILLEGAL_ARGUMENT_ERROR;
788 }
789 }
790
791 void
minimizeSubtags(UErrorCode & status)792 Locale::minimizeSubtags(UErrorCode& status) {
793 if (U_FAILURE(status)) {
794 return;
795 }
796
797 // Except for a few edge cases (like the empty string, that is minimized to
798 // "en__POSIX"), minimized locale ID strings will be either the same length
799 // or shorter than their input.
800 CharString minimizedLocaleID;
801 int32_t minimizedLocaleIDCapacity = static_cast<int32_t>(uprv_strlen(fullName));
802
803 char* buffer;
804 int32_t reslen;
805
806 for (;;) {
807 buffer = minimizedLocaleID.getAppendBuffer(
808 /*minCapacity=*/minimizedLocaleIDCapacity,
809 /*desiredCapacityHint=*/minimizedLocaleIDCapacity,
810 minimizedLocaleIDCapacity,
811 status);
812
813 if (U_FAILURE(status)) {
814 return;
815 }
816
817 reslen = uloc_minimizeSubtags(
818 fullName,
819 buffer,
820 minimizedLocaleIDCapacity,
821 &status);
822
823 if (status != U_BUFFER_OVERFLOW_ERROR) {
824 break;
825 }
826
827 // Because of the internal minimal buffer size of CharString, I can't
828 // think of any input data for which this could possibly ever happen.
829 // Maybe it would be better replaced with an assertion instead?
830 minimizedLocaleIDCapacity = reslen;
831 status = U_ZERO_ERROR;
832 }
833
834 if (U_FAILURE(status)) {
835 return;
836 }
837
838 minimizedLocaleID.append(buffer, reslen, status);
839 if (status == U_STRING_NOT_TERMINATED_WARNING) {
840 status = U_ZERO_ERROR; // Terminators provided by CharString.
841 }
842
843 if (U_FAILURE(status)) {
844 return;
845 }
846
847 init(minimizedLocaleID.data(), /*canonicalize=*/FALSE);
848 if (isBogus()) {
849 status = U_ILLEGAL_ARGUMENT_ERROR;
850 }
851 }
852
853 Locale U_EXPORT2
forLanguageTag(StringPiece tag,UErrorCode & status)854 Locale::forLanguageTag(StringPiece tag, UErrorCode& status)
855 {
856 Locale result(Locale::eBOGUS);
857
858 if (U_FAILURE(status)) {
859 return result;
860 }
861
862 // If a BCP-47 language tag is passed as the language parameter to the
863 // normal Locale constructor, it will actually fall back to invoking
864 // uloc_forLanguageTag() to parse it if it somehow is able to detect that
865 // the string actually is BCP-47. This works well for things like strings
866 // using BCP-47 extensions, but it does not at all work for things like
867 // BCP-47 grandfathered tags (eg. "en-GB-oed") which are possible to also
868 // interpret as ICU locale IDs and because of that won't trigger the BCP-47
869 // parsing. Therefore the code here explicitly calls uloc_forLanguageTag()
870 // and then Locale::init(), instead of just calling the normal constructor.
871
872 // All simple language tags will have the exact same length as ICU locale
873 // ID strings as they have as BCP-47 strings (like "en_US" for "en-US").
874 CharString localeID;
875 int32_t resultCapacity = tag.size();
876
877 char* buffer;
878 int32_t parsedLength, reslen;
879
880 for (;;) {
881 buffer = localeID.getAppendBuffer(
882 /*minCapacity=*/resultCapacity,
883 /*desiredCapacityHint=*/resultCapacity,
884 resultCapacity,
885 status);
886
887 if (U_FAILURE(status)) {
888 return result;
889 }
890
891 reslen = ulocimp_forLanguageTag(
892 tag.data(),
893 tag.length(),
894 buffer,
895 resultCapacity,
896 &parsedLength,
897 &status);
898
899 if (status != U_BUFFER_OVERFLOW_ERROR) {
900 break;
901 }
902
903 // For all BCP-47 language tags that use extensions, the corresponding
904 // ICU locale ID will be longer but uloc_forLanguageTag() does compute
905 // the exact length needed so this memory reallocation will be done at
906 // most once.
907 resultCapacity = reslen;
908 status = U_ZERO_ERROR;
909 }
910
911 if (U_FAILURE(status)) {
912 return result;
913 }
914
915 if (parsedLength != tag.size()) {
916 status = U_ILLEGAL_ARGUMENT_ERROR;
917 return result;
918 }
919
920 localeID.append(buffer, reslen, status);
921 if (status == U_STRING_NOT_TERMINATED_WARNING) {
922 status = U_ZERO_ERROR; // Terminators provided by CharString.
923 }
924
925 if (U_FAILURE(status)) {
926 return result;
927 }
928
929 result.init(localeID.data(), /*canonicalize=*/FALSE);
930 if (result.isBogus()) {
931 status = U_ILLEGAL_ARGUMENT_ERROR;
932 }
933 return result;
934 }
935
936 void
toLanguageTag(ByteSink & sink,UErrorCode & status) const937 Locale::toLanguageTag(ByteSink& sink, UErrorCode& status) const
938 {
939 if (U_FAILURE(status)) {
940 return;
941 }
942
943 if (fIsBogus) {
944 status = U_ILLEGAL_ARGUMENT_ERROR;
945 return;
946 }
947
948 // All simple language tags will have the exact same length as BCP-47
949 // strings as they have as ICU locale IDs (like "en-US" for "en_US").
950 LocalMemory<char> scratch;
951 int32_t scratch_capacity = static_cast<int32_t>(uprv_strlen(fullName));
952
953 if (scratch_capacity == 0) {
954 scratch_capacity = 3; // "und"
955 }
956
957 char* buffer;
958 int32_t result_capacity, reslen;
959
960 for (;;) {
961 if (scratch.allocateInsteadAndReset(scratch_capacity) == nullptr) {
962 status = U_MEMORY_ALLOCATION_ERROR;
963 return;
964 }
965
966 buffer = sink.GetAppendBuffer(
967 /*min_capacity=*/scratch_capacity,
968 /*desired_capacity_hint=*/scratch_capacity,
969 scratch.getAlias(),
970 scratch_capacity,
971 &result_capacity);
972
973 reslen = uloc_toLanguageTag(
974 fullName,
975 buffer,
976 result_capacity,
977 /*strict=*/FALSE,
978 &status);
979
980 if (status != U_BUFFER_OVERFLOW_ERROR) {
981 break;
982 }
983
984 // For some very few edge cases a language tag will be longer as a
985 // BCP-47 string than it is as an ICU locale ID. Most notoriously "C"
986 // expands to the BCP-47 tag "en-US-u-va-posix", 16 times longer, and
987 // it'll take several calls to uloc_toLanguageTag() to figure that out.
988 // https://unicode-org.atlassian.net/browse/ICU-20132
989 scratch_capacity = reslen;
990 status = U_ZERO_ERROR;
991 }
992
993 if (U_FAILURE(status)) {
994 return;
995 }
996
997 sink.Append(buffer, reslen);
998 if (status == U_STRING_NOT_TERMINATED_WARNING) {
999 status = U_ZERO_ERROR; // Terminators not used.
1000 }
1001 }
1002
1003 Locale U_EXPORT2
createFromName(const char * name)1004 Locale::createFromName (const char *name)
1005 {
1006 if (name) {
1007 Locale l("");
1008 l.init(name, FALSE);
1009 return l;
1010 }
1011 else {
1012 return getDefault();
1013 }
1014 }
1015
1016 Locale U_EXPORT2
createCanonical(const char * name)1017 Locale::createCanonical(const char* name) {
1018 Locale loc("");
1019 loc.init(name, TRUE);
1020 return loc;
1021 }
1022
1023 const char *
getISO3Language() const1024 Locale::getISO3Language() const
1025 {
1026 return uloc_getISO3Language(fullName);
1027 }
1028
1029
1030 const char *
getISO3Country() const1031 Locale::getISO3Country() const
1032 {
1033 return uloc_getISO3Country(fullName);
1034 }
1035
1036 /**
1037 * Return the LCID value as specified in the "LocaleID" resource for this
1038 * locale. The LocaleID must be expressed as a hexadecimal number, from
1039 * one to four digits. If the LocaleID resource is not present, or is
1040 * in an incorrect format, 0 is returned. The LocaleID is for use in
1041 * Windows (it is an LCID), but is available on all platforms.
1042 */
1043 uint32_t
getLCID() const1044 Locale::getLCID() const
1045 {
1046 return uloc_getLCID(fullName);
1047 }
1048
getISOCountries()1049 const char* const* U_EXPORT2 Locale::getISOCountries()
1050 {
1051 return uloc_getISOCountries();
1052 }
1053
getISOLanguages()1054 const char* const* U_EXPORT2 Locale::getISOLanguages()
1055 {
1056 return uloc_getISOLanguages();
1057 }
1058
1059 // Set the locale's data based on a posix id.
setFromPOSIXID(const char * posixID)1060 void Locale::setFromPOSIXID(const char *posixID)
1061 {
1062 init(posixID, TRUE);
1063 }
1064
1065 const Locale & U_EXPORT2
getRoot(void)1066 Locale::getRoot(void)
1067 {
1068 return getLocale(eROOT);
1069 }
1070
1071 const Locale & U_EXPORT2
getEnglish(void)1072 Locale::getEnglish(void)
1073 {
1074 return getLocale(eENGLISH);
1075 }
1076
1077 const Locale & U_EXPORT2
getFrench(void)1078 Locale::getFrench(void)
1079 {
1080 return getLocale(eFRENCH);
1081 }
1082
1083 const Locale & U_EXPORT2
getGerman(void)1084 Locale::getGerman(void)
1085 {
1086 return getLocale(eGERMAN);
1087 }
1088
1089 const Locale & U_EXPORT2
getItalian(void)1090 Locale::getItalian(void)
1091 {
1092 return getLocale(eITALIAN);
1093 }
1094
1095 const Locale & U_EXPORT2
getJapanese(void)1096 Locale::getJapanese(void)
1097 {
1098 return getLocale(eJAPANESE);
1099 }
1100
1101 const Locale & U_EXPORT2
getKorean(void)1102 Locale::getKorean(void)
1103 {
1104 return getLocale(eKOREAN);
1105 }
1106
1107 const Locale & U_EXPORT2
getChinese(void)1108 Locale::getChinese(void)
1109 {
1110 return getLocale(eCHINESE);
1111 }
1112
1113 const Locale & U_EXPORT2
getSimplifiedChinese(void)1114 Locale::getSimplifiedChinese(void)
1115 {
1116 return getLocale(eCHINA);
1117 }
1118
1119 const Locale & U_EXPORT2
getTraditionalChinese(void)1120 Locale::getTraditionalChinese(void)
1121 {
1122 return getLocale(eTAIWAN);
1123 }
1124
1125
1126 const Locale & U_EXPORT2
getFrance(void)1127 Locale::getFrance(void)
1128 {
1129 return getLocale(eFRANCE);
1130 }
1131
1132 const Locale & U_EXPORT2
getGermany(void)1133 Locale::getGermany(void)
1134 {
1135 return getLocale(eGERMANY);
1136 }
1137
1138 const Locale & U_EXPORT2
getItaly(void)1139 Locale::getItaly(void)
1140 {
1141 return getLocale(eITALY);
1142 }
1143
1144 const Locale & U_EXPORT2
getJapan(void)1145 Locale::getJapan(void)
1146 {
1147 return getLocale(eJAPAN);
1148 }
1149
1150 const Locale & U_EXPORT2
getKorea(void)1151 Locale::getKorea(void)
1152 {
1153 return getLocale(eKOREA);
1154 }
1155
1156 const Locale & U_EXPORT2
getChina(void)1157 Locale::getChina(void)
1158 {
1159 return getLocale(eCHINA);
1160 }
1161
1162 const Locale & U_EXPORT2
getPRC(void)1163 Locale::getPRC(void)
1164 {
1165 return getLocale(eCHINA);
1166 }
1167
1168 const Locale & U_EXPORT2
getTaiwan(void)1169 Locale::getTaiwan(void)
1170 {
1171 return getLocale(eTAIWAN);
1172 }
1173
1174 const Locale & U_EXPORT2
getUK(void)1175 Locale::getUK(void)
1176 {
1177 return getLocale(eUK);
1178 }
1179
1180 const Locale & U_EXPORT2
getUS(void)1181 Locale::getUS(void)
1182 {
1183 return getLocale(eUS);
1184 }
1185
1186 const Locale & U_EXPORT2
getCanada(void)1187 Locale::getCanada(void)
1188 {
1189 return getLocale(eCANADA);
1190 }
1191
1192 const Locale & U_EXPORT2
getCanadaFrench(void)1193 Locale::getCanadaFrench(void)
1194 {
1195 return getLocale(eCANADA_FRENCH);
1196 }
1197
1198 const Locale &
getLocale(int locid)1199 Locale::getLocale(int locid)
1200 {
1201 Locale *localeCache = getLocaleCache();
1202 U_ASSERT((locid < eMAX_LOCALES)&&(locid>=0));
1203 if (localeCache == NULL) {
1204 // Failure allocating the locale cache.
1205 // The best we can do is return a NULL reference.
1206 locid = 0;
1207 }
1208 return localeCache[locid]; /*operating on NULL*/
1209 }
1210
1211 /*
1212 This function is defined this way in order to get around static
1213 initialization and static destruction.
1214 */
1215 Locale *
getLocaleCache(void)1216 Locale::getLocaleCache(void)
1217 {
1218 UErrorCode status = U_ZERO_ERROR;
1219 umtx_initOnce(gLocaleCacheInitOnce, locale_init, status);
1220 return gLocaleCache;
1221 }
1222
1223 class KeywordEnumeration : public StringEnumeration {
1224 private:
1225 char *keywords;
1226 char *current;
1227 int32_t length;
1228 UnicodeString currUSKey;
1229 static const char fgClassID;/* Warning this is used beyond the typical RTTI usage. */
1230
1231 public:
getStaticClassID(void)1232 static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
getDynamicClassID(void) const1233 virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
1234 public:
KeywordEnumeration(const char * keys,int32_t keywordLen,int32_t currentIndex,UErrorCode & status)1235 KeywordEnumeration(const char *keys, int32_t keywordLen, int32_t currentIndex, UErrorCode &status)
1236 : keywords((char *)&fgClassID), current((char *)&fgClassID), length(0) {
1237 if(U_SUCCESS(status) && keywordLen != 0) {
1238 if(keys == NULL || keywordLen < 0) {
1239 status = U_ILLEGAL_ARGUMENT_ERROR;
1240 } else {
1241 keywords = (char *)uprv_malloc(keywordLen+1);
1242 if (keywords == NULL) {
1243 status = U_MEMORY_ALLOCATION_ERROR;
1244 }
1245 else {
1246 uprv_memcpy(keywords, keys, keywordLen);
1247 keywords[keywordLen] = 0;
1248 current = keywords + currentIndex;
1249 length = keywordLen;
1250 }
1251 }
1252 }
1253 }
1254
1255 virtual ~KeywordEnumeration();
1256
clone() const1257 virtual StringEnumeration * clone() const
1258 {
1259 UErrorCode status = U_ZERO_ERROR;
1260 return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
1261 }
1262
count(UErrorCode &) const1263 virtual int32_t count(UErrorCode &/*status*/) const {
1264 char *kw = keywords;
1265 int32_t result = 0;
1266 while(*kw) {
1267 result++;
1268 kw += uprv_strlen(kw)+1;
1269 }
1270 return result;
1271 }
1272
next(int32_t * resultLength,UErrorCode & status)1273 virtual const char* next(int32_t* resultLength, UErrorCode& status) {
1274 const char* result;
1275 int32_t len;
1276 if(U_SUCCESS(status) && *current != 0) {
1277 result = current;
1278 len = (int32_t)uprv_strlen(current);
1279 current += len+1;
1280 if(resultLength != NULL) {
1281 *resultLength = len;
1282 }
1283 } else {
1284 if(resultLength != NULL) {
1285 *resultLength = 0;
1286 }
1287 result = NULL;
1288 }
1289 return result;
1290 }
1291
snext(UErrorCode & status)1292 virtual const UnicodeString* snext(UErrorCode& status) {
1293 int32_t resultLength = 0;
1294 const char *s = next(&resultLength, status);
1295 return setChars(s, resultLength, status);
1296 }
1297
reset(UErrorCode &)1298 virtual void reset(UErrorCode& /*status*/) {
1299 current = keywords;
1300 }
1301 };
1302
1303 const char KeywordEnumeration::fgClassID = '\0';
1304
~KeywordEnumeration()1305 KeywordEnumeration::~KeywordEnumeration() {
1306 uprv_free(keywords);
1307 }
1308
1309 // A wrapper around KeywordEnumeration that calls uloc_toUnicodeLocaleKey() in
1310 // the next() method for each keyword before returning it.
1311 class UnicodeKeywordEnumeration : public KeywordEnumeration {
1312 public:
1313 using KeywordEnumeration::KeywordEnumeration;
1314 virtual ~UnicodeKeywordEnumeration();
1315
next(int32_t * resultLength,UErrorCode & status)1316 virtual const char* next(int32_t* resultLength, UErrorCode& status) {
1317 const char* legacy_key = KeywordEnumeration::next(nullptr, status);
1318 if (U_SUCCESS(status) && legacy_key != nullptr) {
1319 const char* key = uloc_toUnicodeLocaleKey(legacy_key);
1320 if (key == nullptr) {
1321 status = U_ILLEGAL_ARGUMENT_ERROR;
1322 } else {
1323 if (resultLength != nullptr) {
1324 *resultLength = static_cast<int32_t>(uprv_strlen(key));
1325 }
1326 return key;
1327 }
1328 }
1329 if (resultLength != nullptr) *resultLength = 0;
1330 return nullptr;
1331 }
1332 };
1333
1334 // Out-of-line virtual destructor to serve as the "key function".
1335 UnicodeKeywordEnumeration::~UnicodeKeywordEnumeration() = default;
1336
1337 StringEnumeration *
createKeywords(UErrorCode & status) const1338 Locale::createKeywords(UErrorCode &status) const
1339 {
1340 char keywords[256];
1341 int32_t keywordCapacity = sizeof keywords;
1342 StringEnumeration *result = NULL;
1343
1344 if (U_FAILURE(status)) {
1345 return result;
1346 }
1347
1348 const char* variantStart = uprv_strchr(fullName, '@');
1349 const char* assignment = uprv_strchr(fullName, '=');
1350 if(variantStart) {
1351 if(assignment > variantStart) {
1352 int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status);
1353 if(U_SUCCESS(status) && keyLen) {
1354 result = new KeywordEnumeration(keywords, keyLen, 0, status);
1355 if (!result) {
1356 status = U_MEMORY_ALLOCATION_ERROR;
1357 }
1358 }
1359 } else {
1360 status = U_INVALID_FORMAT_ERROR;
1361 }
1362 }
1363 return result;
1364 }
1365
1366 StringEnumeration *
createUnicodeKeywords(UErrorCode & status) const1367 Locale::createUnicodeKeywords(UErrorCode &status) const
1368 {
1369 char keywords[256];
1370 int32_t keywordCapacity = sizeof keywords;
1371 StringEnumeration *result = NULL;
1372
1373 if (U_FAILURE(status)) {
1374 return result;
1375 }
1376
1377 const char* variantStart = uprv_strchr(fullName, '@');
1378 const char* assignment = uprv_strchr(fullName, '=');
1379 if(variantStart) {
1380 if(assignment > variantStart) {
1381 int32_t keyLen = locale_getKeywords(variantStart+1, '@', keywords, keywordCapacity, NULL, 0, NULL, FALSE, &status);
1382 if(U_SUCCESS(status) && keyLen) {
1383 result = new UnicodeKeywordEnumeration(keywords, keyLen, 0, status);
1384 if (!result) {
1385 status = U_MEMORY_ALLOCATION_ERROR;
1386 }
1387 }
1388 } else {
1389 status = U_INVALID_FORMAT_ERROR;
1390 }
1391 }
1392 return result;
1393 }
1394
1395 int32_t
getKeywordValue(const char * keywordName,char * buffer,int32_t bufLen,UErrorCode & status) const1396 Locale::getKeywordValue(const char* keywordName, char *buffer, int32_t bufLen, UErrorCode &status) const
1397 {
1398 return uloc_getKeywordValue(fullName, keywordName, buffer, bufLen, &status);
1399 }
1400
1401 void
getKeywordValue(StringPiece keywordName,ByteSink & sink,UErrorCode & status) const1402 Locale::getKeywordValue(StringPiece keywordName, ByteSink& sink, UErrorCode& status) const {
1403 if (U_FAILURE(status)) {
1404 return;
1405 }
1406
1407 if (fIsBogus) {
1408 status = U_ILLEGAL_ARGUMENT_ERROR;
1409 return;
1410 }
1411
1412 // TODO: Remove the need for a const char* to a NUL terminated buffer.
1413 const CharString keywordName_nul(keywordName, status);
1414 if (U_FAILURE(status)) {
1415 return;
1416 }
1417
1418 LocalMemory<char> scratch;
1419 int32_t scratch_capacity = 16; // Arbitrarily chosen default size.
1420
1421 char* buffer;
1422 int32_t result_capacity, reslen;
1423
1424 for (;;) {
1425 if (scratch.allocateInsteadAndReset(scratch_capacity) == nullptr) {
1426 status = U_MEMORY_ALLOCATION_ERROR;
1427 return;
1428 }
1429
1430 buffer = sink.GetAppendBuffer(
1431 /*min_capacity=*/scratch_capacity,
1432 /*desired_capacity_hint=*/scratch_capacity,
1433 scratch.getAlias(),
1434 scratch_capacity,
1435 &result_capacity);
1436
1437 reslen = uloc_getKeywordValue(
1438 fullName,
1439 keywordName_nul.data(),
1440 buffer,
1441 result_capacity,
1442 &status);
1443
1444 if (status != U_BUFFER_OVERFLOW_ERROR) {
1445 break;
1446 }
1447
1448 scratch_capacity = reslen;
1449 status = U_ZERO_ERROR;
1450 }
1451
1452 if (U_FAILURE(status)) {
1453 return;
1454 }
1455
1456 sink.Append(buffer, reslen);
1457 if (status == U_STRING_NOT_TERMINATED_WARNING) {
1458 status = U_ZERO_ERROR; // Terminators not used.
1459 }
1460 }
1461
1462 void
getUnicodeKeywordValue(StringPiece keywordName,ByteSink & sink,UErrorCode & status) const1463 Locale::getUnicodeKeywordValue(StringPiece keywordName,
1464 ByteSink& sink,
1465 UErrorCode& status) const {
1466 // TODO: Remove the need for a const char* to a NUL terminated buffer.
1467 const CharString keywordName_nul(keywordName, status);
1468 if (U_FAILURE(status)) {
1469 return;
1470 }
1471
1472 const char* legacy_key = uloc_toLegacyKey(keywordName_nul.data());
1473
1474 if (legacy_key == nullptr) {
1475 status = U_ILLEGAL_ARGUMENT_ERROR;
1476 return;
1477 }
1478
1479 CharString legacy_value;
1480 {
1481 CharStringByteSink sink(&legacy_value);
1482 getKeywordValue(legacy_key, sink, status);
1483 }
1484
1485 if (U_FAILURE(status)) {
1486 return;
1487 }
1488
1489 const char* unicode_value = uloc_toUnicodeLocaleType(
1490 keywordName_nul.data(), legacy_value.data());
1491
1492 if (unicode_value == nullptr) {
1493 status = U_ILLEGAL_ARGUMENT_ERROR;
1494 return;
1495 }
1496
1497 sink.Append(unicode_value, static_cast<int32_t>(uprv_strlen(unicode_value)));
1498 }
1499
1500 void
setKeywordValue(const char * keywordName,const char * keywordValue,UErrorCode & status)1501 Locale::setKeywordValue(const char* keywordName, const char* keywordValue, UErrorCode &status)
1502 {
1503 uloc_setKeywordValue(keywordName, keywordValue, fullName, ULOC_FULLNAME_CAPACITY, &status);
1504 if (U_SUCCESS(status) && baseName == fullName) {
1505 // May have added the first keyword, meaning that the fullName is no longer also the baseName.
1506 initBaseName(status);
1507 }
1508 }
1509
1510 void
setKeywordValue(StringPiece keywordName,StringPiece keywordValue,UErrorCode & status)1511 Locale::setKeywordValue(StringPiece keywordName,
1512 StringPiece keywordValue,
1513 UErrorCode& status) {
1514 // TODO: Remove the need for a const char* to a NUL terminated buffer.
1515 const CharString keywordName_nul(keywordName, status);
1516 const CharString keywordValue_nul(keywordValue, status);
1517 setKeywordValue(keywordName_nul.data(), keywordValue_nul.data(), status);
1518 }
1519
1520 void
setUnicodeKeywordValue(StringPiece keywordName,StringPiece keywordValue,UErrorCode & status)1521 Locale::setUnicodeKeywordValue(StringPiece keywordName,
1522 StringPiece keywordValue,
1523 UErrorCode& status) {
1524 // TODO: Remove the need for a const char* to a NUL terminated buffer.
1525 const CharString keywordName_nul(keywordName, status);
1526 const CharString keywordValue_nul(keywordValue, status);
1527
1528 if (U_FAILURE(status)) {
1529 return;
1530 }
1531
1532 const char* legacy_key = uloc_toLegacyKey(keywordName_nul.data());
1533
1534 if (legacy_key == nullptr) {
1535 status = U_ILLEGAL_ARGUMENT_ERROR;
1536 return;
1537 }
1538
1539 const char* legacy_value =
1540 uloc_toLegacyType(keywordName_nul.data(), keywordValue_nul.data());
1541
1542 if (legacy_value == nullptr) {
1543 status = U_ILLEGAL_ARGUMENT_ERROR;
1544 return;
1545 }
1546
1547 setKeywordValue(legacy_key, legacy_value, status);
1548 }
1549
1550 const char *
getBaseName() const1551 Locale::getBaseName() const {
1552 return baseName;
1553 }
1554
1555 //eof
1556 U_NAMESPACE_END
1557