LCOV - code coverage report
Current view: top level - intl/icu/source/i18n - timezone.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 783 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 67 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // © 2016 and later: Unicode, Inc. and others.
       2             : // License & terms of use: http://www.unicode.org/copyright.html
       3             : /*
       4             : *******************************************************************************
       5             : * Copyright (C) 1997-2016, International Business Machines Corporation and
       6             : * others. All Rights Reserved.
       7             : *******************************************************************************
       8             : *
       9             : * File TIMEZONE.CPP
      10             : *
      11             : * Modification History:
      12             : *
      13             : *   Date        Name        Description
      14             : *   12/05/96    clhuang     Creation.
      15             : *   04/21/97    aliu        General clean-up and bug fixing.
      16             : *   05/08/97    aliu        Fixed Hashtable code per code review.
      17             : *   07/09/97    helena      Changed createInstance to createDefault.
      18             : *   07/29/97    aliu        Updated with all-new list of 96 UNIX-derived
      19             : *                           TimeZones.  Changed mechanism to load from static
      20             : *                           array rather than resource bundle.
      21             : *   07/07/1998  srl         Bugfixes from the Java side: UTC GMT CAT NST
      22             : *                           Added getDisplayName API
      23             : *                           going to add custom parsing.
      24             : *
      25             : *                           ISSUES:
      26             : *                               - should getDisplayName cache something?
      27             : *                               - should custom time zones be cached? [probably]
      28             : *  08/10/98     stephen     Brought getDisplayName() API in-line w/ conventions
      29             : *  08/19/98     stephen     Changed createTimeZone() to never return 0
      30             : *  09/02/98     stephen     Added getOffset(monthLen) and hasSameRules()
      31             : *  09/15/98     stephen     Added getStaticClassID()
      32             : *  02/22/99     stephen     Removed character literals for EBCDIC safety
      33             : *  05/04/99     stephen     Changed initDefault() for Mutex issues
      34             : *  07/12/99     helena      HPUX 11 CC Port.
      35             : *  12/03/99     aliu        Moved data out of static table into icudata.dll.
      36             : *                           Substantial rewrite of zone lookup, default zone, and
      37             : *                           available IDs code.  Misc. cleanup.
      38             : *********************************************************************************/
      39             : 
      40             : #include "utypeinfo.h"  // for 'typeid' to work
      41             : 
      42             : #include "unicode/utypes.h"
      43             : #include "unicode/ustring.h"
      44             : #include "uassert.h"
      45             : #include "ustr_imp.h"
      46             : 
      47             : #ifdef U_DEBUG_TZ
      48             : # include <stdio.h>
      49             : # include "uresimp.h" // for debugging
      50             : 
      51             : static void debug_tz_loc(const char *f, int32_t l)
      52             : {
      53             :   fprintf(stderr, "%s:%d: ", f, l);
      54             : }
      55             : 
      56             : static void debug_tz_msg(const char *pat, ...)
      57             : {
      58             :   va_list ap;
      59             :   va_start(ap, pat);
      60             :   vfprintf(stderr, pat, ap);
      61             :   fflush(stderr);
      62             : }
      63             : static char gStrBuf[256];
      64             : #define U_DEBUG_TZ_STR(x) u_austrncpy(gStrBuf,x,sizeof(gStrBuf)-1)
      65             : // must use double parens, i.e.:  U_DEBUG_TZ_MSG(("four is: %d",4));
      66             : #define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__,__LINE__);debug_tz_msg x;}
      67             : #else
      68             : #define U_DEBUG_TZ_MSG(x)
      69             : #endif
      70             : 
      71             : #if !UCONFIG_NO_FORMATTING
      72             : 
      73             : #include "unicode/simpletz.h"
      74             : #include "unicode/calendar.h"
      75             : #include "unicode/gregocal.h"
      76             : #include "unicode/ures.h"
      77             : #include "unicode/tzfmt.h"
      78             : #include "unicode/numfmt.h"
      79             : #include "gregoimp.h"
      80             : #include "uresimp.h" // struct UResourceBundle
      81             : #include "olsontz.h"
      82             : #include "mutex.h"
      83             : #include "unicode/udata.h"
      84             : #include "ucln_in.h"
      85             : #include "cstring.h"
      86             : #include "cmemory.h"
      87             : #include "unicode/strenum.h"
      88             : #include "uassert.h"
      89             : #include "zonemeta.h"
      90             : 
      91             : #define kZONEINFO "zoneinfo64"
      92             : #define kREGIONS  "Regions"
      93             : #define kZONES    "Zones"
      94             : #define kRULES    "Rules"
      95             : #define kNAMES    "Names"
      96             : #define kTZVERSION  "TZVersion"
      97             : #define kLINKS    "links"
      98             : #define kMAX_CUSTOM_HOUR    23
      99             : #define kMAX_CUSTOM_MIN     59
     100             : #define kMAX_CUSTOM_SEC     59
     101             : #define MINUS 0x002D
     102             : #define PLUS 0x002B
     103             : #define ZERO_DIGIT 0x0030
     104             : #define COLON 0x003A
     105             : 
     106             : // Static data and constants
     107             : 
     108             : static const UChar         WORLD[] = {0x30, 0x30, 0x31, 0x00}; /* "001" */
     109             : 
     110             : static const UChar         GMT_ID[] = {0x47, 0x4D, 0x54, 0x00}; /* "GMT" */
     111             : static const UChar         UNKNOWN_ZONE_ID[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00}; /* "Etc/Unknown" */
     112             : static const int32_t       GMT_ID_LENGTH = 3;
     113             : static const int32_t       UNKNOWN_ZONE_ID_LENGTH = 11;
     114             : 
     115             : static icu::TimeZone* DEFAULT_ZONE = NULL;
     116             : static icu::UInitOnce gDefaultZoneInitOnce = U_INITONCE_INITIALIZER;
     117             : 
     118             : // Prevents DEFAULT_ZONE from being deleted while another thread is cloning it.
     119             : static UMutex gDefaultZoneMutex = U_MUTEX_INITIALIZER;
     120             : 
     121             : static icu::TimeZone* _GMT = NULL;
     122             : static icu::TimeZone* _UNKNOWN_ZONE = NULL;
     123             : static icu::UInitOnce gStaticZonesInitOnce = U_INITONCE_INITIALIZER;
     124             : 
     125             : static char TZDATA_VERSION[16];
     126             : static icu::UInitOnce gTZDataVersionInitOnce = U_INITONCE_INITIALIZER;
     127             : 
     128             : static int32_t* MAP_SYSTEM_ZONES = NULL;
     129             : static int32_t* MAP_CANONICAL_SYSTEM_ZONES = NULL;
     130             : static int32_t* MAP_CANONICAL_SYSTEM_LOCATION_ZONES = NULL;
     131             : 
     132             : static int32_t LEN_SYSTEM_ZONES = 0;
     133             : static int32_t LEN_CANONICAL_SYSTEM_ZONES = 0;
     134             : static int32_t LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
     135             : 
     136             : static icu::UInitOnce gSystemZonesInitOnce = U_INITONCE_INITIALIZER;
     137             : static icu::UInitOnce gCanonicalZonesInitOnce = U_INITONCE_INITIALIZER;
     138             : static icu::UInitOnce gCanonicalLocationZonesInitOnce = U_INITONCE_INITIALIZER;
     139             : 
     140             : U_CDECL_BEGIN
     141           0 : static UBool U_CALLCONV timeZone_cleanup(void)
     142             : {
     143             :     U_NAMESPACE_USE
     144           0 :     delete DEFAULT_ZONE;
     145           0 :     DEFAULT_ZONE = NULL;
     146           0 :     gDefaultZoneInitOnce.reset();
     147             : 
     148           0 :     delete _GMT;
     149           0 :     _GMT = NULL;
     150           0 :     delete _UNKNOWN_ZONE;
     151           0 :     _UNKNOWN_ZONE = NULL;
     152           0 :     gStaticZonesInitOnce.reset();
     153             : 
     154           0 :     uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION));
     155           0 :     gTZDataVersionInitOnce.reset();
     156             : 
     157           0 :     LEN_SYSTEM_ZONES = 0;
     158           0 :     uprv_free(MAP_SYSTEM_ZONES);
     159           0 :     MAP_SYSTEM_ZONES = 0;
     160           0 :     gSystemZonesInitOnce.reset();
     161             : 
     162           0 :     LEN_CANONICAL_SYSTEM_ZONES = 0;
     163           0 :     uprv_free(MAP_CANONICAL_SYSTEM_ZONES);
     164           0 :     MAP_CANONICAL_SYSTEM_ZONES = 0;
     165           0 :     gCanonicalZonesInitOnce.reset();
     166             : 
     167           0 :     LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
     168           0 :     uprv_free(MAP_CANONICAL_SYSTEM_LOCATION_ZONES);
     169           0 :     MAP_CANONICAL_SYSTEM_LOCATION_ZONES = 0;
     170           0 :     gCanonicalLocationZonesInitOnce.reset();
     171             : 
     172           0 :     return TRUE;
     173             : }
     174             : U_CDECL_END
     175             : 
     176             : U_NAMESPACE_BEGIN
     177             : 
     178           0 : static int32_t findInStringArray(UResourceBundle* array, const UnicodeString& id, UErrorCode &status)
     179             : {
     180           0 :     UnicodeString copy;
     181             :     const UChar *u;
     182             :     int32_t len;
     183             : 
     184           0 :     int32_t start = 0;
     185           0 :     int32_t limit = ures_getSize(array);
     186             :     int32_t mid;
     187           0 :     int32_t lastMid = INT32_MAX;
     188           0 :     if(U_FAILURE(status) || (limit < 1)) {
     189           0 :         return -1;
     190             :     }
     191             :     U_DEBUG_TZ_MSG(("fisa: Looking for %s, between %d and %d\n", U_DEBUG_TZ_STR(UnicodeString(id).getTerminatedBuffer()), start, limit));
     192             : 
     193             :     for (;;) {
     194           0 :         mid = (int32_t)((start + limit) / 2);
     195           0 :         if (lastMid == mid) {   /* Have we moved? */
     196           0 :             break;  /* We haven't moved, and it wasn't found. */
     197             :         }
     198           0 :         lastMid = mid;
     199           0 :         u = ures_getStringByIndex(array, mid, &len, &status);
     200           0 :         if (U_FAILURE(status)) {
     201           0 :             break;
     202             :         }
     203             :         U_DEBUG_TZ_MSG(("tz: compare to %s, %d .. [%d] .. %d\n", U_DEBUG_TZ_STR(u), start, mid, limit));
     204           0 :         copy.setTo(TRUE, u, len);
     205           0 :         int r = id.compare(copy);
     206           0 :         if(r==0) {
     207             :             U_DEBUG_TZ_MSG(("fisa: found at %d\n", mid));
     208           0 :             return mid;
     209           0 :         } else if(r<0) {
     210           0 :             limit = mid;
     211             :         } else {
     212           0 :             start = mid;
     213             :         }
     214           0 :     }
     215             :     U_DEBUG_TZ_MSG(("fisa: not found\n"));
     216           0 :     return -1;
     217             : }
     218             : 
     219             : /**
     220             :  * Fetch a specific zone by name.  Replaces the getByKey call.
     221             :  * @param top Top timezone resource
     222             :  * @param id Time zone ID
     223             :  * @param oldbundle Bundle for reuse (or NULL).   see 'ures_open()'
     224             :  * @return the zone's bundle if found, or undefined if error.  Reuses oldbundle.
     225             :  */
     226           0 : static UResourceBundle* getZoneByName(const UResourceBundle* top, const UnicodeString& id, UResourceBundle *oldbundle, UErrorCode& status) {
     227             :     // load the Rules object
     228           0 :     UResourceBundle *tmp = ures_getByKey(top, kNAMES, NULL, &status);
     229             : 
     230             :     // search for the string
     231           0 :     int32_t idx = findInStringArray(tmp, id, status);
     232             : 
     233           0 :     if((idx == -1) && U_SUCCESS(status)) {
     234             :         // not found
     235           0 :         status = U_MISSING_RESOURCE_ERROR;
     236             :         //ures_close(oldbundle);
     237             :         //oldbundle = NULL;
     238             :     } else {
     239             :         U_DEBUG_TZ_MSG(("gzbn: oldbundle= size %d, type %d, %s\n", ures_getSize(tmp), ures_getType(tmp), u_errorName(status)));
     240           0 :         tmp = ures_getByKey(top, kZONES, tmp, &status); // get Zones object from top
     241             :         U_DEBUG_TZ_MSG(("gzbn: loaded ZONES, size %d, type %d, path %s %s\n", ures_getSize(tmp), ures_getType(tmp), ures_getPath(tmp), u_errorName(status)));
     242           0 :         oldbundle = ures_getByIndex(tmp, idx, oldbundle, &status); // get nth Zone object
     243             :         U_DEBUG_TZ_MSG(("gzbn: loaded z#%d, size %d, type %d, path %s, %s\n", idx, ures_getSize(oldbundle), ures_getType(oldbundle), ures_getPath(oldbundle),  u_errorName(status)));
     244             :     }
     245           0 :     ures_close(tmp);
     246           0 :     if(U_FAILURE(status)) {
     247             :         //ures_close(oldbundle);
     248           0 :         return NULL;
     249             :     } else {
     250           0 :         return oldbundle;
     251             :     }
     252             : }
     253             : 
     254             : 
     255           0 : UResourceBundle* TimeZone::loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode& status) {
     256             :     char key[64];
     257           0 :     ruleid.extract(0, sizeof(key)-1, key, (int32_t)sizeof(key)-1, US_INV);
     258             :     U_DEBUG_TZ_MSG(("loadRule(%s)\n", key));
     259           0 :     UResourceBundle *r = ures_getByKey(top, kRULES, oldbundle, &status);
     260             :     U_DEBUG_TZ_MSG(("loadRule(%s) -> kRULES [%s]\n", key, u_errorName(status)));
     261           0 :     r = ures_getByKey(r, key, r, &status);
     262             :     U_DEBUG_TZ_MSG(("loadRule(%s) -> item [%s]\n", key, u_errorName(status)));
     263           0 :     return r;
     264             : }
     265             : 
     266             : /**
     267             :  * Given an ID, open the appropriate resource for the given time zone.
     268             :  * Dereference aliases if necessary.
     269             :  * @param id zone id
     270             :  * @param res resource, which must be ready for use (initialized but not open)
     271             :  * @param ec input-output error code
     272             :  * @return top-level resource bundle
     273             :  */
     274           0 : static UResourceBundle* openOlsonResource(const UnicodeString& id,
     275             :                                           UResourceBundle& res,
     276             :                                           UErrorCode& ec)
     277             : {
     278             : #if U_DEBUG_TZ
     279             :     char buf[128];
     280             :     id.extract(0, sizeof(buf)-1, buf, sizeof(buf), "");
     281             : #endif
     282           0 :     UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
     283             :     U_DEBUG_TZ_MSG(("pre: res sz=%d\n", ures_getSize(&res)));
     284           0 :     /* &res = */ getZoneByName(top, id, &res, ec);
     285             :     // Dereference if this is an alias.  Docs say result should be 1
     286             :     // but it is 0 in 2.8 (?).
     287             :     U_DEBUG_TZ_MSG(("Loading zone '%s' (%s, size %d) - %s\n", buf, ures_getKey((UResourceBundle*)&res), ures_getSize(&res), u_errorName(ec)));
     288           0 :     if (ures_getType(&res) == URES_INT) {
     289           0 :         int32_t deref = ures_getInt(&res, &ec) + 0;
     290             :         U_DEBUG_TZ_MSG(("getInt: %s - type is %d\n", u_errorName(ec), ures_getType(&res)));
     291           0 :         UResourceBundle *ares = ures_getByKey(top, kZONES, NULL, &ec); // dereference Zones section
     292           0 :         ures_getByIndex(ares, deref, &res, &ec);
     293           0 :         ures_close(ares);
     294             :         U_DEBUG_TZ_MSG(("alias to #%d (%s) - %s\n", deref, "??", u_errorName(ec)));
     295             :     } else {
     296             :         U_DEBUG_TZ_MSG(("not an alias - size %d\n", ures_getSize(&res)));
     297             :     }
     298             :     U_DEBUG_TZ_MSG(("%s - final status is %s\n", buf, u_errorName(ec)));
     299           0 :     return top;
     300             : }
     301             : 
     302             : // -------------------------------------
     303             : 
     304             : namespace {
     305             : 
     306           0 : void U_CALLCONV initStaticTimeZones() {
     307             :     // Initialize _GMT independently of other static data; it should
     308             :     // be valid even if we can't load the time zone UDataMemory.
     309           0 :     ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
     310           0 :     _UNKNOWN_ZONE = new SimpleTimeZone(0, UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH));
     311           0 :     _GMT = new SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH));
     312           0 : }
     313             : 
     314             : }  // anonymous namespace
     315             : 
     316             : const TimeZone& U_EXPORT2
     317           0 : TimeZone::getUnknown()
     318             : {
     319           0 :     umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones);
     320           0 :     return *_UNKNOWN_ZONE;
     321             : }
     322             : 
     323             : const TimeZone* U_EXPORT2
     324           0 : TimeZone::getGMT(void)
     325             : {
     326           0 :     umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones);
     327           0 :     return _GMT;
     328             : }
     329             : 
     330             : // *****************************************************************************
     331             : // class TimeZone
     332             : // *****************************************************************************
     333             : 
     334           0 : UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(TimeZone)
     335             : 
     336           0 : TimeZone::TimeZone()
     337           0 :     :   UObject(), fID()
     338             : {
     339           0 : }
     340             : 
     341             : // -------------------------------------
     342             : 
     343           0 : TimeZone::TimeZone(const UnicodeString &id)
     344           0 :     :   UObject(), fID(id)
     345             : {
     346           0 : }
     347             : 
     348             : // -------------------------------------
     349             : 
     350           0 : TimeZone::~TimeZone()
     351             : {
     352           0 : }
     353             : 
     354             : // -------------------------------------
     355             : 
     356           0 : TimeZone::TimeZone(const TimeZone &source)
     357           0 :     :   UObject(source), fID(source.fID)
     358             : {
     359           0 : }
     360             : 
     361             : // -------------------------------------
     362             : 
     363             : TimeZone &
     364           0 : TimeZone::operator=(const TimeZone &right)
     365             : {
     366           0 :     if (this != &right) fID = right.fID;
     367           0 :     return *this;
     368             : }
     369             : 
     370             : // -------------------------------------
     371             : 
     372             : UBool
     373           0 : TimeZone::operator==(const TimeZone& that) const
     374             : {
     375           0 :     return typeid(*this) == typeid(that) &&
     376           0 :         fID == that.fID;
     377             : }
     378             : 
     379             : // -------------------------------------
     380             : 
     381             : namespace {
     382             : TimeZone*
     383           0 : createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) {
     384           0 :     if (U_FAILURE(ec)) {
     385           0 :         return NULL;
     386             :     }
     387           0 :     TimeZone* z = 0;
     388             :     UResourceBundle res;
     389           0 :     ures_initStackObject(&res);
     390             :     U_DEBUG_TZ_MSG(("pre-err=%s\n", u_errorName(ec)));
     391           0 :     UResourceBundle *top = openOlsonResource(id, res, ec);
     392             :     U_DEBUG_TZ_MSG(("post-err=%s\n", u_errorName(ec)));
     393           0 :     if (U_SUCCESS(ec)) {
     394           0 :         z = new OlsonTimeZone(top, &res, id, ec);
     395             :         if (z == NULL) {
     396             :           U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec)));
     397             :         }
     398             :     }
     399           0 :     ures_close(&res);
     400           0 :     ures_close(top);
     401           0 :     if (U_FAILURE(ec)) {
     402             :         U_DEBUG_TZ_MSG(("cstz: failed to create, err %s\n", u_errorName(ec)));
     403           0 :         delete z;
     404           0 :         z = 0;
     405             :     }
     406           0 :     return z;
     407             : }
     408             : 
     409             : /**
     410             :  * Lookup the given name in our system zone table.  If found,
     411             :  * instantiate a new zone of that name and return it.  If not
     412             :  * found, return 0.
     413             :  */
     414             : TimeZone*
     415           0 : createSystemTimeZone(const UnicodeString& id) {
     416           0 :     UErrorCode ec = U_ZERO_ERROR;
     417           0 :     return createSystemTimeZone(id, ec);
     418             : }
     419             : 
     420             : }
     421             : 
     422             : TimeZone* U_EXPORT2
     423           0 : TimeZone::createTimeZone(const UnicodeString& ID)
     424             : {
     425             :     /* We first try to lookup the zone ID in our system list.  If this
     426             :      * fails, we try to parse it as a custom string GMT[+-]hh:mm.  If
     427             :      * all else fails, we return GMT, which is probably not what the
     428             :      * user wants, but at least is a functioning TimeZone object.
     429             :      *
     430             :      * We cannot return NULL, because that would break compatibility
     431             :      * with the JDK.
     432             :      */
     433           0 :     TimeZone* result = createSystemTimeZone(ID);
     434             : 
     435           0 :     if (result == NULL) {
     436             :         U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom"));
     437           0 :         result = createCustomTimeZone(ID);
     438             :     }
     439           0 :     if (result == NULL) {
     440             :         U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)"));
     441           0 :         const TimeZone& unknown = getUnknown();
     442           0 :         if (_UNKNOWN_ZONE == NULL) {                   // Cannot test (&unknown == NULL) because the
     443             :           U_DEBUG_TZ_MSG(("failed to getUnknown()"));  // behavior of NULL references is undefined.
     444             :         } else {
     445           0 :           result = unknown.clone();
     446             :         }
     447             :     }
     448           0 :     return result;
     449             : }
     450             : 
     451             : // -------------------------------------
     452             : 
     453             : TimeZone* U_EXPORT2
     454           0 : TimeZone::detectHostTimeZone()
     455             : {
     456             :     // We access system timezone data through TPlatformUtilities,
     457             :     // including tzset(), timezone, and tzname[].
     458           0 :     int32_t rawOffset = 0;
     459             :     const char *hostID;
     460             : 
     461             :     // First, try to create a system timezone, based
     462             :     // on the string ID in tzname[0].
     463             : 
     464           0 :     uprv_tzset(); // Initialize tz... system data
     465             : 
     466           0 :     uprv_tzname_clear_cache();
     467             : 
     468             :     // Get the timezone ID from the host.  This function should do
     469             :     // any required host-specific remapping; e.g., on Windows this
     470             :     // function maps the Date and Time control panel setting to an
     471             :     // ICU timezone ID.
     472           0 :     hostID = uprv_tzname(0);
     473             : 
     474             :     // Invert sign because UNIX semantics are backwards
     475           0 :     rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND;
     476             : 
     477           0 :     TimeZone* hostZone = NULL;
     478             : 
     479             :     /* Make sure that the string is NULL terminated to prevent BoundsChecker/Purify warnings. */
     480           0 :     UnicodeString hostStrID(hostID, -1, US_INV);
     481           0 :     hostStrID.append((UChar)0);
     482           0 :     hostStrID.truncate(hostStrID.length()-1);
     483           0 :     hostZone = createSystemTimeZone(hostStrID);
     484             : 
     485             : #if U_PLATFORM_USES_ONLY_WIN32_API
     486             :     // hostID points to a heap-allocated location on Windows.
     487             :     uprv_free(const_cast<char *>(hostID));
     488             : #endif
     489             : 
     490           0 :     int32_t hostIDLen = hostStrID.length();
     491           0 :     if (hostZone != NULL && rawOffset != hostZone->getRawOffset()
     492           0 :         && (3 <= hostIDLen && hostIDLen <= 4))
     493             :     {
     494             :         // Uh oh. This probably wasn't a good id.
     495             :         // It was probably an ambiguous abbreviation
     496           0 :         delete hostZone;
     497           0 :         hostZone = NULL;
     498             :     }
     499             : 
     500             :     // Construct a fixed standard zone with the host's ID
     501             :     // and raw offset.
     502           0 :     if (hostZone == NULL) {
     503           0 :         hostZone = new SimpleTimeZone(rawOffset, hostStrID);
     504             :     }
     505             : 
     506             :     // If we _still_ don't have a time zone, use GMT.
     507             :     //
     508             :     // Note: This is extremely unlikely situation. If
     509             :     // new SimpleTimeZone(...) above fails, the following
     510             :     // code may also fail.
     511           0 :     if (hostZone == NULL) {
     512           0 :         const TimeZone* temptz = TimeZone::getGMT();
     513             :         // If we can't use GMT, get out.
     514           0 :         if (temptz == NULL) {
     515           0 :             return NULL;
     516             :         }
     517           0 :         hostZone = temptz->clone();
     518             :     }
     519             : 
     520           0 :     return hostZone;
     521             : }
     522             : 
     523             : // -------------------------------------
     524             : 
     525             : /**
     526             :  * Initialize DEFAULT_ZONE from the system default time zone.  
     527             :  * Upon return, DEFAULT_ZONE will not be NULL, unless operator new()
     528             :  * returns NULL.
     529             :  */
     530           0 : static void U_CALLCONV initDefault()
     531             : {
     532           0 :     ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
     533             : 
     534             :     // If setDefault() has already been called we can skip getting the
     535             :     // default zone information from the system.
     536           0 :     if (DEFAULT_ZONE != NULL) {
     537           0 :         return;
     538             :     }
     539             :     
     540             :     // NOTE:  this code is safely single threaded, being only
     541             :     // run via umtx_initOnce().
     542             :     //
     543             :     // Some of the locale/timezone OS functions may not be thread safe,
     544             :     //
     545             :     // The operating system might actually use ICU to implement timezones.
     546             :     // So we may have ICU calling ICU here, like on AIX.
     547             :     // There shouldn't be a problem with this; initOnce does not hold a mutex
     548             :     // while the init function is being run.
     549             : 
     550             :     // The code detecting the host time zone was separated from this
     551             :     // and implemented as TimeZone::detectHostTimeZone()
     552             : 
     553           0 :     TimeZone *default_zone = TimeZone::detectHostTimeZone();
     554             : 
     555             :     // The only way for DEFAULT_ZONE to be non-null at this point is if the user
     556             :     // made a thread-unsafe call to setDefault() or adoptDefault() in another
     557             :     // thread while this thread was doing something that required getting the default.
     558           0 :     U_ASSERT(DEFAULT_ZONE == NULL);
     559             : 
     560           0 :     DEFAULT_ZONE = default_zone;
     561             : }
     562             : 
     563             : // -------------------------------------
     564             : 
     565             : TimeZone* U_EXPORT2
     566           0 : TimeZone::createDefault()
     567             : {
     568           0 :     umtx_initOnce(gDefaultZoneInitOnce, initDefault);
     569             : 
     570           0 :     Mutex mutex_lock(&gDefaultZoneMutex);
     571           0 :     return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL;
     572             : }
     573             : 
     574             : void
     575           0 : TimeZone::recreateDefault()
     576             : {
     577           0 :     TimeZone *default_zone = TimeZone::detectHostTimeZone();
     578           0 :     adoptDefault(default_zone);
     579           0 : }
     580             : 
     581             : // -------------------------------------
     582             : 
     583             : void U_EXPORT2
     584           0 : TimeZone::adoptDefault(TimeZone* zone)
     585             : {
     586           0 :     if (zone != NULL)
     587             :     {
     588           0 :         Mutex mutex_lock(&gDefaultZoneMutex);
     589           0 :         TimeZone *old = DEFAULT_ZONE;
     590           0 :         DEFAULT_ZONE = zone;
     591           0 :         delete old;
     592           0 :         ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
     593             :     }
     594           0 : }
     595             : // -------------------------------------
     596             : 
     597             : void U_EXPORT2
     598           0 : TimeZone::setDefault(const TimeZone& zone)
     599             : {
     600           0 :     adoptDefault(zone.clone());
     601           0 : }
     602             : 
     603             : //----------------------------------------------------------------------
     604             : 
     605             : 
     606           0 : static void U_CALLCONV initMap(USystemTimeZoneType type, UErrorCode& ec) {
     607           0 :     ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
     608             : 
     609           0 :     UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
     610           0 :     res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section
     611           0 :     if (U_SUCCESS(ec)) {
     612           0 :         int32_t size = ures_getSize(res);
     613           0 :         int32_t *m = (int32_t *)uprv_malloc(size * sizeof(int32_t));
     614           0 :         if (m == NULL) {
     615           0 :             ec = U_MEMORY_ALLOCATION_ERROR;
     616             :         } else {
     617           0 :             int32_t numEntries = 0;
     618           0 :             for (int32_t i = 0; i < size; i++) {
     619           0 :                 UnicodeString id = ures_getUnicodeStringByIndex(res, i, &ec);
     620           0 :                 if (U_FAILURE(ec)) {
     621           0 :                     break;
     622             :                 }
     623           0 :                 if (0 == id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)) {
     624             :                     // exclude Etc/Unknown
     625           0 :                     continue;
     626             :                 }
     627           0 :                 if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
     628           0 :                     UnicodeString canonicalID;
     629           0 :                     ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec);
     630           0 :                     if (U_FAILURE(ec)) {
     631           0 :                         break;
     632             :                     }
     633           0 :                     if (canonicalID != id) {
     634             :                         // exclude aliases
     635           0 :                         continue;
     636             :                     }
     637             :                 }
     638           0 :                 if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
     639           0 :                     const UChar *region = TimeZone::getRegion(id, ec);
     640           0 :                     if (U_FAILURE(ec)) {
     641           0 :                         break;
     642             :                     }
     643           0 :                     if (u_strcmp(region, WORLD) == 0) {
     644             :                        // exclude non-location ("001")
     645           0 :                         continue;
     646             :                     }
     647             :                 }
     648           0 :                 m[numEntries++] = i;
     649             :             }
     650           0 :             if (U_SUCCESS(ec)) {
     651           0 :                 int32_t *tmp = m;
     652           0 :                 m = (int32_t *)uprv_realloc(tmp, numEntries * sizeof(int32_t));
     653           0 :                 if (m == NULL) {
     654             :                     // realloc failed.. use the original one even it has unused
     655             :                     // area at the end
     656           0 :                     m = tmp;
     657             :                 }
     658             : 
     659           0 :                 switch(type) {
     660             :                 case UCAL_ZONE_TYPE_ANY:
     661           0 :                     U_ASSERT(MAP_SYSTEM_ZONES == NULL);
     662           0 :                     MAP_SYSTEM_ZONES = m;
     663           0 :                     LEN_SYSTEM_ZONES = numEntries;
     664           0 :                     break;
     665             :                 case UCAL_ZONE_TYPE_CANONICAL:
     666           0 :                     U_ASSERT(MAP_CANONICAL_SYSTEM_ZONES == NULL);
     667           0 :                     MAP_CANONICAL_SYSTEM_ZONES = m;
     668           0 :                     LEN_CANONICAL_SYSTEM_ZONES = numEntries;
     669           0 :                     break;
     670             :                 case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
     671           0 :                     U_ASSERT(MAP_CANONICAL_SYSTEM_LOCATION_ZONES == NULL);
     672           0 :                     MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m;
     673           0 :                     LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries;
     674           0 :                     break;
     675             :                 }
     676             :             }
     677             :         }
     678             :     }
     679           0 :     ures_close(res);
     680           0 : }
     681             : 
     682             : 
     683             : /**
     684             :  * This is the default implementation for subclasses that do not
     685             :  * override this method.  This implementation calls through to the
     686             :  * 8-argument getOffset() method after suitable computations, and
     687             :  * correctly adjusts GMT millis to local millis when necessary.
     688             :  */
     689           0 : void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
     690             :                          int32_t& dstOffset, UErrorCode& ec) const {
     691           0 :     if (U_FAILURE(ec)) {
     692           0 :         return;
     693             :     }
     694             : 
     695           0 :     rawOffset = getRawOffset();
     696           0 :     if (!local) {
     697           0 :         date += rawOffset; // now in local standard millis
     698             :     }
     699             : 
     700             :     // When local == TRUE, date might not be in local standard
     701             :     // millis.  getOffset taking 7 parameters used here assume
     702             :     // the given time in day is local standard time.
     703             :     // At STD->DST transition, there is a range of time which
     704             :     // does not exist.  When 'date' is in this time range
     705             :     // (and local == TRUE), this method interprets the specified
     706             :     // local time as DST.  At DST->STD transition, there is a
     707             :     // range of time which occurs twice.  In this case, this
     708             :     // method interprets the specified local time as STD.
     709             :     // To support the behavior above, we need to call getOffset
     710             :     // (with 7 args) twice when local == true and DST is
     711             :     // detected in the initial call.
     712           0 :     for (int32_t pass=0; ; ++pass) {
     713             :         int32_t year, month, dom, dow;
     714           0 :         double day = uprv_floor(date / U_MILLIS_PER_DAY);
     715           0 :         int32_t millis = (int32_t) (date - day * U_MILLIS_PER_DAY);
     716             : 
     717           0 :         Grego::dayToFields(day, year, month, dom, dow);
     718             : 
     719           0 :         dstOffset = getOffset(GregorianCalendar::AD, year, month, dom,
     720             :                               (uint8_t) dow, millis,
     721           0 :                               Grego::monthLength(year, month),
     722           0 :                               ec) - rawOffset;
     723             : 
     724             :         // Recompute if local==TRUE, dstOffset!=0.
     725           0 :         if (pass!=0 || !local || dstOffset == 0) {
     726             :             break;
     727             :         }
     728             :         // adjust to local standard millis
     729           0 :         date -= dstOffset;
     730           0 :     }
     731             : }
     732             : 
     733             : // -------------------------------------
     734             : 
     735             : // New available IDs API as of ICU 2.4.  Uses StringEnumeration API.
     736             : 
     737             : class TZEnumeration : public StringEnumeration {
     738             : private:
     739             : 
     740             :     // Map into to zones.  Our results are zone[map[i]] for
     741             :     // i=0..len-1, where zone[i] is the i-th Olson zone.  If map==NULL
     742             :     // then our results are zone[i] for i=0..len-1.  Len will be zero
     743             :     // if the zone data could not be loaded.
     744             :     int32_t* map;
     745             :     int32_t* localMap;
     746             :     int32_t  len;
     747             :     int32_t  pos;
     748             : 
     749           0 :     TZEnumeration(int32_t* mapData, int32_t mapLen, UBool adoptMapData) : pos(0) {
     750           0 :         map = mapData;
     751           0 :         localMap = adoptMapData ? mapData : NULL;
     752           0 :         len = mapLen;
     753           0 :     }
     754             : 
     755           0 :     UBool getID(int32_t i) {
     756           0 :         UErrorCode ec = U_ZERO_ERROR;
     757           0 :         int32_t idLen = 0;
     758           0 :         const UChar* id = NULL;
     759           0 :         UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
     760           0 :         top = ures_getByKey(top, kNAMES, top, &ec); // dereference Zones section
     761           0 :         id = ures_getStringByIndex(top, i, &idLen, &ec);
     762           0 :         if(U_FAILURE(ec)) {
     763           0 :             unistr.truncate(0);
     764             :         }
     765             :         else {
     766           0 :             unistr.fastCopyFrom(UnicodeString(TRUE, id, idLen));
     767             :         }
     768           0 :         ures_close(top);
     769           0 :         return U_SUCCESS(ec);
     770             :     }
     771             : 
     772           0 :     static int32_t* getMap(USystemTimeZoneType type, int32_t& len, UErrorCode& ec) {
     773           0 :         len = 0;
     774           0 :         if (U_FAILURE(ec)) {
     775           0 :             return NULL;
     776             :         }
     777           0 :         int32_t* m = NULL;
     778           0 :         switch (type) {
     779             :         case UCAL_ZONE_TYPE_ANY:
     780           0 :             umtx_initOnce(gSystemZonesInitOnce, &initMap, type, ec);
     781           0 :             m = MAP_SYSTEM_ZONES;
     782           0 :             len = LEN_SYSTEM_ZONES;
     783           0 :             break;
     784             :         case UCAL_ZONE_TYPE_CANONICAL:
     785           0 :             umtx_initOnce(gCanonicalZonesInitOnce, &initMap, type, ec);
     786           0 :             m = MAP_CANONICAL_SYSTEM_ZONES;
     787           0 :             len = LEN_CANONICAL_SYSTEM_ZONES;
     788           0 :             break;
     789             :         case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
     790           0 :             umtx_initOnce(gCanonicalLocationZonesInitOnce, &initMap, type, ec);
     791           0 :             m = MAP_CANONICAL_SYSTEM_LOCATION_ZONES;
     792           0 :             len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES;
     793           0 :             break;
     794             :         default:
     795           0 :             ec = U_ILLEGAL_ARGUMENT_ERROR;
     796           0 :             m = NULL;
     797           0 :             len = 0;
     798           0 :             break;
     799             :         }
     800           0 :         return m;
     801             :     }
     802             : 
     803             : public:
     804             : 
     805             : #define DEFAULT_FILTERED_MAP_SIZE 8
     806             : #define MAP_INCREMENT_SIZE 8
     807             : 
     808           0 :     static TZEnumeration* create(USystemTimeZoneType type, const char* region, const int32_t* rawOffset, UErrorCode& ec) {
     809           0 :         if (U_FAILURE(ec)) {
     810           0 :             return NULL;
     811             :         }
     812             : 
     813             :         int32_t baseLen;
     814           0 :         int32_t *baseMap = getMap(type, baseLen, ec);
     815             : 
     816           0 :         if (U_FAILURE(ec)) {
     817           0 :             return NULL;
     818             :         }
     819             : 
     820             :         // If any additional conditions are available,
     821             :         // create instance local map filtered by the conditions.
     822             : 
     823           0 :         int32_t *filteredMap = NULL;
     824           0 :         int32_t numEntries = 0;
     825             : 
     826           0 :         if (region != NULL || rawOffset != NULL) {
     827           0 :             int32_t filteredMapSize = DEFAULT_FILTERED_MAP_SIZE;
     828           0 :             filteredMap = (int32_t *)uprv_malloc(filteredMapSize * sizeof(int32_t));
     829           0 :             if (filteredMap == NULL) {
     830           0 :                 ec = U_MEMORY_ALLOCATION_ERROR;
     831           0 :                 return NULL;
     832             :             }
     833             : 
     834             :             // Walk through the base map
     835           0 :             UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
     836           0 :             res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section
     837           0 :             for (int32_t i = 0; i < baseLen; i++) {
     838           0 :                 int32_t zidx = baseMap[i];
     839           0 :                 UnicodeString id = ures_getUnicodeStringByIndex(res, zidx, &ec);
     840           0 :                 if (U_FAILURE(ec)) {
     841           0 :                     break;
     842             :                 }
     843           0 :                 if (region != NULL) {
     844             :                     // Filter by region
     845             :                     char tzregion[4]; // max 3 letters + null term
     846           0 :                     TimeZone::getRegion(id, tzregion, sizeof(tzregion), ec);
     847           0 :                     if (U_FAILURE(ec)) {
     848           0 :                         break;
     849             :                     }
     850           0 :                     if (uprv_stricmp(tzregion, region) != 0) {
     851             :                         // region does not match
     852           0 :                         continue;
     853             :                     }
     854             :                 }
     855           0 :                 if (rawOffset != NULL) {
     856             :                     // Filter by raw offset
     857             :                     // Note: This is VERY inefficient
     858           0 :                     TimeZone *z = createSystemTimeZone(id, ec);
     859           0 :                     if (U_FAILURE(ec)) {
     860           0 :                         break;
     861             :                     }
     862           0 :                     int32_t tzoffset = z->getRawOffset();
     863           0 :                     delete z;
     864             : 
     865           0 :                     if (tzoffset != *rawOffset) {
     866           0 :                         continue;
     867             :                     }
     868             :                 }
     869             : 
     870           0 :                 if (filteredMapSize <= numEntries) {
     871           0 :                     filteredMapSize += MAP_INCREMENT_SIZE;
     872           0 :                     int32_t *tmp = (int32_t *)uprv_realloc(filteredMap, filteredMapSize * sizeof(int32_t));
     873           0 :                     if (tmp == NULL) {
     874           0 :                         ec = U_MEMORY_ALLOCATION_ERROR;
     875           0 :                         break;
     876             :                     } else {
     877           0 :                         filteredMap = tmp;
     878             :                     }
     879             :                 }
     880             : 
     881           0 :                 filteredMap[numEntries++] = zidx;
     882             :             }
     883             : 
     884           0 :             if (U_FAILURE(ec)) {
     885           0 :                 uprv_free(filteredMap);
     886           0 :                 filteredMap = NULL;
     887             :             }
     888             : 
     889           0 :             ures_close(res);
     890             :         }
     891             : 
     892           0 :         TZEnumeration *result = NULL;
     893           0 :         if (U_SUCCESS(ec)) {
     894             :             // Finally, create a new enumeration instance
     895           0 :             if (filteredMap == NULL) {
     896           0 :                 result = new TZEnumeration(baseMap, baseLen, FALSE);
     897             :             } else {
     898           0 :                 result = new TZEnumeration(filteredMap, numEntries, TRUE);
     899           0 :                 filteredMap = NULL;
     900             :             }
     901           0 :             if (result == NULL) {
     902           0 :                 ec = U_MEMORY_ALLOCATION_ERROR;
     903             :             }
     904             :         }
     905             : 
     906           0 :         if (filteredMap != NULL) {
     907           0 :             uprv_free(filteredMap);
     908             :         }
     909             : 
     910           0 :         return result;
     911             :     }
     912             : 
     913           0 :     TZEnumeration(const TZEnumeration &other) : StringEnumeration(), map(NULL), localMap(NULL), len(0), pos(0) {
     914           0 :         if (other.localMap != NULL) {
     915           0 :             localMap = (int32_t *)uprv_malloc(other.len * sizeof(int32_t));
     916           0 :             if (localMap != NULL) {
     917           0 :                 len = other.len;
     918           0 :                 uprv_memcpy(localMap, other.localMap, len * sizeof(int32_t));
     919           0 :                 pos = other.pos;
     920           0 :                 map = localMap;
     921             :             } else {
     922           0 :                 len = 0;
     923           0 :                 pos = 0;
     924           0 :                 map = NULL;
     925             :             }
     926             :         } else {
     927           0 :             map = other.map;
     928           0 :             localMap = NULL;
     929           0 :             len = other.len;
     930           0 :             pos = other.pos;
     931             :         }
     932           0 :     }
     933             : 
     934             :     virtual ~TZEnumeration();
     935             : 
     936           0 :     virtual StringEnumeration *clone() const {
     937           0 :         return new TZEnumeration(*this);
     938             :     }
     939             : 
     940           0 :     virtual int32_t count(UErrorCode& status) const {
     941           0 :         return U_FAILURE(status) ? 0 : len;
     942             :     }
     943             : 
     944           0 :     virtual const UnicodeString* snext(UErrorCode& status) {
     945           0 :         if (U_SUCCESS(status) && map != NULL && pos < len) {
     946           0 :             getID(map[pos]);
     947           0 :             ++pos;
     948           0 :             return &unistr;
     949             :         }
     950           0 :         return 0;
     951             :     }
     952             : 
     953           0 :     virtual void reset(UErrorCode& /*status*/) {
     954           0 :         pos = 0;
     955           0 :     }
     956             : 
     957             : public:
     958             :     static UClassID U_EXPORT2 getStaticClassID(void);
     959             :     virtual UClassID getDynamicClassID(void) const;
     960             : };
     961             : 
     962           0 : TZEnumeration::~TZEnumeration() {
     963           0 :     if (localMap != NULL) {
     964           0 :         uprv_free(localMap);
     965             :     }
     966           0 : }
     967             : 
     968           0 : UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TZEnumeration)
     969             : 
     970             : StringEnumeration* U_EXPORT2
     971           0 : TimeZone::createTimeZoneIDEnumeration(
     972             :             USystemTimeZoneType zoneType,
     973             :             const char* region,
     974             :             const int32_t* rawOffset,
     975             :             UErrorCode& ec) {
     976           0 :     return TZEnumeration::create(zoneType, region, rawOffset, ec);
     977             : }
     978             : 
     979             : StringEnumeration* U_EXPORT2
     980           0 : TimeZone::createEnumeration() {
     981           0 :     UErrorCode ec = U_ZERO_ERROR;
     982           0 :     return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, NULL, NULL, ec);
     983             : }
     984             : 
     985             : StringEnumeration* U_EXPORT2
     986           0 : TimeZone::createEnumeration(int32_t rawOffset) {
     987           0 :     UErrorCode ec = U_ZERO_ERROR;
     988           0 :     return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, NULL, &rawOffset, ec);
     989             : }
     990             : 
     991             : StringEnumeration* U_EXPORT2
     992           0 : TimeZone::createEnumeration(const char* country) {
     993           0 :     UErrorCode ec = U_ZERO_ERROR;
     994           0 :     return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, country, NULL, ec);
     995             : }
     996             : 
     997             : // ---------------------------------------
     998             : 
     999             : int32_t U_EXPORT2
    1000           0 : TimeZone::countEquivalentIDs(const UnicodeString& id) {
    1001           0 :     int32_t result = 0;
    1002           0 :     UErrorCode ec = U_ZERO_ERROR;
    1003             :     UResourceBundle res;
    1004           0 :     ures_initStackObject(&res);
    1005             :     U_DEBUG_TZ_MSG(("countEquivalentIDs..\n"));
    1006           0 :     UResourceBundle *top = openOlsonResource(id, res, ec);
    1007           0 :     if (U_SUCCESS(ec)) {
    1008             :         UResourceBundle r;
    1009           0 :         ures_initStackObject(&r);
    1010           0 :         ures_getByKey(&res, kLINKS, &r, &ec);
    1011           0 :         ures_getIntVector(&r, &result, &ec);
    1012           0 :         ures_close(&r);
    1013             :     }
    1014           0 :     ures_close(&res);
    1015           0 :     ures_close(top);
    1016           0 :     return result;
    1017             : }
    1018             : 
    1019             : // ---------------------------------------
    1020             : 
    1021             : const UnicodeString U_EXPORT2
    1022           0 : TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
    1023             :     U_DEBUG_TZ_MSG(("gEI(%d)\n", index));
    1024           0 :     UnicodeString result;
    1025           0 :     UErrorCode ec = U_ZERO_ERROR;
    1026             :     UResourceBundle res;
    1027           0 :     ures_initStackObject(&res);
    1028           0 :     UResourceBundle *top = openOlsonResource(id, res, ec);
    1029           0 :     int32_t zone = -1;
    1030           0 :     if (U_SUCCESS(ec)) {
    1031             :         UResourceBundle r;
    1032           0 :         ures_initStackObject(&r);
    1033             :         int32_t size;
    1034           0 :         ures_getByKey(&res, kLINKS, &r, &ec);
    1035           0 :         const int32_t* v = ures_getIntVector(&r, &size, &ec);
    1036           0 :         if (U_SUCCESS(ec)) {
    1037           0 :             if (index >= 0 && index < size) {
    1038           0 :                 zone = v[index];
    1039             :             }
    1040             :         }
    1041           0 :         ures_close(&r);
    1042             :     }
    1043           0 :     ures_close(&res);
    1044           0 :     if (zone >= 0) {
    1045           0 :         UResourceBundle *ares = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Zones section
    1046           0 :         if (U_SUCCESS(ec)) {
    1047           0 :             int32_t idLen = 0;
    1048           0 :             const UChar* id = ures_getStringByIndex(ares, zone, &idLen, &ec);
    1049           0 :             result.fastCopyFrom(UnicodeString(TRUE, id, idLen));
    1050             :             U_DEBUG_TZ_MSG(("gei(%d) -> %d, len%d, %s\n", index, zone, result.length(), u_errorName(ec)));
    1051             :         }
    1052           0 :         ures_close(ares);
    1053             :     }
    1054           0 :     ures_close(top);
    1055             : #if defined(U_DEBUG_TZ)
    1056             :     if(result.length() ==0) {
    1057             :       U_DEBUG_TZ_MSG(("equiv [__, #%d] -> 0 (%s)\n", index, u_errorName(ec)));
    1058             :     }
    1059             : #endif
    1060           0 :     return result;
    1061             : }
    1062             : 
    1063             : // ---------------------------------------
    1064             : 
    1065             : // These methods are used by ZoneMeta class only.
    1066             : 
    1067             : const UChar*
    1068           0 : TimeZone::findID(const UnicodeString& id) {
    1069           0 :     const UChar *result = NULL;
    1070           0 :     UErrorCode ec = U_ZERO_ERROR;
    1071           0 :     UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
    1072             : 
    1073             :     // resolve zone index by name
    1074           0 :     UResourceBundle *names = ures_getByKey(rb, kNAMES, NULL, &ec);
    1075           0 :     int32_t idx = findInStringArray(names, id, ec);
    1076           0 :     result = ures_getStringByIndex(names, idx, NULL, &ec);
    1077           0 :     if (U_FAILURE(ec)) {
    1078           0 :         result = NULL;
    1079             :     }
    1080           0 :     ures_close(names);
    1081           0 :     ures_close(rb);
    1082           0 :     return result;
    1083             : }
    1084             : 
    1085             : 
    1086             : const UChar*
    1087           0 : TimeZone::dereferOlsonLink(const UnicodeString& id) {
    1088           0 :     const UChar *result = NULL;
    1089           0 :     UErrorCode ec = U_ZERO_ERROR;
    1090           0 :     UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
    1091             : 
    1092             :     // resolve zone index by name
    1093           0 :     UResourceBundle *names = ures_getByKey(rb, kNAMES, NULL, &ec);
    1094           0 :     int32_t idx = findInStringArray(names, id, ec);
    1095           0 :     result = ures_getStringByIndex(names, idx, NULL, &ec);
    1096             : 
    1097             :     // open the zone bundle by index
    1098           0 :     ures_getByKey(rb, kZONES, rb, &ec);
    1099           0 :     ures_getByIndex(rb, idx, rb, &ec); 
    1100             : 
    1101           0 :     if (U_SUCCESS(ec)) {
    1102           0 :         if (ures_getType(rb) == URES_INT) {
    1103             :             // this is a link - dereference the link
    1104           0 :             int32_t deref = ures_getInt(rb, &ec);
    1105           0 :             const UChar* tmp = ures_getStringByIndex(names, deref, NULL, &ec);
    1106           0 :             if (U_SUCCESS(ec)) {
    1107           0 :                 result = tmp;
    1108             :             }
    1109             :         }
    1110             :     }
    1111             : 
    1112           0 :     ures_close(names);
    1113           0 :     ures_close(rb);
    1114             : 
    1115           0 :     return result;
    1116             : }
    1117             : 
    1118             : const UChar*
    1119           0 : TimeZone::getRegion(const UnicodeString& id) {
    1120           0 :     UErrorCode status = U_ZERO_ERROR;
    1121           0 :     return getRegion(id, status);
    1122             : }
    1123             : 
    1124             : const UChar*
    1125           0 : TimeZone::getRegion(const UnicodeString& id, UErrorCode& status) {
    1126           0 :     if (U_FAILURE(status)) {
    1127           0 :         return NULL;
    1128             :     }
    1129           0 :     const UChar *result = NULL;
    1130           0 :     UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &status);
    1131             : 
    1132             :     // resolve zone index by name
    1133           0 :     UResourceBundle *res = ures_getByKey(rb, kNAMES, NULL, &status);
    1134           0 :     int32_t idx = findInStringArray(res, id, status);
    1135             : 
    1136             :     // get region mapping
    1137           0 :     ures_getByKey(rb, kREGIONS, res, &status);
    1138           0 :     const UChar *tmp = ures_getStringByIndex(res, idx, NULL, &status);
    1139           0 :     if (U_SUCCESS(status)) {
    1140           0 :         result = tmp;
    1141             :     }
    1142             : 
    1143           0 :     ures_close(res);
    1144           0 :     ures_close(rb);
    1145             : 
    1146           0 :     return result;
    1147             : }
    1148             : 
    1149             : 
    1150             : // ---------------------------------------
    1151             : int32_t
    1152           0 : TimeZone::getRegion(const UnicodeString& id, char *region, int32_t capacity, UErrorCode& status)
    1153             : {
    1154           0 :     int32_t resultLen = 0;
    1155           0 :     *region = 0;
    1156           0 :     if (U_FAILURE(status)) {
    1157           0 :         return 0;
    1158             :     }
    1159             : 
    1160           0 :     const UChar *uregion = NULL;
    1161             :     // "Etc/Unknown" is not a system zone ID,
    1162             :     // but in the zone data
    1163           0 :     if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) != 0) {
    1164           0 :         uregion = getRegion(id);
    1165             :     }
    1166           0 :     if (uregion == NULL) {
    1167           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
    1168           0 :         return 0;
    1169             :     }
    1170           0 :     resultLen = u_strlen(uregion);
    1171             :     // A region code is represented by invariant characters
    1172           0 :     u_UCharsToChars(uregion, region, uprv_min(resultLen, capacity));
    1173             : 
    1174           0 :     if (capacity < resultLen) {
    1175           0 :         status = U_BUFFER_OVERFLOW_ERROR;
    1176           0 :         return resultLen;
    1177             :     }
    1178             : 
    1179           0 :     return u_terminateChars(region, capacity, resultLen, &status);
    1180             : }
    1181             : 
    1182             : // ---------------------------------------
    1183             : 
    1184             : 
    1185             : UnicodeString&
    1186           0 : TimeZone::getDisplayName(UnicodeString& result) const
    1187             : {
    1188           0 :     return getDisplayName(FALSE,LONG,Locale::getDefault(), result);
    1189             : }
    1190             : 
    1191             : UnicodeString&
    1192           0 : TimeZone::getDisplayName(const Locale& locale, UnicodeString& result) const
    1193             : {
    1194           0 :     return getDisplayName(FALSE, LONG, locale, result);
    1195             : }
    1196             : 
    1197             : UnicodeString&
    1198           0 : TimeZone::getDisplayName(UBool daylight, EDisplayType style, UnicodeString& result)  const
    1199             : {
    1200           0 :     return getDisplayName(daylight,style, Locale::getDefault(), result);
    1201             : }
    1202             : //--------------------------------------
    1203             : int32_t
    1204           0 : TimeZone::getDSTSavings()const {
    1205           0 :     if (useDaylightTime()) {
    1206           0 :         return 3600000;
    1207             :     }
    1208           0 :     return 0;
    1209             : }
    1210             : //---------------------------------------
    1211             : UnicodeString&
    1212           0 : TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& locale, UnicodeString& result) const
    1213             : {
    1214           0 :     UErrorCode status = U_ZERO_ERROR;
    1215           0 :     UDate date = Calendar::getNow();
    1216             :     UTimeZoneFormatTimeType timeType;
    1217             :     int32_t offset;
    1218             : 
    1219           0 :     if (style == GENERIC_LOCATION || style == LONG_GENERIC || style == SHORT_GENERIC) {
    1220           0 :         LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
    1221           0 :         if (U_FAILURE(status)) {
    1222           0 :             result.remove();
    1223           0 :             return result;
    1224             :         }
    1225             :         // Generic format
    1226           0 :         switch (style) {
    1227             :         case GENERIC_LOCATION:
    1228           0 :             tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, *this, date, result, &timeType);
    1229           0 :             break;
    1230             :         case LONG_GENERIC:
    1231           0 :             tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, *this, date, result, &timeType);
    1232           0 :             break;
    1233             :         case SHORT_GENERIC:
    1234           0 :             tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, *this, date, result, &timeType);
    1235           0 :             break;
    1236             :         default:
    1237           0 :             U_ASSERT(FALSE);
    1238             :         }
    1239             :         // Generic format many use Localized GMT as the final fallback.
    1240             :         // When Localized GMT format is used, the result might not be
    1241             :         // appropriate for the requested daylight value.
    1242           0 :         if ((daylight && timeType == UTZFMT_TIME_TYPE_STANDARD) || (!daylight && timeType == UTZFMT_TIME_TYPE_DAYLIGHT)) {
    1243           0 :             offset = daylight ? getRawOffset() + getDSTSavings() : getRawOffset();
    1244           0 :             if (style == SHORT_GENERIC) {
    1245           0 :                 tzfmt->formatOffsetShortLocalizedGMT(offset, result, status);
    1246             :             } else {
    1247           0 :                 tzfmt->formatOffsetLocalizedGMT(offset, result, status);
    1248             :             }
    1249           0 :         }
    1250           0 :     } else if (style == LONG_GMT || style == SHORT_GMT) {
    1251           0 :         LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
    1252           0 :         if (U_FAILURE(status)) {
    1253           0 :             result.remove();
    1254           0 :             return result;
    1255             :         }
    1256           0 :         offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
    1257           0 :         switch (style) {
    1258             :         case LONG_GMT:
    1259           0 :             tzfmt->formatOffsetLocalizedGMT(offset, result, status);
    1260           0 :             break;
    1261             :         case SHORT_GMT:
    1262           0 :             tzfmt->formatOffsetISO8601Basic(offset, FALSE, FALSE, FALSE, result, status);
    1263           0 :             break;
    1264             :         default:
    1265           0 :             U_ASSERT(FALSE);
    1266           0 :         }
    1267             : 
    1268             :     } else {
    1269           0 :         U_ASSERT(style == LONG || style == SHORT || style == SHORT_COMMONLY_USED);
    1270           0 :         UTimeZoneNameType nameType = UTZNM_UNKNOWN;
    1271           0 :         switch (style) {
    1272             :         case LONG:
    1273           0 :             nameType = daylight ? UTZNM_LONG_DAYLIGHT : UTZNM_LONG_STANDARD;
    1274           0 :             break;
    1275             :         case SHORT:
    1276             :         case SHORT_COMMONLY_USED:
    1277           0 :             nameType = daylight ? UTZNM_SHORT_DAYLIGHT : UTZNM_SHORT_STANDARD;
    1278           0 :             break;
    1279             :         default:
    1280           0 :             U_ASSERT(FALSE);
    1281             :         }
    1282           0 :         LocalPointer<TimeZoneNames> tznames(TimeZoneNames::createInstance(locale, status));
    1283           0 :         if (U_FAILURE(status)) {
    1284           0 :             result.remove();
    1285           0 :             return result;
    1286             :         }
    1287           0 :         UnicodeString canonicalID(ZoneMeta::getCanonicalCLDRID(*this));
    1288           0 :         tznames->getDisplayName(canonicalID, nameType, date, result);
    1289           0 :         if (result.isEmpty()) {
    1290             :             // Fallback to localized GMT
    1291           0 :             LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status));
    1292           0 :             offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset();
    1293           0 :             if (style == LONG) {
    1294           0 :                 tzfmt->formatOffsetLocalizedGMT(offset, result, status);
    1295             :             } else {
    1296           0 :                 tzfmt->formatOffsetShortLocalizedGMT(offset, result, status);
    1297             :             }
    1298             :         }
    1299             :     }
    1300           0 :     if (U_FAILURE(status)) {
    1301           0 :         result.remove();
    1302             :     }
    1303           0 :     return  result;
    1304             : }
    1305             : 
    1306             : /**
    1307             :  * Parse a custom time zone identifier and return a corresponding zone.
    1308             :  * @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or
    1309             :  * GMT[+-]hh.
    1310             :  * @return a newly created SimpleTimeZone with the given offset and
    1311             :  * no Daylight Savings Time, or null if the id cannot be parsed.
    1312             : */
    1313             : TimeZone*
    1314           0 : TimeZone::createCustomTimeZone(const UnicodeString& id)
    1315             : {
    1316             :     int32_t sign, hour, min, sec;
    1317           0 :     if (parseCustomID(id, sign, hour, min, sec)) {
    1318           0 :         UnicodeString customID;
    1319           0 :         formatCustomID(hour, min, sec, (sign < 0), customID);
    1320           0 :         int32_t offset = sign * ((hour * 60 + min) * 60 + sec) * 1000;
    1321           0 :         return new SimpleTimeZone(offset, customID);
    1322             :     }
    1323           0 :     return NULL;
    1324             : }
    1325             : 
    1326             : UnicodeString&
    1327           0 : TimeZone::getCustomID(const UnicodeString& id, UnicodeString& normalized, UErrorCode& status) {
    1328           0 :     normalized.remove();
    1329           0 :     if (U_FAILURE(status)) {
    1330           0 :         return normalized;
    1331             :     }
    1332             :     int32_t sign, hour, min, sec;
    1333           0 :     if (parseCustomID(id, sign, hour, min, sec)) {
    1334           0 :         formatCustomID(hour, min, sec, (sign < 0), normalized);
    1335             :     } else {
    1336           0 :         status = U_ILLEGAL_ARGUMENT_ERROR;
    1337             :     }
    1338           0 :     return normalized;
    1339             : }
    1340             : 
    1341             : UBool
    1342           0 : TimeZone::parseCustomID(const UnicodeString& id, int32_t& sign,
    1343             :                         int32_t& hour, int32_t& min, int32_t& sec) {
    1344             :     static const int32_t         kParseFailed = -99999;
    1345             : 
    1346           0 :     NumberFormat* numberFormat = 0;
    1347           0 :     UnicodeString idUppercase = id;
    1348           0 :     idUppercase.toUpper("");
    1349             : 
    1350           0 :     if (id.length() > GMT_ID_LENGTH &&
    1351           0 :         idUppercase.startsWith(GMT_ID, GMT_ID_LENGTH))
    1352             :     {
    1353           0 :         ParsePosition pos(GMT_ID_LENGTH);
    1354           0 :         sign = 1;
    1355           0 :         hour = 0;
    1356           0 :         min = 0;
    1357           0 :         sec = 0;
    1358             : 
    1359           0 :         if (id[pos.getIndex()] == MINUS /*'-'*/) {
    1360           0 :             sign = -1;
    1361           0 :         } else if (id[pos.getIndex()] != PLUS /*'+'*/) {
    1362           0 :             return FALSE;
    1363             :         }
    1364           0 :         pos.setIndex(pos.getIndex() + 1);
    1365             : 
    1366           0 :         UErrorCode success = U_ZERO_ERROR;
    1367           0 :         numberFormat = NumberFormat::createInstance(success);
    1368           0 :         if(U_FAILURE(success)){
    1369           0 :             return FALSE;
    1370             :         }
    1371           0 :         numberFormat->setParseIntegerOnly(TRUE);
    1372             :         //numberFormat->setLenient(TRUE); // TODO: May need to set this, depends on latest timezone parsing
    1373             : 
    1374             :         // Look for either hh:mm, hhmm, or hh
    1375           0 :         int32_t start = pos.getIndex();
    1376           0 :         Formattable n(kParseFailed);
    1377           0 :         numberFormat->parse(id, n, pos);
    1378           0 :         if (pos.getIndex() == start) {
    1379           0 :             delete numberFormat;
    1380           0 :             return FALSE;
    1381             :         }
    1382           0 :         hour = n.getLong();
    1383             : 
    1384           0 :         if (pos.getIndex() < id.length()) {
    1385           0 :             if (pos.getIndex() - start > 2
    1386           0 :                 || id[pos.getIndex()] != COLON) {
    1387           0 :                 delete numberFormat;
    1388           0 :                 return FALSE;
    1389             :             }
    1390             :             // hh:mm
    1391           0 :             pos.setIndex(pos.getIndex() + 1);
    1392           0 :             int32_t oldPos = pos.getIndex();
    1393           0 :             n.setLong(kParseFailed);
    1394           0 :             numberFormat->parse(id, n, pos);
    1395           0 :             if ((pos.getIndex() - oldPos) != 2) {
    1396             :                 // must be 2 digits
    1397           0 :                 delete numberFormat;
    1398           0 :                 return FALSE;
    1399             :             }
    1400           0 :             min = n.getLong();
    1401           0 :             if (pos.getIndex() < id.length()) {
    1402           0 :                 if (id[pos.getIndex()] != COLON) {
    1403           0 :                     delete numberFormat;
    1404           0 :                     return FALSE;
    1405             :                 }
    1406             :                 // [:ss]
    1407           0 :                 pos.setIndex(pos.getIndex() + 1);
    1408           0 :                 oldPos = pos.getIndex();
    1409           0 :                 n.setLong(kParseFailed);
    1410           0 :                 numberFormat->parse(id, n, pos);
    1411           0 :                 if (pos.getIndex() != id.length()
    1412           0 :                         || (pos.getIndex() - oldPos) != 2) {
    1413           0 :                     delete numberFormat;
    1414           0 :                     return FALSE;
    1415             :                 }
    1416           0 :                 sec = n.getLong();
    1417             :             }
    1418             :         } else {
    1419             :             // Supported formats are below -
    1420             :             //
    1421             :             // HHmmss
    1422             :             // Hmmss
    1423             :             // HHmm
    1424             :             // Hmm
    1425             :             // HH
    1426             :             // H
    1427             : 
    1428           0 :             int32_t length = pos.getIndex() - start;
    1429           0 :             if (length <= 0 || 6 < length) {
    1430             :                 // invalid length
    1431           0 :                 delete numberFormat;
    1432           0 :                 return FALSE;
    1433             :             }
    1434           0 :             switch (length) {
    1435             :                 case 1:
    1436             :                 case 2:
    1437             :                     // already set to hour
    1438           0 :                     break;
    1439             :                 case 3:
    1440             :                 case 4:
    1441           0 :                     min = hour % 100;
    1442           0 :                     hour /= 100;
    1443           0 :                     break;
    1444             :                 case 5:
    1445             :                 case 6:
    1446           0 :                     sec = hour % 100;
    1447           0 :                     min = (hour/100) % 100;
    1448           0 :                     hour /= 10000;
    1449           0 :                     break;
    1450             :             }
    1451             :         }
    1452             : 
    1453           0 :         delete numberFormat;
    1454             : 
    1455           0 :         if (hour > kMAX_CUSTOM_HOUR || min > kMAX_CUSTOM_MIN || sec > kMAX_CUSTOM_SEC) {
    1456           0 :             return FALSE;
    1457             :         }
    1458           0 :         return TRUE;
    1459             :     }
    1460           0 :     return FALSE;
    1461             : }
    1462             : 
    1463             : UnicodeString&
    1464           0 : TimeZone::formatCustomID(int32_t hour, int32_t min, int32_t sec,
    1465             :                          UBool negative, UnicodeString& id) {
    1466             :     // Create time zone ID - GMT[+|-]hhmm[ss]
    1467           0 :     id.setTo(GMT_ID, GMT_ID_LENGTH);
    1468           0 :     if (hour | min | sec) {
    1469           0 :         if (negative) {
    1470           0 :             id += (UChar)MINUS;
    1471             :         } else {
    1472           0 :             id += (UChar)PLUS;
    1473             :         }
    1474             : 
    1475           0 :         if (hour < 10) {
    1476           0 :             id += (UChar)ZERO_DIGIT;
    1477             :         } else {
    1478           0 :             id += (UChar)(ZERO_DIGIT + hour/10);
    1479             :         }
    1480           0 :         id += (UChar)(ZERO_DIGIT + hour%10);
    1481           0 :         id += (UChar)COLON;
    1482           0 :         if (min < 10) {
    1483           0 :             id += (UChar)ZERO_DIGIT;
    1484             :         } else {
    1485           0 :             id += (UChar)(ZERO_DIGIT + min/10);
    1486             :         }
    1487           0 :         id += (UChar)(ZERO_DIGIT + min%10);
    1488             : 
    1489           0 :         if (sec) {
    1490           0 :             id += (UChar)COLON;
    1491           0 :             if (sec < 10) {
    1492           0 :                 id += (UChar)ZERO_DIGIT;
    1493             :             } else {
    1494           0 :                 id += (UChar)(ZERO_DIGIT + sec/10);
    1495             :             }
    1496           0 :             id += (UChar)(ZERO_DIGIT + sec%10);
    1497             :         }
    1498             :     }
    1499           0 :     return id;
    1500             : }
    1501             : 
    1502             : 
    1503             : UBool
    1504           0 : TimeZone::hasSameRules(const TimeZone& other) const
    1505             : {
    1506           0 :     return (getRawOffset() == other.getRawOffset() &&
    1507           0 :             useDaylightTime() == other.useDaylightTime());
    1508             : }
    1509             : 
    1510           0 : static void U_CALLCONV initTZDataVersion(UErrorCode &status) {
    1511           0 :     ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
    1512           0 :     int32_t len = 0;
    1513           0 :     UResourceBundle *bundle = ures_openDirect(NULL, kZONEINFO, &status);
    1514           0 :     const UChar *tzver = ures_getStringByKey(bundle, kTZVERSION, &len, &status);
    1515             : 
    1516           0 :     if (U_SUCCESS(status)) {
    1517           0 :         if (len >= (int32_t)sizeof(TZDATA_VERSION)) {
    1518             :             // Ensure that there is always space for a trailing nul in TZDATA_VERSION
    1519           0 :             len = sizeof(TZDATA_VERSION) - 1;
    1520             :         }
    1521           0 :         u_UCharsToChars(tzver, TZDATA_VERSION, len);
    1522             :     }
    1523           0 :     ures_close(bundle);
    1524             : 
    1525           0 : }
    1526             : 
    1527             : const char*
    1528           0 : TimeZone::getTZDataVersion(UErrorCode& status)
    1529             : {
    1530           0 :     umtx_initOnce(gTZDataVersionInitOnce, &initTZDataVersion, status);
    1531           0 :     return (const char*)TZDATA_VERSION;
    1532             : }
    1533             : 
    1534             : UnicodeString&
    1535           0 : TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UErrorCode& status)
    1536             : {
    1537           0 :     UBool isSystemID = FALSE;
    1538           0 :     return getCanonicalID(id, canonicalID, isSystemID, status);
    1539             : }
    1540             : 
    1541             : UnicodeString&
    1542           0 : TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UBool& isSystemID,
    1543             :                          UErrorCode& status)
    1544             : {
    1545           0 :     canonicalID.remove();
    1546           0 :     isSystemID = FALSE;
    1547           0 :     if (U_FAILURE(status)) {
    1548           0 :         return canonicalID;
    1549             :     }
    1550           0 :     if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) == 0) {
    1551             :         // special case - Etc/Unknown is a canonical ID, but not system ID
    1552           0 :         canonicalID.fastCopyFrom(id);
    1553           0 :         isSystemID = FALSE;
    1554             :     } else {
    1555           0 :         ZoneMeta::getCanonicalCLDRID(id, canonicalID, status);
    1556           0 :         if (U_SUCCESS(status)) {
    1557           0 :             isSystemID = TRUE;
    1558             :         } else {
    1559             :             // Not a system ID
    1560           0 :             status = U_ZERO_ERROR;
    1561           0 :             getCustomID(id, canonicalID, status);
    1562             :         }
    1563             :     }
    1564           0 :     return canonicalID;
    1565             : }
    1566             : 
    1567             : UnicodeString&
    1568           0 : TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode& status) {
    1569           0 :     winid.remove();
    1570           0 :     if (U_FAILURE(status)) {
    1571           0 :         return winid;
    1572             :     }
    1573             : 
    1574             :     // canonicalize the input ID
    1575           0 :     UnicodeString canonicalID;
    1576           0 :     UBool isSystemID = FALSE;
    1577             : 
    1578           0 :     getCanonicalID(id, canonicalID, isSystemID, status);
    1579           0 :     if (U_FAILURE(status) || !isSystemID) {
    1580             :         // mapping data is only applicable to tz database IDs
    1581           0 :         if (status == U_ILLEGAL_ARGUMENT_ERROR) {
    1582             :             // getWindowsID() sets an empty string where
    1583             :             // getCanonicalID() sets a U_ILLEGAL_ARGUMENT_ERROR.
    1584           0 :             status = U_ZERO_ERROR;
    1585             :         }
    1586           0 :         return winid;
    1587             :     }
    1588             : 
    1589           0 :     UResourceBundle *mapTimezones = ures_openDirect(NULL, "windowsZones", &status);
    1590           0 :     ures_getByKey(mapTimezones, "mapTimezones", mapTimezones, &status);
    1591             : 
    1592           0 :     if (U_FAILURE(status)) {
    1593           0 :         return winid;
    1594             :     }
    1595             : 
    1596           0 :     UResourceBundle *winzone = NULL;
    1597           0 :     UBool found = FALSE;
    1598           0 :     while (ures_hasNext(mapTimezones) && !found) {
    1599           0 :         winzone = ures_getNextResource(mapTimezones, winzone, &status);
    1600           0 :         if (U_FAILURE(status)) {
    1601           0 :             break;
    1602             :         }
    1603           0 :         if (ures_getType(winzone) != URES_TABLE) {
    1604           0 :             continue;
    1605             :         }
    1606           0 :         UResourceBundle *regionalData = NULL;
    1607           0 :         while (ures_hasNext(winzone) && !found) {
    1608           0 :             regionalData = ures_getNextResource(winzone, regionalData, &status);
    1609           0 :             if (U_FAILURE(status)) {
    1610           0 :                 break;
    1611             :             }
    1612           0 :             if (ures_getType(regionalData) != URES_STRING) {
    1613           0 :                 continue;
    1614             :             }
    1615             :             int32_t len;
    1616           0 :             const UChar *tzids = ures_getString(regionalData, &len, &status);
    1617           0 :             if (U_FAILURE(status)) {
    1618           0 :                 break;
    1619             :             }
    1620             : 
    1621           0 :             const UChar *start = tzids;
    1622           0 :             UBool hasNext = TRUE;
    1623           0 :             while (hasNext) {
    1624           0 :                 const UChar *end = u_strchr(start, (UChar)0x20);
    1625           0 :                 if (end == NULL) {
    1626           0 :                     end = tzids + len;
    1627           0 :                     hasNext = FALSE;
    1628             :                 }
    1629           0 :                 if (canonicalID.compare(start, end - start) == 0) {
    1630           0 :                     winid = UnicodeString(ures_getKey(winzone), -1 , US_INV);
    1631           0 :                     found = TRUE;
    1632           0 :                     break;
    1633             :                 }
    1634           0 :                 start = end + 1;
    1635             :             }
    1636             :         }
    1637           0 :         ures_close(regionalData);
    1638             :     }
    1639           0 :     ures_close(winzone);
    1640           0 :     ures_close(mapTimezones);
    1641             : 
    1642           0 :     return winid;
    1643             : }
    1644             : 
    1645             : #define MAX_WINDOWS_ID_SIZE 128
    1646             : 
    1647             : UnicodeString&
    1648           0 : TimeZone::getIDForWindowsID(const UnicodeString& winid, const char* region, UnicodeString& id, UErrorCode& status) {
    1649           0 :     id.remove();
    1650           0 :     if (U_FAILURE(status)) {
    1651           0 :         return id;
    1652             :     }
    1653             : 
    1654           0 :     UResourceBundle *zones = ures_openDirect(NULL, "windowsZones", &status);
    1655           0 :     ures_getByKey(zones, "mapTimezones", zones, &status);
    1656           0 :     if (U_FAILURE(status)) {
    1657           0 :         ures_close(zones);
    1658           0 :         return id;
    1659             :     }
    1660             : 
    1661           0 :     UErrorCode tmperr = U_ZERO_ERROR;
    1662             :     char winidKey[MAX_WINDOWS_ID_SIZE];
    1663           0 :     int32_t winKeyLen = winid.extract(0, winid.length(), winidKey, sizeof(winidKey) - 1, US_INV);
    1664             : 
    1665           0 :     if (winKeyLen == 0 || winKeyLen >= (int32_t)sizeof(winidKey)) {
    1666           0 :         ures_close(zones);
    1667           0 :         return id;
    1668             :     }
    1669           0 :     winidKey[winKeyLen] = 0;
    1670             : 
    1671           0 :     ures_getByKey(zones, winidKey, zones, &tmperr); // use tmperr, because windows mapping might not
    1672             :                                                     // be avaiable by design
    1673           0 :     if (U_FAILURE(tmperr)) {
    1674           0 :         ures_close(zones);
    1675           0 :         return id;
    1676             :     }
    1677             : 
    1678           0 :     const UChar *tzid = NULL;
    1679           0 :     int32_t len = 0;
    1680           0 :     UBool gotID = FALSE;
    1681           0 :     if (region) {
    1682           0 :         const UChar *tzids = ures_getStringByKey(zones, region, &len, &tmperr); // use tmperr, because
    1683             :                                                                                 // regional mapping is optional
    1684           0 :         if (U_SUCCESS(tmperr)) {
    1685             :             // first ID delimited by space is the defasult one
    1686           0 :             const UChar *end = u_strchr(tzids, (UChar)0x20);
    1687           0 :             if (end == NULL) {
    1688           0 :                 id.setTo(tzids, -1);
    1689             :             } else {
    1690           0 :                 id.setTo(tzids, end - tzids);
    1691             :             }
    1692           0 :             gotID = TRUE;
    1693             :         }
    1694             :     }
    1695             : 
    1696           0 :     if (!gotID) {
    1697           0 :         tzid = ures_getStringByKey(zones, "001", &len, &status);    // using status, because "001" must be
    1698             :                                                                 // available at this point
    1699           0 :         if (U_SUCCESS(status)) {
    1700           0 :             id.setTo(tzid, len);
    1701             :         }
    1702             :     }
    1703             : 
    1704           0 :     ures_close(zones);
    1705           0 :     return id;
    1706             : }
    1707             : 
    1708             : 
    1709             : U_NAMESPACE_END
    1710             : 
    1711             : #endif /* #if !UCONFIG_NO_FORMATTING */
    1712             : 
    1713             : //eof

Generated by: LCOV version 1.13