Home | History | Annotate | Download | only in i18n
      1 /*
      2 *******************************************************************************
      3 * Copyright (C) 2011, International Business Machines Corporation and
      4 * others. All Rights Reserved.
      5 *******************************************************************************
      6 *
      7 * File TZNAMES_IMPL.CPP
      8 *
      9 *******************************************************************************
     10 */
     11 
     12 #include "unicode/utypes.h"
     13 
     14 #if !UCONFIG_NO_FORMATTING
     15 
     16 #include "unicode/ustring.h"
     17 #include "unicode/timezone.h"
     18 
     19 #include "tznames_impl.h"
     20 #include "cmemory.h"
     21 #include "cstring.h"
     22 #include "uassert.h"
     23 #include "uresimp.h"
     24 #include "ureslocs.h"
     25 #include "zonemeta.h"
     26 #include "ucln_in.h"
     27 #include "uvector.h"
     28 #include "olsontz.h"
     29 
     30 
     31 U_NAMESPACE_BEGIN
     32 
     33 #define ZID_KEY_MAX  128
     34 #define MZ_PREFIX_LEN 5
     35 
     36 static const char gZoneStrings[]        = "zoneStrings";
     37 static const char gMZPrefix[]           = "meta:";
     38 
     39 static const char* KEYS[]               = {"lg", "ls", "ld", "sg", "ss", "sd"};
     40 static const int32_t KEYS_SIZE = (sizeof KEYS / sizeof KEYS[0]);
     41 
     42 static const char gCuTag[]              = "cu";
     43 static const char gEcTag[]              = "ec";
     44 
     45 static const char EMPTY[]               = "<empty>";   // place holder for empty ZNames/TZNames
     46 
     47 static const UTimeZoneNameType ALL_NAME_TYPES[] = {
     48     UTZNM_LONG_GENERIC, UTZNM_LONG_STANDARD, UTZNM_LONG_DAYLIGHT,
     49     UTZNM_SHORT_GENERIC, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT,
     50     UTZNM_SHORT_STANDARD_COMMONLY_USED, UTZNM_SHORT_DAYLIGHT_COMMONLY_USED,
     51     UTZNM_UNKNOWN // unknown as the last one
     52 };
     53 
     54 #define DEFAULT_CHARACTERNODE_CAPACITY 1
     55 
     56 // ---------------------------------------------------
     57 // CaracterNode class implementation
     58 // ---------------------------------------------------
     59 void CharacterNode::clear() {
     60     uprv_memset(this, 0, sizeof(*this));
     61 }
     62 
     63 void CharacterNode::deleteValues(UObjectDeleter *valueDeleter) {
     64     if (fValues == NULL) {
     65         // Do nothing.
     66     } else if (!fHasValuesVector) {
     67         if (valueDeleter) {
     68             valueDeleter(fValues);
     69         }
     70     } else {
     71         delete (UVector *)fValues;
     72     }
     73 }
     74 
     75 void
     76 CharacterNode::addValue(void *value, UObjectDeleter *valueDeleter, UErrorCode &status) {
     77     if (U_FAILURE(status)) {
     78         if (valueDeleter) {
     79             valueDeleter(value);
     80         }
     81         return;
     82     }
     83     if (fValues == NULL) {
     84         fValues = value;
     85     } else {
     86         // At least one value already.
     87         if (!fHasValuesVector) {
     88             // There is only one value so far, and not in a vector yet.
     89             // Create a vector and add the old value.
     90             UVector *values = new UVector(valueDeleter, NULL, DEFAULT_CHARACTERNODE_CAPACITY, status);
     91             if (U_FAILURE(status)) {
     92                 if (valueDeleter) {
     93                     valueDeleter(value);
     94                 }
     95                 return;
     96             }
     97             values->addElement(fValues, status);
     98             fValues = values;
     99             fHasValuesVector = TRUE;
    100         }
    101         // Add the new value.
    102         ((UVector *)fValues)->addElement(value, status);
    103     }
    104 }
    105 
    106 // ---------------------------------------------------
    107 // TextTrieMapSearchResultHandler class implementation
    108 // ---------------------------------------------------
    109 TextTrieMapSearchResultHandler::~TextTrieMapSearchResultHandler(){
    110 }
    111 
    112 // ---------------------------------------------------
    113 // TextTrieMap class implementation
    114 // ---------------------------------------------------
    115 TextTrieMap::TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleter)
    116 : fIgnoreCase(ignoreCase), fNodes(NULL), fNodesCapacity(0), fNodesCount(0),
    117   fLazyContents(NULL), fIsEmpty(TRUE), fValueDeleter(valueDeleter) {
    118 }
    119 
    120 TextTrieMap::~TextTrieMap() {
    121     int32_t index;
    122     for (index = 0; index < fNodesCount; ++index) {
    123         fNodes[index].deleteValues(fValueDeleter);
    124     }
    125     uprv_free(fNodes);
    126     if (fLazyContents != NULL) {
    127         for (int32_t i=0; i<fLazyContents->size(); i+=2) {
    128             if (fValueDeleter) {
    129                 fValueDeleter(fLazyContents->elementAt(i+1));
    130             }
    131         }
    132         delete fLazyContents;
    133     }
    134 }
    135 
    136 int32_t TextTrieMap::isEmpty() const {
    137     // Use a separate field for fIsEmpty because it will remain unchanged once the
    138     //   Trie is built, while fNodes and fLazyContents change with the lazy init
    139     //   of the nodes structure.  Trying to test the changing fields has
    140     //   thread safety complications.
    141     return fIsEmpty;
    142 }
    143 
    144 
    145 //  We defer actually building the TextTrieMap node structure until the first time a
    146 //     search is performed.  put() simply saves the parameters in case we do
    147 //     eventually need to build it.
    148 //
    149 void
    150 TextTrieMap::put(const UnicodeString &key, void *value, ZNStringPool &sp, UErrorCode &status) {
    151     const UChar *s = sp.get(key, status);
    152     put(s, value, status);
    153 }
    154 
    155 // This method is for designed for a persistent key, such as string key stored in
    156 // resource bundle.
    157 void
    158 TextTrieMap::put(const UChar *key, void *value, UErrorCode &status) {
    159     fIsEmpty = FALSE;
    160     if (fLazyContents == NULL) {
    161         fLazyContents = new UVector(status);
    162         if (fLazyContents == NULL) {
    163             status = U_MEMORY_ALLOCATION_ERROR;
    164         }
    165     }
    166     if (U_FAILURE(status)) {
    167         return;
    168     }
    169     UChar *s = const_cast<UChar *>(key);
    170     fLazyContents->addElement(s, status);
    171     fLazyContents->addElement(value, status);
    172 }
    173 
    174 void
    175 TextTrieMap::putImpl(const UnicodeString &key, void *value, UErrorCode &status) {
    176     if (fNodes == NULL) {
    177         fNodesCapacity = 512;
    178         fNodes = (CharacterNode *)uprv_malloc(fNodesCapacity * sizeof(CharacterNode));
    179         fNodes[0].clear();  // Init root node.
    180         fNodesCount = 1;
    181     }
    182 
    183     UnicodeString foldedKey;
    184     const UChar *keyBuffer;
    185     int32_t keyLength;
    186     if (fIgnoreCase) {
    187         // Ok to use fastCopyFrom() because we discard the copy when we return.
    188         foldedKey.fastCopyFrom(key).foldCase();
    189         keyBuffer = foldedKey.getBuffer();
    190         keyLength = foldedKey.length();
    191     } else {
    192         keyBuffer = key.getBuffer();
    193         keyLength = key.length();
    194     }
    195 
    196     CharacterNode *node = fNodes;
    197     int32_t index;
    198     for (index = 0; index < keyLength; ++index) {
    199         node = addChildNode(node, keyBuffer[index], status);
    200     }
    201     node->addValue(value, fValueDeleter, status);
    202 }
    203 
    204 UBool
    205 TextTrieMap::growNodes() {
    206     if (fNodesCapacity == 0xffff) {
    207         return FALSE;  // We use 16-bit node indexes.
    208     }
    209     int32_t newCapacity = fNodesCapacity + 1000;
    210     if (newCapacity > 0xffff) {
    211         newCapacity = 0xffff;
    212     }
    213     CharacterNode *newNodes = (CharacterNode *)uprv_malloc(newCapacity * sizeof(CharacterNode));
    214     if (newNodes == NULL) {
    215         return FALSE;
    216     }
    217     uprv_memcpy(newNodes, fNodes, fNodesCount * sizeof(CharacterNode));
    218     uprv_free(fNodes);
    219     fNodes = newNodes;
    220     fNodesCapacity = newCapacity;
    221     return TRUE;
    222 }
    223 
    224 CharacterNode*
    225 TextTrieMap::addChildNode(CharacterNode *parent, UChar c, UErrorCode &status) {
    226     if (U_FAILURE(status)) {
    227         return NULL;
    228     }
    229     // Linear search of the sorted list of children.
    230     uint16_t prevIndex = 0;
    231     uint16_t nodeIndex = parent->fFirstChild;
    232     while (nodeIndex > 0) {
    233         CharacterNode *current = fNodes + nodeIndex;
    234         UChar childCharacter = current->fCharacter;
    235         if (childCharacter == c) {
    236             return current;
    237         } else if (childCharacter > c) {
    238             break;
    239         }
    240         prevIndex = nodeIndex;
    241         nodeIndex = current->fNextSibling;
    242     }
    243 
    244     // Ensure capacity. Grow fNodes[] if needed.
    245     if (fNodesCount == fNodesCapacity) {
    246         int32_t parentIndex = (int32_t)(parent - fNodes);
    247         if (!growNodes()) {
    248             status = U_MEMORY_ALLOCATION_ERROR;
    249             return NULL;
    250         }
    251         parent = fNodes + parentIndex;
    252     }
    253 
    254     // Insert a new child node with c in sorted order.
    255     CharacterNode *node = fNodes + fNodesCount;
    256     node->clear();
    257     node->fCharacter = c;
    258     node->fNextSibling = nodeIndex;
    259     if (prevIndex == 0) {
    260         parent->fFirstChild = (uint16_t)fNodesCount;
    261     } else {
    262         fNodes[prevIndex].fNextSibling = (uint16_t)fNodesCount;
    263     }
    264     ++fNodesCount;
    265     return node;
    266 }
    267 
    268 CharacterNode*
    269 TextTrieMap::getChildNode(CharacterNode *parent, UChar c) const {
    270     // Linear search of the sorted list of children.
    271     uint16_t nodeIndex = parent->fFirstChild;
    272     while (nodeIndex > 0) {
    273         CharacterNode *current = fNodes + nodeIndex;
    274         UChar childCharacter = current->fCharacter;
    275         if (childCharacter == c) {
    276             return current;
    277         } else if (childCharacter > c) {
    278             break;
    279         }
    280         nodeIndex = current->fNextSibling;
    281     }
    282     return NULL;
    283 }
    284 
    285 // Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
    286 static UMTX TextTrieMutex;
    287 
    288 // buildTrie() - The Trie node structure is needed.  Create it from the data that was
    289 //               saved at the time the ZoneStringFormatter was created.  The Trie is only
    290 //               needed for parsing operations, which are less common than formatting,
    291 //               and the Trie is big, which is why its creation is deferred until first use.
    292 void TextTrieMap::buildTrie(UErrorCode &status) {
    293     umtx_lock(&TextTrieMutex);
    294     if (fLazyContents != NULL) {
    295         for (int32_t i=0; i<fLazyContents->size(); i+=2) {
    296             const UChar *key = (UChar *)fLazyContents->elementAt(i);
    297             void  *val = fLazyContents->elementAt(i+1);
    298             UnicodeString keyString(TRUE, key, -1);  // Aliasing UnicodeString constructor.
    299             putImpl(keyString, val, status);
    300         }
    301         delete fLazyContents;
    302         fLazyContents = NULL;
    303     }
    304     umtx_unlock(&TextTrieMutex);
    305 }
    306 
    307 void
    308 TextTrieMap::search(const UnicodeString &text, int32_t start,
    309                   TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
    310     UBool trieNeedsInitialization = FALSE;
    311     UMTX_CHECK(&TextTrieMutex, fLazyContents != NULL, trieNeedsInitialization);
    312     if (trieNeedsInitialization) {
    313         TextTrieMap *nonConstThis = const_cast<TextTrieMap *>(this);
    314         nonConstThis->buildTrie(status);
    315     }
    316     if (fNodes == NULL) {
    317         return;
    318     }
    319     search(fNodes, text, start, start, handler, status);
    320 }
    321 
    322 void
    323 TextTrieMap::search(CharacterNode *node, const UnicodeString &text, int32_t start,
    324                   int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const {
    325     if (U_FAILURE(status)) {
    326         return;
    327     }
    328     if (node->hasValues()) {
    329         if (!handler->handleMatch(index - start, node, status)) {
    330             return;
    331         }
    332         if (U_FAILURE(status)) {
    333             return;
    334         }
    335     }
    336     UChar32 c = text.char32At(index);
    337     if (fIgnoreCase) {
    338         // size of character may grow after fold operation
    339         UnicodeString tmp(c);
    340         tmp.foldCase();
    341         int32_t tmpidx = 0;
    342         while (tmpidx < tmp.length()) {
    343             c = tmp.char32At(tmpidx);
    344             node = getChildNode(node, c);
    345             if (node == NULL) {
    346                 break;
    347             }
    348             tmpidx = tmp.moveIndex32(tmpidx, 1);
    349         }
    350     } else {
    351         node = getChildNode(node, c);
    352     }
    353     if (node != NULL) {
    354         search(node, text, start, index+1, handler, status);
    355     }
    356 }
    357 
    358 // ---------------------------------------------------
    359 // ZNStringPool class implementation
    360 // ---------------------------------------------------
    361 static const int32_t POOL_CHUNK_SIZE = 2000;
    362 struct ZNStringPoolChunk: public UMemory {
    363     ZNStringPoolChunk    *fNext;                       // Ptr to next pool chunk
    364     int32_t               fLimit;                       // Index to start of unused area at end of fStrings
    365     UChar                 fStrings[POOL_CHUNK_SIZE];    //  Strings array
    366     ZNStringPoolChunk();
    367 };
    368 
    369 ZNStringPoolChunk::ZNStringPoolChunk() {
    370     fNext = NULL;
    371     fLimit = 0;
    372 }
    373 
    374 ZNStringPool::ZNStringPool(UErrorCode &status) {
    375     fChunks = NULL;
    376     fHash   = NULL;
    377     if (U_FAILURE(status)) {
    378         return;
    379     }
    380     fChunks = new ZNStringPoolChunk;
    381     if (fChunks == NULL) {
    382         status = U_MEMORY_ALLOCATION_ERROR;
    383         return;
    384     }
    385 
    386     fHash   = uhash_open(uhash_hashUChars      /* keyHash */,
    387                          uhash_compareUChars   /* keyComp */,
    388                          uhash_compareUChars   /* valueComp */,
    389                          &status);
    390     if (U_FAILURE(status)) {
    391         return;
    392     }
    393 }
    394 
    395 ZNStringPool::~ZNStringPool() {
    396     if (fHash != NULL) {
    397         uhash_close(fHash);
    398         fHash = NULL;
    399     }
    400 
    401     while (fChunks != NULL) {
    402         ZNStringPoolChunk *nextChunk = fChunks->fNext;
    403         delete fChunks;
    404         fChunks = nextChunk;
    405     }
    406 }
    407 
    408 static const UChar EmptyString = 0;
    409 
    410 const UChar *ZNStringPool::get(const UChar *s, UErrorCode &status) {
    411     const UChar *pooledString;
    412     if (U_FAILURE(status)) {
    413         return &EmptyString;
    414     }
    415 
    416     pooledString = static_cast<UChar *>(uhash_get(fHash, s));
    417     if (pooledString != NULL) {
    418         return pooledString;
    419     }
    420 
    421     int32_t length = u_strlen(s);
    422     int32_t remainingLength = POOL_CHUNK_SIZE - fChunks->fLimit;
    423     if (remainingLength <= length) {
    424         U_ASSERT(length < POOL_CHUNK_SIZE);
    425         if (length >= POOL_CHUNK_SIZE) {
    426             status = U_INTERNAL_PROGRAM_ERROR;
    427             return &EmptyString;
    428         }
    429         ZNStringPoolChunk *oldChunk = fChunks;
    430         fChunks = new ZNStringPoolChunk;
    431         if (fChunks == NULL) {
    432             status = U_MEMORY_ALLOCATION_ERROR;
    433             return &EmptyString;
    434         }
    435         fChunks->fNext = oldChunk;
    436     }
    437 
    438     UChar *destString = &fChunks->fStrings[fChunks->fLimit];
    439     u_strcpy(destString, s);
    440     fChunks->fLimit += (length + 1);
    441     uhash_put(fHash, destString, destString, &status);
    442     return destString;
    443 }
    444 
    445 
    446 //
    447 //  ZNStringPool::adopt()    Put a string into the hash, but do not copy the string data
    448 //                           into the pool's storage.  Used for strings from resource bundles,
    449 //                           which will perisist for the life of the zone string formatter, and
    450 //                           therefore can be used directly without copying.
    451 const UChar *ZNStringPool::adopt(const UChar * s, UErrorCode &status) {
    452     const UChar *pooledString;
    453     if (U_FAILURE(status)) {
    454         return &EmptyString;
    455     }
    456     if (s != NULL) {
    457         pooledString = static_cast<UChar *>(uhash_get(fHash, s));
    458         if (pooledString == NULL) {
    459             UChar *ncs = const_cast<UChar *>(s);
    460             uhash_put(fHash, ncs, ncs, &status);
    461         }
    462     }
    463     return s;
    464 }
    465 
    466 
    467 const UChar *ZNStringPool::get(const UnicodeString &s, UErrorCode &status) {
    468     UnicodeString &nonConstStr = const_cast<UnicodeString &>(s);
    469     return this->get(nonConstStr.getTerminatedBuffer(), status);
    470 }
    471 
    472 /*
    473  * freeze().   Close the hash table that maps to the pooled strings.
    474  *             After freezing, the pool can not be searched or added to,
    475  *             but all existing references to pooled strings remain valid.
    476  *
    477  *             The main purpose is to recover the storage used for the hash.
    478  */
    479 void ZNStringPool::freeze() {
    480     uhash_close(fHash);
    481     fHash = NULL;
    482 }
    483 
    484 
    485 // ---------------------------------------------------
    486 // ZNames - names common for time zone and meta zone
    487 // ---------------------------------------------------
    488 class ZNames : public UMemory {
    489 public:
    490     virtual ~ZNames();
    491 
    492     static ZNames* createInstance(UResourceBundle* rb, const char* key);
    493     const UChar* getName(UTimeZoneNameType type);
    494 
    495 protected:
    496     ZNames(const UChar** names, UBool shortCommonlyUsed);
    497     static const UChar** loadData(UResourceBundle* rb, const char* key, UBool& shortCommonlyUsed);
    498 
    499 private:
    500     const UChar** fNames;
    501     UBool fShortCommonlyUsed;
    502 };
    503 
    504 ZNames::ZNames(const UChar** names, UBool shortCommonlyUsed)
    505 : fNames(names), fShortCommonlyUsed(shortCommonlyUsed) {
    506 }
    507 
    508 ZNames::~ZNames() {
    509     if (fNames != NULL) {
    510         uprv_free(fNames);
    511     }
    512 }
    513 
    514 ZNames*
    515 ZNames::createInstance(UResourceBundle* rb, const char* key) {
    516     UBool shortCommonlyUsed = FALSE;
    517     const UChar** names = loadData(rb, key, shortCommonlyUsed);
    518     if (names == NULL) {
    519         // No names data available
    520         return NULL;
    521     }
    522     return new ZNames(names, shortCommonlyUsed);
    523 }
    524 
    525 const UChar*
    526 ZNames::getName(UTimeZoneNameType type) {
    527     if (fNames == NULL) {
    528         return NULL;
    529     }
    530     const UChar *name = NULL;
    531     switch(type) {
    532     case UTZNM_LONG_GENERIC:
    533         name = fNames[0];
    534         break;
    535     case UTZNM_LONG_STANDARD:
    536         name = fNames[1];
    537         break;
    538     case UTZNM_LONG_DAYLIGHT:
    539         name = fNames[2];
    540         break;
    541     case UTZNM_SHORT_GENERIC:
    542         if (fShortCommonlyUsed) {
    543             name = fNames[3];
    544         }
    545         break;
    546     case UTZNM_SHORT_STANDARD:
    547         name = fNames[4];
    548         break;
    549     case UTZNM_SHORT_DAYLIGHT:
    550         name = fNames[5];
    551         break;
    552     case UTZNM_SHORT_STANDARD_COMMONLY_USED:
    553         if (fShortCommonlyUsed) {
    554             name = fNames[4];
    555         }
    556         break;
    557     case UTZNM_SHORT_DAYLIGHT_COMMONLY_USED:
    558         if (fShortCommonlyUsed) {
    559             name = fNames[5];
    560         }
    561         break;
    562     default:
    563         name = NULL;
    564     }
    565     return name;
    566 }
    567 
    568 const UChar**
    569 ZNames::loadData(UResourceBundle* rb, const char* key, UBool& shortCommonlyUsed) {
    570     if (rb == NULL || key == NULL || *key == 0) {
    571         return NULL;
    572     }
    573 
    574     UErrorCode status = U_ZERO_ERROR;
    575     const UChar **names = NULL;
    576 
    577     UResourceBundle* rbTable = NULL;
    578     rbTable = ures_getByKeyWithFallback(rb, key, rbTable, &status);
    579     if (U_SUCCESS(status)) {
    580         names = (const UChar **)uprv_malloc(sizeof(const UChar*) * KEYS_SIZE);
    581         if (names != NULL) {
    582             UBool isEmpty = TRUE;
    583             for (int32_t i = 0; i < KEYS_SIZE; i++) {
    584                 status = U_ZERO_ERROR;
    585                 int32_t len = 0;
    586                 const UChar *value = ures_getStringByKeyWithFallback(rbTable, KEYS[i], &len, &status);
    587                 if (U_FAILURE(status) || len == 0) {
    588                     names[i] = NULL;
    589                 } else {
    590                     names[i] = value;
    591                     isEmpty = FALSE;
    592                 }
    593             }
    594             if (isEmpty) {
    595                 // No need to keep the names array
    596                 uprv_free(names);
    597                 names = NULL;
    598             }
    599         }
    600 
    601         if (names != NULL) {
    602             status = U_ZERO_ERROR;
    603             UResourceBundle* cuRes = ures_getByKeyWithFallback(rbTable, gCuTag, NULL, &status);
    604             int32_t cu = ures_getInt(cuRes, &status);
    605             if (U_SUCCESS(status)) {
    606                 shortCommonlyUsed = (cu != 0);
    607             }
    608             ures_close(cuRes);
    609         }
    610     }
    611     ures_close(rbTable);
    612     return names;
    613 }
    614 
    615 // ---------------------------------------------------
    616 // TZNames - names for a time zone
    617 // ---------------------------------------------------
    618 class TZNames : public ZNames {
    619 public:
    620     virtual ~TZNames();
    621 
    622     static TZNames* createInstance(UResourceBundle* rb, const char* key);
    623     const UChar* getLocationName(void);
    624 
    625 private:
    626     TZNames(const UChar** names, UBool shortCommonlyUsed, const UChar* locationName);
    627     const UChar* fLocationName;
    628 };
    629 
    630 TZNames::TZNames(const UChar** names, UBool shortCommonlyUsed, const UChar* locationName)
    631 : ZNames(names, shortCommonlyUsed), fLocationName(locationName) {
    632 }
    633 
    634 TZNames::~TZNames() {
    635 }
    636 
    637 const UChar*
    638 TZNames::getLocationName() {
    639     return fLocationName;
    640 }
    641 
    642 TZNames*
    643 TZNames::createInstance(UResourceBundle* rb, const char* key) {
    644     if (rb == NULL || key == NULL || *key == 0) {
    645         return NULL;
    646     }
    647     TZNames* tznames = NULL;
    648     UErrorCode status = U_ZERO_ERROR;
    649     UResourceBundle* rbTable = ures_getByKeyWithFallback(rb, key, NULL, &status);
    650     if (U_SUCCESS(status)) {
    651         int32_t len = 0;
    652         const UChar* locationName = ures_getStringByKeyWithFallback(rbTable, gEcTag, &len, &status);
    653         if (U_FAILURE(status) || len == 0) {
    654             locationName = NULL;
    655         }
    656 
    657         UBool shortCommonlyUsed = FALSE;
    658         const UChar** names = loadData(rb, key, shortCommonlyUsed);
    659 
    660         if (locationName != NULL || names != NULL) {
    661             tznames = new TZNames(names, shortCommonlyUsed, locationName);
    662         }
    663     }
    664     ures_close(rbTable);
    665     return tznames;
    666 }
    667 
    668 // ---------------------------------------------------
    669 // The meta zone ID enumeration class
    670 // ---------------------------------------------------
    671 class MetaZoneIDsEnumeration : public StringEnumeration {
    672 public:
    673     MetaZoneIDsEnumeration();
    674     MetaZoneIDsEnumeration(const UVector& mzIDs);
    675     MetaZoneIDsEnumeration(UVector* mzIDs);
    676     virtual ~MetaZoneIDsEnumeration();
    677     static UClassID U_EXPORT2 getStaticClassID(void);
    678     virtual UClassID getDynamicClassID(void) const;
    679     virtual const UnicodeString* snext(UErrorCode& status);
    680     virtual void reset(UErrorCode& status);
    681     virtual int32_t count(UErrorCode& status) const;
    682 private:
    683     int32_t fLen;
    684     int32_t fPos;
    685     const UVector* fMetaZoneIDs;
    686     UVector *fLocalVector;
    687 };
    688 
    689 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MetaZoneIDsEnumeration)
    690 
    691 MetaZoneIDsEnumeration::MetaZoneIDsEnumeration()
    692 : fLen(0), fPos(0), fMetaZoneIDs(NULL), fLocalVector(NULL) {
    693 }
    694 
    695 MetaZoneIDsEnumeration::MetaZoneIDsEnumeration(const UVector& mzIDs)
    696 : fPos(0), fMetaZoneIDs(&mzIDs), fLocalVector(NULL) {
    697     fLen = fMetaZoneIDs->size();
    698 }
    699 
    700 MetaZoneIDsEnumeration::MetaZoneIDsEnumeration(UVector *mzIDs)
    701 : fLen(0), fPos(0), fMetaZoneIDs(mzIDs), fLocalVector(mzIDs) {
    702     if (fMetaZoneIDs) {
    703         fLen = fMetaZoneIDs->size();
    704     }
    705 }
    706 
    707 const UnicodeString*
    708 MetaZoneIDsEnumeration::snext(UErrorCode& status) {
    709     if (U_SUCCESS(status) && fMetaZoneIDs != NULL && fPos < fLen) {
    710         unistr.setTo((const UChar*)fMetaZoneIDs->elementAt(fPos++), -1);
    711         return &unistr;
    712     }
    713     return NULL;
    714 }
    715 
    716 void
    717 MetaZoneIDsEnumeration::reset(UErrorCode& /*status*/) {
    718     fPos = 0;
    719 }
    720 
    721 int32_t
    722 MetaZoneIDsEnumeration::count(UErrorCode& /*status*/) const {
    723     return fLen;
    724 }
    725 
    726 MetaZoneIDsEnumeration::~MetaZoneIDsEnumeration() {
    727     if (fLocalVector) {
    728         delete fLocalVector;
    729     }
    730 }
    731 
    732 U_CDECL_BEGIN
    733 /**
    734  * ZNameInfo stores zone name information in the trie
    735  */
    736 typedef struct ZNameInfo {
    737     UTimeZoneNameType   type;
    738     const UChar*        tzID;
    739     const UChar*        mzID;
    740 } ZNameInfo;
    741 
    742 /**
    743  * ZMatchInfo stores zone name match information used by find method
    744  */
    745 typedef struct ZMatchInfo {
    746     const ZNameInfo*    znameInfo;
    747     int32_t             matchLength;
    748 } ZMatchInfo;
    749 U_CDECL_END
    750 
    751 // ---------------------------------------------------
    752 // The class stores time zone name match information
    753 // ---------------------------------------------------
    754 class TimeZoneNameMatchInfoImpl : public TimeZoneNameMatchInfo {
    755 public:
    756     TimeZoneNameMatchInfoImpl(UVector* matches);
    757     ~TimeZoneNameMatchInfoImpl();
    758 
    759     int32_t size() const;
    760     UTimeZoneNameType getNameType(int32_t index) const;
    761     int32_t getMatchLength(int32_t index) const;
    762     UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const;
    763     UnicodeString& getMetaZoneID(int32_t index, UnicodeString& mzID) const;
    764 
    765 private:
    766     UVector* fMatches;  // vector of MatchEntry
    767 };
    768 
    769 TimeZoneNameMatchInfoImpl::TimeZoneNameMatchInfoImpl(UVector* matches)
    770 : fMatches(matches) {
    771 }
    772 
    773 TimeZoneNameMatchInfoImpl::~TimeZoneNameMatchInfoImpl() {
    774     if (fMatches != NULL) {
    775         delete fMatches;
    776     }
    777 }
    778 
    779 int32_t
    780 TimeZoneNameMatchInfoImpl::size() const {
    781     if (fMatches == NULL) {
    782         return 0;
    783     }
    784     return fMatches->size();
    785 }
    786 
    787 UTimeZoneNameType
    788 TimeZoneNameMatchInfoImpl::getNameType(int32_t index) const {
    789     ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
    790     if (minfo != NULL) {
    791         return minfo->znameInfo->type;
    792     }
    793     return UTZNM_UNKNOWN;
    794 }
    795 
    796 int32_t
    797 TimeZoneNameMatchInfoImpl::getMatchLength(int32_t index) const {
    798     ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
    799     if (minfo != NULL) {
    800         return minfo->matchLength;
    801     }
    802     return -1;
    803 }
    804 
    805 UnicodeString&
    806 TimeZoneNameMatchInfoImpl::getTimeZoneID(int32_t index, UnicodeString& tzID) const {
    807     ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
    808     if (minfo != NULL && minfo->znameInfo->tzID != NULL) {
    809         tzID.setTo(TRUE, minfo->znameInfo->tzID, -1);
    810     } else {
    811         tzID.setToBogus();
    812     }
    813     return tzID;
    814 }
    815 
    816 UnicodeString&
    817 TimeZoneNameMatchInfoImpl::getMetaZoneID(int32_t index, UnicodeString& mzID) const {
    818     ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
    819     if (minfo != NULL && minfo->znameInfo->mzID != NULL) {
    820         mzID.setTo(TRUE, minfo->znameInfo->mzID, -1);
    821     } else {
    822         mzID.setToBogus();
    823     }
    824     return mzID;
    825 }
    826 
    827 // ---------------------------------------------------
    828 // ZNameSearchHandler
    829 // ---------------------------------------------------
    830 class ZNameSearchHandler : public TextTrieMapSearchResultHandler {
    831 public:
    832     ZNameSearchHandler(uint32_t types);
    833     virtual ~ZNameSearchHandler();
    834 
    835     UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
    836     UVector* getMatches(int32_t& maxMatchLen);
    837 
    838 private:
    839     uint32_t fTypes;
    840     UVector* fResults;
    841     int32_t fMaxMatchLen;
    842 };
    843 
    844 ZNameSearchHandler::ZNameSearchHandler(uint32_t types)
    845 : fTypes(types), fResults(NULL), fMaxMatchLen(0) {
    846 }
    847 
    848 ZNameSearchHandler::~ZNameSearchHandler() {
    849     if (fResults != NULL) {
    850         delete fResults;
    851     }
    852 }
    853 
    854 UBool
    855 ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
    856     if (U_FAILURE(status)) {
    857         return FALSE;
    858     }
    859     if (node->hasValues()) {
    860         int32_t valuesCount = node->countValues();
    861         for (int32_t i = 0; i < valuesCount; i++) {
    862             ZNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
    863             if (nameinfo == NULL) {
    864                 break;
    865             }
    866             if ((nameinfo->type & fTypes) != 0) {
    867                 // matches a requested type
    868                 if (fResults == NULL) {
    869                     fResults = new UVector(uprv_free, NULL, status);
    870                     if (fResults == NULL) {
    871                         status = U_MEMORY_ALLOCATION_ERROR;
    872                     }
    873                 }
    874                 if (U_SUCCESS(status)) {
    875                     ZMatchInfo *zmatch = (ZMatchInfo *)uprv_malloc(sizeof(ZMatchInfo));
    876                     if (zmatch == NULL) {
    877                         status = U_MEMORY_ALLOCATION_ERROR;
    878                     } else {
    879                         // add the match to the vector
    880                         zmatch->znameInfo = nameinfo;
    881                         zmatch->matchLength = matchLength;
    882                         fResults->addElement(zmatch, status);
    883                         if (U_FAILURE(status)) {
    884                             uprv_free(zmatch);
    885                         } else {
    886                             if (matchLength > fMaxMatchLen) {
    887                                 fMaxMatchLen = matchLength;
    888                             }
    889                         }
    890                     }
    891                 }
    892             }
    893         }
    894     }
    895     return TRUE;
    896 }
    897 
    898 UVector*
    899 ZNameSearchHandler::getMatches(int32_t& maxMatchLen) {
    900     // give the ownership to the caller
    901     UVector *results = fResults;
    902     maxMatchLen = fMaxMatchLen;
    903 
    904     // reset
    905     fResults = NULL;
    906     fMaxMatchLen = 0;
    907     return results;
    908 }
    909 
    910 // ---------------------------------------------------
    911 // TimeZoneNamesImpl
    912 //
    913 // TimeZoneNames implementation class. This is the main
    914 // part of this module.
    915 // ---------------------------------------------------
    916 
    917 U_CDECL_BEGIN
    918 /**
    919  * Deleter for ZNames
    920  */
    921 static void U_CALLCONV
    922 deleteZNames(void *obj) {
    923     if (obj != EMPTY) {
    924         delete (ZNames *)obj;
    925     }
    926 }
    927 /**
    928  * Deleter for TZNames
    929  */
    930 static void U_CALLCONV
    931 deleteTZNames(void *obj) {
    932     if (obj != EMPTY) {
    933         delete (TZNames *)obj;
    934     }
    935 }
    936 
    937 /**
    938  * Deleter for ZNameInfo
    939  */
    940 static void U_CALLCONV
    941 deleteZNameInfo(void *obj) {
    942     uprv_free(obj);
    943 }
    944 
    945 U_CDECL_END
    946 
    947 TimeZoneNamesImpl::TimeZoneNamesImpl(const Locale& locale, UErrorCode& status)
    948 : fLocale(locale),
    949   fLock(NULL),
    950   fZoneStrings(NULL),
    951   fTZNamesMap(NULL),
    952   fMZNamesMap(NULL),
    953   fNamesTrieFullyLoaded(FALSE),
    954   fNamesTrie(TRUE, deleteZNameInfo) {
    955     initialize(locale, status);
    956 }
    957 
    958 void
    959 TimeZoneNamesImpl::initialize(const Locale& locale, UErrorCode& status) {
    960     if (U_FAILURE(status)) {
    961         return;
    962     }
    963 
    964     // Load zoneStrings bundle
    965     UErrorCode tmpsts = U_ZERO_ERROR;   // OK with fallback warning..
    966     fZoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts);
    967     fZoneStrings = ures_getByKeyWithFallback(fZoneStrings, gZoneStrings, fZoneStrings, &tmpsts);
    968     if (U_FAILURE(tmpsts)) {
    969         status = tmpsts;
    970         cleanup();
    971         return;
    972     }
    973 
    974     // Initialize hashtables holding time zone/meta zone names
    975     fMZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
    976     fTZNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
    977     if (U_FAILURE(status)) {
    978         cleanup();
    979         return;
    980     }
    981 
    982     uhash_setValueDeleter(fMZNamesMap, deleteZNames);
    983     uhash_setValueDeleter(fTZNamesMap, deleteTZNames);
    984     // no key deleters for name maps
    985 
    986     // preload zone strings for the default zone
    987     TimeZone *tz = TimeZone::createDefault();
    988     const UChar *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
    989     if (tzID != NULL) {
    990         loadStrings(UnicodeString(tzID));
    991     }
    992     delete tz;
    993 
    994     return;
    995 }
    996 
    997 /*
    998  * This method updates the cache and must be called with a lock,
    999  * except initializer.
   1000  */
   1001 void
   1002 TimeZoneNamesImpl::loadStrings(const UnicodeString& tzCanonicalID) {
   1003     loadTimeZoneNames(tzCanonicalID);
   1004 
   1005     UErrorCode status = U_ZERO_ERROR;
   1006     StringEnumeration *mzIDs = getAvailableMetaZoneIDs(tzCanonicalID, status);
   1007     if (U_SUCCESS(status) && mzIDs != NULL) {
   1008         const UnicodeString *mzID;
   1009         while ((mzID = mzIDs->snext(status))) {
   1010             if (U_FAILURE(status)) {
   1011                 break;
   1012             }
   1013             loadMetaZoneNames(*mzID);
   1014         }
   1015         delete mzIDs;
   1016     }
   1017 }
   1018 
   1019 TimeZoneNamesImpl::~TimeZoneNamesImpl() {
   1020     cleanup();
   1021     umtx_destroy(&fLock);
   1022 }
   1023 
   1024 void
   1025 TimeZoneNamesImpl::cleanup() {
   1026     if (fZoneStrings != NULL) {
   1027         ures_close(fZoneStrings);
   1028         fZoneStrings = NULL;
   1029     }
   1030     if (fMZNamesMap != NULL) {
   1031         uhash_close(fMZNamesMap);
   1032         fMZNamesMap = NULL;
   1033     }
   1034     if (fTZNamesMap != NULL) {
   1035         uhash_close(fTZNamesMap);
   1036         fTZNamesMap = NULL;
   1037     }
   1038 }
   1039 
   1040 StringEnumeration*
   1041 TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const {
   1042     if (U_FAILURE(status)) {
   1043         return NULL;
   1044     }
   1045     const UVector* mzIDs = ZoneMeta::getAvailableMetazoneIDs();
   1046     if (mzIDs == NULL) {
   1047         return new MetaZoneIDsEnumeration();
   1048     }
   1049     return new MetaZoneIDsEnumeration(*mzIDs);
   1050 }
   1051 
   1052 StringEnumeration*
   1053 TimeZoneNamesImpl::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
   1054     if (U_FAILURE(status)) {
   1055         return NULL;
   1056     }
   1057     const UVector* mappings = ZoneMeta::getMetazoneMappings(tzID);
   1058     if (mappings == NULL) {
   1059         return new MetaZoneIDsEnumeration();
   1060     }
   1061 
   1062     MetaZoneIDsEnumeration *senum = NULL;
   1063     UVector* mzIDs = new UVector(NULL, uhash_compareUChars, status);
   1064     if (mzIDs == NULL) {
   1065         status = U_MEMORY_ALLOCATION_ERROR;
   1066     }
   1067     if (U_SUCCESS(status)) {
   1068         for (int32_t i = 0; U_SUCCESS(status) && i < mappings->size(); i++) {
   1069 
   1070             OlsonToMetaMappingEntry *map = (OlsonToMetaMappingEntry *)mappings->elementAt(i);
   1071             const UChar *mzID = map->mzid;
   1072             if (!mzIDs->contains((void *)mzID)) {
   1073                 mzIDs->addElement((void *)mzID, status);
   1074             }
   1075         }
   1076         if (U_SUCCESS(status)) {
   1077             senum = new MetaZoneIDsEnumeration(mzIDs);
   1078         } else {
   1079             delete mzIDs;
   1080         }
   1081     }
   1082     return senum;
   1083 }
   1084 
   1085 UnicodeString&
   1086 TimeZoneNamesImpl::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
   1087     ZoneMeta::getMetazoneID(tzID, date, mzID);
   1088     return mzID;
   1089 }
   1090 
   1091 UnicodeString&
   1092 TimeZoneNamesImpl::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
   1093     ZoneMeta::getZoneIdByMetazone(mzID, UnicodeString(region, -1, US_INV), tzID);
   1094     return tzID;
   1095 }
   1096 
   1097 UnicodeString&
   1098 TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID,
   1099                                           UTimeZoneNameType type,
   1100                                           UnicodeString& name) const {
   1101     name.setToBogus();  // cleanup result.
   1102     if (mzID.isEmpty()) {
   1103         return name;
   1104     }
   1105 
   1106     ZNames *znames = NULL;
   1107     TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
   1108 
   1109     umtx_lock(&nonConstThis->fLock);
   1110     {
   1111         znames = nonConstThis->loadMetaZoneNames(mzID);
   1112     }
   1113     umtx_unlock(&nonConstThis->fLock);
   1114 
   1115     if (znames != NULL) {
   1116         const UChar* s = znames->getName(type);
   1117         if (s != NULL) {
   1118             name.setTo(TRUE, s, -1);
   1119         }
   1120     }
   1121     return name;
   1122 }
   1123 
   1124 UnicodeString&
   1125 TimeZoneNamesImpl::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNameType type, UnicodeString& name) const {
   1126     name.setToBogus();  // cleanup result.
   1127     if (tzID.isEmpty()) {
   1128         return name;
   1129     }
   1130 
   1131     TZNames *tznames = NULL;
   1132     TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
   1133 
   1134     umtx_lock(&nonConstThis->fLock);
   1135     {
   1136         tznames = nonConstThis->loadTimeZoneNames(tzID);
   1137     }
   1138     umtx_unlock(&nonConstThis->fLock);
   1139 
   1140     if (tznames != NULL) {
   1141         const UChar *s = tznames->getName(type);
   1142         if (s != NULL) {
   1143             name.setTo(TRUE, s, -1);
   1144         }
   1145     }
   1146     return name;
   1147 }
   1148 
   1149 UnicodeString&
   1150 TimeZoneNamesImpl::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
   1151     const UChar* locName = NULL;
   1152     TZNames *tznames = NULL;
   1153     TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
   1154 
   1155     umtx_lock(&nonConstThis->fLock);
   1156     {
   1157         tznames = nonConstThis->loadTimeZoneNames(tzID);
   1158     }
   1159     umtx_unlock(&nonConstThis->fLock);
   1160 
   1161     if (tznames != NULL) {
   1162         locName = tznames->getLocationName();
   1163     }
   1164     if (locName != NULL) {
   1165         name.setTo(TRUE, locName, -1);
   1166         return name;
   1167     }
   1168 
   1169     return TimeZoneNames::getExemplarLocationName(tzID, name);
   1170 }
   1171 
   1172 
   1173 // Merge the MZ_PREFIX and mzId
   1174 static void mergeTimeZoneKey(const UnicodeString& mzID, char* result) {
   1175     if (mzID.isEmpty()) {
   1176         result[0] = '\0';
   1177         return;
   1178     }
   1179 
   1180     char mzIdChar[ZID_KEY_MAX + 1];
   1181     int32_t keyLen;
   1182     int32_t prefixLen = uprv_strlen(gMZPrefix);
   1183     keyLen = mzID.extract(0, mzID.length(), mzIdChar, ZID_KEY_MAX + 1, US_INV);
   1184     uprv_memcpy((void *)result, (void *)gMZPrefix, prefixLen);
   1185     uprv_memcpy((void *)(result + prefixLen), (void *)mzIdChar, keyLen);
   1186     result[keyLen + prefixLen] = '\0';
   1187 }
   1188 
   1189 /*
   1190  * This method updates the cache and must be called with a lock
   1191  */
   1192 ZNames*
   1193 TimeZoneNamesImpl::loadMetaZoneNames(const UnicodeString& mzID) {
   1194     if (mzID.length() > (ZID_KEY_MAX - MZ_PREFIX_LEN)) {
   1195         return NULL;
   1196     }
   1197 
   1198     ZNames *znames = NULL;
   1199 
   1200     UErrorCode status = U_ZERO_ERROR;
   1201     UChar mzIDKey[ZID_KEY_MAX + 1];
   1202     mzID.extract(mzIDKey, ZID_KEY_MAX + 1, status);
   1203     U_ASSERT(status == U_ZERO_ERROR);   // already checked length above
   1204     mzIDKey[mzID.length()] = 0;
   1205 
   1206     void *cacheVal = uhash_get(fMZNamesMap, mzIDKey);
   1207     if (cacheVal == NULL) {
   1208         char key[ZID_KEY_MAX + 1];
   1209         mergeTimeZoneKey(mzID, key);
   1210         znames = ZNames::createInstance(fZoneStrings, key);
   1211 
   1212         if (znames == NULL) {
   1213             cacheVal = (void *)EMPTY;
   1214         } else {
   1215             cacheVal = znames;
   1216         }
   1217         // Use the persistent ID as the resource key, so we can
   1218         // avoid duplications.
   1219         const UChar* newKey = ZoneMeta::findMetaZoneID(mzID);
   1220         if (newKey != NULL) {
   1221             uhash_put(fMZNamesMap, (void *)newKey, cacheVal, &status);
   1222             if (U_FAILURE(status)) {
   1223                 if (znames != NULL) {
   1224                     delete znames;
   1225                 }
   1226             } else if (znames != NULL) {
   1227                 // put the name info into the trie
   1228                 for (int32_t i = 0; ALL_NAME_TYPES[i] != UTZNM_UNKNOWN; i++) {
   1229                     const UChar* name = znames->getName(ALL_NAME_TYPES[i]);
   1230                     if (name != NULL) {
   1231                         ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZNameInfo));
   1232                         if (nameinfo != NULL) {
   1233                             nameinfo->type = ALL_NAME_TYPES[i];
   1234                             nameinfo->tzID = NULL;
   1235                             nameinfo->mzID = newKey;
   1236                             fNamesTrie.put(name, nameinfo, status);
   1237                         }
   1238                     }
   1239                 }
   1240             }
   1241 
   1242         } else {
   1243             // Should never happen with a valid input
   1244             if (znames != NULL) {
   1245                 // It's not possible that we get a valid ZNames with unknown ID.
   1246                 // But just in case..
   1247                 delete znames;
   1248                 znames = NULL;
   1249             }
   1250         }
   1251     } else if (cacheVal != EMPTY) {
   1252         znames = (ZNames *)cacheVal;
   1253     }
   1254 
   1255     return znames;
   1256 }
   1257 
   1258 /*
   1259  * This method updates the cache and must be called with a lock
   1260  */
   1261 TZNames*
   1262 TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID) {
   1263     if (tzID.length() > ZID_KEY_MAX) {
   1264         return NULL;
   1265     }
   1266 
   1267     TZNames *tznames = NULL;
   1268 
   1269     UErrorCode status = U_ZERO_ERROR;
   1270     UChar tzIDKey[ZID_KEY_MAX + 1];
   1271     int32_t tzIDKeyLen = tzID.extract(tzIDKey, ZID_KEY_MAX + 1, status);
   1272     U_ASSERT(status == U_ZERO_ERROR);   // already checked length above
   1273     tzIDKey[tzIDKeyLen] = 0;
   1274 
   1275     void *cacheVal = uhash_get(fTZNamesMap, tzIDKey);
   1276     if (cacheVal == NULL) {
   1277         char key[ZID_KEY_MAX + 1];
   1278         UErrorCode status = U_ZERO_ERROR;
   1279         // Replace "/" with ":".
   1280         UnicodeString uKey(tzID);
   1281         for (int32_t i = 0; i < uKey.length(); i++) {
   1282             if (uKey.charAt(i) == (UChar)0x2F) {
   1283                 uKey.setCharAt(i, (UChar)0x3A);
   1284             }
   1285         }
   1286         uKey.extract(0, uKey.length(), key, sizeof(key), US_INV);
   1287         tznames = TZNames::createInstance(fZoneStrings, key);
   1288 
   1289         if (tznames == NULL) {
   1290             cacheVal = (void *)EMPTY;
   1291         } else {
   1292             cacheVal = tznames;
   1293         }
   1294         // Use the persistent ID as the resource key, so we can
   1295         // avoid duplications.
   1296         const UChar* newKey = ZoneMeta::findTimeZoneID(tzID);
   1297         if (newKey != NULL) {
   1298             uhash_put(fTZNamesMap, (void *)newKey, cacheVal, &status);
   1299             if (U_FAILURE(status)) {
   1300                 if (tznames != NULL) {
   1301                     delete tznames;
   1302                 }
   1303             } else if (tznames != NULL) {
   1304                 // put the name info into the trie
   1305                 for (int32_t i = 0; ALL_NAME_TYPES[i] != UTZNM_UNKNOWN; i++) {
   1306                     const UChar* name = tznames->getName(ALL_NAME_TYPES[i]);
   1307                     if (name != NULL) {
   1308                         ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZNameInfo));
   1309                         if (nameinfo != NULL) {
   1310                             nameinfo->type = ALL_NAME_TYPES[i];
   1311                             nameinfo->tzID = newKey;
   1312                             nameinfo->mzID = NULL;
   1313                             fNamesTrie.put(name, nameinfo, status);
   1314                         }
   1315                     }
   1316                 }
   1317             }
   1318         } else {
   1319             // Should never happen with a valid input
   1320             if (tznames != NULL) {
   1321                 // It's not possible that we get a valid TZNames with unknown ID.
   1322                 // But just in case..
   1323                 delete tznames;
   1324                 tznames = NULL;
   1325             }
   1326         }
   1327     } else if (cacheVal != EMPTY) {
   1328         tznames = (TZNames *)cacheVal;
   1329     }
   1330 
   1331     return tznames;
   1332 }
   1333 
   1334 TimeZoneNameMatchInfo*
   1335 TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
   1336     ZNameSearchHandler handler(types);
   1337 
   1338     TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
   1339 
   1340     umtx_lock(&nonConstThis->fLock);
   1341     {
   1342         fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
   1343     }
   1344     umtx_unlock(&nonConstThis->fLock);
   1345 
   1346     if (U_FAILURE(status)) {
   1347         return NULL;
   1348     }
   1349 
   1350     TimeZoneNameMatchInfoImpl *matchInfo = NULL;
   1351 
   1352     int32_t maxLen = 0;
   1353     UVector *results = handler.getMatches(maxLen);
   1354     if (results != NULL && ((maxLen == (text.length() - start)) || fNamesTrieFullyLoaded)) {
   1355         // perfect match
   1356         matchInfo = new TimeZoneNameMatchInfoImpl(results);
   1357         if (matchInfo == NULL) {
   1358             status = U_MEMORY_ALLOCATION_ERROR;
   1359             delete results;
   1360             return NULL;
   1361         }
   1362         return matchInfo;
   1363     }
   1364 
   1365     if (results != NULL) {
   1366         delete results;
   1367     }
   1368 
   1369     // All names are not yet loaded into the trie
   1370     umtx_lock(&nonConstThis->fLock);
   1371     {
   1372         if (!fNamesTrieFullyLoaded) {
   1373             const UnicodeString *id;
   1374 
   1375             // load strings for all zones
   1376             StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
   1377             if (U_SUCCESS(status)) {
   1378                 while ((id = tzIDs->snext(status))) {
   1379                     if (U_FAILURE(status)) {
   1380                         break;
   1381                     }
   1382                     // loadStrings also load related metazone strings
   1383                     nonConstThis->loadStrings(*id);
   1384                 }
   1385             }
   1386             if (tzIDs != NULL) {
   1387                 delete tzIDs;
   1388             }
   1389             if (U_SUCCESS(status)) {
   1390                 nonConstThis->fNamesTrieFullyLoaded = TRUE;
   1391             }
   1392         }
   1393     }
   1394     umtx_unlock(&nonConstThis->fLock);
   1395 
   1396     if (U_FAILURE(status)) {
   1397         return NULL;
   1398     }
   1399 
   1400     umtx_lock(&nonConstThis->fLock);
   1401     {
   1402         // now try it again
   1403         fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
   1404     }
   1405     umtx_unlock(&nonConstThis->fLock);
   1406 
   1407     results = handler.getMatches(maxLen);
   1408     if (results != NULL && maxLen > 0) {
   1409         matchInfo = new TimeZoneNameMatchInfoImpl(results);
   1410         if (matchInfo == NULL) {
   1411             status = U_MEMORY_ALLOCATION_ERROR;
   1412             delete results;
   1413             return NULL;
   1414         }
   1415     }
   1416 
   1417     return matchInfo;
   1418 }
   1419 
   1420 
   1421 U_NAMESPACE_END
   1422 
   1423 
   1424 #endif /* #if !UCONFIG_NO_FORMATTING */
   1425 
   1426 //eof
   1427