/*
*******************************************************************************
-* Copyright (C) 2011-2012, International Business Machines Corporation and
+* Copyright (C) 2011-2013, International Business Machines Corporation and
* others. All Rights Reserved.
*******************************************************************************
*
static const UTimeZoneNameType ALL_NAME_TYPES[] = {
UTZNM_LONG_GENERIC, UTZNM_LONG_STANDARD, UTZNM_LONG_DAYLIGHT,
UTZNM_SHORT_GENERIC, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT,
+ UTZNM_EXEMPLAR_LOCATION,
UTZNM_UNKNOWN // unknown as the last one
};
}
// Mutex for protecting the lazy creation of the Trie node structure on the first call to search().
-static UMTX TextTrieMutex;
+static UMutex TextTrieMutex = U_MUTEX_INITIALIZER;
// buildTrie() - The Trie node structure is needed. Create it from the data that was
// saved at the time the ZoneStringFormatter was created. The Trie is only
virtual ~ZNames();
static ZNames* createInstance(UResourceBundle* rb, const char* key);
- const UChar* getName(UTimeZoneNameType type);
+ virtual const UChar* getName(UTimeZoneNameType type);
protected:
ZNames(const UChar** names);
case UTZNM_SHORT_DAYLIGHT:
name = fNames[5];
break;
+ case UTZNM_EXEMPLAR_LOCATION: // implemeted by subclass
default:
name = NULL;
}
public:
virtual ~TZNames();
- static TZNames* createInstance(UResourceBundle* rb, const char* key);
- const UChar* getLocationName(void);
+ static TZNames* createInstance(UResourceBundle* rb, const char* key, const UnicodeString& tzID);
+ virtual const UChar* getName(UTimeZoneNameType type);
private:
- TZNames(const UChar** names, const UChar* locationName);
+ TZNames(const UChar** names);
const UChar* fLocationName;
+ UChar* fLocationNameOwned;
};
-TZNames::TZNames(const UChar** names, const UChar* locationName)
-: ZNames(names), fLocationName(locationName) {
+TZNames::TZNames(const UChar** names)
+: ZNames(names), fLocationName(NULL), fLocationNameOwned(NULL) {
}
TZNames::~TZNames() {
+ if (fLocationNameOwned) {
+ uprv_free(fLocationNameOwned);
+ }
}
const UChar*
-TZNames::getLocationName() {
- return fLocationName;
+TZNames::getName(UTimeZoneNameType type) {
+ if (type == UTZNM_EXEMPLAR_LOCATION) {
+ return fLocationName;
+ }
+ return ZNames::getName(type);
}
TZNames*
-TZNames::createInstance(UResourceBundle* rb, const char* key) {
+TZNames::createInstance(UResourceBundle* rb, const char* key, const UnicodeString& tzID) {
if (rb == NULL || key == NULL || *key == 0) {
return NULL;
}
- TZNames* tznames = NULL;
+
+ const UChar** names = loadData(rb, key);
+ const UChar* locationName = NULL;
+ UChar* locationNameOwned = NULL;
+
UErrorCode status = U_ZERO_ERROR;
- UResourceBundle* rbTable = ures_getByKeyWithFallback(rb, key, NULL, &status);
- if (U_SUCCESS(status)) {
- int32_t len = 0;
- const UChar* locationName = ures_getStringByKeyWithFallback(rbTable, gEcTag, &len, &status);
- if (U_FAILURE(status) || len == 0) {
- locationName = NULL;
+ int32_t len = 0;
+
+ UResourceBundle* table = ures_getByKeyWithFallback(rb, key, NULL, &status);
+ locationName = ures_getStringByKeyWithFallback(table, gEcTag, &len, &status);
+ // ignore missing resource here
+ status = U_ZERO_ERROR;
+
+ ures_close(table);
+
+ if (locationName == NULL) {
+ UnicodeString tmpName;
+ int32_t tmpNameLen = 0;
+ TimeZoneNamesImpl::getDefaultExemplarLocationName(tzID, tmpName);
+ tmpNameLen = tmpName.length();
+
+ if (tmpNameLen > 0) {
+ locationNameOwned = (UChar*) uprv_malloc(sizeof(UChar) * (tmpNameLen + 1));
+ if (locationNameOwned) {
+ tmpName.extract(locationNameOwned, tmpNameLen + 1, status);
+ locationName = locationNameOwned;
+ }
}
+ }
- const UChar** names = loadData(rb, key);
-
- if (locationName != NULL || names != NULL) {
- tznames = new TZNames(names, locationName);
+ TZNames* tznames = NULL;
+ if (locationName != NULL || names != NULL) {
+ tznames = new TZNames(names);
+ if (tznames == NULL) {
+ if (locationNameOwned) {
+ uprv_free(locationNameOwned);
+ }
}
+ tznames->fLocationName = locationName;
+ tznames->fLocationNameOwned = locationNameOwned;
}
- ures_close(rbTable);
+
return tznames;
}
U_CDECL_END
+static UMutex gLock = U_MUTEX_INITIALIZER;
+
TimeZoneNamesImpl::TimeZoneNamesImpl(const Locale& locale, UErrorCode& status)
: fLocale(locale),
- fLock(NULL),
fZoneStrings(NULL),
fTZNamesMap(NULL),
fMZNamesMap(NULL),
TimeZoneNamesImpl::~TimeZoneNamesImpl() {
cleanup();
- umtx_destroy(&fLock);
}
void
ZNames *znames = NULL;
TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
- umtx_lock(&nonConstThis->fLock);
+ umtx_lock(&gLock);
{
znames = nonConstThis->loadMetaZoneNames(mzID);
}
- umtx_unlock(&nonConstThis->fLock);
+ umtx_unlock(&gLock);
if (znames != NULL) {
const UChar* s = znames->getName(type);
TZNames *tznames = NULL;
TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
- umtx_lock(&nonConstThis->fLock);
+ umtx_lock(&gLock);
{
tznames = nonConstThis->loadTimeZoneNames(tzID);
}
- umtx_unlock(&nonConstThis->fLock);
+ umtx_unlock(&gLock);
if (tznames != NULL) {
const UChar *s = tznames->getName(type);
UnicodeString&
TimeZoneNamesImpl::getExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) const {
+ name.setToBogus(); // cleanup result.
const UChar* locName = NULL;
TZNames *tznames = NULL;
TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
- umtx_lock(&nonConstThis->fLock);
+ umtx_lock(&gLock);
{
tznames = nonConstThis->loadTimeZoneNames(tzID);
}
- umtx_unlock(&nonConstThis->fLock);
+ umtx_unlock(&gLock);
if (tznames != NULL) {
- locName = tznames->getLocationName();
+ locName = tznames->getName(UTZNM_EXEMPLAR_LOCATION);
}
if (locName != NULL) {
name.setTo(TRUE, locName, -1);
- return name;
}
- return TimeZoneNames::getExemplarLocationName(tzID, name);
+ return name;
}
}
}
uKey.extract(0, uKey.length(), key, sizeof(key), US_INV);
- tznames = TZNames::createInstance(fZoneStrings, key);
+ tznames = TZNames::createInstance(fZoneStrings, key, tzID);
if (tznames == NULL) {
cacheVal = (void *)EMPTY;
TimeZoneNamesImpl *nonConstThis = const_cast<TimeZoneNamesImpl *>(this);
- umtx_lock(&nonConstThis->fLock);
+ umtx_lock(&gLock);
{
fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
}
- umtx_unlock(&nonConstThis->fLock);
+ umtx_unlock(&gLock);
if (U_FAILURE(status)) {
return NULL;
delete matches;
// All names are not yet loaded into the trie
- umtx_lock(&nonConstThis->fLock);
+ umtx_lock(&gLock);
{
if (!fNamesTrieFullyLoaded) {
const UnicodeString *id;
}
}
}
- umtx_unlock(&nonConstThis->fLock);
+ umtx_unlock(&gLock);
if (U_FAILURE(status)) {
return NULL;
}
- umtx_lock(&nonConstThis->fLock);
+ umtx_lock(&gLock);
{
// now try it again
fNamesTrie.search(text, start, (TextTrieMapSearchResultHandler *)&handler, status);
}
- umtx_unlock(&nonConstThis->fLock);
+ umtx_unlock(&gLock);
return handler.getMatches(maxLen);
}
+static const UChar gEtcPrefix[] = { 0x45, 0x74, 0x63, 0x2F }; // "Etc/"
+static const int32_t gEtcPrefixLen = 4;
+static const UChar gSystemVPrefix[] = { 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x56, 0x2F }; // "SystemV/
+static const int32_t gSystemVPrefixLen = 8;
+static const UChar gRiyadh8[] = { 0x52, 0x69, 0x79, 0x61, 0x64, 0x68, 0x38 }; // "Riyadh8"
+static const int32_t gRiyadh8Len = 7;
+
+UnicodeString& U_EXPORT2
+TimeZoneNamesImpl::getDefaultExemplarLocationName(const UnicodeString& tzID, UnicodeString& name) {
+ if (tzID.isEmpty() || tzID.startsWith(gEtcPrefix, gEtcPrefixLen)
+ || tzID.startsWith(gSystemVPrefix, gSystemVPrefixLen) || tzID.indexOf(gRiyadh8, gRiyadh8Len, 0) > 0) {
+ name.setToBogus();
+ return name;
+ }
+
+ int32_t sep = tzID.lastIndexOf((UChar)0x2F /* '/' */);
+ if (sep > 0 && sep + 1 < tzID.length()) {
+ name.setTo(tzID, sep + 1);
+ name.findAndReplace(UnicodeString((UChar)0x5f /* _ */),
+ UnicodeString((UChar)0x20 /* space */));
+ } else {
+ name.setToBogus();
+ }
+ return name;
+}
+
U_NAMESPACE_END