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