tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

locdispnames.cpp (35100B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 *
      6 *   Copyright (C) 1997-2016, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 *******************************************************************************
     10 *   file name:  locdispnames.cpp
     11 *   encoding:   UTF-8
     12 *   tab size:   8 (not used)
     13 *   indentation:4
     14 *
     15 *   created on: 2010feb25
     16 *   created by: Markus W. Scherer
     17 *
     18 *   Code for locale display names, separated out from other .cpp files
     19 *   that then do not depend on resource bundle code and display name data.
     20 */
     21 
     22 #include <string_view>
     23 
     24 #include "unicode/utypes.h"
     25 #include "unicode/brkiter.h"
     26 #include "unicode/locid.h"
     27 #include "unicode/uenum.h"
     28 #include "unicode/uloc.h"
     29 #include "unicode/ures.h"
     30 #include "unicode/ustring.h"
     31 #include "charstr.h"
     32 #include "cmemory.h"
     33 #include "cstring.h"
     34 #include "putilimp.h"
     35 #include "ulocimp.h"
     36 #include "uresimp.h"
     37 #include "ureslocs.h"
     38 #include "ustr_imp.h"
     39 
     40 // C++ API ----------------------------------------------------------------- ***
     41 
     42 U_NAMESPACE_BEGIN
     43 
     44 UnicodeString&
     45 Locale::getDisplayLanguage(UnicodeString& dispLang) const
     46 {
     47    return this->getDisplayLanguage(getDefault(), dispLang);
     48 }
     49 
     50 /*We cannot make any assumptions on the size of the output display strings
     51 * Yet, since we are calling through to a C API, we need to set limits on
     52 * buffer size. For all the following getDisplay functions we first attempt
     53 * to fill up a stack allocated buffer. If it is to small we heap allocated
     54 * the exact buffer we need copy it to the UnicodeString and delete it*/
     55 
     56 UnicodeString&
     57 Locale::getDisplayLanguage(const Locale &displayLocale,
     58                           UnicodeString &result) const {
     59    char16_t *buffer;
     60    UErrorCode errorCode=U_ZERO_ERROR;
     61    int32_t length;
     62 
     63    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
     64    if (buffer == nullptr) {
     65        result.truncate(0);
     66        return result;
     67    }
     68 
     69    length=uloc_getDisplayLanguage(getName(), displayLocale.getName(),
     70                                   buffer, result.getCapacity(),
     71                                   &errorCode);
     72    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     73 
     74    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
     75        buffer=result.getBuffer(length);
     76        if (buffer == nullptr) {
     77            result.truncate(0);
     78            return result;
     79        }
     80        errorCode=U_ZERO_ERROR;
     81        length=uloc_getDisplayLanguage(getName(), displayLocale.getName(),
     82                                       buffer, result.getCapacity(),
     83                                       &errorCode);
     84        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
     85    }
     86 
     87    return result;
     88 }
     89 
     90 UnicodeString&
     91 Locale::getDisplayScript(UnicodeString& dispScript) const
     92 {
     93    return this->getDisplayScript(getDefault(), dispScript);
     94 }
     95 
     96 UnicodeString&
     97 Locale::getDisplayScript(const Locale &displayLocale,
     98                          UnicodeString &result) const {
     99    char16_t *buffer;
    100    UErrorCode errorCode=U_ZERO_ERROR;
    101    int32_t length;
    102 
    103    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
    104    if (buffer == nullptr) {
    105        result.truncate(0);
    106        return result;
    107    }
    108 
    109    length=uloc_getDisplayScript(getName(), displayLocale.getName(),
    110                                  buffer, result.getCapacity(),
    111                                  &errorCode);
    112    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    113 
    114    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
    115        buffer=result.getBuffer(length);
    116        if (buffer == nullptr) {
    117            result.truncate(0);
    118            return result;
    119        }
    120        errorCode=U_ZERO_ERROR;
    121        length=uloc_getDisplayScript(getName(), displayLocale.getName(),
    122                                      buffer, result.getCapacity(),
    123                                      &errorCode);
    124        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    125    }
    126 
    127    return result;
    128 }
    129 
    130 UnicodeString&
    131 Locale::getDisplayCountry(UnicodeString& dispCntry) const
    132 {
    133    return this->getDisplayCountry(getDefault(), dispCntry);
    134 }
    135 
    136 UnicodeString&
    137 Locale::getDisplayCountry(const Locale &displayLocale,
    138                          UnicodeString &result) const {
    139    char16_t *buffer;
    140    UErrorCode errorCode=U_ZERO_ERROR;
    141    int32_t length;
    142 
    143    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
    144    if (buffer == nullptr) {
    145        result.truncate(0);
    146        return result;
    147    }
    148 
    149    length=uloc_getDisplayCountry(getName(), displayLocale.getName(),
    150                                  buffer, result.getCapacity(),
    151                                  &errorCode);
    152    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    153 
    154    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
    155        buffer=result.getBuffer(length);
    156        if (buffer == nullptr) {
    157            result.truncate(0);
    158            return result;
    159        }
    160        errorCode=U_ZERO_ERROR;
    161        length=uloc_getDisplayCountry(getName(), displayLocale.getName(),
    162                                      buffer, result.getCapacity(),
    163                                      &errorCode);
    164        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    165    }
    166 
    167    return result;
    168 }
    169 
    170 UnicodeString&
    171 Locale::getDisplayVariant(UnicodeString& dispVar) const
    172 {
    173    return this->getDisplayVariant(getDefault(), dispVar);
    174 }
    175 
    176 UnicodeString&
    177 Locale::getDisplayVariant(const Locale &displayLocale,
    178                          UnicodeString &result) const {
    179    char16_t *buffer;
    180    UErrorCode errorCode=U_ZERO_ERROR;
    181    int32_t length;
    182 
    183    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
    184    if (buffer == nullptr) {
    185        result.truncate(0);
    186        return result;
    187    }
    188 
    189    length=uloc_getDisplayVariant(getName(), displayLocale.getName(),
    190                                  buffer, result.getCapacity(),
    191                                  &errorCode);
    192    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    193 
    194    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
    195        buffer=result.getBuffer(length);
    196        if (buffer == nullptr) {
    197            result.truncate(0);
    198            return result;
    199        }
    200        errorCode=U_ZERO_ERROR;
    201        length=uloc_getDisplayVariant(getName(), displayLocale.getName(),
    202                                      buffer, result.getCapacity(),
    203                                      &errorCode);
    204        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    205    }
    206 
    207    return result;
    208 }
    209 
    210 UnicodeString&
    211 Locale::getDisplayName( UnicodeString& name ) const
    212 {
    213    return this->getDisplayName(getDefault(), name);
    214 }
    215 
    216 UnicodeString&
    217 Locale::getDisplayName(const Locale &displayLocale,
    218                       UnicodeString &result) const {
    219    char16_t *buffer;
    220    UErrorCode errorCode=U_ZERO_ERROR;
    221    int32_t length;
    222 
    223    buffer=result.getBuffer(ULOC_FULLNAME_CAPACITY);
    224    if (buffer == nullptr) {
    225        result.truncate(0);
    226        return result;
    227    }
    228 
    229    length=uloc_getDisplayName(getName(), displayLocale.getName(),
    230                               buffer, result.getCapacity(),
    231                               &errorCode);
    232    result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    233 
    234    if(errorCode==U_BUFFER_OVERFLOW_ERROR) {
    235        buffer=result.getBuffer(length);
    236        if (buffer == nullptr) {
    237            result.truncate(0);
    238            return result;
    239        }
    240        errorCode=U_ZERO_ERROR;
    241        length=uloc_getDisplayName(getName(), displayLocale.getName(),
    242                                   buffer, result.getCapacity(),
    243                                   &errorCode);
    244        result.releaseBuffer(U_SUCCESS(errorCode) ? length : 0);
    245    }
    246 
    247    return result;
    248 }
    249 
    250 #if !UCONFIG_NO_BREAK_ITERATION
    251 
    252 // -------------------------------------
    253 // Gets the objectLocale display name in the default locale language.
    254 UnicodeString& U_EXPORT2
    255 BreakIterator::getDisplayName(const Locale& objectLocale,
    256                             UnicodeString& name)
    257 {
    258    return objectLocale.getDisplayName(name);
    259 }
    260 
    261 // -------------------------------------
    262 // Gets the objectLocale display name in the displayLocale language.
    263 UnicodeString& U_EXPORT2
    264 BreakIterator::getDisplayName(const Locale& objectLocale,
    265                             const Locale& displayLocale,
    266                             UnicodeString& name)
    267 {
    268    return objectLocale.getDisplayName(displayLocale, name);
    269 }
    270 
    271 #endif
    272 
    273 
    274 U_NAMESPACE_END
    275 
    276 // C API ------------------------------------------------------------------- ***
    277 
    278 U_NAMESPACE_USE
    279 
    280 namespace {
    281 
    282 /* ### Constants **************************************************/
    283 
    284 /* These strings describe the resources we attempt to load from
    285 the locale ResourceBundle data file.*/
    286 constexpr char _kLanguages[]       = "Languages";
    287 constexpr char _kScripts[]         = "Scripts";
    288 constexpr char _kScriptsStandAlone[] = "Scripts%stand-alone";
    289 constexpr char _kCountries[]       = "Countries";
    290 constexpr char _kVariants[]        = "Variants";
    291 constexpr char _kKeys[]            = "Keys";
    292 constexpr char _kTypes[]           = "Types";
    293 //constexpr char _kRootName[]        = "root";
    294 constexpr char _kCurrency[]        = "currency";
    295 constexpr char _kCurrencies[]      = "Currencies";
    296 constexpr char _kLocaleDisplayPattern[] = "localeDisplayPattern";
    297 constexpr char _kPattern[]         = "pattern";
    298 constexpr char _kSeparator[]       = "separator";
    299 
    300 /* ### Display name **************************************************/
    301 
    302 int32_t
    303 _getStringOrCopyKey(const char *path, const char *locale,
    304                    const char *tableKey, 
    305                    const char* subTableKey,
    306                    const char *itemKey,
    307                    const char *substitute,
    308                    char16_t *dest, int32_t destCapacity,
    309                    UErrorCode &errorCode) {
    310    if (U_FAILURE(errorCode)) { return 0; }
    311    const char16_t *s = nullptr;
    312    int32_t length = 0;
    313 
    314    if(itemKey==nullptr) {
    315        /* top-level item: normal resource bundle access */
    316        icu::LocalUResourceBundlePointer rb(ures_open(path, locale, &errorCode));
    317 
    318        if(U_SUCCESS(errorCode)) {
    319            s=ures_getStringByKey(rb.getAlias(), tableKey, &length, &errorCode);
    320            /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
    321        }
    322    } else {
    323        bool isLanguageCode = (uprv_strncmp(tableKey, _kLanguages, 9) == 0);
    324        /* Language code should not be a number. If it is, set the error code. */
    325        if (isLanguageCode && uprv_strtol(itemKey, nullptr, 10)) {
    326            errorCode = U_MISSING_RESOURCE_ERROR;
    327        } else {
    328            /* second-level item, use special fallback */
    329            s=uloc_getTableStringWithFallback(path, locale,
    330                                               tableKey,
    331                                               subTableKey,
    332                                               itemKey,
    333                                               &length,
    334                                               &errorCode);
    335            if (U_FAILURE(errorCode) && isLanguageCode && itemKey != nullptr) {
    336                // convert itemKey locale code to canonical form and try again, ICU-20870
    337                errorCode = U_ZERO_ERROR;
    338                Locale canonKey = Locale::createCanonical(itemKey);
    339                s=uloc_getTableStringWithFallback(path, locale,
    340                                                    tableKey,
    341                                                    subTableKey,
    342                                                    canonKey.getName(),
    343                                                    &length,
    344                                                    &errorCode);
    345            }
    346        }
    347    }
    348 
    349    if(U_SUCCESS(errorCode)) {
    350        int32_t copyLength=uprv_min(length, destCapacity);
    351        if(copyLength>0 && s != nullptr) {
    352            u_memcpy(dest, s, copyLength);
    353        }
    354    } else {
    355        /* no string from a resource bundle: convert the substitute */
    356        length = static_cast<int32_t>(uprv_strlen(substitute));
    357        u_charsToUChars(substitute, dest, uprv_min(length, destCapacity));
    358        errorCode = U_USING_DEFAULT_WARNING;
    359    }
    360 
    361    return u_terminateUChars(dest, destCapacity, length, &errorCode);
    362 }
    363 
    364 using UDisplayNameGetter = icu::CharString(std::string_view, UErrorCode&);
    365 
    366 int32_t
    367 _getDisplayNameForComponent(const char *locale,
    368                            const char *displayLocale,
    369                            char16_t *dest, int32_t destCapacity,
    370                            UDisplayNameGetter *getter,
    371                            const char *tag,
    372                            UErrorCode &errorCode) {
    373    if (U_FAILURE(errorCode)) { return 0; }
    374    UErrorCode localStatus;
    375    const char* root = nullptr;
    376 
    377    if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
    378        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    379        return 0;
    380    }
    381 
    382    if (locale == nullptr) {
    383        locale = uloc_getDefault();
    384    }
    385 
    386    localStatus = U_ZERO_ERROR;
    387    icu::CharString localeBuffer = (*getter)(locale, localStatus);
    388    if (U_FAILURE(localStatus)) {
    389        errorCode = U_ILLEGAL_ARGUMENT_ERROR;
    390        return 0;
    391    }
    392    if (localeBuffer.isEmpty()) {
    393        // For the display name, we treat this as unknown language (ICU-20273).
    394        if (getter == ulocimp_getLanguage) {
    395            localeBuffer.append("und", errorCode);
    396        } else {
    397            return u_terminateUChars(dest, destCapacity, 0, &errorCode);
    398        }
    399    }
    400 
    401    root = tag == _kCountries ? U_ICUDATA_REGION : U_ICUDATA_LANG;
    402 
    403    return _getStringOrCopyKey(root, displayLocale,
    404                               tag, nullptr, localeBuffer.data(),
    405                               localeBuffer.data(),
    406                               dest, destCapacity,
    407                               errorCode);
    408 }
    409 
    410 }  // namespace
    411 
    412 U_CAPI int32_t U_EXPORT2
    413 uloc_getDisplayLanguage(const char *locale,
    414                        const char *displayLocale,
    415                        char16_t *dest, int32_t destCapacity,
    416                        UErrorCode *pErrorCode) {
    417    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    418                ulocimp_getLanguage, _kLanguages, *pErrorCode);
    419 }
    420 
    421 U_CAPI int32_t U_EXPORT2
    422 uloc_getDisplayScript(const char* locale,
    423                      const char* displayLocale,
    424                      char16_t *dest, int32_t destCapacity,
    425                      UErrorCode *pErrorCode)
    426 {
    427    if (U_FAILURE(*pErrorCode)) { return 0; }
    428    UErrorCode err = U_ZERO_ERROR;
    429    int32_t res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    430                ulocimp_getScript, _kScriptsStandAlone, err);
    431 
    432    if (destCapacity == 0 && err == U_BUFFER_OVERFLOW_ERROR) {
    433        // For preflight, return the max of the value and the fallback.
    434        int32_t fallback_res = _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    435                                                           ulocimp_getScript, _kScripts, *pErrorCode);
    436        return (fallback_res > res) ? fallback_res : res;
    437    }
    438    if ( err == U_USING_DEFAULT_WARNING ) {
    439        return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    440                                           ulocimp_getScript, _kScripts, *pErrorCode);
    441    } else {
    442        *pErrorCode = err;
    443        return res;
    444    }
    445 }
    446 
    447 static int32_t
    448 uloc_getDisplayScriptInContext(const char* locale,
    449                      const char* displayLocale,
    450                      char16_t *dest, int32_t destCapacity,
    451                      UErrorCode *pErrorCode)
    452 {
    453    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    454                    ulocimp_getScript, _kScripts, *pErrorCode);
    455 }
    456 
    457 U_CAPI int32_t U_EXPORT2
    458 uloc_getDisplayCountry(const char *locale,
    459                       const char *displayLocale,
    460                       char16_t *dest, int32_t destCapacity,
    461                       UErrorCode *pErrorCode) {
    462    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    463                ulocimp_getRegion, _kCountries, *pErrorCode);
    464 }
    465 
    466 /*
    467 * TODO separate variant1_variant2_variant3...
    468 * by getting each tag's display string and concatenating them with ", "
    469 * in between - similar to uloc_getDisplayName()
    470 */
    471 U_CAPI int32_t U_EXPORT2
    472 uloc_getDisplayVariant(const char *locale,
    473                       const char *displayLocale,
    474                       char16_t *dest, int32_t destCapacity,
    475                       UErrorCode *pErrorCode) {
    476    return _getDisplayNameForComponent(locale, displayLocale, dest, destCapacity,
    477                ulocimp_getVariant, _kVariants, *pErrorCode);
    478 }
    479 
    480 /* Instead of having a separate pass for 'special' patterns, reintegrate the two
    481 * so we don't get bitten by preflight bugs again.  We can be reasonably efficient
    482 * without two separate code paths, this code isn't that performance-critical.
    483 *
    484 * This code is general enough to deal with patterns that have a prefix or swap the
    485 * language and remainder components, since we gave developers enough rope to do such
    486 * things if they futz with the pattern data.  But since we don't give them a way to
    487 * specify a pattern for arbitrary combinations of components, there's not much use in
    488 * that.  I don't think our data includes such patterns, the only variable I know if is
    489 * whether there is a space before the open paren, or not.  Oh, and zh uses different
    490 * chars than the standard open/close paren (which ja and ko use, btw).
    491 */
    492 U_CAPI int32_t U_EXPORT2
    493 uloc_getDisplayName(const char *locale,
    494                    const char *displayLocale,
    495                    char16_t *dest, int32_t destCapacity,
    496                    UErrorCode *pErrorCode)
    497 {
    498    static const char16_t defaultSeparator[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
    499    static const char16_t sub0[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
    500    static const char16_t sub1[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
    501    static const int32_t subLen = 3;
    502    static const char16_t defaultPattern[10] = {
    503        0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
    504    }; /* {0} ({1}) */
    505    static const int32_t defaultPatLen = 9;
    506    static const int32_t defaultSub0Pos = 0;
    507    static const int32_t defaultSub1Pos = 5;
    508 
    509    int32_t length; /* of formatted result */
    510 
    511    const char16_t *separator;
    512    int32_t sepLen = 0;
    513    const char16_t *pattern;
    514    int32_t patLen = 0;
    515    int32_t sub0Pos, sub1Pos;
    516    
    517    char16_t formatOpenParen         = 0x0028; // (
    518    char16_t formatReplaceOpenParen  = 0x005B; // [
    519    char16_t formatCloseParen        = 0x0029; // )
    520    char16_t formatReplaceCloseParen = 0x005D; // ]
    521 
    522    UBool haveLang = true; /* assume true, set false if we find we don't have
    523                              a lang component in the locale */
    524    UBool haveRest = true; /* assume true, set false if we find we don't have
    525                              any other component in the locale */
    526    UBool retry = false; /* set true if we need to retry, see below */
    527 
    528    int32_t langi = 0; /* index of the language substitution (0 or 1), virtually always 0 */
    529 
    530    if(pErrorCode==nullptr || U_FAILURE(*pErrorCode)) {
    531        return 0;
    532    }
    533 
    534    if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
    535        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    536        return 0;
    537    }
    538 
    539    {
    540        UErrorCode status = U_ZERO_ERROR;
    541 
    542        icu::LocalUResourceBundlePointer locbundle(
    543                ures_open(U_ICUDATA_LANG, displayLocale, &status));
    544        icu::LocalUResourceBundlePointer dspbundle(
    545                ures_getByKeyWithFallback(locbundle.getAlias(), _kLocaleDisplayPattern, nullptr, &status));
    546 
    547        separator=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kSeparator, &sepLen, &status);
    548        pattern=ures_getStringByKeyWithFallback(dspbundle.getAlias(), _kPattern, &patLen, &status);
    549    }
    550 
    551    /* If we couldn't find any data, then use the defaults */
    552    if(sepLen == 0) {
    553       separator = defaultSeparator;
    554    }
    555    /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
    556     * here since we are trying to build the display string in place in the dest buffer,
    557     * and to handle it as a pattern would entail having separate storage for the
    558     * substrings that need to be combined (the first of which may be the result of
    559     * previous such combinations). So for now we continue to treat the portion between
    560     * {0} and {1} as a string to be appended when joining substrings, ignoring anything
    561     * that is before {0} or after {1} (no existing separator pattern has any such thing).
    562     * This is similar to how pattern is handled below.
    563     */
    564    {
    565        char16_t *p0=u_strstr(separator, sub0);
    566        char16_t *p1=u_strstr(separator, sub1);
    567        if (p0==nullptr || p1==nullptr || p1<p0) {
    568            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    569            return 0;
    570        }
    571        separator = (const char16_t *)p0 + subLen;
    572        sepLen = static_cast<int32_t>(p1 - separator);
    573    }
    574 
    575    if(patLen==0 || (patLen==defaultPatLen && !u_strncmp(pattern, defaultPattern, patLen))) {
    576        pattern=defaultPattern;
    577        patLen=defaultPatLen;
    578        sub0Pos=defaultSub0Pos;
    579        sub1Pos=defaultSub1Pos;
    580        // use default formatOpenParen etc. set above
    581    } else { /* non-default pattern */
    582        char16_t *p0=u_strstr(pattern, sub0);
    583        char16_t *p1=u_strstr(pattern, sub1);
    584        if (p0==nullptr || p1==nullptr) {
    585            *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
    586            return 0;
    587        }
    588        sub0Pos = static_cast<int32_t>(p0-pattern);
    589        sub1Pos = static_cast<int32_t>(p1-pattern);
    590        if (sub1Pos < sub0Pos) { /* a very odd pattern */
    591            int32_t t=sub0Pos; sub0Pos=sub1Pos; sub1Pos=t;
    592            langi=1;
    593        }
    594        if (u_strchr(pattern, 0xFF08) != nullptr) {
    595            formatOpenParen         = 0xFF08; // fullwidth (
    596            formatReplaceOpenParen  = 0xFF3B; // fullwidth [
    597            formatCloseParen        = 0xFF09; // fullwidth )
    598            formatReplaceCloseParen = 0xFF3D; // fullwidth ]
    599        }
    600    }
    601 
    602    /* We loop here because there is one case in which after the first pass we could need to
    603     * reextract the data.  If there's initial padding before the first element, we put in
    604     * the padding and then write that element.  If it turns out there's no second element,
    605     * we didn't need the padding.  If we do need the data (no preflight), and the first element
    606     * would have fit but for the padding, we need to reextract.  In this case (only) we
    607     * adjust the parameters so padding is not added, and repeat.
    608     */
    609    do {
    610        char16_t* p=dest;
    611        int32_t patPos=0; /* position in the pattern, used for non-substitution portions */
    612        int32_t langLen=0; /* length of language substitution */
    613        int32_t langPos=0; /* position in output of language substitution */
    614        int32_t restLen=0; /* length of 'everything else' substitution */
    615        int32_t restPos=0; /* position in output of 'everything else' substitution */
    616        icu::LocalUEnumerationPointer kenum; /* keyword enumeration */
    617 
    618        /* prefix of pattern, extremely likely to be empty */
    619        if(sub0Pos) {
    620            if(destCapacity >= sub0Pos) {
    621                while (patPos < sub0Pos) {
    622                    *p++ = pattern[patPos++];
    623                }
    624            } else {
    625                patPos=sub0Pos;
    626            }
    627            length=sub0Pos;
    628        } else {
    629            length=0;
    630        }
    631 
    632        for(int32_t subi=0,resti=0;subi<2;) { /* iterate through patterns 0 and 1*/
    633            UBool subdone = false; /* set true when ready to move to next substitution */
    634 
    635            /* prep p and cap for calls to get display components, pin cap to 0 since
    636               they complain if cap is negative */
    637            int32_t cap=destCapacity-length;
    638            if (cap <= 0) {
    639                cap=0;
    640            } else {
    641                p=dest+length;
    642            }
    643 
    644            if (subi == langi) { /* {0}*/
    645                if(haveLang) {
    646                    langPos=length;
    647                    langLen=uloc_getDisplayLanguage(locale, displayLocale, p, cap, pErrorCode);
    648                    length+=langLen;
    649                    haveLang=langLen>0;
    650                }
    651                subdone=true;
    652            } else { /* {1} */
    653                if(!haveRest) {
    654                    subdone=true;
    655                } else {
    656                    int32_t len; /* length of component (plus other stuff) we just fetched */
    657                    switch(resti++) {
    658                        case 0:
    659                            restPos=length;
    660                            len=uloc_getDisplayScriptInContext(locale, displayLocale, p, cap, pErrorCode);
    661                            break;
    662                        case 1:
    663                            len=uloc_getDisplayCountry(locale, displayLocale, p, cap, pErrorCode);
    664                            break;
    665                        case 2:
    666                            len=uloc_getDisplayVariant(locale, displayLocale, p, cap, pErrorCode);
    667                            break;
    668                        case 3:
    669                            kenum.adoptInstead(uloc_openKeywords(locale, pErrorCode));
    670                            U_FALLTHROUGH;
    671                        default: {
    672                            const char* kw=uenum_next(kenum.getAlias(), &len, pErrorCode);
    673                            if (kw == nullptr) {
    674                                len=0; /* mark that we didn't add a component */
    675                                subdone=true;
    676                            } else {
    677                                /* incorporating this behavior into the loop made it even more complex,
    678                                   so just special case it here */
    679                                len = uloc_getDisplayKeyword(kw, displayLocale, p, cap, pErrorCode);
    680                                if(len) {
    681                                    if(len < cap) {
    682                                        p[len]=0x3d; /* '=', assume we'll need it */
    683                                    }
    684                                    len+=1;
    685 
    686                                    /* adjust for call to get keyword */
    687                                    cap-=len;
    688                                    if(cap <= 0) {
    689                                        cap=0;
    690                                    } else {
    691                                        p+=len;
    692                                    }
    693                                }
    694                                /* reset for call below */
    695                                if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
    696                                    *pErrorCode=U_ZERO_ERROR;
    697                                }
    698                                int32_t vlen = uloc_getDisplayKeywordValue(locale, kw, displayLocale,
    699                                                                           p, cap, pErrorCode);
    700                                if(len) {
    701                                    if(vlen==0) {
    702                                        --len; /* remove unneeded '=' */
    703                                    }
    704                                    /* restore cap and p to what they were at start */
    705                                    cap=destCapacity-length;
    706                                    if(cap <= 0) {
    707                                        cap=0;
    708                                    } else {
    709                                        p=dest+length;
    710                                    }
    711                                }
    712                                len+=vlen; /* total we added for key + '=' + value */
    713                            }
    714                        } break;
    715                    } /* end switch */
    716 
    717                    if (len>0) {
    718                        /* we added a component, so add separator and write it if there's room. */
    719                        if(len+sepLen<=cap) {
    720                            const char16_t * plimit = p + len;
    721                            for (; p < plimit; p++) {
    722                                if (*p == formatOpenParen) {
    723                                    *p = formatReplaceOpenParen;
    724                                } else if (*p == formatCloseParen) {
    725                                    *p = formatReplaceCloseParen;
    726                                }
    727                            }
    728                            for(int32_t i=0;i<sepLen;++i) {
    729                                *p++=separator[i];
    730                            }
    731                        }
    732                        length+=len+sepLen;
    733                    } else if(subdone) {
    734                        /* remove separator if we added it */
    735                        if (length!=restPos) {
    736                            length-=sepLen;
    737                        }
    738                        restLen=length-restPos;
    739                        haveRest=restLen>0;
    740                    }
    741                }
    742            }
    743 
    744            if(*pErrorCode == U_BUFFER_OVERFLOW_ERROR) {
    745                *pErrorCode=U_ZERO_ERROR;
    746            }
    747 
    748            if(subdone) {
    749                if(haveLang && haveRest) {
    750                    /* append internal portion of pattern, the first time,
    751                       or last portion of pattern the second time */
    752                    int32_t padLen;
    753                    patPos+=subLen;
    754                    padLen=(subi==0 ? sub1Pos : patLen)-patPos;
    755                    if(length+padLen <= destCapacity) {
    756                        p=dest+length;
    757                        for(int32_t i=0;i<padLen;++i) {
    758                            *p++=pattern[patPos++];
    759                        }
    760                    } else {
    761                        patPos+=padLen;
    762                    }
    763                    length+=padLen;
    764                } else if(subi==0) {
    765                    /* don't have first component, reset for second component */
    766                    sub0Pos=0;
    767                    length=0;
    768                } else if(length>0) {
    769                    /* true length is the length of just the component we got. */
    770                    length=haveLang?langLen:restLen;
    771                    if(dest && sub0Pos!=0) {
    772                        if (sub0Pos+length<=destCapacity) {
    773                            /* first component not at start of result,
    774                               but we have full component in buffer. */
    775                            u_memmove(dest, dest+(haveLang?langPos:restPos), length);
    776                        } else {
    777                            /* would have fit, but didn't because of pattern prefix. */
    778                            sub0Pos=0; /* stops initial padding (and a second retry,
    779                                          so we won't end up here again) */
    780                            retry=true;
    781                        }
    782                    }
    783                }
    784 
    785                ++subi; /* move on to next substitution */
    786            }
    787        }
    788    } while(retry);
    789 
    790    return u_terminateUChars(dest, destCapacity, length, pErrorCode);
    791 }
    792 
    793 U_CAPI int32_t U_EXPORT2
    794 uloc_getDisplayKeyword(const char* keyword,
    795                       const char* displayLocale,
    796                       char16_t* dest,
    797                       int32_t destCapacity,
    798                       UErrorCode* status){
    799 
    800    /* argument checking */
    801    if(status==nullptr || U_FAILURE(*status)) {
    802        return 0;
    803    }
    804 
    805    if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
    806        *status=U_ILLEGAL_ARGUMENT_ERROR;
    807        return 0;
    808    }
    809 
    810 
    811    /* pass itemKey=nullptr to look for a top-level item */
    812    return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
    813                               _kKeys, nullptr,
    814                               keyword, 
    815                               keyword,      
    816                               dest, destCapacity,
    817                               *status);
    818 
    819 }
    820 
    821 
    822 #define UCURRENCY_DISPLAY_NAME_INDEX 1
    823 
    824 U_CAPI int32_t U_EXPORT2
    825 uloc_getDisplayKeywordValue(   const char* locale,
    826                               const char* keyword,
    827                               const char* displayLocale,
    828                               char16_t* dest,
    829                               int32_t destCapacity,
    830                               UErrorCode* status){
    831 
    832 
    833    /* argument checking */
    834    if(status==nullptr || U_FAILURE(*status)) {
    835        return 0;
    836    }
    837 
    838    if(destCapacity<0 || (destCapacity>0 && dest==nullptr)) {
    839        *status=U_ILLEGAL_ARGUMENT_ERROR;
    840        return 0;
    841    }
    842 
    843    /* get the keyword value */
    844    CharString keywordValue;
    845    if (keyword != nullptr && *keyword != '\0') {
    846        keywordValue = ulocimp_getKeywordValue(locale, keyword, *status);
    847    }
    848 
    849    /* 
    850     * if the keyword is equal to currency .. then to get the display name 
    851     * we need to do the fallback ourselves
    852     */
    853    if(uprv_stricmp(keyword, _kCurrency)==0){
    854 
    855        int32_t dispNameLen = 0;
    856        const char16_t *dispName = nullptr;
    857 
    858        icu::LocalUResourceBundlePointer bundle(
    859                ures_open(U_ICUDATA_CURR, displayLocale, status));
    860        icu::LocalUResourceBundlePointer currencies(
    861                ures_getByKey(bundle.getAlias(), _kCurrencies, nullptr, status));
    862        icu::LocalUResourceBundlePointer currency(
    863                ures_getByKeyWithFallback(currencies.getAlias(), keywordValue.data(), nullptr, status));
    864 
    865        dispName = ures_getStringByIndex(currency.getAlias(), UCURRENCY_DISPLAY_NAME_INDEX, &dispNameLen, status);
    866 
    867        if(U_FAILURE(*status)){
    868            if(*status == U_MISSING_RESOURCE_ERROR){
    869                /* we just want to write the value over if nothing is available */
    870                *status = U_USING_DEFAULT_WARNING;
    871            }else{
    872                return 0;
    873            }
    874        }
    875 
    876        /* now copy the dispName over if not nullptr */
    877        if(dispName != nullptr){
    878            if(dispNameLen <= destCapacity){
    879                u_memcpy(dest, dispName, dispNameLen);
    880                return u_terminateUChars(dest, destCapacity, dispNameLen, status);
    881            }else{
    882                *status = U_BUFFER_OVERFLOW_ERROR;
    883                return dispNameLen;
    884            }
    885        }else{
    886            /* we have not found the display name for the value .. just copy over */
    887            if(keywordValue.length() <= destCapacity){
    888                u_charsToUChars(keywordValue.data(), dest, keywordValue.length());
    889                return u_terminateUChars(dest, destCapacity, keywordValue.length(), status);
    890            }else{
    891                 *status = U_BUFFER_OVERFLOW_ERROR;
    892                return keywordValue.length();
    893            }
    894        }
    895 
    896        
    897    }else{
    898 
    899        return _getStringOrCopyKey(U_ICUDATA_LANG, displayLocale,
    900                                   _kTypes, keyword, 
    901                                   keywordValue.data(),
    902                                   keywordValue.data(),
    903                                   dest, destCapacity,
    904                                   *status);
    905    }
    906 }