tor-browser

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

tznames_impl.cpp (78282B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 * Copyright (C) 2011-2016, International Business Machines Corporation and
      6 * others. All Rights Reserved.
      7 *******************************************************************************
      8 *
      9 * File TZNAMES_IMPL.CPP
     10 *
     11 *******************************************************************************
     12 */
     13 
     14 #include "unicode/utypes.h"
     15 
     16 #if !UCONFIG_NO_FORMATTING
     17 
     18 #include "unicode/strenum.h"
     19 #include "unicode/stringpiece.h"
     20 #include "unicode/ustring.h"
     21 #include "unicode/timezone.h"
     22 #include "unicode/utf16.h"
     23 
     24 #include "tznames_impl.h"
     25 #include "charstr.h"
     26 #include "cmemory.h"
     27 #include "cstring.h"
     28 #include "uassert.h"
     29 #include "mutex.h"
     30 #include "resource.h"
     31 #include "ulocimp.h"
     32 #include "uresimp.h"
     33 #include "ureslocs.h"
     34 #include "zonemeta.h"
     35 #include "ucln_in.h"
     36 #include "uinvchar.h"
     37 #include "uvector.h"
     38 #include "olsontz.h"
     39 
     40 U_NAMESPACE_BEGIN
     41 
     42 #define ZID_KEY_MAX  128
     43 #define MZ_PREFIX_LEN 5
     44 
     45 static const char gZoneStrings[]        = "zoneStrings";
     46 static const char gMZPrefix[]           = "meta:";
     47 
     48 static const char EMPTY[]               = "<empty>";   // place holder for empty ZNames
     49 static const char DUMMY_LOADER[]        = "<dummy>";   // place holder for dummy ZNamesLoader
     50 static const char16_t NO_NAME[]            = { 0 };   // for empty no-fallback time zone names
     51 
     52 // stuff for TZDBTimeZoneNames
     53 static const char* TZDBNAMES_KEYS[]               = {"ss", "sd"};
     54 static const int32_t TZDBNAMES_KEYS_SIZE = UPRV_LENGTHOF(TZDBNAMES_KEYS);
     55 
     56 static UMutex gDataMutex;
     57 
     58 static UHashtable* gTZDBNamesMap = nullptr;
     59 static icu::UInitOnce gTZDBNamesMapInitOnce {};
     60 
     61 static TextTrieMap* gTZDBNamesTrie = nullptr;
     62 static icu::UInitOnce gTZDBNamesTrieInitOnce {};
     63 
     64 // The order in which strings are stored may be different than the order in the public enum.
     65 enum UTimeZoneNameTypeIndex {
     66    UTZNM_INDEX_UNKNOWN = -1,
     67    UTZNM_INDEX_EXEMPLAR_LOCATION,
     68    UTZNM_INDEX_LONG_GENERIC,
     69    UTZNM_INDEX_LONG_STANDARD,
     70    UTZNM_INDEX_LONG_DAYLIGHT,
     71    UTZNM_INDEX_SHORT_GENERIC,
     72    UTZNM_INDEX_SHORT_STANDARD,
     73    UTZNM_INDEX_SHORT_DAYLIGHT,
     74    UTZNM_INDEX_COUNT
     75 };
     76 static const char16_t* const EMPTY_NAMES[UTZNM_INDEX_COUNT] = {
     77    nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
     78 };
     79 
     80 U_CDECL_BEGIN
     81 static UBool U_CALLCONV tzdbTimeZoneNames_cleanup() {
     82    if (gTZDBNamesMap != nullptr) {
     83        uhash_close(gTZDBNamesMap);
     84        gTZDBNamesMap = nullptr;
     85    }
     86    gTZDBNamesMapInitOnce.reset();
     87 
     88    if (gTZDBNamesTrie != nullptr) {
     89        delete gTZDBNamesTrie;
     90        gTZDBNamesTrie = nullptr;
     91    }
     92    gTZDBNamesTrieInitOnce.reset();
     93 
     94    return true;
     95 }
     96 U_CDECL_END
     97 
     98 /**
     99 * ZNameInfo stores zone name information in the trie
    100 */
    101 struct ZNameInfo {
    102    UTimeZoneNameType   type;
    103    const char16_t*        tzID;
    104    const char16_t*        mzID;
    105 };
    106 
    107 /**
    108 * ZMatchInfo stores zone name match information used by find method
    109 */
    110 struct ZMatchInfo {
    111    const ZNameInfo*    znameInfo;
    112    int32_t             matchLength;
    113 };
    114 
    115 // Helper functions
    116 static void mergeTimeZoneKey(const UnicodeString& mzID, char* result, size_t capacity, UErrorCode& status);
    117 
    118 #define DEFAULT_CHARACTERNODE_CAPACITY 1
    119 
    120 // ---------------------------------------------------
    121 // CharacterNode class implementation
    122 // ---------------------------------------------------
    123 void CharacterNode::clear() {
    124    uprv_memset(this, 0, sizeof(*this));
    125 }
    126 
    127 void CharacterNode::deleteValues(UObjectDeleter *valueDeleter) {
    128    if (fValues == nullptr) {
    129        // Do nothing.
    130    } else if (!fHasValuesVector) {
    131        if (valueDeleter) {
    132            valueDeleter(fValues);
    133        }
    134    } else {
    135        delete static_cast<UVector*>(fValues);
    136    }
    137 }
    138 
    139 void
    140 CharacterNode::addValue(void *value, UObjectDeleter *valueDeleter, UErrorCode &status) {
    141    if (U_FAILURE(status)) {
    142        if (valueDeleter) {
    143            valueDeleter(value);
    144        }
    145        return;
    146    }
    147    if (fValues == nullptr) {
    148        fValues = value;
    149    } else {
    150        // At least one value already.
    151        if (!fHasValuesVector) {
    152            // There is only one value so far, and not in a vector yet.
    153            // Create a vector and add the old value.
    154            LocalPointer<UVector> values(
    155                new UVector(valueDeleter, nullptr, DEFAULT_CHARACTERNODE_CAPACITY, status), status);
    156            if (U_FAILURE(status)) {
    157                if (valueDeleter) {
    158                    valueDeleter(value);
    159                }
    160                return;
    161            }
    162            if (values->hasDeleter()) {
    163                values->adoptElement(fValues, status);
    164            } else {
    165                values->addElement(fValues, status);
    166            }
    167            fValues = values.orphan();
    168            fHasValuesVector = true;
    169        }
    170        // Add the new value.
    171        UVector* values = static_cast<UVector*>(fValues);
    172        if (values->hasDeleter()) {
    173            values->adoptElement(value, status);
    174        } else {
    175            values->addElement(value, status);
    176        }
    177    }
    178 }
    179 
    180 // ---------------------------------------------------
    181 // TextTrieMapSearchResultHandler class implementation
    182 // ---------------------------------------------------
    183 TextTrieMapSearchResultHandler::~TextTrieMapSearchResultHandler(){
    184 }
    185 
    186 // ---------------------------------------------------
    187 // TextTrieMap class implementation
    188 // ---------------------------------------------------
    189 TextTrieMap::TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleter)
    190 : fIgnoreCase(ignoreCase), fNodes(nullptr), fNodesCapacity(0), fNodesCount(0), 
    191  fLazyContents(nullptr), fIsEmpty(true), fValueDeleter(valueDeleter) {
    192 }
    193 
    194 TextTrieMap::~TextTrieMap() {
    195    int32_t index;
    196    for (index = 0; index < fNodesCount; ++index) {
    197        fNodes[index].deleteValues(fValueDeleter);
    198    }
    199    uprv_free(fNodes);
    200    if (fLazyContents != nullptr) {
    201        for (int32_t i=0; i<fLazyContents->size(); i+=2) {
    202            if (fValueDeleter) {
    203                fValueDeleter(fLazyContents->elementAt(i+1));
    204            }
    205        } 
    206        delete fLazyContents;
    207    }
    208 }
    209 
    210 int32_t TextTrieMap::isEmpty() const {
    211    // Use a separate field for fIsEmpty because it will remain unchanged once the
    212    //   Trie is built, while fNodes and fLazyContents change with the lazy init
    213    //   of the nodes structure.  Trying to test the changing fields has
    214    //   thread safety complications.
    215    return fIsEmpty;
    216 }
    217 
    218 
    219 //  We defer actually building the TextTrieMap node structure until the first time a
    220 //     search is performed.  put() simply saves the parameters in case we do
    221 //     eventually need to build it.
    222 //     
    223 void
    224 TextTrieMap::put(const UnicodeString &key, void *value, ZNStringPool &sp, UErrorCode &status) {
    225    const char16_t *s = sp.get(key, status);
    226    put(s, value, status);
    227 }
    228 
    229 // This method is designed for a persistent key, such as string key stored in
    230 // resource bundle.
    231 void
    232 TextTrieMap::put(const char16_t *key, void *value, UErrorCode &status) {
    233    fIsEmpty = false;
    234    if (fLazyContents == nullptr) {
    235        LocalPointer<UVector> lpLazyContents(new UVector(status), status);
    236        fLazyContents = lpLazyContents.orphan();
    237    }
    238    if (U_SUCCESS(status)) {
    239        U_ASSERT(fLazyContents != nullptr);
    240        char16_t *s = const_cast<char16_t *>(key);
    241        fLazyContents->addElement(s, status);
    242        if (U_SUCCESS(status)) {
    243            fLazyContents->addElement(value, status);
    244            return;
    245        }
    246    }
    247    if (fValueDeleter) {
    248        fValueDeleter(value);
    249    }
    250 }
    251 
    252 void
    253 TextTrieMap::putImpl(const UnicodeString &key, void *value, UErrorCode &status) {
    254    if (fNodes == nullptr) {
    255        fNodesCapacity = 512;
    256        fNodes = static_cast<CharacterNode*>(uprv_malloc(fNodesCapacity * sizeof(CharacterNode)));
    257        if (fNodes == nullptr) {
    258            status = U_MEMORY_ALLOCATION_ERROR;
    259            return;
    260        }
    261        fNodes[0].clear();  // Init root node.
    262        fNodesCount = 1;
    263    }
    264 
    265    UnicodeString foldedKey;
    266    const char16_t *keyBuffer;
    267    int32_t keyLength;
    268    if (fIgnoreCase) {
    269        // Ok to use fastCopyFrom() because we discard the copy when we return.
    270        foldedKey.fastCopyFrom(key).foldCase();
    271        keyBuffer = foldedKey.getBuffer();
    272        keyLength = foldedKey.length();
    273    } else {
    274        keyBuffer = key.getBuffer();
    275        keyLength = key.length();
    276    }
    277 
    278    CharacterNode *node = fNodes;
    279    int32_t index;
    280    for (index = 0; index < keyLength; ++index) {
    281        node = addChildNode(node, keyBuffer[index], status);
    282    }
    283    node->addValue(value, fValueDeleter, status);
    284 }
    285 
    286 UBool
    287 TextTrieMap::growNodes() {
    288    if (fNodesCapacity == 0xffff) {
    289        return false;  // We use 16-bit node indexes.
    290    }
    291    int32_t newCapacity = fNodesCapacity + 1000;
    292    if (newCapacity > 0xffff) {
    293        newCapacity = 0xffff;
    294    }
    295    CharacterNode* newNodes = static_cast<CharacterNode*>(uprv_malloc(newCapacity * sizeof(CharacterNode)));
    296    if (newNodes == nullptr) {
    297        return false;
    298    }
    299    uprv_memcpy(newNodes, fNodes, fNodesCount * sizeof(CharacterNode));
    300    uprv_free(fNodes);
    301    fNodes = newNodes;
    302    fNodesCapacity = newCapacity;
    303    return true;
    304 }
    305 
    306 CharacterNode*
    307 TextTrieMap::addChildNode(CharacterNode *parent, char16_t c, UErrorCode &status) {
    308    if (U_FAILURE(status)) {
    309        return nullptr;
    310    }
    311    // Linear search of the sorted list of children.
    312    uint16_t prevIndex = 0;
    313    uint16_t nodeIndex = parent->fFirstChild;
    314    while (nodeIndex > 0) {
    315        CharacterNode *current = fNodes + nodeIndex;
    316        char16_t childCharacter = current->fCharacter;
    317        if (childCharacter == c) {
    318            return current;
    319        } else if (childCharacter > c) {
    320            break;
    321        }
    322        prevIndex = nodeIndex;
    323        nodeIndex = current->fNextSibling;
    324    }
    325 
    326    // Ensure capacity. Grow fNodes[] if needed.
    327    if (fNodesCount == fNodesCapacity) {
    328        int32_t parentIndex = static_cast<int32_t>(parent - fNodes);
    329        if (!growNodes()) {
    330            status = U_MEMORY_ALLOCATION_ERROR;
    331            return nullptr;
    332        }
    333        parent = fNodes + parentIndex;
    334    }
    335 
    336    // Insert a new child node with c in sorted order.
    337    CharacterNode *node = fNodes + fNodesCount;
    338    node->clear();
    339    node->fCharacter = c;
    340    node->fNextSibling = nodeIndex;
    341    if (prevIndex == 0) {
    342        parent->fFirstChild = static_cast<uint16_t>(fNodesCount);
    343    } else {
    344        fNodes[prevIndex].fNextSibling = static_cast<uint16_t>(fNodesCount);
    345    }
    346    ++fNodesCount;
    347    return node;
    348 }
    349 
    350 CharacterNode*
    351 TextTrieMap::getChildNode(CharacterNode *parent, char16_t c) const {
    352    // Linear search of the sorted list of children.
    353    uint16_t nodeIndex = parent->fFirstChild;
    354    while (nodeIndex > 0) {
    355        CharacterNode *current = fNodes + nodeIndex;
    356        char16_t childCharacter = current->fCharacter;
    357        if (childCharacter == c) {
    358            return current;
    359        } else if (childCharacter > c) {
    360            break;
    361        }
    362        nodeIndex = current->fNextSibling;
    363    }
    364    return nullptr;
    365 }
    366 
    367 
    368 // buildTrie() - The Trie node structure is needed.  Create it from the data that was
    369 //               saved at the time the ZoneStringFormatter was created.  The Trie is only
    370 //               needed for parsing operations, which are less common than formatting,
    371 //               and the Trie is big, which is why its creation is deferred until first use.
    372 void TextTrieMap::buildTrie(UErrorCode &status) {
    373    if (fLazyContents != nullptr) {
    374        for (int32_t i=0; i<fLazyContents->size(); i+=2) {
    375            const char16_t* key = static_cast<char16_t*>(fLazyContents->elementAt(i));
    376            void  *val = fLazyContents->elementAt(i+1);
    377            UnicodeString keyString(true, key, -1);  // Aliasing UnicodeString constructor.
    378            putImpl(keyString, val, status);
    379        }
    380        delete fLazyContents;
    381        fLazyContents = nullptr; 
    382    }
    383 }
    384 
    385 void
    386 TextTrieMap::search(const UnicodeString &text, int32_t start,
    387                  TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
    388    {
    389        // TODO: if locking the mutex for each check proves to be a performance problem,
    390        //       add a flag of type atomic_int32_t to class TextTrieMap, and use only
    391        //       the ICU atomic safe functions for assigning and testing.
    392        //       Don't test the pointer fLazyContents.
    393        //       Don't do unless it's really required.
    394 
    395        // Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
    396        static UMutex TextTrieMutex;
    397 
    398        Mutex lock(&TextTrieMutex);
    399        if (fLazyContents != nullptr) {
    400            TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
    401            nonConstThis->buildTrie(status);
    402        }
    403    }
    404    if (fNodes == nullptr) {
    405        return;
    406    }
    407    search(fNodes, text, start, start, handler, status);
    408 }
    409 
    410 void
    411 TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t start,
    412                  int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
    413    if (U_FAILURE(status)) {
    414        return;
    415    }
    416    if (node->hasValues()) {
    417        if (!handler->handleMatch(index - start, node, status)) {
    418            return;
    419        }
    420        if (U_FAILURE(status)) {
    421            return;
    422        }
    423    }
    424    if (fIgnoreCase) {
    425        // for folding we need to get a complete code point.
    426        // size of character may grow after fold operation;
    427        // then we need to get result as UTF16 code units.
    428        UChar32 c32 = text.char32At(index);
    429        index += U16_LENGTH(c32);
    430        UnicodeString tmp(c32);
    431        tmp.foldCase();
    432        int32_t tmpidx = 0;
    433        while (tmpidx < tmp.length()) {
    434            char16_t c = tmp.charAt(tmpidx++);
    435            node = getChildNode(node, c);
    436            if (node == nullptr) {
    437                break;
    438            }
    439        }
    440    } else {
    441        // here we just get the next UTF16 code unit
    442        char16_t c = text.charAt(index++);
    443        node = getChildNode(node, c);
    444    }
    445    if (node != nullptr) {
    446        search(node, text, start, index, handler, status);
    447    }
    448 }
    449 
    450 // ---------------------------------------------------
    451 // ZNStringPool class implementation
    452 // ---------------------------------------------------
    453 static const int32_t POOL_CHUNK_SIZE = 2000;
    454 struct ZNStringPoolChunk: public UMemory {
    455    ZNStringPoolChunk    *fNext;                       // Ptr to next pool chunk
    456    int32_t               fLimit;                       // Index to start of unused area at end of fStrings
    457    char16_t              fStrings[POOL_CHUNK_SIZE];    //  Strings array
    458    ZNStringPoolChunk();
    459 };
    460 
    461 ZNStringPoolChunk::ZNStringPoolChunk() {
    462    fNext = nullptr;
    463    fLimit = 0;
    464 }
    465 
    466 ZNStringPool::ZNStringPool(UErrorCode &status) {
    467    fChunks = nullptr;
    468    fHash   = nullptr;
    469    if (U_FAILURE(status)) {
    470        return;
    471    }
    472    fChunks = new ZNStringPoolChunk;
    473    if (fChunks == nullptr) {
    474        status = U_MEMORY_ALLOCATION_ERROR;
    475        return;
    476    }
    477 
    478    fHash   = uhash_open(uhash_hashUChars      /* keyHash */, 
    479                         uhash_compareUChars   /* keyComp */, 
    480                         uhash_compareUChars   /* valueComp */, 
    481                         &status);
    482    if (U_FAILURE(status)) {
    483        return;
    484    }
    485 }
    486 
    487 ZNStringPool::~ZNStringPool() {
    488    if (fHash != nullptr) {
    489        uhash_close(fHash);
    490        fHash = nullptr;
    491    }
    492 
    493    while (fChunks != nullptr) {
    494        ZNStringPoolChunk *nextChunk = fChunks->fNext;
    495        delete fChunks;
    496        fChunks = nextChunk;
    497    }
    498 }
    499 
    500 static const char16_t EmptyString = 0;
    501 
    502 const char16_t *ZNStringPool::get(const char16_t *s, UErrorCode &status) {
    503    const char16_t *pooledString;
    504    if (U_FAILURE(status)) {
    505        return &EmptyString;
    506    }
    507 
    508    pooledString = static_cast<char16_t *>(uhash_get(fHash, s));
    509    if (pooledString != nullptr) {
    510        return pooledString;
    511    }
    512 
    513    int32_t length = u_strlen(s);
    514    int32_t remainingLength = POOL_CHUNK_SIZE - fChunks->fLimit;
    515    if (remainingLength <= length) {
    516        U_ASSERT(length < POOL_CHUNK_SIZE);
    517        if (length >= POOL_CHUNK_SIZE) {
    518            status = U_INTERNAL_PROGRAM_ERROR;
    519            return &EmptyString;
    520        }
    521        ZNStringPoolChunk *oldChunk = fChunks;
    522        fChunks = new ZNStringPoolChunk;
    523        if (fChunks == nullptr) {
    524            status = U_MEMORY_ALLOCATION_ERROR;
    525            return &EmptyString;
    526        }
    527        fChunks->fNext = oldChunk;
    528    }
    529    
    530    char16_t *destString = &fChunks->fStrings[fChunks->fLimit];
    531    u_strcpy(destString, s);
    532    fChunks->fLimit += (length + 1);
    533    uhash_put(fHash, destString, destString, &status);
    534    return destString;
    535 }        
    536 
    537 
    538 //
    539 //  ZNStringPool::adopt()    Put a string into the hash, but do not copy the string data
    540 //                           into the pool's storage.  Used for strings from resource bundles,
    541 //                           which will persist for the life of the zone string formatter, and
    542 //                           therefore can be used directly without copying.
    543 const char16_t *ZNStringPool::adopt(const char16_t * s, UErrorCode &status) {
    544    const char16_t *pooledString;
    545    if (U_FAILURE(status)) {
    546        return &EmptyString;
    547    }
    548    if (s != nullptr) {
    549        pooledString = static_cast<char16_t *>(uhash_get(fHash, s));
    550        if (pooledString == nullptr) {
    551            char16_t *ncs = const_cast<char16_t *>(s);
    552            uhash_put(fHash, ncs, ncs, &status);
    553        }
    554    }
    555    return s;
    556 }
    557 
    558    
    559 const char16_t *ZNStringPool::get(const UnicodeString &s, UErrorCode &status) {
    560    UnicodeString &nonConstStr = const_cast<UnicodeString &>(s);
    561    return this->get(nonConstStr.getTerminatedBuffer(), status);
    562 }
    563 
    564 /*
    565 * freeze().   Close the hash table that maps to the pooled strings.
    566 *             After freezing, the pool can not be searched or added to,
    567 *             but all existing references to pooled strings remain valid.
    568 *
    569 *             The main purpose is to recover the storage used for the hash.
    570 */
    571 void ZNStringPool::freeze() {
    572    uhash_close(fHash);
    573    fHash = nullptr;
    574 }
    575 
    576 
    577 /**
    578 * This class stores name data for a meta zone or time zone.
    579 */
    580 class ZNames : public UMemory {
    581 private:
    582    friend class TimeZoneNamesImpl;
    583 
    584    static UTimeZoneNameTypeIndex getTZNameTypeIndex(UTimeZoneNameType type) {
    585        switch(type) {
    586        case UTZNM_EXEMPLAR_LOCATION: return UTZNM_INDEX_EXEMPLAR_LOCATION;
    587        case UTZNM_LONG_GENERIC: return UTZNM_INDEX_LONG_GENERIC;
    588        case UTZNM_LONG_STANDARD: return UTZNM_INDEX_LONG_STANDARD;
    589        case UTZNM_LONG_DAYLIGHT: return UTZNM_INDEX_LONG_DAYLIGHT;
    590        case UTZNM_SHORT_GENERIC: return UTZNM_INDEX_SHORT_GENERIC;
    591        case UTZNM_SHORT_STANDARD: return UTZNM_INDEX_SHORT_STANDARD;
    592        case UTZNM_SHORT_DAYLIGHT: return UTZNM_INDEX_SHORT_DAYLIGHT;
    593        default: return UTZNM_INDEX_UNKNOWN;
    594        }
    595    }
    596    static UTimeZoneNameType getTZNameType(UTimeZoneNameTypeIndex index) {
    597        switch(index) {
    598        case UTZNM_INDEX_EXEMPLAR_LOCATION: return UTZNM_EXEMPLAR_LOCATION;
    599        case UTZNM_INDEX_LONG_GENERIC: return UTZNM_LONG_GENERIC;
    600        case UTZNM_INDEX_LONG_STANDARD: return UTZNM_LONG_STANDARD;
    601        case UTZNM_INDEX_LONG_DAYLIGHT: return UTZNM_LONG_DAYLIGHT;
    602        case UTZNM_INDEX_SHORT_GENERIC: return UTZNM_SHORT_GENERIC;
    603        case UTZNM_INDEX_SHORT_STANDARD: return UTZNM_SHORT_STANDARD;
    604        case UTZNM_INDEX_SHORT_DAYLIGHT: return UTZNM_SHORT_DAYLIGHT;
    605        default: return UTZNM_UNKNOWN;
    606        }
    607    }
    608 
    609    const char16_t* fNames[UTZNM_INDEX_COUNT];
    610    UBool fDidAddIntoTrie;
    611 
    612    // Whether we own the location string, if computed rather than loaded from a bundle.
    613    // A meta zone names instance never has an exemplar location string.
    614    UBool fOwnsLocationName;
    615 
    616    ZNames(const char16_t* names[], const char16_t* locationName)
    617            : fDidAddIntoTrie(false) {
    618        uprv_memcpy(fNames, names, sizeof(fNames));
    619        if (locationName != nullptr) {
    620            fOwnsLocationName = true;
    621            fNames[UTZNM_INDEX_EXEMPLAR_LOCATION] = locationName;
    622        } else {
    623            fOwnsLocationName = false;
    624        }
    625    }
    626 
    627 public:
    628    ~ZNames() {
    629        if (fOwnsLocationName) {
    630            const char16_t* locationName = fNames[UTZNM_INDEX_EXEMPLAR_LOCATION];
    631            U_ASSERT(locationName != nullptr);
    632            uprv_free((void*) locationName);
    633        }
    634    }
    635 
    636 private:
    637    static void* createMetaZoneAndPutInCache(UHashtable* cache, const char16_t* names[],
    638            const UnicodeString& mzID, UErrorCode& status) {
    639        if (U_FAILURE(status)) { return nullptr; }
    640        U_ASSERT(names != nullptr);
    641 
    642        // Use the persistent ID as the resource key, so we can
    643        // avoid duplications.
    644        // TODO: Is there a more efficient way, like intern() in Java?
    645        void* key = (void*) ZoneMeta::findMetaZoneID(mzID);
    646        void* value;
    647        if (uprv_memcmp(names, EMPTY_NAMES, sizeof(EMPTY_NAMES)) == 0) {
    648            value = (void*) EMPTY;
    649        } else {
    650            value = (void*) (new ZNames(names, nullptr));
    651            if (value == nullptr) {
    652                status = U_MEMORY_ALLOCATION_ERROR;
    653                return nullptr;
    654            }
    655        }
    656        uhash_put(cache, key, value, &status);
    657        return value;
    658    }
    659 
    660    static void* createTimeZoneAndPutInCache(UHashtable* cache, const char16_t* names[],
    661            const UnicodeString& tzID, UErrorCode& status) {
    662        if (U_FAILURE(status)) { return nullptr; }
    663        U_ASSERT(names != nullptr);
    664 
    665        // If necessary, compute the location name from the time zone name.
    666        char16_t* locationName = nullptr;
    667        if (names[UTZNM_INDEX_EXEMPLAR_LOCATION] == nullptr) {
    668            UnicodeString locationNameUniStr;
    669            TimeZoneNamesImpl::getDefaultExemplarLocationName(tzID, locationNameUniStr);
    670 
    671            // Copy the computed location name to the heap
    672            if (locationNameUniStr.length() > 0) {
    673                const char16_t* buff = locationNameUniStr.getTerminatedBuffer();
    674                int32_t len = sizeof(char16_t) * (locationNameUniStr.length() + 1);
    675                locationName = static_cast<char16_t*>(uprv_malloc(len));
    676                if (locationName == nullptr) {
    677                    status = U_MEMORY_ALLOCATION_ERROR;
    678                    return nullptr;
    679                }
    680                uprv_memcpy(locationName, buff, len);
    681            }
    682        }
    683 
    684        // Use the persistent ID as the resource key, so we can
    685        // avoid duplications.
    686        // TODO: Is there a more efficient way, like intern() in Java?
    687        void* key = (void*) ZoneMeta::findTimeZoneID(tzID);
    688        void* value = (void*) (new ZNames(names, locationName));
    689        if (value == nullptr) {
    690            status = U_MEMORY_ALLOCATION_ERROR;
    691            return nullptr;
    692        }
    693        uhash_put(cache, key, value, &status);
    694        return value;
    695    }
    696 
    697    const char16_t* getName(UTimeZoneNameType type) const {
    698        UTimeZoneNameTypeIndex index = getTZNameTypeIndex(type);
    699        return index >= 0 ? fNames[index] : nullptr;
    700    }
    701 
    702    void addAsMetaZoneIntoTrie(const char16_t* mzID, TextTrieMap& trie, UErrorCode& status) {
    703        addNamesIntoTrie(mzID, nullptr, trie, status);
    704    }
    705    void addAsTimeZoneIntoTrie(const char16_t* tzID, TextTrieMap& trie, UErrorCode& status) {
    706        addNamesIntoTrie(nullptr, tzID, trie, status);
    707    }
    708 
    709    void addNamesIntoTrie(const char16_t* mzID, const char16_t* tzID, TextTrieMap& trie,
    710            UErrorCode& status) {
    711        if (U_FAILURE(status)) { return; }
    712        if (fDidAddIntoTrie) { return; }
    713        fDidAddIntoTrie = true;
    714 
    715        for (int32_t i = 0; i < UTZNM_INDEX_COUNT; i++) {
    716            const char16_t* name = fNames[i];
    717            if (name != nullptr) {
    718                LocalMemory<ZNameInfo> nameinfo(static_cast<ZNameInfo*>(uprv_malloc(sizeof(ZNameInfo))));
    719                if (nameinfo.isNull()) {
    720                    status = U_MEMORY_ALLOCATION_ERROR;
    721                    return;
    722                }
    723                nameinfo->mzID = mzID;
    724                nameinfo->tzID = tzID;
    725                nameinfo->type = getTZNameType(static_cast<UTimeZoneNameTypeIndex>(i));
    726                trie.put(name, nameinfo.orphan(), status); // trie.put() takes ownership of the key
    727                if (U_FAILURE(status)) {
    728                    return;
    729                }
    730            }
    731        }
    732    }
    733 
    734 public:
    735    struct ZNamesLoader;
    736 };
    737 
    738 struct ZNames::ZNamesLoader : public ResourceSink {
    739    const char16_t *names[UTZNM_INDEX_COUNT];
    740 
    741    ZNamesLoader() {
    742        clear();
    743    }
    744    virtual ~ZNamesLoader();
    745 
    746    /** Reset for loading another set of names. */
    747    void clear() {
    748        uprv_memcpy(names, EMPTY_NAMES, sizeof(names));
    749    }
    750 
    751    void loadMetaZone(const UResourceBundle* zoneStrings, const UnicodeString& mzID, UErrorCode& errorCode) {
    752        if (U_FAILURE(errorCode)) { return; }
    753 
    754        char key[ZID_KEY_MAX + 1];
    755        mergeTimeZoneKey(mzID, key, sizeof(key), errorCode);
    756 
    757        loadNames(zoneStrings, key, errorCode);
    758    }
    759 
    760    void loadTimeZone(const UResourceBundle* zoneStrings, const UnicodeString& tzID, UErrorCode& errorCode) {
    761        // Replace "/" with ":".
    762        UnicodeString uKey(tzID);
    763        for (int32_t i = 0; i < uKey.length(); i++) {
    764            if (uKey.charAt(i) == static_cast<char16_t>(0x2F)) {
    765                uKey.setCharAt(i, static_cast<char16_t>(0x3A));
    766            }
    767        }
    768 
    769        char key[ZID_KEY_MAX + 1];
    770        if (uKey.length() > ZID_KEY_MAX) {
    771            errorCode = U_INTERNAL_PROGRAM_ERROR;
    772            return;
    773        }
    774        uKey.extract(0, uKey.length(), key, sizeof(key), US_INV);
    775 
    776        loadNames(zoneStrings, key, errorCode);
    777    }
    778 
    779    void loadNames(const UResourceBundle* zoneStrings, const char* key, UErrorCode& errorCode) {
    780        U_ASSERT(zoneStrings != nullptr);
    781        U_ASSERT(key != nullptr);
    782        U_ASSERT(key[0] != '\0');
    783 
    784        UErrorCode localStatus = U_ZERO_ERROR;
    785        clear();
    786        ures_getAllItemsWithFallback(zoneStrings, key, *this, localStatus);
    787 
    788        // Ignore errors, but propagate possible warnings.
    789        if (U_SUCCESS(localStatus)) {
    790            errorCode = localStatus;
    791        }
    792    }
    793 
    794    void setNameIfEmpty(const char* key, const ResourceValue* value, UErrorCode& errorCode) {
    795        UTimeZoneNameTypeIndex type = nameTypeFromKey(key);
    796        if (type == UTZNM_INDEX_UNKNOWN) { return; }
    797        if (names[type] == nullptr) {
    798            int32_t length;
    799            // 'NO_NAME' indicates internally that this field should remain empty.  It will be
    800            // replaced by 'nullptr' in getNames()
    801            names[type] = (value == nullptr) ? NO_NAME : value->getString(length, errorCode);
    802        }
    803    }
    804 
    805    virtual void put(const char* key, ResourceValue& value, UBool /*noFallback*/,
    806            UErrorCode &errorCode) override {
    807        ResourceTable namesTable = value.getTable(errorCode);
    808        if (U_FAILURE(errorCode)) { return; }
    809        for (int32_t i = 0; namesTable.getKeyAndValue(i, key, value); ++i) {
    810            if (value.isNoInheritanceMarker()) {
    811                setNameIfEmpty(key, nullptr, errorCode);
    812            } else {
    813                setNameIfEmpty(key, &value, errorCode);
    814            }
    815        }
    816    }
    817 
    818    static UTimeZoneNameTypeIndex nameTypeFromKey(const char *key) {
    819        char c0, c1;
    820        if ((c0 = key[0]) == 0 || (c1 = key[1]) == 0 || key[2] != 0) {
    821            return UTZNM_INDEX_UNKNOWN;
    822        }
    823        if (c0 == 'l') {
    824            return c1 == 'g' ? UTZNM_INDEX_LONG_GENERIC :
    825                    c1 == 's' ? UTZNM_INDEX_LONG_STANDARD :
    826                        c1 == 'd' ? UTZNM_INDEX_LONG_DAYLIGHT : UTZNM_INDEX_UNKNOWN;
    827        } else if (c0 == 's') {
    828            return c1 == 'g' ? UTZNM_INDEX_SHORT_GENERIC :
    829                    c1 == 's' ? UTZNM_INDEX_SHORT_STANDARD :
    830                        c1 == 'd' ? UTZNM_INDEX_SHORT_DAYLIGHT : UTZNM_INDEX_UNKNOWN;
    831        } else if (c0 == 'e' && c1 == 'c') {
    832            return UTZNM_INDEX_EXEMPLAR_LOCATION;
    833        }
    834        return UTZNM_INDEX_UNKNOWN;
    835    }
    836 
    837    /**
    838    * Returns an array of names.  It is the caller's responsibility to copy the data into a
    839    * permanent location, as the returned array is owned by the loader instance and may be
    840    * cleared or leave scope.
    841    *
    842    * This is different than Java, where the array will no longer be modified and null
    843    * may be returned.
    844    */
    845    const char16_t** getNames() {
    846        // Remove 'NO_NAME' references in the array and replace with 'nullptr'
    847        for (int32_t i = 0; i < UTZNM_INDEX_COUNT; ++i) {
    848            if (names[i] == NO_NAME) {
    849                names[i] = nullptr;
    850            }
    851        }
    852        return names;
    853    }
    854 };
    855 
    856 ZNames::ZNamesLoader::~ZNamesLoader() {}
    857 
    858 
    859 // ---------------------------------------------------
    860 // The meta zone ID enumeration class
    861 // ---------------------------------------------------
    862 class MetaZoneIDsEnumeration : public StringEnumeration {
    863 public:
    864    MetaZoneIDsEnumeration();
    865    MetaZoneIDsEnumeration(const UVector& mzIDs);
    866    MetaZoneIDsEnumeration(LocalPointer<UVector> mzIDs);
    867    virtual ~MetaZoneIDsEnumeration();
    868    static UClassID U_EXPORT2 getStaticClassID();
    869    virtual UClassID getDynamicClassID() const override;
    870    virtual const UnicodeString* snext(UErrorCode& status) override;
    871    virtual void reset(UErrorCode& status) override;
    872    virtual int32_t count(UErrorCode& status) const override;
    873 private:
    874    int32_t fLen;
    875    int32_t fPos;
    876    const UVector* fMetaZoneIDs;
    877    LocalPointer<UVector> fLocalVector;
    878 };
    879 
    880 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MetaZoneIDsEnumeration)
    881 
    882 MetaZoneIDsEnumeration::MetaZoneIDsEnumeration() 
    883 : fLen(0), fPos(0), fMetaZoneIDs(nullptr), fLocalVector(nullptr) {
    884 }
    885 
    886 MetaZoneIDsEnumeration::MetaZoneIDsEnumeration(const UVector& mzIDs) 
    887 : fPos(0), fMetaZoneIDs(&mzIDs), fLocalVector(nullptr) {
    888    fLen = fMetaZoneIDs->size();
    889 }
    890 
    891 MetaZoneIDsEnumeration::MetaZoneIDsEnumeration(LocalPointer<UVector> mzIDs)
    892 : fLen(0), fPos(0), fMetaZoneIDs(nullptr), fLocalVector(std::move(mzIDs)) {
    893    fMetaZoneIDs = fLocalVector.getAlias();
    894    if (fMetaZoneIDs) {
    895        fLen = fMetaZoneIDs->size();
    896    }
    897 }
    898 
    899 const UnicodeString*
    900 MetaZoneIDsEnumeration::snext(UErrorCode& status) {
    901    if (U_SUCCESS(status) && fMetaZoneIDs != nullptr && fPos < fLen) {
    902        unistr.setTo(static_cast<const char16_t*>(fMetaZoneIDs->elementAt(fPos++)), -1);
    903        return &unistr;
    904    }
    905    return nullptr;
    906 }
    907 
    908 void
    909 MetaZoneIDsEnumeration::reset(UErrorCode& /*status*/) {
    910    fPos = 0;
    911 }
    912 
    913 int32_t
    914 MetaZoneIDsEnumeration::count(UErrorCode& /*status*/) const {
    915    return fLen;
    916 }
    917 
    918 MetaZoneIDsEnumeration::~MetaZoneIDsEnumeration() {
    919 }
    920 
    921 
    922 // ---------------------------------------------------
    923 // ZNameSearchHandler
    924 // ---------------------------------------------------
    925 class ZNameSearchHandler : public TextTrieMapSearchResultHandler {
    926 public:
    927    ZNameSearchHandler(uint32_t types);
    928    virtual ~ZNameSearchHandler();
    929 
    930    UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) override;
    931    TimeZoneNames::MatchInfoCollection* getMatches(int32_t& maxMatchLen);
    932 
    933 private:
    934    uint32_t fTypes;
    935    int32_t fMaxMatchLen;
    936    TimeZoneNames::MatchInfoCollection* fResults;
    937 };
    938 
    939 ZNameSearchHandler::ZNameSearchHandler(uint32_t types) 
    940 : fTypes(types), fMaxMatchLen(0), fResults(nullptr) {
    941 }
    942 
    943 ZNameSearchHandler::~ZNameSearchHandler() {
    944    delete fResults;
    945 }
    946 
    947 UBool
    948 ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
    949    if (U_FAILURE(status)) {
    950        return false;
    951    }
    952    if (node->hasValues()) {
    953        int32_t valuesCount = node->countValues();
    954        for (int32_t i = 0; i < valuesCount; i++) {
    955            ZNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
    956            if (nameinfo == nullptr) {
    957                continue;
    958            }
    959            if ((nameinfo->type & fTypes) != 0) {
    960                // matches a requested type
    961                if (fResults == nullptr) {
    962                    fResults = new TimeZoneNames::MatchInfoCollection();
    963                    if (fResults == nullptr) {
    964                        status = U_MEMORY_ALLOCATION_ERROR;
    965                    }
    966                }
    967                if (U_SUCCESS(status)) {
    968                    U_ASSERT(fResults != nullptr);
    969                    if (nameinfo->tzID) {
    970                        fResults->addZone(nameinfo->type, matchLength, UnicodeString(nameinfo->tzID, -1), status);
    971                    } else {
    972                        U_ASSERT(nameinfo->mzID);
    973                        fResults->addMetaZone(nameinfo->type, matchLength, UnicodeString(nameinfo->mzID, -1), status);
    974                    }
    975                    if (U_SUCCESS(status) && matchLength > fMaxMatchLen) {
    976                        fMaxMatchLen = matchLength;
    977                    }
    978                }
    979            }
    980        }
    981    }
    982    return true;
    983 }
    984 
    985 TimeZoneNames::MatchInfoCollection*
    986 ZNameSearchHandler::getMatches(int32_t& maxMatchLen) {
    987    // give the ownership to the caller
    988    TimeZoneNames::MatchInfoCollection* results = fResults;
    989    maxMatchLen = fMaxMatchLen;
    990 
    991    // reset
    992    fResults = nullptr;
    993    fMaxMatchLen = 0;
    994    return results;
    995 }
    996 
    997 // ---------------------------------------------------
    998 // TimeZoneNamesImpl
    999 //
   1000 // TimeZoneNames implementation class. This is the main
   1001 // part of this module.
   1002 // ---------------------------------------------------
   1003 
   1004 U_CDECL_BEGIN
   1005 /**
   1006 * Deleter for ZNames
   1007 */
   1008 static void U_CALLCONV
   1009 deleteZNames(void *obj) {
   1010    if (obj != EMPTY) {
   1011        delete (ZNames*) obj;
   1012    }
   1013 }
   1014 
   1015 /**
   1016 * Deleter for ZNameInfo
   1017 */
   1018 static void U_CALLCONV
   1019 deleteZNameInfo(void *obj) {
   1020    uprv_free(obj);
   1021 }
   1022 
   1023 U_CDECL_END
   1024 
   1025 TimeZoneNamesImpl::TimeZoneNamesImpl(const Locale& locale, UErrorCode& status)
   1026 : fLocale(locale),
   1027  fZoneStrings(nullptr),
   1028  fTZNamesMap(nullptr),
   1029  fMZNamesMap(nullptr),
   1030  fNamesTrieFullyLoaded(false),
   1031  fNamesFullyLoaded(false),
   1032  fNamesTrie(true, deleteZNameInfo) {
   1033    initialize(locale, status);
   1034 }
   1035 
   1036 void
   1037 TimeZoneNamesImpl::initialize(const Locale& locale, UErrorCode& status) {
   1038    if (U_FAILURE(status)) {
   1039        return;
   1040    }
   1041 
   1042    // Load zoneStrings bundle
   1043    UErrorCode tmpsts = U_ZERO_ERROR;   // OK with fallback warning..
   1044    fZoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts);
   1045    fZoneStrings = ures_getByKeyWithFallback(fZoneStrings, gZoneStrings, fZoneStrings, &tmpsts);
   1046    if (U_FAILURE(tmpsts)) {
   1047        status = tmpsts;
   1048        cleanup();
   1049        return;
   1050    }
   1051 
   1052    // Initialize hashtables holding time zone/meta zone names
   1053    fMZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status);
   1054    fTZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status);
   1055    if (U_FAILURE(status)) {
   1056        cleanup();
   1057        return;
   1058    }
   1059 
   1060    uhash_setValueDeleter(fMZNamesMap, deleteZNames);
   1061    uhash_setValueDeleter(fTZNamesMap, deleteZNames);
   1062    // no key deleters for name maps
   1063 
   1064    // preload zone strings for the default zone
   1065    TimeZone *tz = TimeZone::createDefault();
   1066    const char16_t *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
   1067    if (tzID != nullptr) {
   1068        loadStrings(UnicodeString(tzID), status);
   1069    }
   1070    delete tz;
   1071 }
   1072 
   1073 /*
   1074 * This method updates the cache and must be called with a lock,
   1075 * except initializer.
   1076 */
   1077 void
   1078 TimeZoneNamesImpl::loadStrings(const UnicodeString& tzCanonicalID, UErrorCode& status) {
   1079    loadTimeZoneNames(tzCanonicalID, status);
   1080    LocalPointer<StringEnumeration> mzIDs(getAvailableMetaZoneIDs(tzCanonicalID, status));
   1081    if (U_FAILURE(status)) { return; }
   1082    U_ASSERT(!mzIDs.isNull());
   1083 
   1084    const UnicodeString *mzID;
   1085    while (((mzID = mzIDs->snext(status)) != nullptr) && U_SUCCESS(status)) {
   1086        loadMetaZoneNames(*mzID, status);
   1087    }
   1088 }
   1089 
   1090 TimeZoneNamesImpl::~TimeZoneNamesImpl() {
   1091    cleanup();
   1092 }
   1093 
   1094 void
   1095 TimeZoneNamesImpl::cleanup() {
   1096    if (fZoneStrings != nullptr) {
   1097        ures_close(fZoneStrings);
   1098        fZoneStrings = nullptr;
   1099    }
   1100    if (fMZNamesMap != nullptr) {
   1101        uhash_close(fMZNamesMap);
   1102        fMZNamesMap = nullptr;
   1103    }
   1104    if (fTZNamesMap != nullptr) {
   1105        uhash_close(fTZNamesMap);
   1106        fTZNamesMap = nullptr;
   1107    }
   1108 }
   1109 
   1110 bool
   1111 TimeZoneNamesImpl::operator==(const TimeZoneNames& other) const {
   1112    if (this == &other) {
   1113        return true;
   1114    }
   1115    // No implementation for now
   1116    return false;
   1117 }
   1118 
   1119 TimeZoneNamesImpl*
   1120 TimeZoneNamesImpl::clone() const {
   1121    UErrorCode status = U_ZERO_ERROR;
   1122    return new TimeZoneNamesImpl(fLocale, status);
   1123 }
   1124 
   1125 StringEnumeration*
   1126 TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const {
   1127    return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
   1128 }
   1129 
   1130 // static implementation of getAvailableMetaZoneIDs(UErrorCode&)
   1131 StringEnumeration*
   1132 TimeZoneNamesImpl::_getAvailableMetaZoneIDs(UErrorCode& status) {
   1133    if (U_FAILURE(status)) {
   1134        return nullptr;
   1135    }
   1136    const UVector* mzIDs = ZoneMeta::getAvailableMetazoneIDs();
   1137    if (mzIDs == nullptr) {
   1138        return new MetaZoneIDsEnumeration();
   1139    }
   1140    return new MetaZoneIDsEnumeration(*mzIDs);
   1141 }
   1142 
   1143 StringEnumeration*
   1144 TimeZoneNamesImpl::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
   1145    return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status);
   1146 }
   1147 
   1148 // static implementation of getAvailableMetaZoneIDs(const UnicodeString&, UErrorCode&)
   1149 StringEnumeration*
   1150 TimeZoneNamesImpl::_getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) {
   1151    if (U_FAILURE(status)) {
   1152        return nullptr;
   1153    }
   1154    const UVector* mappings = ZoneMeta::getMetazoneMappings(tzID);
   1155    if (mappings == nullptr) {
   1156        return new MetaZoneIDsEnumeration();
   1157    }
   1158 
   1159    LocalPointer<MetaZoneIDsEnumeration> senum;
   1160    LocalPointer<UVector> mzIDs(new UVector(nullptr, uhash_compareUChars, status), status);
   1161    if (U_SUCCESS(status)) {
   1162        U_ASSERT(mzIDs.isValid());
   1163        for (int32_t i = 0; U_SUCCESS(status) && i < mappings->size(); i++) {
   1164 
   1165            OlsonToMetaMappingEntry* map = static_cast<OlsonToMetaMappingEntry*>(mappings->elementAt(i));
   1166            const char16_t *mzID = map->mzid;
   1167            if (!mzIDs->contains((void *)mzID)) {
   1168                mzIDs->addElement((void *)mzID, status);
   1169            }
   1170        }
   1171        if (U_SUCCESS(status)) {
   1172            senum.adoptInsteadAndCheckErrorCode(new MetaZoneIDsEnumeration(std::move(mzIDs)), status);
   1173        }
   1174    }
   1175    return U_SUCCESS(status) ? senum.orphan() : nullptr;
   1176 }
   1177 
   1178 UnicodeString&
   1179 TimeZoneNamesImpl::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
   1180    return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID);
   1181 }
   1182 
   1183 // static implementation of getMetaZoneID
   1184 UnicodeString&
   1185 TimeZoneNamesImpl::_getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) {
   1186    ZoneMeta::getMetazoneID(tzID, date, mzID);
   1187    return mzID;
   1188 }
   1189 
   1190 UnicodeString&
   1191 TimeZoneNamesImpl::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
   1192    return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID);
   1193 }
   1194 
   1195 // static implementation of getReferenceZoneID
   1196 UnicodeString&
   1197 TimeZoneNamesImpl::_getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) {
   1198    ZoneMeta::getZoneIdByMetazone(mzID, UnicodeString(region, -1, US_INV), tzID);
   1199    return tzID;
   1200 }
   1201 
   1202 UnicodeString&
   1203 TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID,
   1204                                          UTimeZoneNameType type,
   1205                                          UnicodeString& name) const {
   1206    name.setToBogus();  // cleanup result.
   1207    if (mzID.isEmpty()) {
   1208        return name;
   1209    }
   1210 
   1211    ZNames *znames = nullptr;
   1212    TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
   1213 
   1214    {
   1215        Mutex lock(&gDataMutex);
   1216        UErrorCode status = U_ZERO_ERROR;
   1217        znames = nonConstThis->loadMetaZoneNames(mzID, status);
   1218        if (U_FAILURE(status)) { return name; }
   1219    }
   1220 
   1221    if (znames != nullptr) {
   1222        const char16_t* s = znames->getName(type);
   1223        if (s != nullptr) {
   1224            name.setTo(true, s, -1);
   1225        }
   1226    }
   1227    return name;
   1228 }
   1229 
   1230 UnicodeString&
   1231 TimeZoneNamesImpl::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const {
   1232    name.setToBogus();  // cleanup result.
   1233    if (tzID.isEmpty()) {
   1234        return name;
   1235    }
   1236 
   1237    ZNames *tznames = nullptr;
   1238    TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
   1239 
   1240    {
   1241        Mutex lock(&gDataMutex);
   1242        UErrorCode status = U_ZERO_ERROR;
   1243        tznames = nonConstThis->loadTimeZoneNames(tzID, status);
   1244        if (U_FAILURE(status)) { return name; }
   1245    }
   1246 
   1247    if (tznames != nullptr) {
   1248        const char16_t *s = tznames->getName(type);
   1249        if (s != nullptr) {
   1250            name.setTo(true, s, -1);
   1251        }
   1252    }
   1253    return name;
   1254 }
   1255 
   1256 UnicodeString&
   1257 TimeZoneNamesImpl::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
   1258    name.setToBogus();  // cleanup result.
   1259    const char16_t* locName = nullptr;
   1260    ZNames *tznames = nullptr;
   1261    TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
   1262 
   1263    {
   1264        Mutex lock(&gDataMutex);
   1265        UErrorCode status = U_ZERO_ERROR;
   1266        tznames = nonConstThis->loadTimeZoneNames(tzID, status);
   1267        if (U_FAILURE(status)) { return name; }
   1268    }
   1269 
   1270    if (tznames != nullptr) {
   1271        locName = tznames->getName(UTZNM_EXEMPLAR_LOCATION);
   1272    }
   1273    if (locName != nullptr) {
   1274        name.setTo(true, locName, -1);
   1275    }
   1276 
   1277    return name;
   1278 }
   1279 
   1280 
   1281 // Merge the MZ_PREFIX and mzId
   1282 static void mergeTimeZoneKey(const UnicodeString& mzID, char* result, size_t capacity,
   1283                             UErrorCode& status) {
   1284    if (U_FAILURE(status)) {
   1285        return;
   1286    }
   1287    if (mzID.isEmpty()) {
   1288        result[0] = '\0';
   1289        return;
   1290    }
   1291 
   1292    if (MZ_PREFIX_LEN + 1 > capacity) {
   1293        result[0] = '\0';
   1294        status = U_INTERNAL_PROGRAM_ERROR;
   1295        return;
   1296    }
   1297    uprv_memcpy((void *)result, (void *)gMZPrefix, MZ_PREFIX_LEN);
   1298    if (static_cast<size_t>(MZ_PREFIX_LEN +  mzID.length() + 1) > capacity) {
   1299        result[0] = '\0';
   1300        status = U_INTERNAL_PROGRAM_ERROR;
   1301        return;
   1302    }
   1303    int32_t keyLen = mzID.extract(0, mzID.length(), result + MZ_PREFIX_LEN,
   1304                                  static_cast<int32_t>(capacity - MZ_PREFIX_LEN), US_INV);
   1305    result[keyLen + MZ_PREFIX_LEN] = '\0';
   1306 }
   1307 
   1308 /*
   1309 * This method updates the cache and must be called with a lock
   1310 */
   1311 ZNames*
   1312 TimeZoneNamesImpl::loadMetaZoneNames(const UnicodeString& mzID, UErrorCode& status) {
   1313    if (U_FAILURE(status)) { return nullptr; }
   1314    if (mzID.length() > ZID_KEY_MAX - MZ_PREFIX_LEN) {
   1315        status = U_INTERNAL_PROGRAM_ERROR;
   1316        return nullptr;
   1317    }
   1318 
   1319    char16_t mzIDKey[ZID_KEY_MAX + 1];
   1320    mzID.extract(mzIDKey, ZID_KEY_MAX, status);
   1321    if (U_FAILURE(status)) {
   1322        return nullptr;
   1323    }
   1324    mzIDKey[mzID.length()] = 0;
   1325 
   1326    void* mznames = uhash_get(fMZNamesMap, mzIDKey);
   1327    if (mznames == nullptr) {
   1328        ZNames::ZNamesLoader loader;
   1329        loader.loadMetaZone(fZoneStrings, mzID, status);
   1330        mznames = ZNames::createMetaZoneAndPutInCache(fMZNamesMap, loader.getNames(), mzID, status);
   1331        if (U_FAILURE(status)) { return nullptr; }
   1332    }
   1333 
   1334    if (mznames != EMPTY) {
   1335        return static_cast<ZNames*>(mznames);
   1336    } else {
   1337        return nullptr;
   1338    }
   1339 }
   1340 
   1341 /*
   1342 * This method updates the cache and must be called with a lock
   1343 */
   1344 ZNames*
   1345 TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID, UErrorCode& status) {
   1346    if (U_FAILURE(status)) { return nullptr; }
   1347    if (tzID.length() > ZID_KEY_MAX) {
   1348        status = U_INTERNAL_PROGRAM_ERROR;
   1349        return nullptr;
   1350    }
   1351 
   1352    char16_t tzIDKey[ZID_KEY_MAX + 1];
   1353    int32_t tzIDKeyLen = tzID.extract(tzIDKey, ZID_KEY_MAX, status);
   1354    U_ASSERT(U_SUCCESS(status));   // already checked length above
   1355    tzIDKey[tzIDKeyLen] = 0;
   1356 
   1357    void *tznames = uhash_get(fTZNamesMap, tzIDKey);
   1358    if (tznames == nullptr) {
   1359        ZNames::ZNamesLoader loader;
   1360        loader.loadTimeZone(fZoneStrings, tzID, status);
   1361        tznames = ZNames::createTimeZoneAndPutInCache(fTZNamesMap, loader.getNames(), tzID, status);
   1362        if (U_FAILURE(status)) { return nullptr; }
   1363    }
   1364 
   1365    // tznames is never EMPTY
   1366    return static_cast<ZNames*>(tznames);
   1367 }
   1368 
   1369 TimeZoneNames::MatchInfoCollection*
   1370 TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
   1371    ZNameSearchHandler handler(types);
   1372    TimeZoneNames::MatchInfoCollection* matches;
   1373    TimeZoneNamesImpl* nonConstThis = const_cast<TimeZoneNamesImpl*>(this);
   1374 
   1375    // Synchronize so that data is not loaded multiple times.
   1376    // TODO: Consider more fine-grained synchronization.
   1377    {
   1378        Mutex lock(&gDataMutex);
   1379 
   1380        // First try of lookup.
   1381        matches = doFind(handler, text, start, status);
   1382        if (U_FAILURE(status)) { return nullptr; }
   1383        if (matches != nullptr) {
   1384            return matches;
   1385        }
   1386 
   1387        // All names are not yet loaded into the trie.
   1388        // We may have loaded names for formatting several time zones,
   1389        // and might be parsing one of those.
   1390        // Populate the parsing trie from all of the already-loaded names.
   1391        nonConstThis->addAllNamesIntoTrie(status);
   1392 
   1393        // Second try of lookup.
   1394        matches = doFind(handler, text, start, status);
   1395        if (U_FAILURE(status)) { return nullptr; }
   1396        if (matches != nullptr) {
   1397            return matches;
   1398        }
   1399 
   1400        // There are still some names we haven't loaded into the trie yet.
   1401        // Load everything now.
   1402        nonConstThis->internalLoadAllDisplayNames(status);
   1403        nonConstThis->addAllNamesIntoTrie(status);
   1404        nonConstThis->fNamesTrieFullyLoaded = true;
   1405        if (U_FAILURE(status)) { return nullptr; }
   1406 
   1407        // Third try: we must return this one.
   1408        return doFind(handler, text, start, status);
   1409    }
   1410 }
   1411 
   1412 TimeZoneNames::MatchInfoCollection*
   1413 TimeZoneNamesImpl::doFind(ZNameSearchHandler& handler,
   1414        const UnicodeString& text, int32_t start, UErrorCode& status) const {
   1415 
   1416    fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
   1417    if (U_FAILURE(status)) { return nullptr; }
   1418 
   1419    int32_t maxLen = 0;
   1420    TimeZoneNames::MatchInfoCollection* matches = handler.getMatches(maxLen);
   1421    if (matches != nullptr && ((maxLen == (text.length() - start)) || fNamesTrieFullyLoaded)) {
   1422        // perfect match, or no more names available
   1423        return matches;
   1424    }
   1425    delete matches;
   1426    return nullptr;
   1427 }
   1428 
   1429 // Caller must synchronize.
   1430 void TimeZoneNamesImpl::addAllNamesIntoTrie(UErrorCode& status) {
   1431    if (U_FAILURE(status)) return;
   1432    int32_t pos;
   1433    const UHashElement* element;
   1434 
   1435    pos = UHASH_FIRST;
   1436    while ((element = uhash_nextElement(fMZNamesMap, &pos)) != nullptr) {
   1437        if (element->value.pointer == EMPTY) { continue; }
   1438        char16_t* mzID = static_cast<char16_t*>(element->key.pointer);
   1439        ZNames* znames = static_cast<ZNames*>(element->value.pointer);
   1440        znames->addAsMetaZoneIntoTrie(mzID, fNamesTrie, status);
   1441        if (U_FAILURE(status)) { return; }
   1442    }
   1443 
   1444    pos = UHASH_FIRST;
   1445    while ((element = uhash_nextElement(fTZNamesMap, &pos)) != nullptr) {
   1446        if (element->value.pointer == EMPTY) { continue; }
   1447        char16_t* tzID = static_cast<char16_t*>(element->key.pointer);
   1448        ZNames* znames = static_cast<ZNames*>(element->value.pointer);
   1449        znames->addAsTimeZoneIntoTrie(tzID, fNamesTrie, status);
   1450        if (U_FAILURE(status)) { return; }
   1451    }
   1452 }
   1453 
   1454 U_CDECL_BEGIN
   1455 static void U_CALLCONV
   1456 deleteZNamesLoader(void* obj) {
   1457    if (obj == DUMMY_LOADER) { return; }
   1458    const ZNames::ZNamesLoader* loader = (const ZNames::ZNamesLoader*) obj;
   1459    delete loader;
   1460 }
   1461 U_CDECL_END
   1462 
   1463 struct TimeZoneNamesImpl::ZoneStringsLoader : public ResourceSink {
   1464    TimeZoneNamesImpl& tzn;
   1465    UHashtable* keyToLoader;
   1466 
   1467    ZoneStringsLoader(TimeZoneNamesImpl& _tzn, UErrorCode& status)
   1468            : tzn(_tzn) {
   1469        keyToLoader = uhash_open(uhash_hashChars, uhash_compareChars, nullptr, &status);
   1470        if (U_FAILURE(status)) { return; }
   1471        uhash_setKeyDeleter(keyToLoader, uprv_free);
   1472        uhash_setValueDeleter(keyToLoader, deleteZNamesLoader);
   1473    }
   1474    virtual ~ZoneStringsLoader();
   1475 
   1476    void* createKey(const char* key, UErrorCode& status) {
   1477        int32_t len = sizeof(char) * (static_cast<int32_t>(uprv_strlen(key)) + 1);
   1478        char* newKey = static_cast<char*>(uprv_malloc(len));
   1479        if (newKey == nullptr) {
   1480            status = U_MEMORY_ALLOCATION_ERROR;
   1481            return nullptr;
   1482        }
   1483        uprv_memcpy(newKey, key, len);
   1484        newKey[len-1] = '\0';
   1485        return (void*) newKey;
   1486    }
   1487 
   1488    UBool isMetaZone(const char* key) {
   1489        return (uprv_strlen(key) >= MZ_PREFIX_LEN && uprv_memcmp(key, gMZPrefix, MZ_PREFIX_LEN) == 0);
   1490    }
   1491 
   1492    UnicodeString mzIDFromKey(const char* key) {
   1493        return UnicodeString(key + MZ_PREFIX_LEN, static_cast<int32_t>(uprv_strlen(key)) - MZ_PREFIX_LEN, US_INV);
   1494    }
   1495 
   1496    UnicodeString tzIDFromKey(const char* key) {
   1497        UnicodeString tzID(key, -1, US_INV);
   1498        // Replace all colons ':' with slashes '/'
   1499        for (int i=0; i<tzID.length(); i++) {
   1500            if (tzID.charAt(i) == 0x003A) {
   1501                tzID.setCharAt(i, 0x002F);
   1502            }
   1503        }
   1504        return tzID;
   1505    }
   1506 
   1507    void load(UErrorCode& status) {
   1508        ures_getAllItemsWithFallback(tzn.fZoneStrings, "", *this, status);
   1509        if (U_FAILURE(status)) { return; }
   1510 
   1511        int32_t pos = UHASH_FIRST;
   1512        const UHashElement* element;
   1513        while ((element = uhash_nextElement(keyToLoader, &pos)) != nullptr) {
   1514            if (element->value.pointer == DUMMY_LOADER) { continue; }
   1515            ZNames::ZNamesLoader* loader = static_cast<ZNames::ZNamesLoader*>(element->value.pointer);
   1516            char* key = static_cast<char*>(element->key.pointer);
   1517 
   1518            if (isMetaZone(key)) {
   1519                UnicodeString mzID = mzIDFromKey(key);
   1520                ZNames::createMetaZoneAndPutInCache(tzn.fMZNamesMap, loader->getNames(), mzID, status);
   1521            } else {
   1522                UnicodeString tzID = tzIDFromKey(key);
   1523                ZNames::createTimeZoneAndPutInCache(tzn.fTZNamesMap, loader->getNames(), tzID, status);
   1524            }
   1525            if (U_FAILURE(status)) { return; }
   1526        }
   1527    }
   1528 
   1529    void consumeNamesTable(const char *key, ResourceValue &value, UBool noFallback,
   1530            UErrorCode &status) {
   1531        if (U_FAILURE(status)) { return; }
   1532 
   1533        void* loader = uhash_get(keyToLoader, key);
   1534        if (loader == nullptr) {
   1535            if (isMetaZone(key)) {
   1536                UnicodeString mzID = mzIDFromKey(key);
   1537                void* cacheVal = uhash_get(tzn.fMZNamesMap, mzID.getTerminatedBuffer());
   1538                if (cacheVal != nullptr) {
   1539                    // We have already loaded the names for this meta zone.
   1540                    loader = (void*) DUMMY_LOADER;
   1541                } else {
   1542                    loader = (void*) new ZNames::ZNamesLoader();
   1543                    if (loader == nullptr) {
   1544                        status = U_MEMORY_ALLOCATION_ERROR;
   1545                        return;
   1546                    }
   1547                }
   1548            } else {
   1549                UnicodeString tzID = tzIDFromKey(key);
   1550                void* cacheVal = uhash_get(tzn.fTZNamesMap, tzID.getTerminatedBuffer());
   1551                if (cacheVal != nullptr) {
   1552                    // We have already loaded the names for this time zone.
   1553                    loader = (void*) DUMMY_LOADER;
   1554                } else {
   1555                    loader = (void*) new ZNames::ZNamesLoader();
   1556                    if (loader == nullptr) {
   1557                        status = U_MEMORY_ALLOCATION_ERROR;
   1558                        return;
   1559                    }
   1560                }
   1561            }
   1562 
   1563            void* newKey = createKey(key, status);
   1564            if (U_FAILURE(status)) {
   1565                deleteZNamesLoader(loader);
   1566                return;
   1567            }
   1568 
   1569            uhash_put(keyToLoader, newKey, loader, &status);
   1570            if (U_FAILURE(status)) { return; }
   1571        }
   1572 
   1573        if (loader != DUMMY_LOADER) {
   1574            // Let the ZNamesLoader consume the names table.
   1575            static_cast<ZNames::ZNamesLoader*>(loader)->put(key, value, noFallback, status);
   1576        }
   1577    }
   1578 
   1579    virtual void put(const char *key, ResourceValue &value, UBool noFallback,
   1580            UErrorCode &status) override {
   1581        ResourceTable timeZonesTable = value.getTable(status);
   1582        if (U_FAILURE(status)) { return; }
   1583        for (int32_t i = 0; timeZonesTable.getKeyAndValue(i, key, value); ++i) {
   1584            U_ASSERT(!value.isNoInheritanceMarker());
   1585            if (value.getType() == URES_TABLE) {
   1586                consumeNamesTable(key, value, noFallback, status);
   1587            } else {
   1588                // Ignore fields that aren't tables (e.g., fallbackFormat and regionFormatStandard).
   1589                // All time zone fields are tables.
   1590            }
   1591            if (U_FAILURE(status)) { return; }
   1592        }
   1593    }
   1594 };
   1595 
   1596 // Virtual destructors must be defined out of line.
   1597 TimeZoneNamesImpl::ZoneStringsLoader::~ZoneStringsLoader() {
   1598    uhash_close(keyToLoader);
   1599 }
   1600 
   1601 void TimeZoneNamesImpl::loadAllDisplayNames(UErrorCode& status) {
   1602    if (U_FAILURE(status)) return;
   1603 
   1604    {
   1605        Mutex lock(&gDataMutex);
   1606        internalLoadAllDisplayNames(status);
   1607    }
   1608 }
   1609 
   1610 void TimeZoneNamesImpl::getDisplayNames(const UnicodeString& tzID,
   1611        const UTimeZoneNameType types[], int32_t numTypes,
   1612        UDate date, UnicodeString dest[], UErrorCode& status) const {
   1613    if (U_FAILURE(status)) return;
   1614 
   1615    if (tzID.isEmpty()) { return; }
   1616    void* tznames = nullptr;
   1617    void* mznames = nullptr;
   1618    TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl*>(this);
   1619 
   1620    // Load the time zone strings
   1621    {
   1622        Mutex lock(&gDataMutex);
   1623        tznames = (void*) nonConstThis->loadTimeZoneNames(tzID, status);
   1624        if (U_FAILURE(status)) { return; }
   1625    }
   1626    U_ASSERT(tznames != nullptr);
   1627 
   1628    // Load the values into the dest array
   1629    for (int i = 0; i < numTypes; i++) {
   1630        UTimeZoneNameType type = types[i];
   1631        const char16_t* name = static_cast<ZNames*>(tznames)->getName(type);
   1632        if (name == nullptr) {
   1633            if (mznames == nullptr) {
   1634                // Load the meta zone name
   1635                UnicodeString mzID;
   1636                getMetaZoneID(tzID, date, mzID);
   1637                if (mzID.isEmpty()) {
   1638                    mznames = (void*) EMPTY;
   1639                } else {
   1640                    // Load the meta zone strings
   1641                    // Mutex is scoped to the "else" statement
   1642                    Mutex lock(&gDataMutex);
   1643                    mznames = (void*) nonConstThis->loadMetaZoneNames(mzID, status);
   1644                    if (U_FAILURE(status)) { return; }
   1645                    // Note: when the metazone doesn't exist, in Java, loadMetaZoneNames returns
   1646                    // a dummy object instead of nullptr.
   1647                    if (mznames == nullptr) {
   1648                        mznames = (void*) EMPTY;
   1649                    }
   1650                }
   1651            }
   1652            U_ASSERT(mznames != nullptr);
   1653            if (mznames != EMPTY) {
   1654                name = static_cast<ZNames*>(mznames)->getName(type);
   1655            }
   1656        }
   1657        if (name != nullptr) {
   1658            dest[i].setTo(true, name, -1);
   1659        } else {
   1660            dest[i].setToBogus();
   1661        }
   1662    }
   1663 }
   1664 
   1665 // Caller must synchronize.
   1666 void TimeZoneNamesImpl::internalLoadAllDisplayNames(UErrorCode& status) {
   1667    if (!fNamesFullyLoaded) {
   1668        fNamesFullyLoaded = true;
   1669 
   1670        ZoneStringsLoader loader(*this, status);
   1671        loader.load(status);
   1672        if (U_FAILURE(status)) { return; }
   1673 
   1674        const UnicodeString *id;
   1675 
   1676        // load strings for all zones
   1677        StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(
   1678            UCAL_ZONE_TYPE_CANONICAL, nullptr, nullptr, status);
   1679        if (U_SUCCESS(status)) {
   1680            while ((id = tzIDs->snext(status)) != nullptr) {
   1681                if (U_FAILURE(status)) {
   1682                    break;
   1683                }
   1684                UnicodeString copy(*id);
   1685                void* value = uhash_get(fTZNamesMap, copy.getTerminatedBuffer());
   1686                if (value == nullptr) {
   1687                    // loadStrings also loads related metazone strings
   1688                    loadStrings(*id, status);
   1689                }
   1690            }
   1691        }
   1692        delete tzIDs;
   1693    }
   1694 }
   1695 
   1696 
   1697 
   1698 static const char16_t gEtcPrefix[]         = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
   1699 static const int32_t gEtcPrefixLen      = 4;
   1700 static const char16_t gSystemVPrefix[]     = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
   1701 static const int32_t gSystemVPrefixLen  = 8;
   1702 static const char16_t gRiyadh8[]           = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
   1703 static const int32_t gRiyadh8Len       = 7;
   1704 
   1705 UnicodeString& U_EXPORT2
   1706 TimeZoneNamesImpl::getDefaultExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) {
   1707    if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
   1708        || tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
   1709        name.setToBogus();
   1710        return name;
   1711    }
   1712 
   1713    int32_t sep = tzID.lastIndexOf(static_cast<char16_t>(0x2F) /* '/' */);
   1714    if (sep > 0 && sep + 1 < tzID.length()) {
   1715        name.setTo(tzID, sep + 1);
   1716        name.findAndReplace(UnicodeString(static_cast<char16_t>(0x5f) /* _ */),
   1717                            UnicodeString(static_cast<char16_t>(0x20) /* space */));
   1718    } else {
   1719        name.setToBogus();
   1720    }
   1721    return name;
   1722 }
   1723 
   1724 // ---------------------------------------------------
   1725 // TZDBTimeZoneNames and its supporting classes
   1726 //
   1727 // TZDBTimeZoneNames is an implementation class of
   1728 // TimeZoneNames holding the IANA tz database abbreviations.
   1729 // ---------------------------------------------------
   1730 
   1731 class TZDBNames : public UMemory {
   1732 public:
   1733    virtual ~TZDBNames();
   1734 
   1735    static TZDBNames* createInstance(UResourceBundle* rb, const char* key);
   1736    const char16_t* getName(UTimeZoneNameType type) const;
   1737    const char** getParseRegions(int32_t& numRegions) const;
   1738 
   1739 protected:
   1740    TZDBNames(const char16_t** names, char** regions, int32_t numRegions);
   1741 
   1742 private:
   1743    const char16_t** fNames;
   1744    char** fRegions;
   1745    int32_t fNumRegions;
   1746 };
   1747 
   1748 TZDBNames::TZDBNames(const char16_t** names, char** regions, int32_t numRegions)
   1749    :   fNames(names),
   1750        fRegions(regions),
   1751        fNumRegions(numRegions) {
   1752 }
   1753 
   1754 TZDBNames::~TZDBNames() {
   1755    if (fNames != nullptr) {
   1756        uprv_free(fNames);
   1757    }
   1758    if (fRegions != nullptr) {
   1759        char **p = fRegions;
   1760        for (int32_t i = 0; i < fNumRegions; p++, i++) {
   1761            uprv_free(*p);
   1762        }
   1763        uprv_free(fRegions);
   1764    }
   1765 }
   1766 
   1767 TZDBNames*
   1768 TZDBNames::createInstance(UResourceBundle* rb, const char* key) {
   1769    if (rb == nullptr || key == nullptr || *key == 0) {
   1770        return nullptr;
   1771    }
   1772 
   1773    UErrorCode status = U_ZERO_ERROR;
   1774 
   1775    const char16_t **names = nullptr;
   1776    char** regions = nullptr;
   1777    int32_t numRegions = 0;
   1778 
   1779    int32_t len = 0;
   1780 
   1781    UResourceBundle* rbTable = nullptr;
   1782    rbTable = ures_getByKey(rb, key, rbTable, &status);
   1783    if (U_FAILURE(status)) {
   1784        return nullptr;
   1785    }
   1786 
   1787    names = static_cast<const char16_t**>(uprv_malloc(sizeof(const char16_t*) * TZDBNAMES_KEYS_SIZE));
   1788    UBool isEmpty = true;
   1789    if (names != nullptr) {
   1790        for (int32_t i = 0; i < TZDBNAMES_KEYS_SIZE; i++) {
   1791            status = U_ZERO_ERROR;
   1792            const char16_t *value = ures_getStringByKey(rbTable, TZDBNAMES_KEYS[i], &len, &status);
   1793            if (U_FAILURE(status) || len == 0) {
   1794                names[i] = nullptr;
   1795            } else {
   1796                names[i] = value;
   1797                isEmpty = false;
   1798            }
   1799        }
   1800    }
   1801 
   1802    if (isEmpty) {
   1803        if (names != nullptr) {
   1804            uprv_free(names);
   1805        }
   1806        return nullptr;
   1807    }
   1808 
   1809    UResourceBundle *regionsRes = ures_getByKey(rbTable, "parseRegions", nullptr, &status);
   1810    UBool regionError = false;
   1811    if (U_SUCCESS(status)) {
   1812        numRegions = ures_getSize(regionsRes);
   1813        if (numRegions > 0) {
   1814            regions = static_cast<char**>(uprv_malloc(sizeof(char*) * numRegions));
   1815            if (regions != nullptr) {
   1816                char **pRegion = regions;
   1817                for (int32_t i = 0; i < numRegions; i++, pRegion++) {
   1818                    *pRegion = nullptr;
   1819                }
   1820                // filling regions
   1821                pRegion = regions;
   1822                for (int32_t i = 0; i < numRegions; i++, pRegion++) {
   1823                    status = U_ZERO_ERROR;
   1824                    const char16_t *uregion = ures_getStringByIndex(regionsRes, i, &len, &status);
   1825                    if (U_FAILURE(status)) {
   1826                        regionError = true;
   1827                        break;
   1828                    }
   1829                    *pRegion = static_cast<char*>(uprv_malloc(sizeof(char) * (len + 1)));
   1830                    if (*pRegion == nullptr) {
   1831                        regionError = true;
   1832                        break;
   1833                    }
   1834                    u_UCharsToChars(uregion, *pRegion, len);
   1835                    (*pRegion)[len] = 0;
   1836                }
   1837            }
   1838        }
   1839    }
   1840    ures_close(regionsRes);
   1841    ures_close(rbTable);
   1842 
   1843    if (regionError) {
   1844        if (names != nullptr) {
   1845            uprv_free(names);
   1846        }
   1847        if (regions != nullptr) {
   1848            char **p = regions;
   1849            for (int32_t i = 0; i < numRegions; p++, i++) {
   1850                uprv_free(*p);
   1851            }
   1852            uprv_free(regions);
   1853        }
   1854        return nullptr;
   1855    }
   1856 
   1857    return new TZDBNames(names, regions, numRegions);
   1858 }
   1859 
   1860 const char16_t*
   1861 TZDBNames::getName(UTimeZoneNameType type) const {
   1862    if (fNames == nullptr) {
   1863        return nullptr;
   1864    }
   1865    const char16_t *name = nullptr;
   1866    switch(type) {
   1867    case UTZNM_SHORT_STANDARD:
   1868        name = fNames[0];
   1869        break;
   1870    case UTZNM_SHORT_DAYLIGHT:
   1871        name = fNames[1];
   1872        break;
   1873    default:
   1874        name = nullptr;
   1875    }
   1876    return name;
   1877 }
   1878 
   1879 const char**
   1880 TZDBNames::getParseRegions(int32_t& numRegions) const {
   1881    if (fRegions == nullptr) {
   1882        numRegions = 0;
   1883    } else {
   1884        numRegions = fNumRegions;
   1885    }
   1886    return (const char**)fRegions;
   1887 }
   1888 
   1889 U_CDECL_BEGIN
   1890 /**
   1891 * TZDBNameInfo stores metazone name information for the IANA abbreviations
   1892 * in the trie
   1893 */
   1894 typedef struct TZDBNameInfo {
   1895    const char16_t*        mzID;
   1896    UTimeZoneNameType   type;
   1897    UBool               ambiguousType;
   1898    const char**        parseRegions;
   1899    int32_t             nRegions;
   1900 } TZDBNameInfo;
   1901 U_CDECL_END
   1902 
   1903 
   1904 class TZDBNameSearchHandler : public TextTrieMapSearchResultHandler {
   1905 public:
   1906    TZDBNameSearchHandler(uint32_t types, StringPiece region);
   1907    virtual ~TZDBNameSearchHandler();
   1908 
   1909    UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) override;
   1910    TimeZoneNames::MatchInfoCollection* getMatches(int32_t& maxMatchLen);
   1911 
   1912 private:
   1913    uint32_t fTypes;
   1914    int32_t fMaxMatchLen;
   1915    TimeZoneNames::MatchInfoCollection* fResults;
   1916    StringPiece fRegion;
   1917 };
   1918 
   1919 TZDBNameSearchHandler::TZDBNameSearchHandler(uint32_t types, StringPiece region)
   1920 : fTypes(types), fMaxMatchLen(0), fResults(nullptr), fRegion(region) {
   1921 }
   1922 
   1923 TZDBNameSearchHandler::~TZDBNameSearchHandler() {
   1924    delete fResults;
   1925 }
   1926 
   1927 UBool
   1928 TZDBNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
   1929    if (U_FAILURE(status)) {
   1930        return false;
   1931    }
   1932 
   1933    TZDBNameInfo *match = nullptr;
   1934    TZDBNameInfo *defaultRegionMatch = nullptr;
   1935 
   1936    if (node->hasValues()) {
   1937        int32_t valuesCount = node->countValues();
   1938        for (int32_t i = 0; i < valuesCount; i++) {
   1939            TZDBNameInfo *ninfo = (TZDBNameInfo *)node->getValue(i);
   1940            if (ninfo == nullptr) {
   1941                continue;
   1942            }
   1943            if ((ninfo->type & fTypes) != 0) {
   1944                // Some tz database abbreviations are ambiguous. For example,
   1945                // CST means either Central Standard Time or China Standard Time.
   1946                // Unlike CLDR time zone display names, this implementation
   1947                // does not use unique names. And TimeZoneFormat does not expect
   1948                // multiple results returned for the same time zone type.
   1949                // For this reason, this implementation resolve one among same
   1950                // zone type with a same name at this level.
   1951                if (ninfo->parseRegions == nullptr) {
   1952                    // parseRegions == null means this is the default metazone
   1953                    // mapping for the abbreviation.
   1954                    if (defaultRegionMatch == nullptr) {
   1955                        match = defaultRegionMatch = ninfo;
   1956                    }
   1957                } else {
   1958                    UBool matchRegion = false;
   1959                    // non-default metazone mapping for an abbreviation
   1960                    // comes with applicable regions. For example, the default
   1961                    // metazone mapping for "CST" is America_Central,
   1962                    // but if region is one of CN/MO/TW, "CST" is parsed
   1963                    // as metazone China (China Standard Time).
   1964                    for (int32_t j = 0; j < ninfo->nRegions; j++) {
   1965                        const char *region = ninfo->parseRegions[j];
   1966                        if (fRegion == region) {
   1967                            match = ninfo;
   1968                            matchRegion = true;
   1969                            break;
   1970                        }
   1971                    }
   1972                    if (matchRegion) {
   1973                        break;
   1974                    }
   1975                    if (match == nullptr) {
   1976                        match = ninfo;
   1977                    }
   1978                }
   1979            }
   1980        }
   1981 
   1982        if (match != nullptr) {
   1983            UTimeZoneNameType ntype = match->type;
   1984            // Note: Workaround for duplicated standard/daylight names
   1985            // The tz database contains a few zones sharing a
   1986            // same name for both standard time and daylight saving
   1987            // time. For example, Australia/Sydney observes DST,
   1988            // but "EST" is used for both standard and daylight.
   1989            // When both SHORT_STANDARD and SHORT_DAYLIGHT are included
   1990            // in the find operation, we cannot tell which one was
   1991            // actually matched.
   1992            // TimeZoneFormat#parse returns a matched name type (standard
   1993            // or daylight) and DateFormat implementation uses the info to
   1994            // to adjust actual time. To avoid false type information,
   1995            // this implementation replaces the name type with SHORT_GENERIC.
   1996            if (match->ambiguousType
   1997                    && (ntype == UTZNM_SHORT_STANDARD || ntype == UTZNM_SHORT_DAYLIGHT)
   1998                    && (fTypes & UTZNM_SHORT_STANDARD) != 0
   1999                    && (fTypes & UTZNM_SHORT_DAYLIGHT) != 0) {
   2000                ntype = UTZNM_SHORT_GENERIC;
   2001            }
   2002 
   2003            if (fResults == nullptr) {
   2004                fResults = new TimeZoneNames::MatchInfoCollection();
   2005                if (fResults == nullptr) {
   2006                    status = U_MEMORY_ALLOCATION_ERROR;
   2007                }
   2008            }
   2009            if (U_SUCCESS(status)) {
   2010                U_ASSERT(fResults != nullptr);
   2011                U_ASSERT(match->mzID != nullptr);
   2012                fResults->addMetaZone(ntype, matchLength, UnicodeString(match->mzID, -1), status);
   2013                if (U_SUCCESS(status) && matchLength > fMaxMatchLen) {
   2014                    fMaxMatchLen = matchLength;
   2015                }
   2016            }
   2017        }
   2018    }
   2019    return true;
   2020 }
   2021 
   2022 TimeZoneNames::MatchInfoCollection*
   2023 TZDBNameSearchHandler::getMatches(int32_t& maxMatchLen) {
   2024    // give the ownership to the caller
   2025    TimeZoneNames::MatchInfoCollection* results = fResults;
   2026    maxMatchLen = fMaxMatchLen;
   2027 
   2028    // reset
   2029    fResults = nullptr;
   2030    fMaxMatchLen = 0;
   2031    return results;
   2032 }
   2033 
   2034 U_CDECL_BEGIN
   2035 /**
   2036 * Deleter for TZDBNames
   2037 */
   2038 static void U_CALLCONV
   2039 deleteTZDBNames(void *obj) {
   2040    if (obj != EMPTY) {
   2041        delete (TZDBNames *)obj;
   2042    }
   2043 }
   2044 
   2045 static void U_CALLCONV initTZDBNamesMap(UErrorCode &status) {
   2046    gTZDBNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, nullptr, &status);
   2047    if (U_FAILURE(status)) {
   2048        gTZDBNamesMap = nullptr;
   2049        return;
   2050    }
   2051    // no key deleters for tzdb name maps
   2052    uhash_setValueDeleter(gTZDBNamesMap, deleteTZDBNames);
   2053    ucln_i18n_registerCleanup(UCLN_I18N_TZDBTIMEZONENAMES, tzdbTimeZoneNames_cleanup);
   2054 }
   2055 
   2056 /**
   2057 * Deleter for TZDBNameInfo
   2058 */
   2059 static void U_CALLCONV
   2060 deleteTZDBNameInfo(void *obj) {
   2061    if (obj != nullptr) {
   2062        uprv_free(obj);
   2063    }
   2064 }
   2065 
   2066 static void U_CALLCONV prepareFind(UErrorCode &status) {
   2067    if (U_FAILURE(status)) {
   2068        return;
   2069    }
   2070    gTZDBNamesTrie = new TextTrieMap(true, deleteTZDBNameInfo);
   2071    if (gTZDBNamesTrie == nullptr) {
   2072        status = U_MEMORY_ALLOCATION_ERROR;
   2073        return;
   2074    }
   2075 
   2076    const UnicodeString *mzID;
   2077    StringEnumeration *mzIDs = TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
   2078    if (U_SUCCESS(status)) {
   2079        while ((mzID = mzIDs->snext(status)) != nullptr && U_SUCCESS(status)) {
   2080            const TZDBNames *names = TZDBTimeZoneNames::getMetaZoneNames(*mzID, status);
   2081            if (U_FAILURE(status)) {
   2082                break;
   2083            }
   2084            if (names == nullptr) {
   2085                continue;
   2086            }
   2087            const char16_t *std = names->getName(UTZNM_SHORT_STANDARD);
   2088            const char16_t *dst = names->getName(UTZNM_SHORT_DAYLIGHT);
   2089            if (std == nullptr && dst == nullptr) {
   2090                continue;
   2091            }
   2092            int32_t numRegions = 0;
   2093            const char **parseRegions = names->getParseRegions(numRegions);
   2094 
   2095            // The tz database contains a few zones sharing a
   2096            // same name for both standard time and daylight saving
   2097            // time. For example, Australia/Sydney observes DST,
   2098            // but "EST" is used for both standard and daylight.
   2099            // we need to store the information for later processing.
   2100            UBool ambiguousType = (std != nullptr && dst != nullptr && u_strcmp(std, dst) == 0);
   2101 
   2102            const char16_t *uMzID = ZoneMeta::findMetaZoneID(*mzID);
   2103            if (std != nullptr) {
   2104                TZDBNameInfo *stdInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNameInfo));
   2105                if (stdInf == nullptr) {
   2106                    status = U_MEMORY_ALLOCATION_ERROR;
   2107                    break;
   2108                }
   2109                stdInf->mzID = uMzID;
   2110                stdInf->type = UTZNM_SHORT_STANDARD;
   2111                stdInf->ambiguousType = ambiguousType;
   2112                stdInf->parseRegions = parseRegions;
   2113                stdInf->nRegions = numRegions;
   2114                gTZDBNamesTrie->put(std, stdInf, status);
   2115            }
   2116            if (U_SUCCESS(status) && dst != nullptr) {
   2117                TZDBNameInfo *dstInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNameInfo));
   2118                if (dstInf == nullptr) {
   2119                    status = U_MEMORY_ALLOCATION_ERROR;
   2120                    break;
   2121                }
   2122                dstInf->mzID = uMzID;
   2123                dstInf->type = UTZNM_SHORT_DAYLIGHT;
   2124                dstInf->ambiguousType = ambiguousType;
   2125                dstInf->parseRegions = parseRegions;
   2126                dstInf->nRegions = numRegions;
   2127                gTZDBNamesTrie->put(dst, dstInf, status);
   2128            }
   2129        }
   2130    }
   2131    delete mzIDs;
   2132 
   2133    if (U_FAILURE(status)) {
   2134        delete gTZDBNamesTrie;
   2135        gTZDBNamesTrie = nullptr;
   2136        return;
   2137    }
   2138 
   2139    ucln_i18n_registerCleanup(UCLN_I18N_TZDBTIMEZONENAMES, tzdbTimeZoneNames_cleanup);
   2140 }
   2141 
   2142 U_CDECL_END
   2143 
   2144 TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale)
   2145 : fLocale(locale), fRegion() {
   2146    UBool useWorld = true;
   2147    const char* region = fLocale.getCountry();
   2148    int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
   2149    if (regionLen == 0) {
   2150        UErrorCode status = U_ZERO_ERROR;
   2151        CharString loc = ulocimp_addLikelySubtags(fLocale.getName(), status);
   2152        CharString tmp;
   2153        ulocimp_getSubtags(loc.toStringPiece(), nullptr, nullptr, &tmp, nullptr, nullptr, status);
   2154        fRegion = tmp.toStringPiece();
   2155        U_ASSERT(fRegion.isEmpty() == tmp.isEmpty());
   2156        if (U_SUCCESS(status)) {
   2157            useWorld = false;
   2158        }
   2159    } else {
   2160        fRegion = {region, static_cast<std::string_view::size_type>(regionLen)};
   2161        U_ASSERT(!fRegion.isEmpty());
   2162        useWorld = false;
   2163    }
   2164    if (useWorld) {
   2165        fRegion = "001";
   2166        U_ASSERT(!fRegion.isEmpty());
   2167    }
   2168 }
   2169 
   2170 TZDBTimeZoneNames::~TZDBTimeZoneNames() {
   2171 }
   2172 
   2173 bool
   2174 TZDBTimeZoneNames::operator==(const TimeZoneNames& other) const {
   2175    if (this == &other) {
   2176        return true;
   2177    }
   2178    // No implementation for now
   2179    return false;
   2180 }
   2181 
   2182 TZDBTimeZoneNames*
   2183 TZDBTimeZoneNames::clone() const {
   2184    return new TZDBTimeZoneNames(fLocale);
   2185 }
   2186 
   2187 StringEnumeration*
   2188 TZDBTimeZoneNames::getAvailableMetaZoneIDs(UErrorCode& status) const {
   2189    return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
   2190 }
   2191 
   2192 StringEnumeration*
   2193 TZDBTimeZoneNames::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
   2194    return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status);
   2195 }
   2196 
   2197 UnicodeString&
   2198 TZDBTimeZoneNames::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
   2199    return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID);
   2200 }
   2201 
   2202 UnicodeString&
   2203 TZDBTimeZoneNames::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
   2204    return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID);
   2205 }
   2206 
   2207 UnicodeString&
   2208 TZDBTimeZoneNames::getMetaZoneDisplayName(const UnicodeString& mzID,
   2209                                          UTimeZoneNameType type,
   2210                                          UnicodeString& name) const {
   2211    name.setToBogus();
   2212    if (mzID.isEmpty()) {
   2213        return name;
   2214    }
   2215 
   2216    UErrorCode status = U_ZERO_ERROR;
   2217    const TZDBNames *tzdbNames = TZDBTimeZoneNames::getMetaZoneNames(mzID, status);
   2218    if (U_SUCCESS(status)) {
   2219        if (tzdbNames != nullptr) {
   2220            const char16_t *s = tzdbNames->getName(type);
   2221            if (s != nullptr) {
   2222                name.setTo(true, s, -1);
   2223            }
   2224        }
   2225    }
   2226 
   2227    return name;
   2228 }
   2229 
   2230 UnicodeString&
   2231 TZDBTimeZoneNames::getTimeZoneDisplayName(const UnicodeString& /* tzID */, UTimeZoneNameType /* type */, UnicodeString& name) const {
   2232    // No abbreviations associated a zone directly for now.
   2233    name.setToBogus();
   2234    return name;
   2235 }
   2236 
   2237 TZDBTimeZoneNames::MatchInfoCollection*
   2238 TZDBTimeZoneNames::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
   2239    umtx_initOnce(gTZDBNamesTrieInitOnce, &prepareFind, status);
   2240    if (U_FAILURE(status)) {
   2241        return nullptr;
   2242    }
   2243 
   2244    TZDBNameSearchHandler handler(types, fRegion.data());
   2245    gTZDBNamesTrie->search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
   2246    if (U_FAILURE(status)) {
   2247        return nullptr;
   2248    }
   2249    int32_t maxLen = 0;
   2250    return handler.getMatches(maxLen);
   2251 }
   2252 
   2253 const TZDBNames*
   2254 TZDBTimeZoneNames::getMetaZoneNames(const UnicodeString& mzID, UErrorCode& status) {
   2255    umtx_initOnce(gTZDBNamesMapInitOnce, &initTZDBNamesMap, status);
   2256    if (U_FAILURE(status)) {
   2257        return nullptr;
   2258    }
   2259 
   2260    TZDBNames* tzdbNames = nullptr;
   2261 
   2262    char16_t mzIDKey[ZID_KEY_MAX + 1];
   2263    mzID.extract(mzIDKey, ZID_KEY_MAX, status);
   2264    if (U_FAILURE(status)) {
   2265        return nullptr;
   2266    }
   2267    mzIDKey[mzID.length()] = 0;
   2268    if (!uprv_isInvariantUString(mzIDKey, mzID.length())) {
   2269        status = U_ILLEGAL_ARGUMENT_ERROR;
   2270        return nullptr;
   2271    }
   2272 
   2273    static UMutex gTZDBNamesMapLock;
   2274    umtx_lock(&gTZDBNamesMapLock);
   2275    {
   2276        void *cacheVal = uhash_get(gTZDBNamesMap, mzIDKey);
   2277        if (cacheVal == nullptr) {
   2278            UResourceBundle *zoneStringsRes = ures_openDirect(U_ICUDATA_ZONE, "tzdbNames", &status);
   2279            zoneStringsRes = ures_getByKey(zoneStringsRes, gZoneStrings, zoneStringsRes, &status);
   2280            char key[ZID_KEY_MAX + 1];
   2281            mergeTimeZoneKey(mzID, key, sizeof(key), status);
   2282            if (U_SUCCESS(status)) {
   2283                tzdbNames = TZDBNames::createInstance(zoneStringsRes, key);
   2284 
   2285                if (tzdbNames == nullptr) {
   2286                    cacheVal = (void *)EMPTY;
   2287                } else {
   2288                    cacheVal = tzdbNames;
   2289                }
   2290                // Use the persistent ID as the resource key, so we can
   2291                // avoid duplications.
   2292                // TODO: Is there a more efficient way, like intern() in Java?
   2293                void* newKey = (void*) ZoneMeta::findMetaZoneID(mzID);
   2294                if (newKey != nullptr) {
   2295                    uhash_put(gTZDBNamesMap, newKey, cacheVal, &status);
   2296                    if (U_FAILURE(status)) {
   2297                        if (tzdbNames != nullptr) {
   2298                            delete tzdbNames;
   2299                            tzdbNames = nullptr;
   2300                        }
   2301                    }
   2302                } else {
   2303                    // Should never happen with a valid input
   2304                    if (tzdbNames != nullptr) {
   2305                        // It's not possible that we get a valid tzdbNames with unknown ID.
   2306                        // But just in case..
   2307                        delete tzdbNames;
   2308                        tzdbNames = nullptr;
   2309                    }
   2310                }
   2311            }
   2312            ures_close(zoneStringsRes);
   2313        } else if (cacheVal != EMPTY) {
   2314            tzdbNames = static_cast<TZDBNames*>(cacheVal);
   2315        }
   2316    }
   2317    umtx_unlock(&gTZDBNamesMapLock);
   2318 
   2319    return tzdbNames;
   2320 }
   2321 
   2322 U_NAMESPACE_END
   2323 
   2324 
   2325 #endif /* #if !UCONFIG_NO_FORMATTING */
   2326 
   2327 //eof