]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/tznames_impl.cpp
ICU-511.25.tar.gz
[apple/icu.git] / icuSources / i18n / tznames_impl.cpp
index a699ec8c0b4ead79e2d7735aa72feae60c4d2446..e3b0c3c043192cf25a2e0e13f7fc2f2d95639684 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2011-2012, International Business Machines Corporation and
+* Copyright (C) 2011-2013, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 *
@@ -46,6 +46,7 @@ static const char EMPTY[]               = "<empty>";   // place holder for empty
 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
 };
 
@@ -282,7 +283,7 @@ TextTrieMap::getChildNode(CharacterNode *parent, UChar c) const {
 }
 
 // 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
@@ -489,7 +490,7 @@ public:
     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);
@@ -544,6 +545,7 @@ ZNames::getName(UTimeZoneNameType type) {
     case UTZNM_SHORT_DAYLIGHT:
         name = fNames[5];
         break;
+    case UTZNM_EXEMPLAR_LOCATION:   // implemeted by subclass
     default:
         name = NULL;
     }
@@ -594,48 +596,80 @@ class TZNames : public ZNames {
 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;
 }
 
@@ -837,9 +871,10 @@ deleteZNameInfo(void *obj) {
 
 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),
@@ -911,7 +946,6 @@ TimeZoneNamesImpl::loadStrings(const UnicodeString& tzCanonicalID) {
 
 TimeZoneNamesImpl::~TimeZoneNamesImpl() {
     cleanup();
-    umtx_destroy(&fLock);
 }
 
 void
@@ -1015,11 +1049,11 @@ TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID,
     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);
@@ -1040,11 +1074,11 @@ TimeZoneNamesImpl::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNa
     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);
@@ -1057,25 +1091,25 @@ TimeZoneNamesImpl::getTimeZoneDisplayName(const UnicodeString& tzID, UTimeZoneNa
 
 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;
 }
 
 
@@ -1193,7 +1227,7 @@ TimeZoneNamesImpl::loadTimeZoneNames(const UnicodeString& tzID) {
             }
         }
         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;
@@ -1246,11 +1280,11 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types
 
     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;
@@ -1266,7 +1300,7 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types
     delete matches;
 
     // All names are not yet loaded into the trie
-    umtx_lock(&nonConstThis->fLock);
+    umtx_lock(&gLock);
     {
         if (!fNamesTrieFullyLoaded) {
             const UnicodeString *id;
@@ -1290,22 +1324,48 @@ TimeZoneNamesImpl::find(const UnicodeString& text, int32_t start, uint32_t types
             }
         }
     }
-    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