OLD | NEW |
1 /* | 1 /* |
2 ******************************************************************************* | 2 ******************************************************************************* |
3 * Copyright (C) 2011-2013, International Business Machines Corporation and | 3 * Copyright (C) 2011-2014, International Business Machines Corporation and |
4 * others. All Rights Reserved. | 4 * others. All Rights Reserved. |
5 ******************************************************************************* | 5 ******************************************************************************* |
6 * | 6 * |
7 * File TZNAMES_IMPL.CPP | 7 * File TZNAMES_IMPL.CPP |
8 * | 8 * |
9 ******************************************************************************* | 9 ******************************************************************************* |
10 */ | 10 */ |
11 | 11 |
12 #include "unicode/utypes.h" | 12 #include "unicode/utypes.h" |
13 | 13 |
(...skipping 30 matching lines...) Expand all Loading... |
44 | 44 |
45 static const char EMPTY[] = "<empty>"; // place holder for empty
ZNames/TZNames | 45 static const char EMPTY[] = "<empty>"; // place holder for empty
ZNames/TZNames |
46 | 46 |
47 static const UTimeZoneNameType ALL_NAME_TYPES[] = { | 47 static const UTimeZoneNameType ALL_NAME_TYPES[] = { |
48 UTZNM_LONG_GENERIC, UTZNM_LONG_STANDARD, UTZNM_LONG_DAYLIGHT, | 48 UTZNM_LONG_GENERIC, UTZNM_LONG_STANDARD, UTZNM_LONG_DAYLIGHT, |
49 UTZNM_SHORT_GENERIC, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT, | 49 UTZNM_SHORT_GENERIC, UTZNM_SHORT_STANDARD, UTZNM_SHORT_DAYLIGHT, |
50 UTZNM_EXEMPLAR_LOCATION, | 50 UTZNM_EXEMPLAR_LOCATION, |
51 UTZNM_UNKNOWN // unknown as the last one | 51 UTZNM_UNKNOWN // unknown as the last one |
52 }; | 52 }; |
53 | 53 |
| 54 // stuff for TZDBTimeZoneNames |
| 55 static const char* TZDBNAMES_KEYS[] = {"ss", "sd"}; |
| 56 static const int32_t TZDBNAMES_KEYS_SIZE = (sizeof TZDBNAMES_KEYS / sizeof TZDBN
AMES_KEYS[0]); |
| 57 |
| 58 static UMutex gTZDBNamesMapLock = U_MUTEX_INITIALIZER; |
| 59 |
| 60 static UHashtable* gTZDBNamesMap = NULL; |
| 61 static icu::UInitOnce gTZDBNamesMapInitOnce = U_INITONCE_INITIALIZER; |
| 62 |
| 63 static TextTrieMap* gTZDBNamesTrie = NULL; |
| 64 static icu::UInitOnce gTZDBNamesTrieInitOnce = U_INITONCE_INITIALIZER; |
| 65 |
| 66 U_CDECL_BEGIN |
| 67 static 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 } |
| 82 U_CDECL_END |
| 83 |
54 #define DEFAULT_CHARACTERNODE_CAPACITY 1 | 84 #define DEFAULT_CHARACTERNODE_CAPACITY 1 |
55 | 85 |
56 // --------------------------------------------------- | 86 // --------------------------------------------------- |
57 // CharacterNode class implementation | 87 // CharacterNode class implementation |
58 // --------------------------------------------------- | 88 // --------------------------------------------------- |
59 void CharacterNode::clear() { | 89 void CharacterNode::clear() { |
60 uprv_memset(this, 0, sizeof(*this)); | 90 uprv_memset(this, 0, sizeof(*this)); |
61 } | 91 } |
62 | 92 |
63 void CharacterNode::deleteValues(UObjectDeleter *valueDeleter) { | 93 void CharacterNode::deleteValues(UObjectDeleter *valueDeleter) { |
(...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 UBool | 822 UBool |
793 ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node,
UErrorCode &status) { | 823 ZNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *node,
UErrorCode &status) { |
794 if (U_FAILURE(status)) { | 824 if (U_FAILURE(status)) { |
795 return FALSE; | 825 return FALSE; |
796 } | 826 } |
797 if (node->hasValues()) { | 827 if (node->hasValues()) { |
798 int32_t valuesCount = node->countValues(); | 828 int32_t valuesCount = node->countValues(); |
799 for (int32_t i = 0; i < valuesCount; i++) { | 829 for (int32_t i = 0; i < valuesCount; i++) { |
800 ZNameInfo *nameinfo = (ZNameInfo *)node->getValue(i); | 830 ZNameInfo *nameinfo = (ZNameInfo *)node->getValue(i); |
801 if (nameinfo == NULL) { | 831 if (nameinfo == NULL) { |
802 break; | 832 continue; |
803 } | 833 } |
804 if ((nameinfo->type & fTypes) != 0) { | 834 if ((nameinfo->type & fTypes) != 0) { |
805 // matches a requested type | 835 // matches a requested type |
806 if (fResults == NULL) { | 836 if (fResults == NULL) { |
807 fResults = new TimeZoneNames::MatchInfoCollection(); | 837 fResults = new TimeZoneNames::MatchInfoCollection(); |
808 if (fResults == NULL) { | 838 if (fResults == NULL) { |
809 status = U_MEMORY_ALLOCATION_ERROR; | 839 status = U_MEMORY_ALLOCATION_ERROR; |
810 } | 840 } |
811 } | 841 } |
812 if (U_SUCCESS(status)) { | 842 if (U_SUCCESS(status)) { |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
979 } | 1009 } |
980 | 1010 |
981 TimeZoneNames* | 1011 TimeZoneNames* |
982 TimeZoneNamesImpl::clone() const { | 1012 TimeZoneNamesImpl::clone() const { |
983 UErrorCode status = U_ZERO_ERROR; | 1013 UErrorCode status = U_ZERO_ERROR; |
984 return new TimeZoneNamesImpl(fLocale, status); | 1014 return new TimeZoneNamesImpl(fLocale, status); |
985 } | 1015 } |
986 | 1016 |
987 StringEnumeration* | 1017 StringEnumeration* |
988 TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const { | 1018 TimeZoneNamesImpl::getAvailableMetaZoneIDs(UErrorCode& status) const { |
| 1019 return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status); |
| 1020 } |
| 1021 |
| 1022 // static implementation of getAvailableMetaZoneIDs(UErrorCode&) |
| 1023 StringEnumeration* |
| 1024 TimeZoneNamesImpl::_getAvailableMetaZoneIDs(UErrorCode& status) { |
989 if (U_FAILURE(status)) { | 1025 if (U_FAILURE(status)) { |
990 return NULL; | 1026 return NULL; |
991 } | 1027 } |
992 const UVector* mzIDs = ZoneMeta::getAvailableMetazoneIDs(); | 1028 const UVector* mzIDs = ZoneMeta::getAvailableMetazoneIDs(); |
993 if (mzIDs == NULL) { | 1029 if (mzIDs == NULL) { |
994 return new MetaZoneIDsEnumeration(); | 1030 return new MetaZoneIDsEnumeration(); |
995 } | 1031 } |
996 return new MetaZoneIDsEnumeration(*mzIDs); | 1032 return new MetaZoneIDsEnumeration(*mzIDs); |
997 } | 1033 } |
998 | 1034 |
999 StringEnumeration* | 1035 StringEnumeration* |
1000 TimeZoneNamesImpl::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode
& status) const { | 1036 TimeZoneNamesImpl::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode
& status) const { |
| 1037 return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status); |
| 1038 } |
| 1039 |
| 1040 // static implementation of getAvailableMetaZoneIDs(const UnicodeString&, UError
Code&) |
| 1041 StringEnumeration* |
| 1042 TimeZoneNamesImpl::_getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCod
e& status) { |
1001 if (U_FAILURE(status)) { | 1043 if (U_FAILURE(status)) { |
1002 return NULL; | 1044 return NULL; |
1003 } | 1045 } |
1004 const UVector* mappings = ZoneMeta::getMetazoneMappings(tzID); | 1046 const UVector* mappings = ZoneMeta::getMetazoneMappings(tzID); |
1005 if (mappings == NULL) { | 1047 if (mappings == NULL) { |
1006 return new MetaZoneIDsEnumeration(); | 1048 return new MetaZoneIDsEnumeration(); |
1007 } | 1049 } |
1008 | 1050 |
1009 MetaZoneIDsEnumeration *senum = NULL; | 1051 MetaZoneIDsEnumeration *senum = NULL; |
1010 UVector* mzIDs = new UVector(NULL, uhash_compareUChars, status); | 1052 UVector* mzIDs = new UVector(NULL, uhash_compareUChars, status); |
(...skipping 14 matching lines...) Expand all Loading... |
1025 senum = new MetaZoneIDsEnumeration(mzIDs); | 1067 senum = new MetaZoneIDsEnumeration(mzIDs); |
1026 } else { | 1068 } else { |
1027 delete mzIDs; | 1069 delete mzIDs; |
1028 } | 1070 } |
1029 } | 1071 } |
1030 return senum; | 1072 return senum; |
1031 } | 1073 } |
1032 | 1074 |
1033 UnicodeString& | 1075 UnicodeString& |
1034 TimeZoneNamesImpl::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeS
tring& mzID) const { | 1076 TimeZoneNamesImpl::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeS
tring& mzID) const { |
| 1077 return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID); |
| 1078 } |
| 1079 |
| 1080 // static implementation of getMetaZoneID |
| 1081 UnicodeString& |
| 1082 TimeZoneNamesImpl::_getMetaZoneID(const UnicodeString& tzID, UDate date, Unicode
String& mzID) { |
1035 ZoneMeta::getMetazoneID(tzID, date, mzID); | 1083 ZoneMeta::getMetazoneID(tzID, date, mzID); |
1036 return mzID; | 1084 return mzID; |
1037 } | 1085 } |
1038 | 1086 |
1039 UnicodeString& | 1087 UnicodeString& |
1040 TimeZoneNamesImpl::getReferenceZoneID(const UnicodeString& mzID, const char* reg
ion, UnicodeString& tzID) const { | 1088 TimeZoneNamesImpl::getReferenceZoneID(const UnicodeString& mzID, const char* reg
ion, UnicodeString& tzID) const { |
| 1089 return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID); |
| 1090 } |
| 1091 |
| 1092 // static implementaion of getReferenceZoneID |
| 1093 UnicodeString& |
| 1094 TimeZoneNamesImpl::_getReferenceZoneID(const UnicodeString& mzID, const char* re
gion, UnicodeString& tzID) { |
1041 ZoneMeta::getZoneIdByMetazone(mzID, UnicodeString(region, -1, US_INV), tzID)
; | 1095 ZoneMeta::getZoneIdByMetazone(mzID, UnicodeString(region, -1, US_INV), tzID)
; |
1042 return tzID; | 1096 return tzID; |
1043 } | 1097 } |
1044 | 1098 |
| 1099 |
1045 UnicodeString& | 1100 UnicodeString& |
1046 TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID, | 1101 TimeZoneNamesImpl::getMetaZoneDisplayName(const UnicodeString& mzID, |
1047 UTimeZoneNameType type, | 1102 UTimeZoneNameType type, |
1048 UnicodeString& name) const { | 1103 UnicodeString& name) const { |
1049 name.setToBogus(); // cleanup result. | 1104 name.setToBogus(); // cleanup result. |
1050 if (mzID.isEmpty()) { | 1105 if (mzID.isEmpty()) { |
1051 return name; | 1106 return name; |
1052 } | 1107 } |
1053 | 1108 |
1054 ZNames *znames = NULL; | 1109 ZNames *znames = NULL; |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1163 cacheVal = znames; | 1218 cacheVal = znames; |
1164 } | 1219 } |
1165 // Use the persistent ID as the resource key, so we can | 1220 // Use the persistent ID as the resource key, so we can |
1166 // avoid duplications. | 1221 // avoid duplications. |
1167 const UChar* newKey = ZoneMeta::findMetaZoneID(mzID); | 1222 const UChar* newKey = ZoneMeta::findMetaZoneID(mzID); |
1168 if (newKey != NULL) { | 1223 if (newKey != NULL) { |
1169 uhash_put(fMZNamesMap, (void *)newKey, cacheVal, &status); | 1224 uhash_put(fMZNamesMap, (void *)newKey, cacheVal, &status); |
1170 if (U_FAILURE(status)) { | 1225 if (U_FAILURE(status)) { |
1171 if (znames != NULL) { | 1226 if (znames != NULL) { |
1172 delete znames; | 1227 delete znames; |
| 1228 znames = NULL; |
1173 } | 1229 } |
1174 } else if (znames != NULL) { | 1230 } else if (znames != NULL) { |
1175 // put the name info into the trie | 1231 // put the name info into the trie |
1176 for (int32_t i = 0; ALL_NAME_TYPES[i] != UTZNM_UNKNOWN; i++) { | 1232 for (int32_t i = 0; ALL_NAME_TYPES[i] != UTZNM_UNKNOWN; i++) { |
1177 const UChar* name = znames->getName(ALL_NAME_TYPES[i]); | 1233 const UChar* name = znames->getName(ALL_NAME_TYPES[i]); |
1178 if (name != NULL) { | 1234 if (name != NULL) { |
1179 ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZN
ameInfo)); | 1235 ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZN
ameInfo)); |
1180 if (nameinfo != NULL) { | 1236 if (nameinfo != NULL) { |
1181 nameinfo->type = ALL_NAME_TYPES[i]; | 1237 nameinfo->type = ALL_NAME_TYPES[i]; |
1182 nameinfo->tzID = NULL; | 1238 nameinfo->tzID = NULL; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1240 cacheVal = tznames; | 1296 cacheVal = tznames; |
1241 } | 1297 } |
1242 // Use the persistent ID as the resource key, so we can | 1298 // Use the persistent ID as the resource key, so we can |
1243 // avoid duplications. | 1299 // avoid duplications. |
1244 const UChar* newKey = ZoneMeta::findTimeZoneID(tzID); | 1300 const UChar* newKey = ZoneMeta::findTimeZoneID(tzID); |
1245 if (newKey != NULL) { | 1301 if (newKey != NULL) { |
1246 uhash_put(fTZNamesMap, (void *)newKey, cacheVal, &status); | 1302 uhash_put(fTZNamesMap, (void *)newKey, cacheVal, &status); |
1247 if (U_FAILURE(status)) { | 1303 if (U_FAILURE(status)) { |
1248 if (tznames != NULL) { | 1304 if (tznames != NULL) { |
1249 delete tznames; | 1305 delete tznames; |
| 1306 tznames = NULL; |
1250 } | 1307 } |
1251 } else if (tznames != NULL) { | 1308 } else if (tznames != NULL) { |
1252 // put the name info into the trie | 1309 // put the name info into the trie |
1253 for (int32_t i = 0; ALL_NAME_TYPES[i] != UTZNM_UNKNOWN; i++) { | 1310 for (int32_t i = 0; ALL_NAME_TYPES[i] != UTZNM_UNKNOWN; i++) { |
1254 const UChar* name = tznames->getName(ALL_NAME_TYPES[i]); | 1311 const UChar* name = tznames->getName(ALL_NAME_TYPES[i]); |
1255 if (name != NULL) { | 1312 if (name != NULL) { |
1256 ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZN
ameInfo)); | 1313 ZNameInfo *nameinfo = (ZNameInfo *)uprv_malloc(sizeof(ZN
ameInfo)); |
1257 if (nameinfo != NULL) { | 1314 if (nameinfo != NULL) { |
1258 nameinfo->type = ALL_NAME_TYPES[i]; | 1315 nameinfo->type = ALL_NAME_TYPES[i]; |
1259 nameinfo->tzID = newKey; | 1316 nameinfo->tzID = newKey; |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1364 if (sep > 0 && sep + 1 < tzID.length()) { | 1421 if (sep > 0 && sep + 1 < tzID.length()) { |
1365 name.setTo(tzID, sep + 1); | 1422 name.setTo(tzID, sep + 1); |
1366 name.findAndReplace(UnicodeString((UChar)0x5f /* _ */), | 1423 name.findAndReplace(UnicodeString((UChar)0x5f /* _ */), |
1367 UnicodeString((UChar)0x20 /* space */)); | 1424 UnicodeString((UChar)0x20 /* space */)); |
1368 } else { | 1425 } else { |
1369 name.setToBogus(); | 1426 name.setToBogus(); |
1370 } | 1427 } |
1371 return name; | 1428 return name; |
1372 } | 1429 } |
1373 | 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 |
| 1438 class TZDBNames : public UMemory { |
| 1439 public: |
| 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 |
| 1446 protected: |
| 1447 TZDBNames(const UChar** names, char** regions, int32_t numRegions); |
| 1448 |
| 1449 private: |
| 1450 const UChar** fNames; |
| 1451 char** fRegions; |
| 1452 int32_t fNumRegions; |
| 1453 }; |
| 1454 |
| 1455 TZDBNames::TZDBNames(const UChar** names, char** regions, int32_t numRegions) |
| 1456 : fNames(names), |
| 1457 fRegions(regions), |
| 1458 fNumRegions(numRegions) { |
| 1459 } |
| 1460 |
| 1461 TZDBNames::~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 |
| 1474 TZDBNames* |
| 1475 TZDBNames::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_SI
ZE); |
| 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 |
| 1567 const UChar* |
| 1568 TZDBNames::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 |
| 1586 const char** |
| 1587 TZDBNames::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 |
| 1596 U_CDECL_BEGIN |
| 1597 /** |
| 1598 * TZDBNameInfo stores metazone name information for the IANA abbreviations |
| 1599 * in the trie |
| 1600 */ |
| 1601 typedef struct TZDBNameInfo { |
| 1602 const UChar* mzID; |
| 1603 UTimeZoneNameType type; |
| 1604 UBool ambiguousType; |
| 1605 const char** parseRegions; |
| 1606 int32_t nRegions; |
| 1607 } TZDBNameInfo; |
| 1608 U_CDECL_END |
| 1609 |
| 1610 |
| 1611 class TZDBNameSearchHandler : public TextTrieMapSearchResultHandler { |
| 1612 public: |
| 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 |
| 1619 private: |
| 1620 uint32_t fTypes; |
| 1621 int32_t fMaxMatchLen; |
| 1622 TimeZoneNames::MatchInfoCollection* fResults; |
| 1623 const char* fRegion; |
| 1624 }; |
| 1625 |
| 1626 TZDBNameSearchHandler::TZDBNameSearchHandler(uint32_t types, const char* region)
|
| 1627 : fTypes(types), fMaxMatchLen(0), fResults(NULL), fRegion(region) { |
| 1628 } |
| 1629 |
| 1630 TZDBNameSearchHandler::~TZDBNameSearchHandler() { |
| 1631 if (fResults != NULL) { |
| 1632 delete fResults; |
| 1633 } |
| 1634 } |
| 1635 |
| 1636 UBool |
| 1637 TZDBNameSearchHandler::handleMatch(int32_t matchLength, const CharacterNode *nod
e, 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_DA
YLIGHT) |
| 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->m
zID, -1), status); |
| 1722 if (U_SUCCESS(status) && matchLength > fMaxMatchLen) { |
| 1723 fMaxMatchLen = matchLength; |
| 1724 } |
| 1725 } |
| 1726 } |
| 1727 } |
| 1728 return TRUE; |
| 1729 } |
| 1730 |
| 1731 TimeZoneNames::MatchInfoCollection* |
| 1732 TZDBNameSearchHandler::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 |
| 1743 U_CDECL_BEGIN |
| 1744 /** |
| 1745 * Deleter for TZDBNames |
| 1746 */ |
| 1747 static void U_CALLCONV |
| 1748 deleteTZDBNames(void *obj) { |
| 1749 if (obj != EMPTY) { |
| 1750 delete (TZDBNames *)obj; |
| 1751 } |
| 1752 } |
| 1753 |
| 1754 static void U_CALLCONV initTZDBNamesMap(UErrorCode &status) { |
| 1755 gTZDBNamesMap = uhash_open(uhash_hashUChars, uhash_compareUChars, NULL, &sta
tus); |
| 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_cle
anup); |
| 1763 } |
| 1764 |
| 1765 /** |
| 1766 * Deleter for TZDBNameInfo |
| 1767 */ |
| 1768 static void U_CALLCONV |
| 1769 deleteTZDBNameInfo(void *obj) { |
| 1770 if (obj != NULL) { |
| 1771 uprv_free(obj); |
| 1772 } |
| 1773 } |
| 1774 |
| 1775 static 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(statu
s); |
| 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, d
st) == 0); |
| 1807 |
| 1808 const UChar *uMzID = ZoneMeta::findMetaZoneID(*mzID); |
| 1809 if (std != NULL) { |
| 1810 TZDBNameInfo *stdInf = (TZDBNameInfo *)uprv_malloc(sizeof(TZDBNa
meInfo)); |
| 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(TZDBNa
meInfo)); |
| 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_cle
anup); |
| 1846 } |
| 1847 |
| 1848 U_CDECL_END |
| 1849 |
| 1850 TZDBTimeZoneNames::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 |
| 1872 TZDBTimeZoneNames::~TZDBTimeZoneNames() { |
| 1873 } |
| 1874 |
| 1875 UBool |
| 1876 TZDBTimeZoneNames::operator==(const TimeZoneNames& other) const { |
| 1877 if (this == &other) { |
| 1878 return TRUE; |
| 1879 } |
| 1880 // No implementation for now |
| 1881 return FALSE; |
| 1882 } |
| 1883 |
| 1884 TimeZoneNames* |
| 1885 TZDBTimeZoneNames::clone() const { |
| 1886 return new TZDBTimeZoneNames(fLocale); |
| 1887 } |
| 1888 |
| 1889 StringEnumeration* |
| 1890 TZDBTimeZoneNames::getAvailableMetaZoneIDs(UErrorCode& status) const { |
| 1891 return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(status); |
| 1892 } |
| 1893 |
| 1894 StringEnumeration* |
| 1895 TZDBTimeZoneNames::getAvailableMetaZoneIDs(const UnicodeString& tzID, UErrorCode
& status) const { |
| 1896 return TimeZoneNamesImpl::_getAvailableMetaZoneIDs(tzID, status); |
| 1897 } |
| 1898 |
| 1899 UnicodeString& |
| 1900 TZDBTimeZoneNames::getMetaZoneID(const UnicodeString& tzID, UDate date, UnicodeS
tring& mzID) const { |
| 1901 return TimeZoneNamesImpl::_getMetaZoneID(tzID, date, mzID); |
| 1902 } |
| 1903 |
| 1904 UnicodeString& |
| 1905 TZDBTimeZoneNames::getReferenceZoneID(const UnicodeString& mzID, const char* reg
ion, UnicodeString& tzID) const { |
| 1906 return TimeZoneNamesImpl::_getReferenceZoneID(mzID, region, tzID); |
| 1907 } |
| 1908 |
| 1909 UnicodeString& |
| 1910 TZDBTimeZoneNames::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, statu
s); |
| 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 |
| 1930 UnicodeString& |
| 1931 TZDBTimeZoneNames::getTimeZoneDisplayName(const UnicodeString& /* tzID */, UTime
ZoneNameType /* type */, UnicodeString& name) const { |
| 1932 // No abbreviations associated a zone directly for now. |
| 1933 name.setToBogus(); |
| 1934 return name; |
| 1935 } |
| 1936 |
| 1937 TZDBTimeZoneNames::MatchInfoCollection* |
| 1938 TZDBTimeZoneNames::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 *)&handl
er, status); |
| 1946 if (U_FAILURE(status)) { |
| 1947 return NULL; |
| 1948 } |
| 1949 int32_t maxLen = 0; |
| 1950 return handler.getMatches(maxLen); |
| 1951 } |
| 1952 |
| 1953 const TZDBNames* |
| 1954 TZDBTimeZoneNames::getMetaZoneNames(const UnicodeString& mzID, UErrorCode& statu
s) { |
| 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, "t
zdbNames", &status); |
| 1972 zoneStringsRes = ures_getByKey(zoneStringsRes, gZoneStrings, zoneStr
ingsRes, &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 |
1374 U_NAMESPACE_END | 2014 U_NAMESPACE_END |
1375 | 2015 |
1376 | 2016 |
1377 #endif /* #if !UCONFIG_NO_FORMATTING */ | 2017 #endif /* #if !UCONFIG_NO_FORMATTING */ |
1378 | 2018 |
1379 //eof | 2019 //eof |
OLD | NEW |