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