summaryrefslogtreecommitdiff
path: root/deps/node/deps/icu-small/source/i18n/tzgnames.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'deps/node/deps/icu-small/source/i18n/tzgnames.cpp')
-rw-r--r--deps/node/deps/icu-small/source/i18n/tzgnames.cpp1324
1 files changed, 0 insertions, 1324 deletions
diff --git a/deps/node/deps/icu-small/source/i18n/tzgnames.cpp b/deps/node/deps/icu-small/source/i18n/tzgnames.cpp
deleted file mode 100644
index 5f5b7db3..00000000
--- a/deps/node/deps/icu-small/source/i18n/tzgnames.cpp
+++ /dev/null
@@ -1,1324 +0,0 @@
-// © 2016 and later: Unicode, Inc. and others.
-// License & terms of use: http://www.unicode.org/copyright.html
-/*
-*******************************************************************************
-* Copyright (C) 2011-2016, International Business Machines Corporation and
-* others. All Rights Reserved.
-*******************************************************************************
-*/
-
-#include "unicode/utypes.h"
-
-#if !UCONFIG_NO_FORMATTING
-
-#include "tzgnames.h"
-
-#include "unicode/basictz.h"
-#include "unicode/locdspnm.h"
-#include "unicode/rbtz.h"
-#include "unicode/simpleformatter.h"
-#include "unicode/simpletz.h"
-#include "unicode/strenum.h"
-#include "unicode/vtzone.h"
-
-#include "cmemory.h"
-#include "cstring.h"
-#include "mutex.h"
-#include "uhash.h"
-#include "uassert.h"
-#include "umutex.h"
-#include "uresimp.h"
-#include "ureslocs.h"
-#include "zonemeta.h"
-#include "tznames_impl.h"
-#include "olsontz.h"
-#include "ucln_in.h"
-
-U_NAMESPACE_BEGIN
-
-#define ZID_KEY_MAX 128
-
-static const char gZoneStrings[] = "zoneStrings";
-
-static const char gRegionFormatTag[] = "regionFormat";
-static const char gFallbackFormatTag[] = "fallbackFormat";
-
-static const UChar gEmpty[] = {0x00};
-
-static const UChar gDefRegionPattern[] = {0x7B, 0x30, 0x7D, 0x00}; // "{0}"
-static const UChar gDefFallbackPattern[] = {0x7B, 0x31, 0x7D, 0x20, 0x28, 0x7B, 0x30, 0x7D, 0x29, 0x00}; // "{1} ({0})"
-
-static const double kDstCheckRange = (double)184*U_MILLIS_PER_DAY;
-
-
-
-U_CDECL_BEGIN
-
-typedef struct PartialLocationKey {
- const UChar* tzID;
- const UChar* mzID;
- UBool isLong;
-} PartialLocationKey;
-
-/**
- * Hash function for partial location name hash key
- */
-static int32_t U_CALLCONV
-hashPartialLocationKey(const UHashTok key) {
- // <tzID>&<mzID>#[L|S]
- PartialLocationKey *p = (PartialLocationKey *)key.pointer;
- UnicodeString str(p->tzID);
- str.append((UChar)0x26)
- .append(p->mzID, -1)
- .append((UChar)0x23)
- .append((UChar)(p->isLong ? 0x4C : 0x53));
- return str.hashCode();
-}
-
-/**
- * Comparer for partial location name hash key
- */
-static UBool U_CALLCONV
-comparePartialLocationKey(const UHashTok key1, const UHashTok key2) {
- PartialLocationKey *p1 = (PartialLocationKey *)key1.pointer;
- PartialLocationKey *p2 = (PartialLocationKey *)key2.pointer;
-
- if (p1 == p2) {
- return TRUE;
- }
- if (p1 == NULL || p2 == NULL) {
- return FALSE;
- }
- // We just check identity of tzID/mzID
- return (p1->tzID == p2->tzID && p1->mzID == p2->mzID && p1->isLong == p2->isLong);
-}
-
-/**
- * Deleter for GNameInfo
- */
-static void U_CALLCONV
-deleteGNameInfo(void *obj) {
- uprv_free(obj);
-}
-
-/**
- * GNameInfo stores zone name information in the local trie
- */
-typedef struct GNameInfo {
- UTimeZoneGenericNameType type;
- const UChar* tzID;
-} ZNameInfo;
-
-/**
- * GMatchInfo stores zone name match information used by find method
- */
-typedef struct GMatchInfo {
- const GNameInfo* gnameInfo;
- int32_t matchLength;
- UTimeZoneFormatTimeType timeType;
-} ZMatchInfo;
-
-U_CDECL_END
-
-// ---------------------------------------------------
-// The class stores time zone generic name match information
-// ---------------------------------------------------
-class TimeZoneGenericNameMatchInfo : public UMemory {
-public:
- TimeZoneGenericNameMatchInfo(UVector* matches);
- ~TimeZoneGenericNameMatchInfo();
-
- int32_t size() const;
- UTimeZoneGenericNameType getGenericNameType(int32_t index) const;
- int32_t getMatchLength(int32_t index) const;
- UnicodeString& getTimeZoneID(int32_t index, UnicodeString& tzID) const;
-
-private:
- UVector* fMatches; // vector of MatchEntry
-};
-
-TimeZoneGenericNameMatchInfo::TimeZoneGenericNameMatchInfo(UVector* matches)
-: fMatches(matches) {
-}
-
-TimeZoneGenericNameMatchInfo::~TimeZoneGenericNameMatchInfo() {
- if (fMatches != NULL) {
- delete fMatches;
- }
-}
-
-int32_t
-TimeZoneGenericNameMatchInfo::size() const {
- if (fMatches == NULL) {
- return 0;
- }
- return fMatches->size();
-}
-
-UTimeZoneGenericNameType
-TimeZoneGenericNameMatchInfo::getGenericNameType(int32_t index) const {
- GMatchInfo *minfo = (GMatchInfo *)fMatches->elementAt(index);
- if (minfo != NULL) {
- return static_cast<UTimeZoneGenericNameType>(minfo->gnameInfo->type);
- }
- return UTZGNM_UNKNOWN;
-}
-
-int32_t
-TimeZoneGenericNameMatchInfo::getMatchLength(int32_t index) const {
- ZMatchInfo *minfo = (ZMatchInfo *)fMatches->elementAt(index);
- if (minfo != NULL) {
- return minfo->matchLength;
- }
- return -1;
-}
-
-UnicodeString&
-TimeZoneGenericNameMatchInfo::getTimeZoneID(int32_t index, UnicodeString& tzID) const {
- GMatchInfo *minfo = (GMatchInfo *)fMatches->elementAt(index);
- if (minfo != NULL && minfo->gnameInfo->tzID != NULL) {
- tzID.setTo(TRUE, minfo->gnameInfo->tzID, -1);
- } else {
- tzID.setToBogus();
- }
- return tzID;
-}
-
-// ---------------------------------------------------
-// GNameSearchHandler
-// ---------------------------------------------------
-class GNameSearchHandler : public TextTrieMapSearchResultHandler {
-public:
- GNameSearchHandler(uint32_t types);
- virtual ~GNameSearchHandler();
-
- UBool handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status);
- UVector* getMatches(int32_t& maxMatchLen);
-
-private:
- uint32_t fTypes;
- UVector* fResults;
- int32_t fMaxMatchLen;
-};
-
-GNameSearchHandler::GNameSearchHandler(uint32_t types)
-: fTypes(types), fResults(NULL), fMaxMatchLen(0) {
-}
-
-GNameSearchHandler::~GNameSearchHandler() {
- if (fResults != NULL) {
- delete fResults;
- }
-}
-
-UBool
-GNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node, UErrorCode &status) {
- if (U_FAILURE(status)) {
- return FALSE;
- }
- if (node->hasValues()) {
- int32_t valuesCount = node->countValues();
- for (int32_t i = 0; i < valuesCount; i++) {
- GNameInfo *nameinfo = (ZNameInfo *)node->getValue(i);
- if (nameinfo == NULL) {
- break;
- }
- if ((nameinfo->type & fTypes) != 0) {
- // matches a requested type
- if (fResults == NULL) {
- fResults = new UVector(uprv_free, NULL, status);
- if (fResults == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- }
- if (U_SUCCESS(status)) {
- U_ASSERT(fResults != NULL);
- GMatchInfo *gmatch = (GMatchInfo *)uprv_malloc(sizeof(GMatchInfo));
- if (gmatch == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- } else {
- // add the match to the vector
- gmatch->gnameInfo = nameinfo;
- gmatch->matchLength = matchLength;
- gmatch->timeType = UTZFMT_TIME_TYPE_UNKNOWN;
- fResults->addElement(gmatch, status);
- if (U_FAILURE(status)) {
- uprv_free(gmatch);
- } else {
- if (matchLength > fMaxMatchLen) {
- fMaxMatchLen = matchLength;
- }
- }
- }
- }
- }
- }
- }
- return TRUE;
-}
-
-UVector*
-GNameSearchHandler::getMatches(int32_t& maxMatchLen) {
- // give the ownership to the caller
- UVector *results = fResults;
- maxMatchLen = fMaxMatchLen;
-
- // reset
- fResults = NULL;
- fMaxMatchLen = 0;
- return results;
-}
-
-static UMutex gLock = U_MUTEX_INITIALIZER;
-
-class TZGNCore : public UMemory {
-public:
- TZGNCore(const Locale& locale, UErrorCode& status);
- virtual ~TZGNCore();
-
- UnicodeString& getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
- UDate date, UnicodeString& name) const;
-
- UnicodeString& getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const;
-
- int32_t findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
- UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const;
-
-private:
- Locale fLocale;
- const TimeZoneNames* fTimeZoneNames;
- UHashtable* fLocationNamesMap;
- UHashtable* fPartialLocationNamesMap;
-
- SimpleFormatter fRegionFormat;
- SimpleFormatter fFallbackFormat;
-
- LocaleDisplayNames* fLocaleDisplayNames;
- ZNStringPool fStringPool;
-
- TextTrieMap fGNamesTrie;
- UBool fGNamesTrieFullyLoaded;
-
- char fTargetRegion[ULOC_COUNTRY_CAPACITY];
-
- void initialize(const Locale& locale, UErrorCode& status);
- void cleanup();
-
- void loadStrings(const UnicodeString& tzCanonicalID);
-
- const UChar* getGenericLocationName(const UnicodeString& tzCanonicalID);
-
- UnicodeString& formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type,
- UDate date, UnicodeString& name) const;
-
- UnicodeString& getPartialLocationName(const UnicodeString& tzCanonicalID,
- const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
- UnicodeString& name) const;
-
- const UChar* getPartialLocationName(const UnicodeString& tzCanonicalID,
- const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName);
-
- TimeZoneGenericNameMatchInfo* findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
-
- TimeZoneNames::MatchInfoCollection* findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const;
-};
-
-
-// ---------------------------------------------------
-// TZGNCore - core implmentation of TimeZoneGenericNames
-//
-// TimeZoneGenericNames is parallel to TimeZoneNames,
-// but handles run-time generated time zone names.
-// This is the main part of this module.
-// ---------------------------------------------------
-TZGNCore::TZGNCore(const Locale& locale, UErrorCode& status)
-: fLocale(locale),
- fTimeZoneNames(NULL),
- fLocationNamesMap(NULL),
- fPartialLocationNamesMap(NULL),
- fLocaleDisplayNames(NULL),
- fStringPool(status),
- fGNamesTrie(TRUE, deleteGNameInfo),
- fGNamesTrieFullyLoaded(FALSE) {
- initialize(locale, status);
-}
-
-TZGNCore::~TZGNCore() {
- cleanup();
-}
-
-void
-TZGNCore::initialize(const Locale& locale, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return;
- }
-
- // TimeZoneNames
- fTimeZoneNames = TimeZoneNames::createInstance(locale, status);
- if (U_FAILURE(status)) {
- return;
- }
-
- // Initialize format patterns
- UnicodeString rpat(TRUE, gDefRegionPattern, -1);
- UnicodeString fpat(TRUE, gDefFallbackPattern, -1);
-
- UErrorCode tmpsts = U_ZERO_ERROR; // OK with fallback warning..
- UResourceBundle *zoneStrings = ures_open(U_ICUDATA_ZONE, locale.getName(), &tmpsts);
- zoneStrings = ures_getByKeyWithFallback(zoneStrings, gZoneStrings, zoneStrings, &tmpsts);
-
- if (U_SUCCESS(tmpsts)) {
- const UChar *regionPattern = ures_getStringByKeyWithFallback(zoneStrings, gRegionFormatTag, NULL, &tmpsts);
- if (U_SUCCESS(tmpsts) && u_strlen(regionPattern) > 0) {
- rpat.setTo(regionPattern, -1);
- }
- tmpsts = U_ZERO_ERROR;
- const UChar *fallbackPattern = ures_getStringByKeyWithFallback(zoneStrings, gFallbackFormatTag, NULL, &tmpsts);
- if (U_SUCCESS(tmpsts) && u_strlen(fallbackPattern) > 0) {
- fpat.setTo(fallbackPattern, -1);
- }
- }
- ures_close(zoneStrings);
-
- fRegionFormat.applyPatternMinMaxArguments(rpat, 1, 1, status);
- fFallbackFormat.applyPatternMinMaxArguments(fpat, 2, 2, status);
- if (U_FAILURE(status)) {
- cleanup();
- return;
- }
-
- // locale display names
- fLocaleDisplayNames = LocaleDisplayNames::createInstance(locale);
-
- // hash table for names - no key/value deleters
- fLocationNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &status);
- if (U_FAILURE(status)) {
- cleanup();
- return;
- }
-
- fPartialLocationNamesMap = uhash_open(hashPartialLocationKey, comparePartialLocationKey, NULL, &status);
- if (U_FAILURE(status)) {
- cleanup();
- return;
- }
- uhash_setKeyDeleter(fPartialLocationNamesMap, uprv_free);
- // no value deleter
-
- // target region
- const char* region = fLocale.getCountry();
- int32_t regionLen = static_cast<int32_t>(uprv_strlen(region));
- if (regionLen == 0) {
- char loc[ULOC_FULLNAME_CAPACITY];
- uloc_addLikelySubtags(fLocale.getName(), loc, sizeof(loc), &status);
-
- regionLen = uloc_getCountry(loc, fTargetRegion, sizeof(fTargetRegion), &status);
- if (U_SUCCESS(status)) {
- fTargetRegion[regionLen] = 0;
- } else {
- cleanup();
- return;
- }
- } else if (regionLen < (int32_t)sizeof(fTargetRegion)) {
- uprv_strcpy(fTargetRegion, region);
- } else {
- fTargetRegion[0] = 0;
- }
-
- // preload generic names for the default zone
- TimeZone *tz = TimeZone::createDefault();
- const UChar *tzID = ZoneMeta::getCanonicalCLDRID(*tz);
- if (tzID != NULL) {
- loadStrings(UnicodeString(TRUE, tzID, -1));
- }
- delete tz;
-}
-
-void
-TZGNCore::cleanup() {
- if (fLocaleDisplayNames != NULL) {
- delete fLocaleDisplayNames;
- }
- if (fTimeZoneNames != NULL) {
- delete fTimeZoneNames;
- }
-
- uhash_close(fLocationNamesMap);
- uhash_close(fPartialLocationNamesMap);
-}
-
-
-UnicodeString&
-TZGNCore::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
- name.setToBogus();
- switch (type) {
- case UTZGNM_LOCATION:
- {
- const UChar* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
- if (tzCanonicalID != NULL) {
- getGenericLocationName(UnicodeString(TRUE, tzCanonicalID, -1), name);
- }
- }
- break;
- case UTZGNM_LONG:
- case UTZGNM_SHORT:
- formatGenericNonLocationName(tz, type, date, name);
- if (name.isEmpty()) {
- const UChar* tzCanonicalID = ZoneMeta::getCanonicalCLDRID(tz);
- if (tzCanonicalID != NULL) {
- getGenericLocationName(UnicodeString(TRUE, tzCanonicalID, -1), name);
- }
- }
- break;
- default:
- break;
- }
- return name;
-}
-
-UnicodeString&
-TZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
- if (tzCanonicalID.isEmpty()) {
- name.setToBogus();
- return name;
- }
-
- const UChar *locname = NULL;
- TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
- umtx_lock(&gLock);
- {
- locname = nonConstThis->getGenericLocationName(tzCanonicalID);
- }
- umtx_unlock(&gLock);
-
- if (locname == NULL) {
- name.setToBogus();
- } else {
- name.setTo(locname, u_strlen(locname));
- }
-
- return name;
-}
-
-/*
- * This method updates the cache and must be called with a lock
- */
-const UChar*
-TZGNCore::getGenericLocationName(const UnicodeString& tzCanonicalID) {
- U_ASSERT(!tzCanonicalID.isEmpty());
- if (tzCanonicalID.length() > ZID_KEY_MAX) {
- return NULL;
- }
-
- UErrorCode status = U_ZERO_ERROR;
- UChar tzIDKey[ZID_KEY_MAX + 1];
- int32_t tzIDKeyLen = tzCanonicalID.extract(tzIDKey, ZID_KEY_MAX + 1, status);
- U_ASSERT(status == U_ZERO_ERROR); // already checked length above
- tzIDKey[tzIDKeyLen] = 0;
-
- const UChar *locname = (const UChar *)uhash_get(fLocationNamesMap, tzIDKey);
-
- if (locname != NULL) {
- // gEmpty indicate the name is not available
- if (locname == gEmpty) {
- return NULL;
- }
- return locname;
- }
-
- // Construct location name
- UnicodeString name;
- UnicodeString usCountryCode;
- UBool isPrimary = FALSE;
-
- ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode, &isPrimary);
-
- if (!usCountryCode.isEmpty()) {
- if (isPrimary) {
- // If this is the primary zone in the country, use the country name.
- char countryCode[ULOC_COUNTRY_CAPACITY];
- U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY);
- int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INV);
- countryCode[ccLen] = 0;
-
- UnicodeString country;
- fLocaleDisplayNames->regionDisplayName(countryCode, country);
- fRegionFormat.format(country, name, status);
- } else {
- // If this is not the primary zone in the country,
- // use the exemplar city name.
-
- // getExemplarLocationName should retur non-empty string
- // if the time zone is associated with a region
-
- UnicodeString city;
- fTimeZoneNames->getExemplarLocationName(tzCanonicalID, city);
- fRegionFormat.format(city, name, status);
- }
- if (U_FAILURE(status)) {
- return NULL;
- }
- }
-
- locname = name.isEmpty() ? NULL : fStringPool.get(name, status);
- if (U_SUCCESS(status)) {
- // Cache the result
- const UChar* cacheID = ZoneMeta::findTimeZoneID(tzCanonicalID);
- U_ASSERT(cacheID != NULL);
- if (locname == NULL) {
- // gEmpty to indicate - no location name available
- uhash_put(fLocationNamesMap, (void *)cacheID, (void *)gEmpty, &status);
- } else {
- uhash_put(fLocationNamesMap, (void *)cacheID, (void *)locname, &status);
- if (U_FAILURE(status)) {
- locname = NULL;
- } else {
- // put the name info into the trie
- GNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(GNameInfo));
- if (nameinfo != NULL) {
- nameinfo->type = UTZGNM_LOCATION;
- nameinfo->tzID = cacheID;
- fGNamesTrie.put(locname, nameinfo, status);
- }
- }
- }
- }
-
- return locname;
-}
-
-UnicodeString&
-TZGNCore::formatGenericNonLocationName(const TimeZone& tz, UTimeZoneGenericNameType type, UDate date, UnicodeString& name) const {
- U_ASSERT(type == UTZGNM_LONG || type == UTZGNM_SHORT);
- name.setToBogus();
-
- const UChar* uID = ZoneMeta::getCanonicalCLDRID(tz);
- if (uID == NULL) {
- return name;
- }
-
- UnicodeString tzID(TRUE, uID, -1);
-
- // Try to get a name from time zone first
- UTimeZoneNameType nameType = (type == UTZGNM_LONG) ? UTZNM_LONG_GENERIC : UTZNM_SHORT_GENERIC;
- fTimeZoneNames->getTimeZoneDisplayName(tzID, nameType, name);
-
- if (!name.isEmpty()) {
- return name;
- }
-
- // Try meta zone
- UChar mzIDBuf[32];
- UnicodeString mzID(mzIDBuf, 0, UPRV_LENGTHOF(mzIDBuf));
- fTimeZoneNames->getMetaZoneID(tzID, date, mzID);
- if (!mzID.isEmpty()) {
- UErrorCode status = U_ZERO_ERROR;
- UBool useStandard = FALSE;
- int32_t raw, sav;
- UChar tmpNameBuf[ZONE_NAME_U16_MAX];
-
- tz.getOffset(date, FALSE, raw, sav, status);
- if (U_FAILURE(status)) {
- return name;
- }
-
- if (sav == 0) {
- useStandard = TRUE;
-
- TimeZone *tmptz = tz.clone();
- // Check if the zone actually uses daylight saving time around the time
- BasicTimeZone *btz = NULL;
- if (dynamic_cast<OlsonTimeZone *>(tmptz) != NULL
- || dynamic_cast<SimpleTimeZone *>(tmptz) != NULL
- || dynamic_cast<RuleBasedTimeZone *>(tmptz) != NULL
- || dynamic_cast<VTimeZone *>(tmptz) != NULL) {
- btz = (BasicTimeZone*)tmptz;
- }
-
- if (btz != NULL) {
- TimeZoneTransition before;
- UBool beforTrs = btz->getPreviousTransition(date, TRUE, before);
- if (beforTrs
- && (date - before.getTime() < kDstCheckRange)
- && before.getFrom()->getDSTSavings() != 0) {
- useStandard = FALSE;
- } else {
- TimeZoneTransition after;
- UBool afterTrs = btz->getNextTransition(date, FALSE, after);
- if (afterTrs
- && (after.getTime() - date < kDstCheckRange)
- && after.getTo()->getDSTSavings() != 0) {
- useStandard = FALSE;
- }
- }
- } else {
- // If not BasicTimeZone... only if the instance is not an ICU's implementation.
- // We may get a wrong answer in edge case, but it should practically work OK.
- tmptz->getOffset(date - kDstCheckRange, FALSE, raw, sav, status);
- if (sav != 0) {
- useStandard = FALSE;
- } else {
- tmptz->getOffset(date + kDstCheckRange, FALSE, raw, sav, status);
- if (sav != 0){
- useStandard = FALSE;
- }
- }
- if (U_FAILURE(status)) {
- delete tmptz;
- return name;
- }
- }
- delete tmptz;
- }
- if (useStandard) {
- UTimeZoneNameType stdNameType = (nameType == UTZNM_LONG_GENERIC)
- ? UTZNM_LONG_STANDARD : UTZNM_SHORT_STANDARD;
- UnicodeString stdName(tmpNameBuf, 0, UPRV_LENGTHOF(tmpNameBuf));
- fTimeZoneNames->getDisplayName(tzID, stdNameType, date, stdName);
- if (!stdName.isEmpty()) {
- name.setTo(stdName);
-
- // TODO: revisit this issue later
- // In CLDR, a same display name is used for both generic and standard
- // for some meta zones in some locales. This looks like a data bugs.
- // For now, we check if the standard name is different from its generic
- // name below.
- UChar genNameBuf[ZONE_NAME_U16_MAX];
- UnicodeString mzGenericName(genNameBuf, 0, UPRV_LENGTHOF(genNameBuf));
- fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzGenericName);
- if (stdName.caseCompare(mzGenericName, 0) == 0) {
- name.setToBogus();
- }
- }
- }
- if (name.isEmpty()) {
- // Get a name from meta zone
- UnicodeString mzName(tmpNameBuf, 0, UPRV_LENGTHOF(tmpNameBuf));
- fTimeZoneNames->getMetaZoneDisplayName(mzID, nameType, mzName);
- if (!mzName.isEmpty()) {
- // Check if we need to use a partial location format.
- // This check is done by comparing offset with the meta zone's
- // golden zone at the given date.
- UChar idBuf[32];
- UnicodeString goldenID(idBuf, 0, UPRV_LENGTHOF(idBuf));
- fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, goldenID);
- if (!goldenID.isEmpty() && goldenID != tzID) {
- TimeZone *goldenZone = TimeZone::createTimeZone(goldenID);
- int32_t raw1, sav1;
-
- // Check offset in the golden zone with wall time.
- // With getOffset(date, false, offsets1),
- // you may get incorrect results because of time overlap at DST->STD
- // transition.
- goldenZone->getOffset(date + raw + sav, TRUE, raw1, sav1, status);
- delete goldenZone;
- if (U_SUCCESS(status)) {
- if (raw != raw1 || sav != sav1) {
- // Now we need to use a partial location format
- getPartialLocationName(tzID, mzID, (nameType == UTZNM_LONG_GENERIC), mzName, name);
- } else {
- name.setTo(mzName);
- }
- }
- } else {
- name.setTo(mzName);
- }
- }
- }
- }
- return name;
-}
-
-UnicodeString&
-TZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID,
- const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName,
- UnicodeString& name) const {
- name.setToBogus();
- if (tzCanonicalID.isEmpty() || mzID.isEmpty() || mzDisplayName.isEmpty()) {
- return name;
- }
-
- const UChar *uplname = NULL;
- TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
- umtx_lock(&gLock);
- {
- uplname = nonConstThis->getPartialLocationName(tzCanonicalID, mzID, isLong, mzDisplayName);
- }
- umtx_unlock(&gLock);
-
- if (uplname == NULL) {
- name.setToBogus();
- } else {
- name.setTo(TRUE, uplname, -1);
- }
- return name;
-}
-
-/*
- * This method updates the cache and must be called with a lock
- */
-const UChar*
-TZGNCore::getPartialLocationName(const UnicodeString& tzCanonicalID,
- const UnicodeString& mzID, UBool isLong, const UnicodeString& mzDisplayName) {
- U_ASSERT(!tzCanonicalID.isEmpty());
- U_ASSERT(!mzID.isEmpty());
- U_ASSERT(!mzDisplayName.isEmpty());
-
- PartialLocationKey key;
- key.tzID = ZoneMeta::findTimeZoneID(tzCanonicalID);
- key.mzID = ZoneMeta::findMetaZoneID(mzID);
- key.isLong = isLong;
- U_ASSERT(key.tzID != NULL && key.mzID != NULL);
-
- const UChar* uplname = (const UChar*)uhash_get(fPartialLocationNamesMap, (void *)&key);
- if (uplname != NULL) {
- return uplname;
- }
-
- UnicodeString location;
- UnicodeString usCountryCode;
- ZoneMeta::getCanonicalCountry(tzCanonicalID, usCountryCode);
- if (!usCountryCode.isEmpty()) {
- char countryCode[ULOC_COUNTRY_CAPACITY];
- U_ASSERT(usCountryCode.length() < ULOC_COUNTRY_CAPACITY);
- int32_t ccLen = usCountryCode.extract(0, usCountryCode.length(), countryCode, sizeof(countryCode), US_INV);
- countryCode[ccLen] = 0;
-
- UnicodeString regionalGolden;
- fTimeZoneNames->getReferenceZoneID(mzID, countryCode, regionalGolden);
- if (tzCanonicalID == regionalGolden) {
- // Use country name
- fLocaleDisplayNames->regionDisplayName(countryCode, location);
- } else {
- // Otherwise, use exemplar city name
- fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location);
- }
- } else {
- fTimeZoneNames->getExemplarLocationName(tzCanonicalID, location);
- if (location.isEmpty()) {
- // This could happen when the time zone is not associated with a country,
- // and its ID is not hierarchical, for example, CST6CDT.
- // We use the canonical ID itself as the location for this case.
- location.setTo(tzCanonicalID);
- }
- }
-
- UErrorCode status = U_ZERO_ERROR;
- UnicodeString name;
- fFallbackFormat.format(location, mzDisplayName, name, status);
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- uplname = fStringPool.get(name, status);
- if (U_SUCCESS(status)) {
- // Add the name to cache
- PartialLocationKey* cacheKey = (PartialLocationKey *)uprv_malloc(sizeof(PartialLocationKey));
- if (cacheKey != NULL) {
- cacheKey->tzID = key.tzID;
- cacheKey->mzID = key.mzID;
- cacheKey->isLong = key.isLong;
- uhash_put(fPartialLocationNamesMap, (void *)cacheKey, (void *)uplname, &status);
- if (U_FAILURE(status)) {
- uprv_free(cacheKey);
- } else {
- // put the name to the local trie as well
- GNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(GNameInfo));
- if (nameinfo != NULL) {
- nameinfo->type = isLong ? UTZGNM_LONG : UTZGNM_SHORT;
- nameinfo->tzID = key.tzID;
- fGNamesTrie.put(uplname, nameinfo, status);
- }
- }
- }
- }
- return uplname;
-}
-
-/*
- * This method updates the cache and must be called with a lock,
- * except initializer.
- */
-void
-TZGNCore::loadStrings(const UnicodeString& tzCanonicalID) {
- // load the generic location name
- getGenericLocationName(tzCanonicalID);
-
- // partial location names
- UErrorCode status = U_ZERO_ERROR;
-
- const UnicodeString *mzID;
- UnicodeString goldenID;
- UnicodeString mzGenName;
- UTimeZoneNameType genNonLocTypes[] = {
- UTZNM_LONG_GENERIC, UTZNM_SHORT_GENERIC,
- UTZNM_UNKNOWN /*terminator*/
- };
-
- StringEnumeration *mzIDs = fTimeZoneNames->getAvailableMetaZoneIDs(tzCanonicalID, status);
- while ((mzID = mzIDs->snext(status)) != NULL) {
- if (U_FAILURE(status)) {
- break;
- }
- // if this time zone is not the golden zone of the meta zone,
- // partial location name (such as "PT (Los Angeles)") might be
- // available.
- fTimeZoneNames->getReferenceZoneID(*mzID, fTargetRegion, goldenID);
- if (tzCanonicalID != goldenID) {
- for (int32_t i = 0; genNonLocTypes[i] != UTZNM_UNKNOWN; i++) {
- fTimeZoneNames->getMetaZoneDisplayName(*mzID, genNonLocTypes[i], mzGenName);
- if (!mzGenName.isEmpty()) {
- // getPartialLocationName formats a name and put it into the trie
- getPartialLocationName(tzCanonicalID, *mzID,
- (genNonLocTypes[i] == UTZNM_LONG_GENERIC), mzGenName);
- }
- }
- }
- }
- if (mzIDs != NULL) {
- delete mzIDs;
- }
-}
-
-int32_t
-TZGNCore::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
- UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const {
- timeType = UTZFMT_TIME_TYPE_UNKNOWN;
- tzID.setToBogus();
-
- if (U_FAILURE(status)) {
- return 0;
- }
-
- // Find matches in the TimeZoneNames first
- TimeZoneNames::MatchInfoCollection *tznamesMatches = findTimeZoneNames(text, start, types, status);
- if (U_FAILURE(status)) {
- return 0;
- }
-
- int32_t bestMatchLen = 0;
- UTimeZoneFormatTimeType bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
- UnicodeString bestMatchTzID;
- // UBool isLongStandard = FALSE; // workaround - see the comments below
- UBool isStandard = FALSE; // TODO: Temporary hack (on hack) for short standard name/location name conflict (found in zh_Hant), should be removed after CLDR 21m1 integration
-
- if (tznamesMatches != NULL) {
- UnicodeString mzID;
- for (int32_t i = 0; i < tznamesMatches->size(); i++) {
- int32_t len = tznamesMatches->getMatchLengthAt(i);
- if (len > bestMatchLen) {
- bestMatchLen = len;
- if (!tznamesMatches->getTimeZoneIDAt(i, bestMatchTzID)) {
- // name for a meta zone
- if (tznamesMatches->getMetaZoneIDAt(i, mzID)) {
- fTimeZoneNames->getReferenceZoneID(mzID, fTargetRegion, bestMatchTzID);
- }
- }
- UTimeZoneNameType nameType = tznamesMatches->getNameTypeAt(i);
- if (U_FAILURE(status)) {
- break;
- }
- switch (nameType) {
- case UTZNM_LONG_STANDARD:
- // isLongStandard = TRUE;
- case UTZNM_SHORT_STANDARD: // this one is never used for generic, but just in case
- isStandard = TRUE; // TODO: Remove this later, see the comments above.
- bestMatchTimeType = UTZFMT_TIME_TYPE_STANDARD;
- break;
- case UTZNM_LONG_DAYLIGHT:
- case UTZNM_SHORT_DAYLIGHT: // this one is never used for generic, but just in case
- bestMatchTimeType = UTZFMT_TIME_TYPE_DAYLIGHT;
- break;
- default:
- bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
- }
- }
- }
- delete tznamesMatches;
- if (U_FAILURE(status)) {
- return 0;
- }
-
- if (bestMatchLen == (text.length() - start)) {
- // Full match
-
- //tzID.setTo(bestMatchTzID);
- //timeType = bestMatchTimeType;
- //return bestMatchLen;
-
- // TODO Some time zone uses a same name for the long standard name
- // and the location name. When the match is a long standard name,
- // then we need to check if the name is same with the location name.
- // This is probably a data error or a design bug.
-/*
- if (!isLongStandard) {
- tzID.setTo(bestMatchTzID);
- timeType = bestMatchTimeType;
- return bestMatchLen;
- }
-*/
- // TODO The deprecation of commonlyUsed flag introduced the name
- // conflict not only for long standard names, but short standard names too.
- // These short names (found in zh_Hant) should be gone once we clean
- // up CLDR time zone display name data. Once the short name conflict
- // problem (with location name) is resolved, we should change the condition
- // below back to the original one above. -Yoshito (2011-09-14)
- if (!isStandard) {
- tzID.setTo(bestMatchTzID);
- timeType = bestMatchTimeType;
- return bestMatchLen;
- }
- }
- }
-
- // Find matches in the local trie
- TimeZoneGenericNameMatchInfo *localMatches = findLocal(text, start, types, status);
- if (U_FAILURE(status)) {
- return 0;
- }
- if (localMatches != NULL) {
- for (int32_t i = 0; i < localMatches->size(); i++) {
- int32_t len = localMatches->getMatchLength(i);
-
- // TODO See the above TODO. We use len >= bestMatchLen
- // because of the long standard/location name collision
- // problem. If it is also a location name, carrying
- // timeType = UTZFMT_TIME_TYPE_STANDARD will cause a
- // problem in SimpleDateFormat
- if (len >= bestMatchLen) {
- bestMatchLen = localMatches->getMatchLength(i);
- bestMatchTimeType = UTZFMT_TIME_TYPE_UNKNOWN; // because generic
- localMatches->getTimeZoneID(i, bestMatchTzID);
- }
- }
- delete localMatches;
- }
-
- if (bestMatchLen > 0) {
- timeType = bestMatchTimeType;
- tzID.setTo(bestMatchTzID);
- }
- return bestMatchLen;
-}
-
-TimeZoneGenericNameMatchInfo*
-TZGNCore::findLocal(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
- GNameSearchHandler handler(types);
-
- TZGNCore *nonConstThis = const_cast<TZGNCore *>(this);
-
- umtx_lock(&gLock);
- {
- fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
- }
- umtx_unlock(&gLock);
-
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- TimeZoneGenericNameMatchInfo *gmatchInfo = NULL;
-
- int32_t maxLen = 0;
- UVector *results = handler.getMatches(maxLen);
- if (results != NULL && ((maxLen == (text.length() - start)) || fGNamesTrieFullyLoaded)) {
- // perfect match
- gmatchInfo = new TimeZoneGenericNameMatchInfo(results);
- if (gmatchInfo == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete results;
- return NULL;
- }
- return gmatchInfo;
- }
-
- if (results != NULL) {
- delete results;
- }
-
- // All names are not yet loaded into the local trie.
- // Load all available names into the trie. This could be very heavy.
- umtx_lock(&gLock);
- {
- if (!fGNamesTrieFullyLoaded) {
- StringEnumeration *tzIDs = TimeZone::createTimeZoneIDEnumeration(UCAL_ZONE_TYPE_CANONICAL, NULL, NULL, status);
- if (U_SUCCESS(status)) {
- const UnicodeString *tzID;
- while ((tzID = tzIDs->snext(status)) != NULL) {
- if (U_FAILURE(status)) {
- break;
- }
- nonConstThis->loadStrings(*tzID);
- }
- }
- if (tzIDs != NULL) {
- delete tzIDs;
- }
-
- if (U_SUCCESS(status)) {
- nonConstThis->fGNamesTrieFullyLoaded = TRUE;
- }
- }
- }
- umtx_unlock(&gLock);
-
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- umtx_lock(&gLock);
- {
- // now try it again
- fGNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
- }
- umtx_unlock(&gLock);
-
- results = handler.getMatches(maxLen);
- if (results != NULL && maxLen > 0) {
- gmatchInfo = new TimeZoneGenericNameMatchInfo(results);
- if (gmatchInfo == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- delete results;
- return NULL;
- }
- }
-
- return gmatchInfo;
-}
-
-TimeZoneNames::MatchInfoCollection*
-TZGNCore::findTimeZoneNames(const UnicodeString& text, int32_t start, uint32_t types, UErrorCode& status) const {
- // Check if the target name typs is really in the TimeZoneNames
- uint32_t nameTypes = 0;
- if (types & UTZGNM_LONG) {
- nameTypes |= (UTZNM_LONG_GENERIC | UTZNM_LONG_STANDARD);
- }
- if (types & UTZGNM_SHORT) {
- nameTypes |= (UTZNM_SHORT_GENERIC | UTZNM_SHORT_STANDARD);
- }
-
- if (types) {
- // Find matches in the TimeZoneNames
- return fTimeZoneNames->find(text, start, nameTypes, status);
- }
-
- return NULL;
-}
-
-typedef struct TZGNCoreRef {
- TZGNCore* obj;
- int32_t refCount;
- double lastAccess;
-} TZGNCoreRef;
-
-// TZGNCore object cache handling
-static UMutex gTZGNLock = U_MUTEX_INITIALIZER;
-static UHashtable *gTZGNCoreCache = NULL;
-static UBool gTZGNCoreCacheInitialized = FALSE;
-
-// Access count - incremented every time up to SWEEP_INTERVAL,
-// then reset to 0
-static int32_t gAccessCount = 0;
-
-// Interval for calling the cache sweep function - every 100 times
-#define SWEEP_INTERVAL 100
-
-// Cache expiration in millisecond. When a cached entry is no
-// longer referenced and exceeding this threshold since last
-// access time, then the cache entry will be deleted by the sweep
-// function. For now, 3 minutes.
-#define CACHE_EXPIRATION 180000.0
-
-U_CDECL_BEGIN
-/**
- * Cleanup callback func
- */
-static UBool U_CALLCONV tzgnCore_cleanup(void)
-{
- if (gTZGNCoreCache != NULL) {
- uhash_close(gTZGNCoreCache);
- gTZGNCoreCache = NULL;
- }
- gTZGNCoreCacheInitialized = FALSE;
- return TRUE;
-}
-
-/**
- * Deleter for TZGNCoreRef
- */
-static void U_CALLCONV
-deleteTZGNCoreRef(void *obj) {
- icu::TZGNCoreRef *entry = (icu::TZGNCoreRef*)obj;
- delete (icu::TZGNCore*) entry->obj;
- uprv_free(entry);
-}
-U_CDECL_END
-
-/**
- * Function used for removing unreferrenced cache entries exceeding
- * the expiration time. This function must be called with in the mutex
- * block.
- */
-static void sweepCache() {
- int32_t pos = UHASH_FIRST;
- const UHashElement* elem;
- double now = (double)uprv_getUTCtime();
-
- while ((elem = uhash_nextElement(gTZGNCoreCache, &pos)) != NULL) {
- TZGNCoreRef *entry = (TZGNCoreRef *)elem->value.pointer;
- if (entry->refCount <= 0 && (now - entry->lastAccess) > CACHE_EXPIRATION) {
- // delete this entry
- uhash_removeElement(gTZGNCoreCache, elem);
- }
- }
-}
-
-TimeZoneGenericNames::TimeZoneGenericNames()
-: fRef(0) {
-}
-
-TimeZoneGenericNames::~TimeZoneGenericNames() {
- umtx_lock(&gTZGNLock);
- {
- U_ASSERT(fRef->refCount > 0);
- // Just decrement the reference count
- fRef->refCount--;
- }
- umtx_unlock(&gTZGNLock);
-}
-
-TimeZoneGenericNames*
-TimeZoneGenericNames::createInstance(const Locale& locale, UErrorCode& status) {
- if (U_FAILURE(status)) {
- return NULL;
- }
- TimeZoneGenericNames* instance = new TimeZoneGenericNames();
- if (instance == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- return NULL;
- }
-
- TZGNCoreRef *cacheEntry = NULL;
- {
- Mutex lock(&gTZGNLock);
-
- if (!gTZGNCoreCacheInitialized) {
- // Create empty hashtable
- gTZGNCoreCache = uhash_open(uhash_hashChars, uhash_compareChars, NULL, &status);
- if (U_SUCCESS(status)) {
- uhash_setKeyDeleter(gTZGNCoreCache, uprv_free);
- uhash_setValueDeleter(gTZGNCoreCache, deleteTZGNCoreRef);
- gTZGNCoreCacheInitialized = TRUE;
- ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONEGENERICNAMES, tzgnCore_cleanup);
- }
- }
- if (U_FAILURE(status)) {
- return NULL;
- }
-
- // Check the cache, if not available, create new one and cache
- const char *key = locale.getName();
- cacheEntry = (TZGNCoreRef *)uhash_get(gTZGNCoreCache, key);
- if (cacheEntry == NULL) {
- TZGNCore *tzgnCore = NULL;
- char *newKey = NULL;
-
- tzgnCore = new TZGNCore(locale, status);
- if (tzgnCore == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- }
- if (U_SUCCESS(status)) {
- newKey = (char *)uprv_malloc(uprv_strlen(key) + 1);
- if (newKey == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- } else {
- uprv_strcpy(newKey, key);
- }
- }
- if (U_SUCCESS(status)) {
- cacheEntry = (TZGNCoreRef *)uprv_malloc(sizeof(TZGNCoreRef));
- if (cacheEntry == NULL) {
- status = U_MEMORY_ALLOCATION_ERROR;
- } else {
- cacheEntry->obj = tzgnCore;
- cacheEntry->refCount = 1;
- cacheEntry->lastAccess = (double)uprv_getUTCtime();
-
- uhash_put(gTZGNCoreCache, newKey, cacheEntry, &status);
- }
- }
- if (U_FAILURE(status)) {
- if (tzgnCore != NULL) {
- delete tzgnCore;
- }
- if (newKey != NULL) {
- uprv_free(newKey);
- }
- if (cacheEntry != NULL) {
- uprv_free(cacheEntry);
- }
- cacheEntry = NULL;
- }
- } else {
- // Update the reference count
- cacheEntry->refCount++;
- cacheEntry->lastAccess = (double)uprv_getUTCtime();
- }
- gAccessCount++;
- if (gAccessCount >= SWEEP_INTERVAL) {
- // sweep
- sweepCache();
- gAccessCount = 0;
- }
- } // End of mutex locked block
-
- if (cacheEntry == NULL) {
- delete instance;
- return NULL;
- }
-
- instance->fRef = cacheEntry;
- return instance;
-}
-
-UBool
-TimeZoneGenericNames::operator==(const TimeZoneGenericNames& other) const {
- // Just compare if the other object also use the same
- // ref entry
- return fRef == other.fRef;
-}
-
-TimeZoneGenericNames*
-TimeZoneGenericNames::clone() const {
- TimeZoneGenericNames* other = new TimeZoneGenericNames();
- if (other) {
- umtx_lock(&gTZGNLock);
- {
- // Just increments the reference count
- fRef->refCount++;
- other->fRef = fRef;
- }
- umtx_unlock(&gTZGNLock);
- }
- return other;
-}
-
-UnicodeString&
-TimeZoneGenericNames::getDisplayName(const TimeZone& tz, UTimeZoneGenericNameType type,
- UDate date, UnicodeString& name) const {
- return fRef->obj->getDisplayName(tz, type, date, name);
-}
-
-UnicodeString&
-TimeZoneGenericNames::getGenericLocationName(const UnicodeString& tzCanonicalID, UnicodeString& name) const {
- return fRef->obj->getGenericLocationName(tzCanonicalID, name);
-}
-
-int32_t
-TimeZoneGenericNames::findBestMatch(const UnicodeString& text, int32_t start, uint32_t types,
- UnicodeString& tzID, UTimeZoneFormatTimeType& timeType, UErrorCode& status) const {
- return fRef->obj->findBestMatch(text, start, types, tzID, timeType, status);
-}
-
-U_NAMESPACE_END
-#endif