diff options
Diffstat (limited to 'Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp')
-rw-r--r-- | Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp | 873 |
1 files changed, 873 insertions, 0 deletions
diff --git a/Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp b/Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp new file mode 100644 index 00000000000..0e67c687c28 --- /dev/null +++ b/Build/source/libs/icu/icu-xetex/i18n/zonemeta.cpp @@ -0,0 +1,873 @@ +/* +******************************************************************************* +* Copyright (C) 2007, International Business Machines Corporation and * +* others. All Rights Reserved. * +******************************************************************************* +*/ + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +#include "zonemeta.h" + +#include "unicode/timezone.h" +#include "unicode/ustring.h" +#include "unicode/putil.h" + +#include "umutex.h" +#include "uvector.h" +#include "cmemory.h" +#include "gregoimp.h" +#include "cstring.h" +#include "ucln_in.h" + +static UBool gZoneMetaInitialized = FALSE; + +// Metazone mapping tables +static UMTX gZoneMetaLock = NULL; +static U_NAMESPACE_QUALIFIER Hashtable *gCanonicalMap = NULL; +static U_NAMESPACE_QUALIFIER Hashtable *gOlsonToMeta = NULL; +static U_NAMESPACE_QUALIFIER Hashtable *gMetaToOlson = NULL; + +U_CDECL_BEGIN +/** + * Cleanup callback func + */ +static UBool U_CALLCONV zoneMeta_cleanup(void) +{ + umtx_destroy(&gZoneMetaLock); + + if (gCanonicalMap != NULL) { + delete gCanonicalMap; + gCanonicalMap = NULL; + } + + if (gOlsonToMeta != NULL) { + delete gOlsonToMeta; + gOlsonToMeta = NULL; + } + + if (gMetaToOlson != NULL) { + delete gMetaToOlson; + gMetaToOlson = NULL; + } + + gZoneMetaInitialized = FALSE; + + return TRUE; +} + +/** + * Deleter for UVector + */ +static void U_CALLCONV +deleteUVector(void *obj) { + delete (U_NAMESPACE_QUALIFIER UVector*) obj; +} + +/** + * Deleter for CanonicalMapEntry + */ +static void U_CALLCONV +deleteCanonicalMapEntry(void *obj) { + U_NAMESPACE_QUALIFIER CanonicalMapEntry *entry = (U_NAMESPACE_QUALIFIER CanonicalMapEntry*)obj; + uprv_free(entry->id); + uprv_free(entry); +} + +/** + * Deleter for OlsonToMetaMappingEntry + */ +static void U_CALLCONV +deleteOlsonToMetaMappingEntry(void *obj) { + U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry *entry = (U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry*)obj; + uprv_free(entry); +} + +/** + * Deleter for MetaToOlsonMappingEntry + */ +static void U_CALLCONV +deleteMetaToOlsonMappingEntry(void *obj) { + U_NAMESPACE_QUALIFIER MetaToOlsonMappingEntry *entry = (U_NAMESPACE_QUALIFIER MetaToOlsonMappingEntry*)obj; + uprv_free(entry->territory); + uprv_free(entry); +} +U_CDECL_END + +U_NAMESPACE_BEGIN + +#define ZID_KEY_MAX 128 +static const char gZoneStringsTag[] = "zoneStrings"; +static const char gUseMetazoneTag[] = "um"; + +static const char gSupplementalData[] = "supplementalData"; +static const char gMapTimezonesTag[] = "mapTimezones"; +static const char gMetazonesTag[] = "metazones"; +static const char gZoneFormattingTag[] = "zoneFormatting"; +static const char gTerritoryTag[] = "territory"; +static const char gAliasesTag[] = "aliases"; +static const char gMultizoneTag[] = "multizone"; + +static const char gMetazoneInfo[] = "metazoneInfo"; +static const char gMetazoneMappings[] = "metazoneMappings"; + +#define MZID_PREFIX_LEN 5 +static const char gMetazoneIdPrefix[] = "meta:"; + +static const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001" + +#define ASCII_DIGIT(c) (((c)>=0x30 && (c)<=0x39) ? (c)-0x30 : -1) + +/* + * Convert a date string used by metazone mappings to UDate. + * The format used by CLDR metazone mapping is "yyyy-MM-dd HH:mm". + */ + static UDate parseDate (const UChar *text, UErrorCode &status) { + if (U_FAILURE(status)) { + return 0; + } + int32_t len = u_strlen(text); + if (len != 16 && len != 10) { + // It must be yyyy-MM-dd HH:mm (length 16) or yyyy-MM-dd (length 10) + status = U_INVALID_FORMAT_ERROR; + return 0; + } + + int32_t year = 0, month = 0, day = 0, hour = 0, min = 0, n; + int32_t idx; + + // "yyyy" (0 - 3) + for (idx = 0; idx <= 3 && U_SUCCESS(status); idx++) { + n = ASCII_DIGIT(text[idx]); + if (n >= 0) { + year = 10*year + n; + } else { + status = U_INVALID_FORMAT_ERROR; + } + } + // "MM" (5 - 6) + for (idx = 5; idx <= 6 && U_SUCCESS(status); idx++) { + n = ASCII_DIGIT(text[idx]); + if (n >= 0) { + month = 10*month + n; + } else { + status = U_INVALID_FORMAT_ERROR; + } + } + // "dd" (8 - 9) + for (idx = 8; idx <= 9 && U_SUCCESS(status); idx++) { + n = ASCII_DIGIT(text[idx]); + if (n >= 0) { + day = 10*day + n; + } else { + status = U_INVALID_FORMAT_ERROR; + } + } + if (len == 16) { + // "HH" (11 - 12) + for (idx = 11; idx <= 12 && U_SUCCESS(status); idx++) { + n = ASCII_DIGIT(text[idx]); + if (n >= 0) { + hour = 10*hour + n; + } else { + status = U_INVALID_FORMAT_ERROR; + } + } + // "mm" (14 - 15) + for (idx = 14; idx <= 15 && U_SUCCESS(status); idx++) { + n = ASCII_DIGIT(text[idx]); + if (n >= 0) { + min = 10*min + n; + } else { + status = U_INVALID_FORMAT_ERROR; + } + } + } + + if (U_SUCCESS(status)) { + UDate date = Grego::fieldsToDay(year, month - 1, day) * U_MILLIS_PER_DAY + + hour * U_MILLIS_PER_HOUR + min * U_MILLIS_PER_MINUTE; + return date; + } + return 0; +} + + /* + * Initialize global objects + */ +void +ZoneMeta::initialize(void) { + UBool initialized; + UMTX_CHECK(&gZoneMetaLock, gZoneMetaInitialized, initialized); + if (initialized) { + return; + } + + // Initialize hash tables + Hashtable *tmpCanonicalMap = createCanonicalMap(); + Hashtable *tmpOlsonToMeta = createOlsonToMetaMap(); + if (tmpOlsonToMeta == NULL) { + // With ICU 3.8 data + tmpOlsonToMeta = createOlsonToMetaMapOld(); + } + Hashtable *tmpMetaToOlson = createMetaToOlsonMap(); + + umtx_lock(&gZoneMetaLock); + if (gZoneMetaInitialized) { + // Another thread already created mappings + delete tmpCanonicalMap; + delete tmpOlsonToMeta; + delete tmpMetaToOlson; + } else { + gZoneMetaInitialized = TRUE; + gCanonicalMap = tmpCanonicalMap; + gOlsonToMeta = tmpOlsonToMeta; + gMetaToOlson = tmpMetaToOlson; + ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup); + } + umtx_unlock(&gZoneMetaLock); +} + +Hashtable* +ZoneMeta::createCanonicalMap(void) { + UErrorCode status = U_ZERO_ERROR; + + Hashtable *canonicalMap = NULL; + UResourceBundle *zoneFormatting = NULL; + UResourceBundle *tzitem = NULL; + UResourceBundle *aliases = NULL; + + canonicalMap = new Hashtable(uhash_compareUnicodeString, NULL, status); + if (U_FAILURE(status)) { + return NULL; + } + canonicalMap->setValueDeleter(deleteCanonicalMapEntry); + + zoneFormatting = ures_openDirect(NULL, gSupplementalData, &status); + zoneFormatting = ures_getByKey(zoneFormatting, gZoneFormattingTag, zoneFormatting, &status); + if (U_FAILURE(status)) { + goto error_cleanup; + } + + while (ures_hasNext(zoneFormatting)) { + tzitem = ures_getNextResource(zoneFormatting, tzitem, &status); + if (U_FAILURE(status)) { + status = U_ZERO_ERROR; + continue; + } + if (ures_getType(tzitem) != URES_TABLE) { + continue; + } + + int32_t territoryLen; + const UChar *territory = ures_getStringByKey(tzitem, gTerritoryTag, &territoryLen, &status); + if (U_FAILURE(status)) { + territory = NULL; + status = U_ZERO_ERROR; + } + + int32_t tzidLen = 0; + char tzid[ZID_KEY_MAX]; + const char *tzkey = ures_getKey(tzitem); + uprv_strcpy(tzid, tzkey); + // Replace ':' with '/' + char *p = tzid; + while (*p) { + if (*p == ':') { + *p = '/'; + } + p++; + tzidLen++; + } + + // Create canonical map entry + CanonicalMapEntry *entry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry)); + if (entry == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + goto error_cleanup; + } + entry->id = (UChar*)uprv_malloc((tzidLen + 1) * sizeof(UChar)); + if (entry->id == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + uprv_free(entry); + goto error_cleanup; + } + u_charsToUChars(tzid, entry->id, tzidLen + 1); + + if (territory == NULL || u_strcmp(territory, gWorld) == 0) { + entry->country = NULL; + } else { + entry->country = territory; + } + + // Put this entry to the table + canonicalMap->put(UnicodeString(entry->id), entry, status); + if (U_FAILURE(status)) { + deleteCanonicalMapEntry(entry); + goto error_cleanup; + } + + // Get aliases + aliases = ures_getByKey(tzitem, gAliasesTag, aliases, &status); + if (U_FAILURE(status)) { + // No aliases + status = U_ZERO_ERROR; + continue; + } + + while (ures_hasNext(aliases)) { + const UChar* alias = ures_getNextString(aliases, NULL, NULL, &status); + if (U_FAILURE(status)) { + status = U_ZERO_ERROR; + continue; + } + // Create canonical map entry for this alias + entry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry)); + if (entry == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + goto error_cleanup; + } + entry->id = (UChar*)uprv_malloc((tzidLen + 1) * sizeof(UChar)); + if (entry->id == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + uprv_free(entry); + goto error_cleanup; + } + u_charsToUChars(tzid, entry->id, tzidLen + 1); + + if (territory == NULL || u_strcmp(territory, gWorld) == 0) { + entry->country = NULL; + } else { + entry->country = territory; + } + canonicalMap->put(UnicodeString(alias), entry, status); + if (U_FAILURE(status)) { + deleteCanonicalMapEntry(entry); + goto error_cleanup; + } + } + } + +normal_cleanup: + ures_close(aliases); + ures_close(tzitem); + ures_close(zoneFormatting); + return canonicalMap; + +error_cleanup: + delete canonicalMap; + canonicalMap = NULL; + + goto normal_cleanup; +} + +/* + * Creating Olson tzid to metazone mappings from resource (3.8.1 and beyond) + */ +Hashtable* +ZoneMeta::createOlsonToMetaMap(void) { + UErrorCode status = U_ZERO_ERROR; + + Hashtable *olsonToMeta = NULL; + UResourceBundle *metazoneMappings = NULL; + UResourceBundle *zoneItem = NULL; + UResourceBundle *mz = NULL; + StringEnumeration *tzids = NULL; + + olsonToMeta = new Hashtable(uhash_compareUnicodeString, NULL, status); + if (U_FAILURE(status)) { + return NULL; + } + olsonToMeta->setValueDeleter(deleteUVector); + + // Read metazone mappings from metazoneInfo bundle + metazoneMappings = ures_openDirect(NULL, gMetazoneInfo, &status); + metazoneMappings = ures_getByKey(metazoneMappings, gMetazoneMappings, metazoneMappings, &status); + if (U_FAILURE(status)) { + goto error_cleanup; + } + + // Walk through all canonical tzids + char zidkey[ZID_KEY_MAX]; + + tzids = TimeZone::createEnumeration(); + const UnicodeString *tzid; + while ((tzid = tzids->snext(status))) { + if (U_FAILURE(status)) { + goto error_cleanup; + } + // We may skip aliases, because the bundle + // contains only canonical IDs. For now, try + // all of them. + tzid->extract(0, tzid->length(), zidkey, sizeof(zidkey), US_INV); + zidkey[sizeof(zidkey)-1] = 0; // NULL terminate just in case. + + // Replace '/' with ':' + UBool foundSep = FALSE; + char *p = zidkey; + while (*p) { + if (*p == '/') { + *p = ':'; + foundSep = TRUE; + } + p++; + } + if (!foundSep) { + // A valid time zone key has at least one separator + continue; + } + + zoneItem = ures_getByKey(metazoneMappings, zidkey, zoneItem, &status); + if (U_FAILURE(status)) { + status = U_ZERO_ERROR; + continue; + } + + UVector *mzMappings = NULL; + while (ures_hasNext(zoneItem)) { + mz = ures_getNextResource(zoneItem, mz, &status); + const UChar *mz_name = ures_getStringByIndex(mz, 0, NULL, &status); + const UChar *mz_from = ures_getStringByIndex(mz, 1, NULL, &status); + const UChar *mz_to = ures_getStringByIndex(mz, 2, NULL, &status); + + if(U_FAILURE(status)){ + status = U_ZERO_ERROR; + continue; + } + // We do not want to use SimpleDateformat to parse boundary dates, + // because this code could be triggered by the initialization code + // used by SimpleDateFormat. + UDate from = parseDate(mz_from, status); + UDate to = parseDate(mz_to, status); + if (U_FAILURE(status)) { + status = U_ZERO_ERROR; + continue; + } + + OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry)); + if (entry == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + break; + } + entry->mzid = mz_name; + entry->from = from; + entry->to = to; + + if (mzMappings == NULL) { + mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status); + if (U_FAILURE(status)) { + delete mzMappings; + deleteOlsonToMetaMappingEntry(entry); + uprv_free(entry); + break; + } + } + + mzMappings->addElement(entry, status); + if (U_FAILURE(status)) { + break; + } + } + + if (U_FAILURE(status)) { + if (mzMappings != NULL) { + delete mzMappings; + } + goto error_cleanup; + } + if (mzMappings != NULL) { + olsonToMeta->put(*tzid, mzMappings, status); + if (U_FAILURE(status)) { + delete mzMappings; + goto error_cleanup; + } + } + } + +normal_cleanup: + if (tzids != NULL) { + delete tzids; + } + ures_close(zoneItem); + ures_close(mz); + ures_close(metazoneMappings); + return olsonToMeta; + +error_cleanup: + if (olsonToMeta != NULL) { + delete olsonToMeta; + olsonToMeta = NULL; + } + goto normal_cleanup; +} + +/* + * Creating Olson tzid to metazone mappings from ICU resource (3.8) + */ +Hashtable* +ZoneMeta::createOlsonToMetaMapOld(void) { + UErrorCode status = U_ZERO_ERROR; + + Hashtable *olsonToMeta = NULL; + UResourceBundle *zoneStringsArray = NULL; + UResourceBundle *mz = NULL; + UResourceBundle *zoneItem = NULL; + UResourceBundle *useMZ = NULL; + StringEnumeration *tzids = NULL; + + olsonToMeta = new Hashtable(uhash_compareUnicodeString, NULL, status); + if (U_FAILURE(status)) { + return NULL; + } + olsonToMeta->setValueDeleter(deleteUVector); + + // Read metazone mappings from root bundle + zoneStringsArray = ures_openDirect(NULL, "", &status); + zoneStringsArray = ures_getByKey(zoneStringsArray, gZoneStringsTag, zoneStringsArray, &status); + if (U_FAILURE(status)) { + goto error_cleanup; + } + + // Walk through all canonical tzids + char zidkey[ZID_KEY_MAX]; + + tzids = TimeZone::createEnumeration(); + const UnicodeString *tzid; + while ((tzid = tzids->snext(status))) { + if (U_FAILURE(status)) { + goto error_cleanup; + } + // We may skip aliases, because the bundle + // contains only canonical IDs. For now, try + // all of them. + tzid->extract(0, tzid->length(), zidkey, sizeof(zidkey), US_INV); + zidkey[sizeof(zidkey)-1] = 0; // NULL terminate just in case. + + // Replace '/' with ':' + UBool foundSep = FALSE; + char *p = zidkey; + while (*p) { + if (*p == '/') { + *p = ':'; + foundSep = TRUE; + } + p++; + } + if (!foundSep) { + // A valid time zone key has at least one separator + continue; + } + + zoneItem = ures_getByKey(zoneStringsArray, zidkey, zoneItem, &status); + useMZ = ures_getByKey(zoneItem, gUseMetazoneTag, useMZ, &status); + if (U_FAILURE(status)) { + status = U_ZERO_ERROR; + continue; + } + + UVector *mzMappings = NULL; + while (ures_hasNext(useMZ)) { + mz = ures_getNextResource(useMZ, mz, &status); + const UChar *mz_name = ures_getStringByIndex(mz, 0, NULL, &status); + const UChar *mz_from = ures_getStringByIndex(mz, 1, NULL, &status); + const UChar *mz_to = ures_getStringByIndex(mz, 2, NULL, &status); + + if(U_FAILURE(status)){ + status = U_ZERO_ERROR; + continue; + } + // We do not want to use SimpleDateformat to parse boundary dates, + // because this code could be triggered by the initialization code + // used by SimpleDateFormat. + UDate from = parseDate(mz_from, status); + UDate to = parseDate(mz_to, status); + if (U_FAILURE(status)) { + status = U_ZERO_ERROR; + continue; + } + + OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry)); + if (entry == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + break; + } + entry->mzid = mz_name; + entry->from = from; + entry->to = to; + + if (mzMappings == NULL) { + mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status); + if (U_FAILURE(status)) { + delete mzMappings; + deleteOlsonToMetaMappingEntry(entry); + uprv_free(entry); + break; + } + } + + mzMappings->addElement(entry, status); + if (U_FAILURE(status)) { + break; + } + } + + if (U_FAILURE(status)) { + if (mzMappings != NULL) { + delete mzMappings; + } + goto error_cleanup; + } + if (mzMappings != NULL) { + olsonToMeta->put(*tzid, mzMappings, status); + if (U_FAILURE(status)) { + delete mzMappings; + goto error_cleanup; + } + } + } + +normal_cleanup: + if (tzids != NULL) { + delete tzids; + } + ures_close(zoneItem); + ures_close(useMZ); + ures_close(mz); + ures_close(zoneStringsArray); + return olsonToMeta; + +error_cleanup: + if (olsonToMeta != NULL) { + delete olsonToMeta; + } + goto normal_cleanup; +} + +Hashtable* +ZoneMeta::createMetaToOlsonMap(void) { + UErrorCode status = U_ZERO_ERROR; + + Hashtable *metaToOlson = NULL; + UResourceBundle *metazones = NULL; + UResourceBundle *mz = NULL; + + metaToOlson = new Hashtable(uhash_compareUnicodeString, NULL, status); + if (U_FAILURE(status)) { + return NULL; + } + metaToOlson->setValueDeleter(deleteUVector); + + metazones = ures_openDirect(NULL, gSupplementalData, &status); + metazones = ures_getByKey(metazones, gMapTimezonesTag, metazones, &status); + metazones = ures_getByKey(metazones, gMetazonesTag, metazones, &status); + if (U_FAILURE(status)) { + goto error_cleanup; + } + + while (ures_hasNext(metazones)) { + mz = ures_getNextResource(metazones, mz, &status); + if (U_FAILURE(status)) { + status = U_ZERO_ERROR; + continue; + } + const char *mzkey = ures_getKey(mz); + if (uprv_strncmp(mzkey, gMetazoneIdPrefix, MZID_PREFIX_LEN) == 0) { + const char *mzid = mzkey + MZID_PREFIX_LEN; + const char *territory = uprv_strrchr(mzid, '_'); + int32_t mzidLen = 0; + int32_t territoryLen = 0; + if (territory) { + mzidLen = territory - mzid; + territory++; + territoryLen = uprv_strlen(territory); + } + if (mzidLen > 0 && territoryLen > 0) { + int32_t tzidLen; + const UChar *tzid = ures_getStringByIndex(mz, 0, &tzidLen, &status); + if (U_SUCCESS(status)) { + // Create MetaToOlsonMappingEntry + MetaToOlsonMappingEntry *entry = (MetaToOlsonMappingEntry*)uprv_malloc(sizeof(MetaToOlsonMappingEntry)); + if (entry == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + goto error_cleanup; + } + entry->id = tzid; + entry->territory = (UChar*)uprv_malloc((territoryLen + 1) * sizeof(UChar)); + if (entry->territory == NULL) { + status = U_MEMORY_ALLOCATION_ERROR; + uprv_free(entry); + goto error_cleanup; + } + u_charsToUChars(territory, entry->territory, territoryLen + 1); + + // Check if mapping entries for metazone is already available + UnicodeString mzidStr(mzid, mzidLen, US_INV); + UVector *tzMappings = (UVector*)metaToOlson->get(mzidStr); + if (tzMappings == NULL) { + // Create new UVector and put it into the hashtable + tzMappings = new UVector(deleteMetaToOlsonMappingEntry, NULL, status); + metaToOlson->put(mzidStr, tzMappings, status); + if (U_FAILURE(status)) { + if (tzMappings != NULL) { + delete tzMappings; + } + deleteMetaToOlsonMappingEntry(entry); + goto error_cleanup; + } + } + tzMappings->addElement(entry, status); + if (U_FAILURE(status)) { + goto error_cleanup; + } + } else { + status = U_ZERO_ERROR; + } + } + } + } + +normal_cleanup: + ures_close(mz); + ures_close(metazones); + return metaToOlson; + +error_cleanup: + if (metaToOlson != NULL) { + delete metaToOlson; + } + goto normal_cleanup; +} + +UnicodeString& +ZoneMeta::getCanonicalID(const UnicodeString &tzid, UnicodeString &canonicalID) { + const CanonicalMapEntry *entry = getCanonicalInfo(tzid); + if (entry != NULL) { + canonicalID.setTo(entry->id); + } else { + // Use the input tzid + canonicalID.setTo(tzid); + } + return canonicalID; +} + +UnicodeString& +ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) { + const CanonicalMapEntry *entry = getCanonicalInfo(tzid); + if (entry != NULL && entry->country != NULL) { + canonicalCountry.setTo(entry->country); + } else { + // Use the input tzid + canonicalCountry.remove(); + } + return canonicalCountry; +} + +const CanonicalMapEntry* +ZoneMeta::getCanonicalInfo(const UnicodeString &tzid) { + initialize(); + CanonicalMapEntry *entry = NULL; + UnicodeString canonicalOlsonId; + TimeZone::getOlsonCanonicalID(tzid, canonicalOlsonId); + if (!canonicalOlsonId.isEmpty()) { + if (gCanonicalMap != NULL) { + entry = (CanonicalMapEntry*)gCanonicalMap->get(tzid); + } + } + return entry; +} + +UnicodeString& +ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) { + UErrorCode status = U_ZERO_ERROR; + + // Get canonical country for the zone + getCanonicalCountry(tzid, country); + + if (!country.isEmpty()) { + UResourceBundle *supplementalDataBundle = ures_openDirect(NULL, gSupplementalData, &status); + UResourceBundle *zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status); + UResourceBundle *multizone = ures_getByKey(zoneFormatting, gMultizoneTag, NULL, &status); + + if (U_SUCCESS(status)) { + while (ures_hasNext(multizone)) { + int32_t len; + const UChar* multizoneCountry = ures_getNextString(multizone, &len, NULL, &status); + if (country.compare(multizoneCountry, len) == 0) { + // Included in the multizone country list + country.remove(); + break; + } + } + } + + ures_close(multizone); + ures_close(zoneFormatting); + ures_close(supplementalDataBundle); + } + + return country; +} + +UnicodeString& +ZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result) { + UBool isSet = FALSE; + const UVector *mappings = getMetazoneMappings(tzid); + if (mappings != NULL) { + for (int32_t i = 0; i < mappings->size(); i++) { + OlsonToMetaMappingEntry *mzm = (OlsonToMetaMappingEntry*)mappings->elementAt(i); + if (mzm->from <= date && mzm->to > date) { + result.setTo(mzm->mzid, -1); + isSet = TRUE; + break; + } + } + } + if (!isSet) { + result.remove(); + } + return result; +} + +const UVector* +ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) { + initialize(); + const UVector *result = NULL; + if (gOlsonToMeta != NULL) { + result = (UVector*)gOlsonToMeta->get(tzid); + } + return result; +} + +UnicodeString& +ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString ®ion, UnicodeString &result) { + initialize(); + UBool isSet = FALSE; + if (gMetaToOlson != NULL) { + UVector *mappings = (UVector*)gMetaToOlson->get(mzid); + if (mappings != NULL) { + // Find a preferred time zone for the given region. + for (int32_t i = 0; i < mappings->size(); i++) { + MetaToOlsonMappingEntry *olsonmap = (MetaToOlsonMappingEntry*)mappings->elementAt(i); + if (region.compare(olsonmap->territory, -1) == 0) { + result.setTo(olsonmap->id); + isSet = TRUE; + break; + } else if (u_strcmp(olsonmap->territory, gWorld) == 0) { + result.setTo(olsonmap->id); + isSet = TRUE; + } + } + } + } + if (!isSet) { + result.remove(); + } + return result; +} + + +U_NAMESPACE_END + +#endif /* #if !UCONFIG_NO_FORMATTING */ |