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