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