LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - tznames_impl.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 1147 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 132 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13