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