+ U_ASSERT(fResults != NULL);
+ U_ASSERT(match->mzID != NULL);
+ fResults->addMetaZone(ntype, matchLength, UnicodeString(match->mzID, -1), status);
+ if (U_SUCCESS(status) && matchLength > fMaxMatchLen) {
+ fMaxMatchLen = matchLength;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+TimeZoneNames::MatchInfoCollection*
+TZDBNameSearchHandler::getMatches(int32_t& maxMatchLen) {
+ // give the ownership to the caller
+ TimeZoneNames::MatchInfoCollection* results = fResults;
+ maxMatchLen = fMaxMatchLen;
+
+ // reset
+ fResults = NULL;
+ fMaxMatchLen = 0;
+ return results;
+}
+
+U_CDECL_BEGIN
+/**
+ * Deleter for TZDBNames
+ */
+static void U_CALLCONV
+deleteTZDBNames(void *obj) {
+ if (obj != EMPTY) {
+ delete (TZDBNames *)obj;
+ }
+}
+
+static void U_CALLCONV initTZDBNamesMap(UErrorCode &status) {
+ gTZDBNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
+ if (U_FAILURE(status)) {
+ gTZDBNamesMap = NULL;
+ return;
+ }
+ // no key deleters for tzdb name maps
+ uhash_setValueDeleter(gTZDBNamesMap, deleteTZDBNames);
+ ucln_i18n_registerCleanup(UCLN_I18N_TZDBTIMEZONENAMES, tzdbTimeZoneNames_cleanup);
+}
+
+/**
+ * Deleter for TZDBNameInfo
+ */
+static void U_CALLCONV
+deleteTZDBNameInfo(void *obj) {
+ if (obj != NULL) {
+ uprv_free(obj);
+ }
+}
+
+static void U_CALLCONV prepareFind(UErrorCode &status) {
+ if (U_FAILURE(status)) {
+ return;
+ }
+ gTZDBNamesTrie = new TextTrieMap(TRUE, deleteTZDBNameInfo);
+ if (gTZDBNamesTrie == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ const UnicodeString *mzID;
+ StringEnumeration *mzIDs = TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
+ if (U_SUCCESS(status)) {
+ while ((mzID = mzIDs->snext(status)) != 0 && U_SUCCESS(status)) {
+ const TZDBNames *names = TZDBTimeZoneNames::getMetaZoneNames(*mzID, status);
+ if (U_FAILURE(status)) {
+ break;
+ }
+ if (names == NULL) {
+ continue;
+ }
+ const UChar *std = names->getName(UTZNM_SHORT_STANDARD);
+ const UChar *dst = names->getName(UTZNM_SHORT_DAYLIGHT);
+ if (std == NULL && dst == NULL) {
+ continue;
+ }
+ int32_t numRegions = 0;
+ const char **parseRegions = names->getParseRegions(numRegions);
+
+ // The tz database contains a few zones sharing a
+ // same name for both standard time and daylight saving
+ // time. For example, Australia/Sydney observes DST,
+ // but "EST" is used for both standard and daylight.
+ // we need to store the information for later processing.
+ UBool ambiguousType = (std != NULL && dst != NULL && u_strcmp(std, dst) == 0);
+
+ const UChar *uMzID = ZoneMeta::findMetaZoneID(*mzID);
+ if (std != NULL) {
+ TZDBNameInfo *stdInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNameInfo));
+ if (stdInf == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ stdInf->mzID = uMzID;
+ stdInf->type = UTZNM_SHORT_STANDARD;
+ stdInf->ambiguousType = ambiguousType;
+ stdInf->parseRegions = parseRegions;
+ stdInf->nRegions = numRegions;
+ gTZDBNamesTrie->put(std, stdInf, status);
+ }
+ if (U_SUCCESS(status) && dst != NULL) {
+ TZDBNameInfo *dstInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNameInfo));
+ if (dstInf == NULL) {
+ status = U_MEMORY_ALLOCATION_ERROR;
+ break;
+ }
+ dstInf->mzID = uMzID;
+ dstInf->type = UTZNM_SHORT_DAYLIGHT;
+ dstInf->ambiguousType = ambiguousType;
+ dstInf->parseRegions = parseRegions;
+ dstInf->nRegions = numRegions;
+ gTZDBNamesTrie->put(dst, dstInf, status);
+ }
+ }
+ }
+ delete mzIDs;
+
+ if (U_FAILURE(status)) {
+ delete gTZDBNamesTrie;
+ gTZDBNamesTrie = NULL;
+ return;
+ }
+
+ ucln_i18n_registerCleanup(UCLN_I18N_TZDBTIMEZONENAMES, tzdbTimeZoneNames_cleanup);
+}
+
+U_CDECL_END
+
+TZDBTimeZoneNames::TZDBTimeZoneNames(const Locale& locale)
+: fLocale(locale) {
+ UBool useWorld = TRUE;
+ const char* region = fLocale.getCountry();
+ int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
+ if (regionLen == 0) {
+ UErrorCode status = U_ZERO_ERROR;
+ char loc[ULOC_FULLNAME_CAPACITY];
+ uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
+ regionLen = uloc_getCountry(loc, fRegion, sizeof(fRegion), &status);
+ if (U_SUCCESS(status) && regionLen < (int32_t)sizeof(fRegion)) {
+ useWorld = FALSE;
+ }
+ } else if (regionLen < (int32_t)sizeof(fRegion)) {
+ uprv_strcpy(fRegion, region);
+ useWorld = FALSE;
+ }
+ if (useWorld) {
+ uprv_strcpy(fRegion, "001");
+ }
+}
+
+TZDBTimeZoneNames::~TZDBTimeZoneNames() {
+}
+
+UBool
+TZDBTimeZoneNames::operator==(const TimeZoneNames& other) const {
+ if (this == &other) {
+ return TRUE;
+ }
+ // No implementation for now
+ return FALSE;
+}
+
+TimeZoneNames*
+TZDBTimeZoneNames::clone() const {
+ return new TZDBTimeZoneNames(fLocale);
+}
+
+StringEnumeration*
+TZDBTimeZoneNames::getAvailableMetaZoneIDs(UErrorCode& status) const {
+ return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status);
+}
+
+StringEnumeration*
+TZDBTimeZoneNames::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode& status) const {
+ return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status);
+}
+
+UnicodeString&
+TZDBTimeZoneNames::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeString& mzID) const {
+ return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID);
+}
+
+UnicodeString&
+TZDBTimeZoneNames::getReferenceZoneID(const UnicodeString& mzID, const char* region, UnicodeString& tzID) const {
+ return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID);
+}
+
+UnicodeString&
+TZDBTimeZoneNames::getMetaZoneDisplayName(const UnicodeString& mzID,
+ UTimeZoneNameType type,
+ UnicodeString& name) const {
+ name.setToBogus();
+ if (mzID.isEmpty()) {
+ return name;
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ const TZDBNames *tzdbNames = TZDBTimeZoneNames::getMetaZoneNames(mzID, status);
+ if (U_SUCCESS(status)) {
+ if (tzdbNames != NULL) {
+ const UChar *s = tzdbNames->getName(type);
+ if (s != NULL) {
+ name.setTo(TRUE, s, -1);