Home | History | Annotate | Download | only in common
      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
    116 deleteLocale(void *obj) {
    117     delete (icu::Locale *) obj;
    118 }
    119 
    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 
    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 
    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
    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 *
    241 locale_get_default(void)
    242 {
    243     U_NAMESPACE_USE
    244     return Locale::getDefault().getName();
    245 }
    246 
    247 
    248 U_NAMESPACE_BEGIN
    249 
    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 
    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  */
    282 Locale::Locale(Locale::ELocaleType)
    283     : UObject(), fullName(fullNameBuffer), baseName(NULL)
    284 {
    285     setToBogus();
    286 }
    287 
    288 
    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 
    426 Locale::Locale(const Locale &other)
    427     : UObject(other), fullName(fullNameBuffer), baseName(NULL)
    428 {
    429     *this = other;
    430 }
    431 
    432 Locale::Locale(Locale&& other) U_NOEXCEPT
    433     : UObject(other), fullName(fullNameBuffer), baseName(fullName) {
    434   *this = std::move(other);
    435 }
    436 
    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 
    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 *
    500 Locale::clone() const {
    501     return new Locale(*this);
    502 }
    503 
    504 UBool
    505 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*/
    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
    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
    679 Locale::hashCode() const
    680 {
    681     return ustr_hashCharsN(fullName, static_cast<int32_t>(uprv_strlen(fullName)));
    682 }
    683 
    684 void
    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
    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
    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
    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
    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
    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
    937 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
   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
   1017 Locale::createCanonical(const char* name) {
   1018     Locale loc("");
   1019     loc.init(name, TRUE);
   1020     return loc;
   1021 }
   1022 
   1023 const char *
   1024 Locale::getISO3Language() const
   1025 {
   1026     return uloc_getISO3Language(fullName);
   1027 }
   1028 
   1029 
   1030 const char *
   1031 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
   1044 Locale::getLCID() const
   1045 {
   1046     return uloc_getLCID(fullName);
   1047 }
   1048 
   1049 const char* const* U_EXPORT2 Locale::getISOCountries()
   1050 {
   1051     return uloc_getISOCountries();
   1052 }
   1053 
   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.
   1060 void Locale::setFromPOSIXID(const char *posixID)
   1061 {
   1062     init(posixID, TRUE);
   1063 }
   1064 
   1065 const Locale & U_EXPORT2
   1066 Locale::getRoot(void)
   1067 {
   1068     return getLocale(eROOT);
   1069 }
   1070 
   1071 const Locale & U_EXPORT2
   1072 Locale::getEnglish(void)
   1073 {
   1074     return getLocale(eENGLISH);
   1075 }
   1076 
   1077 const Locale & U_EXPORT2
   1078 Locale::getFrench(void)
   1079 {
   1080     return getLocale(eFRENCH);
   1081 }
   1082 
   1083 const Locale & U_EXPORT2
   1084 Locale::getGerman(void)
   1085 {
   1086     return getLocale(eGERMAN);
   1087 }
   1088 
   1089 const Locale & U_EXPORT2
   1090 Locale::getItalian(void)
   1091 {
   1092     return getLocale(eITALIAN);
   1093 }
   1094 
   1095 const Locale & U_EXPORT2
   1096 Locale::getJapanese(void)
   1097 {
   1098     return getLocale(eJAPANESE);
   1099 }
   1100 
   1101 const Locale & U_EXPORT2
   1102 Locale::getKorean(void)
   1103 {
   1104     return getLocale(eKOREAN);
   1105 }
   1106 
   1107 const Locale & U_EXPORT2
   1108 Locale::getChinese(void)
   1109 {
   1110     return getLocale(eCHINESE);
   1111 }
   1112 
   1113 const Locale & U_EXPORT2
   1114 Locale::getSimplifiedChinese(void)
   1115 {
   1116     return getLocale(eCHINA);
   1117 }
   1118 
   1119 const Locale & U_EXPORT2
   1120 Locale::getTraditionalChinese(void)
   1121 {
   1122     return getLocale(eTAIWAN);
   1123 }
   1124 
   1125 
   1126 const Locale & U_EXPORT2
   1127 Locale::getFrance(void)
   1128 {
   1129     return getLocale(eFRANCE);
   1130 }
   1131 
   1132 const Locale & U_EXPORT2
   1133 Locale::getGermany(void)
   1134 {
   1135     return getLocale(eGERMANY);
   1136 }
   1137 
   1138 const Locale & U_EXPORT2
   1139 Locale::getItaly(void)
   1140 {
   1141     return getLocale(eITALY);
   1142 }
   1143 
   1144 const Locale & U_EXPORT2
   1145 Locale::getJapan(void)
   1146 {
   1147     return getLocale(eJAPAN);
   1148 }
   1149 
   1150 const Locale & U_EXPORT2
   1151 Locale::getKorea(void)
   1152 {
   1153     return getLocale(eKOREA);
   1154 }
   1155 
   1156 const Locale & U_EXPORT2
   1157 Locale::getChina(void)
   1158 {
   1159     return getLocale(eCHINA);
   1160 }
   1161 
   1162 const Locale & U_EXPORT2
   1163 Locale::getPRC(void)
   1164 {
   1165     return getLocale(eCHINA);
   1166 }
   1167 
   1168 const Locale & U_EXPORT2
   1169 Locale::getTaiwan(void)
   1170 {
   1171     return getLocale(eTAIWAN);
   1172 }
   1173 
   1174 const Locale & U_EXPORT2
   1175 Locale::getUK(void)
   1176 {
   1177     return getLocale(eUK);
   1178 }
   1179 
   1180 const Locale & U_EXPORT2
   1181 Locale::getUS(void)
   1182 {
   1183     return getLocale(eUS);
   1184 }
   1185 
   1186 const Locale & U_EXPORT2
   1187 Locale::getCanada(void)
   1188 {
   1189     return getLocale(eCANADA);
   1190 }
   1191 
   1192 const Locale & U_EXPORT2
   1193 Locale::getCanadaFrench(void)
   1194 {
   1195     return getLocale(eCANADA_FRENCH);
   1196 }
   1197 
   1198 const Locale &
   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 *
   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:
   1232     static UClassID U_EXPORT2 getStaticClassID(void) { return (UClassID)&fgClassID; }
   1233     virtual UClassID getDynamicClassID(void) const { return getStaticClassID(); }
   1234 public:
   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 
   1257     virtual StringEnumeration * clone() const
   1258     {
   1259         UErrorCode status = U_ZERO_ERROR;
   1260         return new KeywordEnumeration(keywords, length, (int32_t)(current - keywords), status);
   1261     }
   1262 
   1263     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 
   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 
   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 
   1298     virtual void reset(UErrorCode& /*status*/) {
   1299         current = keywords;
   1300     }
   1301 };
   1302 
   1303 const char KeywordEnumeration::fgClassID = '\0';
   1304 
   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 
   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 *
   1338 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 *
   1367 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
   1396 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
   1402 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
   1463 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
   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
   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
   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 *
   1551 Locale::getBaseName() const {
   1552     return baseName;
   1553 }
   1554 
   1555 //eof
   1556 U_NAMESPACE_END
   1557