1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/timezone.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1669 @@ 1.4 +/* 1.5 +******************************************************************************* 1.6 +* Copyright (C) 1997-2013, International Business Machines Corporation and 1.7 +* others. All Rights Reserved. 1.8 +******************************************************************************* 1.9 +* 1.10 +* File TIMEZONE.CPP 1.11 +* 1.12 +* Modification History: 1.13 +* 1.14 +* Date Name Description 1.15 +* 12/05/96 clhuang Creation. 1.16 +* 04/21/97 aliu General clean-up and bug fixing. 1.17 +* 05/08/97 aliu Fixed Hashtable code per code review. 1.18 +* 07/09/97 helena Changed createInstance to createDefault. 1.19 +* 07/29/97 aliu Updated with all-new list of 96 UNIX-derived 1.20 +* TimeZones. Changed mechanism to load from static 1.21 +* array rather than resource bundle. 1.22 +* 07/07/1998 srl Bugfixes from the Java side: UTC GMT CAT NST 1.23 +* Added getDisplayName API 1.24 +* going to add custom parsing. 1.25 +* 1.26 +* ISSUES: 1.27 +* - should getDisplayName cache something? 1.28 +* - should custom time zones be cached? [probably] 1.29 +* 08/10/98 stephen Brought getDisplayName() API in-line w/ conventions 1.30 +* 08/19/98 stephen Changed createTimeZone() to never return 0 1.31 +* 09/02/98 stephen Added getOffset(monthLen) and hasSameRules() 1.32 +* 09/15/98 stephen Added getStaticClassID() 1.33 +* 02/22/99 stephen Removed character literals for EBCDIC safety 1.34 +* 05/04/99 stephen Changed initDefault() for Mutex issues 1.35 +* 07/12/99 helena HPUX 11 CC Port. 1.36 +* 12/03/99 aliu Moved data out of static table into icudata.dll. 1.37 +* Substantial rewrite of zone lookup, default zone, and 1.38 +* available IDs code. Misc. cleanup. 1.39 +*********************************************************************************/ 1.40 + 1.41 +#include "utypeinfo.h" // for 'typeid' to work 1.42 + 1.43 +#include "unicode/utypes.h" 1.44 +#include "unicode/ustring.h" 1.45 +#include "uassert.h" 1.46 +#include "ustr_imp.h" 1.47 + 1.48 +#ifdef U_DEBUG_TZ 1.49 +# include <stdio.h> 1.50 +# include "uresimp.h" // for debugging 1.51 + 1.52 +static void debug_tz_loc(const char *f, int32_t l) 1.53 +{ 1.54 + fprintf(stderr, "%s:%d: ", f, l); 1.55 +} 1.56 + 1.57 +static void debug_tz_msg(const char *pat, ...) 1.58 +{ 1.59 + va_list ap; 1.60 + va_start(ap, pat); 1.61 + vfprintf(stderr, pat, ap); 1.62 + fflush(stderr); 1.63 +} 1.64 +static char gStrBuf[256]; 1.65 +#define U_DEBUG_TZ_STR(x) u_austrncpy(gStrBuf,x,sizeof(gStrBuf)-1) 1.66 +// must use double parens, i.e.: U_DEBUG_TZ_MSG(("four is: %d",4)); 1.67 +#define U_DEBUG_TZ_MSG(x) {debug_tz_loc(__FILE__,__LINE__);debug_tz_msg x;} 1.68 +#else 1.69 +#define U_DEBUG_TZ_MSG(x) 1.70 +#endif 1.71 + 1.72 +#if !UCONFIG_NO_FORMATTING 1.73 + 1.74 +#include "unicode/simpletz.h" 1.75 +#include "unicode/calendar.h" 1.76 +#include "unicode/gregocal.h" 1.77 +#include "unicode/ures.h" 1.78 +#include "unicode/tzfmt.h" 1.79 +#include "unicode/numfmt.h" 1.80 +#include "gregoimp.h" 1.81 +#include "uresimp.h" // struct UResourceBundle 1.82 +#include "olsontz.h" 1.83 +#include "mutex.h" 1.84 +#include "unicode/udata.h" 1.85 +#include "ucln_in.h" 1.86 +#include "cstring.h" 1.87 +#include "cmemory.h" 1.88 +#include "unicode/strenum.h" 1.89 +#include "uassert.h" 1.90 +#include "zonemeta.h" 1.91 + 1.92 +#define kZONEINFO "zoneinfo64" 1.93 +#define kREGIONS "Regions" 1.94 +#define kZONES "Zones" 1.95 +#define kRULES "Rules" 1.96 +#define kNAMES "Names" 1.97 +#define kTZVERSION "TZVersion" 1.98 +#define kLINKS "links" 1.99 +#define kMAX_CUSTOM_HOUR 23 1.100 +#define kMAX_CUSTOM_MIN 59 1.101 +#define kMAX_CUSTOM_SEC 59 1.102 +#define MINUS 0x002D 1.103 +#define PLUS 0x002B 1.104 +#define ZERO_DIGIT 0x0030 1.105 +#define COLON 0x003A 1.106 + 1.107 +// Static data and constants 1.108 + 1.109 +static const UChar WORLD[] = {0x30, 0x30, 0x31, 0x00}; /* "001" */ 1.110 + 1.111 +static const UChar GMT_ID[] = {0x47, 0x4D, 0x54, 0x00}; /* "GMT" */ 1.112 +static const UChar UNKNOWN_ZONE_ID[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00}; /* "Etc/Unknown" */ 1.113 +static const int32_t GMT_ID_LENGTH = 3; 1.114 +static const int32_t UNKNOWN_ZONE_ID_LENGTH = 11; 1.115 + 1.116 +static icu::TimeZone* DEFAULT_ZONE = NULL; 1.117 +static icu::UInitOnce gDefaultZoneInitOnce = U_INITONCE_INITIALIZER; 1.118 + 1.119 +static icu::TimeZone* _GMT = NULL; 1.120 +static icu::TimeZone* _UNKNOWN_ZONE = NULL; 1.121 +static icu::UInitOnce gStaticZonesInitOnce = U_INITONCE_INITIALIZER; 1.122 + 1.123 +static char TZDATA_VERSION[16]; 1.124 +static icu::UInitOnce gTZDataVersionInitOnce = U_INITONCE_INITIALIZER; 1.125 + 1.126 +static int32_t* MAP_SYSTEM_ZONES = NULL; 1.127 +static int32_t* MAP_CANONICAL_SYSTEM_ZONES = NULL; 1.128 +static int32_t* MAP_CANONICAL_SYSTEM_LOCATION_ZONES = NULL; 1.129 + 1.130 +static int32_t LEN_SYSTEM_ZONES = 0; 1.131 +static int32_t LEN_CANONICAL_SYSTEM_ZONES = 0; 1.132 +static int32_t LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0; 1.133 + 1.134 +static icu::UInitOnce gSystemZonesInitOnce = U_INITONCE_INITIALIZER; 1.135 +static icu::UInitOnce gCanonicalZonesInitOnce = U_INITONCE_INITIALIZER; 1.136 +static icu::UInitOnce gCanonicalLocationZonesInitOnce = U_INITONCE_INITIALIZER; 1.137 + 1.138 +U_CDECL_BEGIN 1.139 +static UBool U_CALLCONV timeZone_cleanup(void) 1.140 +{ 1.141 + U_NAMESPACE_USE 1.142 + delete DEFAULT_ZONE; 1.143 + DEFAULT_ZONE = NULL; 1.144 + gDefaultZoneInitOnce.reset(); 1.145 + 1.146 + delete _GMT; 1.147 + _GMT = NULL; 1.148 + delete _UNKNOWN_ZONE; 1.149 + _UNKNOWN_ZONE = NULL; 1.150 + gStaticZonesInitOnce.reset(); 1.151 + 1.152 + uprv_memset(TZDATA_VERSION, 0, sizeof(TZDATA_VERSION)); 1.153 + gTZDataVersionInitOnce.reset(); 1.154 + 1.155 + LEN_SYSTEM_ZONES = 0; 1.156 + uprv_free(MAP_SYSTEM_ZONES); 1.157 + MAP_SYSTEM_ZONES = 0; 1.158 + gSystemZonesInitOnce.reset(); 1.159 + 1.160 + LEN_CANONICAL_SYSTEM_ZONES = 0; 1.161 + uprv_free(MAP_CANONICAL_SYSTEM_ZONES); 1.162 + MAP_CANONICAL_SYSTEM_ZONES = 0; 1.163 + gCanonicalZonesInitOnce.reset(); 1.164 + 1.165 + LEN_CANONICAL_SYSTEM_LOCATION_ZONES = 0; 1.166 + uprv_free(MAP_CANONICAL_SYSTEM_LOCATION_ZONES); 1.167 + MAP_CANONICAL_SYSTEM_LOCATION_ZONES = 0; 1.168 + gCanonicalLocationZonesInitOnce.reset(); 1.169 + 1.170 + return TRUE; 1.171 +} 1.172 +U_CDECL_END 1.173 + 1.174 +U_NAMESPACE_BEGIN 1.175 + 1.176 +static int32_t findInStringArray(UResourceBundle* array, const UnicodeString& id, UErrorCode &status) 1.177 +{ 1.178 + UnicodeString copy; 1.179 + const UChar *u; 1.180 + int32_t len; 1.181 + 1.182 + int32_t start = 0; 1.183 + int32_t limit = ures_getSize(array); 1.184 + int32_t mid; 1.185 + int32_t lastMid = INT32_MAX; 1.186 + if(U_FAILURE(status) || (limit < 1)) { 1.187 + return -1; 1.188 + } 1.189 + U_DEBUG_TZ_MSG(("fisa: Looking for %s, between %d and %d\n", U_DEBUG_TZ_STR(UnicodeString(id).getTerminatedBuffer()), start, limit)); 1.190 + 1.191 + for (;;) { 1.192 + mid = (int32_t)((start + limit) / 2); 1.193 + if (lastMid == mid) { /* Have we moved? */ 1.194 + break; /* We haven't moved, and it wasn't found. */ 1.195 + } 1.196 + lastMid = mid; 1.197 + u = ures_getStringByIndex(array, mid, &len, &status); 1.198 + if (U_FAILURE(status)) { 1.199 + break; 1.200 + } 1.201 + U_DEBUG_TZ_MSG(("tz: compare to %s, %d .. [%d] .. %d\n", U_DEBUG_TZ_STR(u), start, mid, limit)); 1.202 + copy.setTo(TRUE, u, len); 1.203 + int r = id.compare(copy); 1.204 + if(r==0) { 1.205 + U_DEBUG_TZ_MSG(("fisa: found at %d\n", mid)); 1.206 + return mid; 1.207 + } else if(r<0) { 1.208 + limit = mid; 1.209 + } else { 1.210 + start = mid; 1.211 + } 1.212 + } 1.213 + U_DEBUG_TZ_MSG(("fisa: not found\n")); 1.214 + return -1; 1.215 +} 1.216 + 1.217 +/** 1.218 + * Fetch a specific zone by name. Replaces the getByKey call. 1.219 + * @param top Top timezone resource 1.220 + * @param id Time zone ID 1.221 + * @param oldbundle Bundle for reuse (or NULL). see 'ures_open()' 1.222 + * @return the zone's bundle if found, or undefined if error. Reuses oldbundle. 1.223 + */ 1.224 +static UResourceBundle* getZoneByName(const UResourceBundle* top, const UnicodeString& id, UResourceBundle *oldbundle, UErrorCode& status) { 1.225 + // load the Rules object 1.226 + UResourceBundle *tmp = ures_getByKey(top, kNAMES, NULL, &status); 1.227 + 1.228 + // search for the string 1.229 + int32_t idx = findInStringArray(tmp, id, status); 1.230 + 1.231 + if((idx == -1) && U_SUCCESS(status)) { 1.232 + // not found 1.233 + status = U_MISSING_RESOURCE_ERROR; 1.234 + //ures_close(oldbundle); 1.235 + //oldbundle = NULL; 1.236 + } else { 1.237 + U_DEBUG_TZ_MSG(("gzbn: oldbundle= size %d, type %d, %s\n", ures_getSize(tmp), ures_getType(tmp), u_errorName(status))); 1.238 + tmp = ures_getByKey(top, kZONES, tmp, &status); // get Zones object from top 1.239 + 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))); 1.240 + oldbundle = ures_getByIndex(tmp, idx, oldbundle, &status); // get nth Zone object 1.241 + 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))); 1.242 + } 1.243 + ures_close(tmp); 1.244 + if(U_FAILURE(status)) { 1.245 + //ures_close(oldbundle); 1.246 + return NULL; 1.247 + } else { 1.248 + return oldbundle; 1.249 + } 1.250 +} 1.251 + 1.252 + 1.253 +UResourceBundle* TimeZone::loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode& status) { 1.254 + char key[64]; 1.255 + ruleid.extract(0, sizeof(key)-1, key, (int32_t)sizeof(key)-1, US_INV); 1.256 + U_DEBUG_TZ_MSG(("loadRule(%s)\n", key)); 1.257 + UResourceBundle *r = ures_getByKey(top, kRULES, oldbundle, &status); 1.258 + U_DEBUG_TZ_MSG(("loadRule(%s) -> kRULES [%s]\n", key, u_errorName(status))); 1.259 + r = ures_getByKey(r, key, r, &status); 1.260 + U_DEBUG_TZ_MSG(("loadRule(%s) -> item [%s]\n", key, u_errorName(status))); 1.261 + return r; 1.262 +} 1.263 + 1.264 +/** 1.265 + * Given an ID, open the appropriate resource for the given time zone. 1.266 + * Dereference aliases if necessary. 1.267 + * @param id zone id 1.268 + * @param res resource, which must be ready for use (initialized but not open) 1.269 + * @param ec input-output error code 1.270 + * @return top-level resource bundle 1.271 + */ 1.272 +static UResourceBundle* openOlsonResource(const UnicodeString& id, 1.273 + UResourceBundle& res, 1.274 + UErrorCode& ec) 1.275 +{ 1.276 +#if U_DEBUG_TZ 1.277 + char buf[128]; 1.278 + id.extract(0, sizeof(buf)-1, buf, sizeof(buf), ""); 1.279 +#endif 1.280 + UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec); 1.281 + U_DEBUG_TZ_MSG(("pre: res sz=%d\n", ures_getSize(&res))); 1.282 + /* &res = */ getZoneByName(top, id, &res, ec); 1.283 + // Dereference if this is an alias. Docs say result should be 1 1.284 + // but it is 0 in 2.8 (?). 1.285 + U_DEBUG_TZ_MSG(("Loading zone '%s' (%s, size %d) - %s\n", buf, ures_getKey((UResourceBundle*)&res), ures_getSize(&res), u_errorName(ec))); 1.286 + if (ures_getType(&res) == URES_INT) { 1.287 + int32_t deref = ures_getInt(&res, &ec) + 0; 1.288 + U_DEBUG_TZ_MSG(("getInt: %s - type is %d\n", u_errorName(ec), ures_getType(&res))); 1.289 + UResourceBundle *ares = ures_getByKey(top, kZONES, NULL, &ec); // dereference Zones section 1.290 + ures_getByIndex(ares, deref, &res, &ec); 1.291 + ures_close(ares); 1.292 + U_DEBUG_TZ_MSG(("alias to #%d (%s) - %s\n", deref, "??", u_errorName(ec))); 1.293 + } else { 1.294 + U_DEBUG_TZ_MSG(("not an alias - size %d\n", ures_getSize(&res))); 1.295 + } 1.296 + U_DEBUG_TZ_MSG(("%s - final status is %s\n", buf, u_errorName(ec))); 1.297 + return top; 1.298 +} 1.299 + 1.300 +// ------------------------------------- 1.301 + 1.302 +namespace { 1.303 + 1.304 +void U_CALLCONV initStaticTimeZones() { 1.305 + // Initialize _GMT independently of other static data; it should 1.306 + // be valid even if we can't load the time zone UDataMemory. 1.307 + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); 1.308 + _UNKNOWN_ZONE = new SimpleTimeZone(0, UnicodeString(TRUE, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)); 1.309 + _GMT = new SimpleTimeZone(0, UnicodeString(TRUE, GMT_ID, GMT_ID_LENGTH)); 1.310 +} 1.311 + 1.312 +} // anonymous namespace 1.313 + 1.314 +const TimeZone& U_EXPORT2 1.315 +TimeZone::getUnknown() 1.316 +{ 1.317 + umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones); 1.318 + return *_UNKNOWN_ZONE; 1.319 +} 1.320 + 1.321 +const TimeZone* U_EXPORT2 1.322 +TimeZone::getGMT(void) 1.323 +{ 1.324 + umtx_initOnce(gStaticZonesInitOnce, &initStaticTimeZones); 1.325 + return _GMT; 1.326 +} 1.327 + 1.328 +// ***************************************************************************** 1.329 +// class TimeZone 1.330 +// ***************************************************************************** 1.331 + 1.332 +UOBJECT_DEFINE_ABSTRACT_RTTI_IMPLEMENTATION(TimeZone) 1.333 + 1.334 +TimeZone::TimeZone() 1.335 + : UObject(), fID() 1.336 +{ 1.337 +} 1.338 + 1.339 +// ------------------------------------- 1.340 + 1.341 +TimeZone::TimeZone(const UnicodeString &id) 1.342 + : UObject(), fID(id) 1.343 +{ 1.344 +} 1.345 + 1.346 +// ------------------------------------- 1.347 + 1.348 +TimeZone::~TimeZone() 1.349 +{ 1.350 +} 1.351 + 1.352 +// ------------------------------------- 1.353 + 1.354 +TimeZone::TimeZone(const TimeZone &source) 1.355 + : UObject(source), fID(source.fID) 1.356 +{ 1.357 +} 1.358 + 1.359 +// ------------------------------------- 1.360 + 1.361 +TimeZone & 1.362 +TimeZone::operator=(const TimeZone &right) 1.363 +{ 1.364 + if (this != &right) fID = right.fID; 1.365 + return *this; 1.366 +} 1.367 + 1.368 +// ------------------------------------- 1.369 + 1.370 +UBool 1.371 +TimeZone::operator==(const TimeZone& that) const 1.372 +{ 1.373 + return typeid(*this) == typeid(that) && 1.374 + fID == that.fID; 1.375 +} 1.376 + 1.377 +// ------------------------------------- 1.378 + 1.379 +namespace { 1.380 +TimeZone* 1.381 +createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) { 1.382 + if (U_FAILURE(ec)) { 1.383 + return NULL; 1.384 + } 1.385 + TimeZone* z = 0; 1.386 + UResourceBundle res; 1.387 + ures_initStackObject(&res); 1.388 + U_DEBUG_TZ_MSG(("pre-err=%s\n", u_errorName(ec))); 1.389 + UResourceBundle *top = openOlsonResource(id, res, ec); 1.390 + U_DEBUG_TZ_MSG(("post-err=%s\n", u_errorName(ec))); 1.391 + if (U_SUCCESS(ec)) { 1.392 + z = new OlsonTimeZone(top, &res, id, ec); 1.393 + if (z == NULL) { 1.394 + U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec))); 1.395 + } 1.396 + } 1.397 + ures_close(&res); 1.398 + ures_close(top); 1.399 + if (U_FAILURE(ec)) { 1.400 + U_DEBUG_TZ_MSG(("cstz: failed to create, err %s\n", u_errorName(ec))); 1.401 + delete z; 1.402 + z = 0; 1.403 + } 1.404 + return z; 1.405 +} 1.406 + 1.407 +/** 1.408 + * Lookup the given name in our system zone table. If found, 1.409 + * instantiate a new zone of that name and return it. If not 1.410 + * found, return 0. 1.411 + */ 1.412 +TimeZone* 1.413 +createSystemTimeZone(const UnicodeString& id) { 1.414 + UErrorCode ec = U_ZERO_ERROR; 1.415 + return createSystemTimeZone(id, ec); 1.416 +} 1.417 + 1.418 +} 1.419 + 1.420 +TimeZone* U_EXPORT2 1.421 +TimeZone::createTimeZone(const UnicodeString& ID) 1.422 +{ 1.423 + /* We first try to lookup the zone ID in our system list. If this 1.424 + * fails, we try to parse it as a custom string GMT[+-]hh:mm. If 1.425 + * all else fails, we return GMT, which is probably not what the 1.426 + * user wants, but at least is a functioning TimeZone object. 1.427 + * 1.428 + * We cannot return NULL, because that would break compatibility 1.429 + * with the JDK. 1.430 + */ 1.431 + TimeZone* result = createSystemTimeZone(ID); 1.432 + 1.433 + if (result == 0) { 1.434 + U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom")); 1.435 + result = createCustomTimeZone(ID); 1.436 + } 1.437 + if (result == 0) { 1.438 + U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)")); 1.439 + result = getUnknown().clone(); 1.440 + } 1.441 + return result; 1.442 +} 1.443 + 1.444 +// ------------------------------------- 1.445 + 1.446 +/** 1.447 + * Initialize DEFAULT_ZONE from the system default time zone. 1.448 + * Upon return, DEFAULT_ZONE will not be NULL, unless operator new() 1.449 + * returns NULL. 1.450 + */ 1.451 +static void U_CALLCONV initDefault() 1.452 +{ 1.453 + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); 1.454 + 1.455 + // If setDefault() has already been called we can skip getting the 1.456 + // default zone information from the system. 1.457 + if (DEFAULT_ZONE != NULL) { 1.458 + return; 1.459 + } 1.460 + 1.461 + // We access system timezone data through TPlatformUtilities, 1.462 + // including tzset(), timezone, and tzname[]. 1.463 + int32_t rawOffset = 0; 1.464 + const char *hostID; 1.465 + 1.466 + // First, try to create a system timezone, based 1.467 + // on the string ID in tzname[0]. 1.468 + 1.469 + // NOTE: this code is safely single threaded, being only 1.470 + // run via umtx_initOnce(). 1.471 + // 1.472 + // Some of the locale/timezone OS functions may not be thread safe, 1.473 + // 1.474 + // The operating system might actually use ICU to implement timezones. 1.475 + // So we may have ICU calling ICU here, like on AIX. 1.476 + // There shouldn't be a problem with this; initOnce does not hold a mutex 1.477 + // while the init function is being run. 1.478 + 1.479 + uprv_tzset(); // Initialize tz... system data 1.480 + 1.481 + // Get the timezone ID from the host. This function should do 1.482 + // any required host-specific remapping; e.g., on Windows this 1.483 + // function maps the Date and Time control panel setting to an 1.484 + // ICU timezone ID. 1.485 + hostID = uprv_tzname(0); 1.486 + 1.487 + // Invert sign because UNIX semantics are backwards 1.488 + rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND; 1.489 + 1.490 + TimeZone* default_zone = NULL; 1.491 + 1.492 + /* Make sure that the string is NULL terminated to prevent BoundsChecker/Purify warnings. */ 1.493 + UnicodeString hostStrID(hostID, -1, US_INV); 1.494 + hostStrID.append((UChar)0); 1.495 + hostStrID.truncate(hostStrID.length()-1); 1.496 + default_zone = createSystemTimeZone(hostStrID); 1.497 + 1.498 +#if U_PLATFORM_USES_ONLY_WIN32_API 1.499 + // hostID points to a heap-allocated location on Windows. 1.500 + uprv_free(const_cast<char *>(hostID)); 1.501 +#endif 1.502 + 1.503 + int32_t hostIDLen = hostStrID.length(); 1.504 + if (default_zone != NULL && rawOffset != default_zone->getRawOffset() 1.505 + && (3 <= hostIDLen && hostIDLen <= 4)) 1.506 + { 1.507 + // Uh oh. This probably wasn't a good id. 1.508 + // It was probably an ambiguous abbreviation 1.509 + delete default_zone; 1.510 + default_zone = NULL; 1.511 + } 1.512 + 1.513 + // Construct a fixed standard zone with the host's ID 1.514 + // and raw offset. 1.515 + if (default_zone == NULL) { 1.516 + default_zone = new SimpleTimeZone(rawOffset, hostStrID); 1.517 + } 1.518 + 1.519 + // If we _still_ don't have a time zone, use GMT. 1.520 + if (default_zone == NULL) { 1.521 + const TimeZone* temptz = TimeZone::getGMT(); 1.522 + // If we can't use GMT, get out. 1.523 + if (temptz == NULL) { 1.524 + return; 1.525 + } 1.526 + default_zone = temptz->clone(); 1.527 + } 1.528 + 1.529 + // The only way for DEFAULT_ZONE to be non-null at this point is if the user 1.530 + // made a thread-unsafe call to setDefault() or adoptDefault() in another 1.531 + // thread while this thread was doing something that required getting the default. 1.532 + U_ASSERT(DEFAULT_ZONE == NULL); 1.533 + 1.534 + DEFAULT_ZONE = default_zone; 1.535 +} 1.536 + 1.537 +// ------------------------------------- 1.538 + 1.539 +TimeZone* U_EXPORT2 1.540 +TimeZone::createDefault() 1.541 +{ 1.542 + umtx_initOnce(gDefaultZoneInitOnce, initDefault); 1.543 + return (DEFAULT_ZONE != NULL) ? DEFAULT_ZONE->clone() : NULL; 1.544 +} 1.545 + 1.546 +// ------------------------------------- 1.547 + 1.548 +void U_EXPORT2 1.549 +TimeZone::adoptDefault(TimeZone* zone) 1.550 +{ 1.551 + if (zone != NULL) 1.552 + { 1.553 + TimeZone *old = DEFAULT_ZONE; 1.554 + DEFAULT_ZONE = zone; 1.555 + delete old; 1.556 + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); 1.557 + } 1.558 +} 1.559 +// ------------------------------------- 1.560 + 1.561 +void U_EXPORT2 1.562 +TimeZone::setDefault(const TimeZone& zone) 1.563 +{ 1.564 + adoptDefault(zone.clone()); 1.565 +} 1.566 + 1.567 +//---------------------------------------------------------------------- 1.568 + 1.569 + 1.570 +static void U_CALLCONV initMap(USystemTimeZoneType type, UErrorCode& ec) { 1.571 + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); 1.572 + 1.573 + UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec); 1.574 + res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section 1.575 + if (U_SUCCESS(ec)) { 1.576 + int32_t size = ures_getSize(res); 1.577 + int32_t *m = (int32_t *)uprv_malloc(size * sizeof(int32_t)); 1.578 + if (m == NULL) { 1.579 + ec = U_MEMORY_ALLOCATION_ERROR; 1.580 + } else { 1.581 + int32_t numEntries = 0; 1.582 + for (int32_t i = 0; i < size; i++) { 1.583 + UnicodeString id = ures_getUnicodeStringByIndex(res, i, &ec); 1.584 + if (U_FAILURE(ec)) { 1.585 + break; 1.586 + } 1.587 + if (0 == id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)) { 1.588 + // exclude Etc/Unknown 1.589 + continue; 1.590 + } 1.591 + if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) { 1.592 + UnicodeString canonicalID; 1.593 + ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec); 1.594 + if (U_FAILURE(ec)) { 1.595 + break; 1.596 + } 1.597 + if (canonicalID != id) { 1.598 + // exclude aliases 1.599 + continue; 1.600 + } 1.601 + } 1.602 + if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) { 1.603 + const UChar *region = TimeZone::getRegion(id, ec); 1.604 + if (U_FAILURE(ec)) { 1.605 + break; 1.606 + } 1.607 + if (u_strcmp(region, WORLD) == 0) { 1.608 + // exclude non-location ("001") 1.609 + continue; 1.610 + } 1.611 + } 1.612 + m[numEntries++] = i; 1.613 + } 1.614 + if (U_SUCCESS(ec)) { 1.615 + int32_t *tmp = m; 1.616 + m = (int32_t *)uprv_realloc(tmp, numEntries * sizeof(int32_t)); 1.617 + if (m == NULL) { 1.618 + // realloc failed.. use the original one even it has unused 1.619 + // area at the end 1.620 + m = tmp; 1.621 + } 1.622 + 1.623 + switch(type) { 1.624 + case UCAL_ZONE_TYPE_ANY: 1.625 + U_ASSERT(MAP_SYSTEM_ZONES == NULL); 1.626 + MAP_SYSTEM_ZONES = m; 1.627 + LEN_SYSTEM_ZONES = numEntries; 1.628 + break; 1.629 + case UCAL_ZONE_TYPE_CANONICAL: 1.630 + U_ASSERT(MAP_CANONICAL_SYSTEM_ZONES == NULL); 1.631 + MAP_CANONICAL_SYSTEM_ZONES = m; 1.632 + LEN_CANONICAL_SYSTEM_ZONES = numEntries; 1.633 + break; 1.634 + case UCAL_ZONE_TYPE_CANONICAL_LOCATION: 1.635 + U_ASSERT(MAP_CANONICAL_SYSTEM_LOCATION_ZONES == NULL); 1.636 + MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m; 1.637 + LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries; 1.638 + break; 1.639 + } 1.640 + } 1.641 + } 1.642 + } 1.643 + ures_close(res); 1.644 +} 1.645 + 1.646 + 1.647 +/** 1.648 + * This is the default implementation for subclasses that do not 1.649 + * override this method. This implementation calls through to the 1.650 + * 8-argument getOffset() method after suitable computations, and 1.651 + * correctly adjusts GMT millis to local millis when necessary. 1.652 + */ 1.653 +void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset, 1.654 + int32_t& dstOffset, UErrorCode& ec) const { 1.655 + if (U_FAILURE(ec)) { 1.656 + return; 1.657 + } 1.658 + 1.659 + rawOffset = getRawOffset(); 1.660 + if (!local) { 1.661 + date += rawOffset; // now in local standard millis 1.662 + } 1.663 + 1.664 + // When local == TRUE, date might not be in local standard 1.665 + // millis. getOffset taking 7 parameters used here assume 1.666 + // the given time in day is local standard time. 1.667 + // At STD->DST transition, there is a range of time which 1.668 + // does not exist. When 'date' is in this time range 1.669 + // (and local == TRUE), this method interprets the specified 1.670 + // local time as DST. At DST->STD transition, there is a 1.671 + // range of time which occurs twice. In this case, this 1.672 + // method interprets the specified local time as STD. 1.673 + // To support the behavior above, we need to call getOffset 1.674 + // (with 7 args) twice when local == true and DST is 1.675 + // detected in the initial call. 1.676 + for (int32_t pass=0; ; ++pass) { 1.677 + int32_t year, month, dom, dow; 1.678 + double day = uprv_floor(date / U_MILLIS_PER_DAY); 1.679 + int32_t millis = (int32_t) (date - day * U_MILLIS_PER_DAY); 1.680 + 1.681 + Grego::dayToFields(day, year, month, dom, dow); 1.682 + 1.683 + dstOffset = getOffset(GregorianCalendar::AD, year, month, dom, 1.684 + (uint8_t) dow, millis, 1.685 + Grego::monthLength(year, month), 1.686 + ec) - rawOffset; 1.687 + 1.688 + // Recompute if local==TRUE, dstOffset!=0. 1.689 + if (pass!=0 || !local || dstOffset == 0) { 1.690 + break; 1.691 + } 1.692 + // adjust to local standard millis 1.693 + date -= dstOffset; 1.694 + } 1.695 +} 1.696 + 1.697 +// ------------------------------------- 1.698 + 1.699 +// New available IDs API as of ICU 2.4. Uses StringEnumeration API. 1.700 + 1.701 +class TZEnumeration : public StringEnumeration { 1.702 +private: 1.703 + 1.704 + // Map into to zones. Our results are zone[map[i]] for 1.705 + // i=0..len-1, where zone[i] is the i-th Olson zone. If map==NULL 1.706 + // then our results are zone[i] for i=0..len-1. Len will be zero 1.707 + // if the zone data could not be loaded. 1.708 + int32_t* map; 1.709 + int32_t* localMap; 1.710 + int32_t len; 1.711 + int32_t pos; 1.712 + 1.713 + TZEnumeration(int32_t* mapData, int32_t mapLen, UBool adoptMapData) : pos(0) { 1.714 + map = mapData; 1.715 + localMap = adoptMapData ? mapData : NULL; 1.716 + len = mapLen; 1.717 + } 1.718 + 1.719 + UBool getID(int32_t i) { 1.720 + UErrorCode ec = U_ZERO_ERROR; 1.721 + int32_t idLen = 0; 1.722 + const UChar* id = NULL; 1.723 + UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec); 1.724 + top = ures_getByKey(top, kNAMES, top, &ec); // dereference Zones section 1.725 + id = ures_getStringByIndex(top, i, &idLen, &ec); 1.726 + if(U_FAILURE(ec)) { 1.727 + unistr.truncate(0); 1.728 + } 1.729 + else { 1.730 + unistr.fastCopyFrom(UnicodeString(TRUE, id, idLen)); 1.731 + } 1.732 + ures_close(top); 1.733 + return U_SUCCESS(ec); 1.734 + } 1.735 + 1.736 + static int32_t* getMap(USystemTimeZoneType type, int32_t& len, UErrorCode& ec) { 1.737 + len = 0; 1.738 + if (U_FAILURE(ec)) { 1.739 + return NULL; 1.740 + } 1.741 + int32_t* m = NULL; 1.742 + switch (type) { 1.743 + case UCAL_ZONE_TYPE_ANY: 1.744 + umtx_initOnce(gSystemZonesInitOnce, &initMap, type, ec); 1.745 + m = MAP_SYSTEM_ZONES; 1.746 + len = LEN_SYSTEM_ZONES; 1.747 + break; 1.748 + case UCAL_ZONE_TYPE_CANONICAL: 1.749 + umtx_initOnce(gCanonicalZonesInitOnce, &initMap, type, ec); 1.750 + m = MAP_CANONICAL_SYSTEM_ZONES; 1.751 + len = LEN_CANONICAL_SYSTEM_ZONES; 1.752 + break; 1.753 + case UCAL_ZONE_TYPE_CANONICAL_LOCATION: 1.754 + umtx_initOnce(gCanonicalLocationZonesInitOnce, &initMap, type, ec); 1.755 + m = MAP_CANONICAL_SYSTEM_LOCATION_ZONES; 1.756 + len = LEN_CANONICAL_SYSTEM_LOCATION_ZONES; 1.757 + break; 1.758 + default: 1.759 + ec = U_ILLEGAL_ARGUMENT_ERROR; 1.760 + m = NULL; 1.761 + len = 0; 1.762 + break; 1.763 + } 1.764 + return m; 1.765 + } 1.766 + 1.767 +public: 1.768 + 1.769 +#define DEFAULT_FILTERED_MAP_SIZE 8 1.770 +#define MAP_INCREMENT_SIZE 8 1.771 + 1.772 + static TZEnumeration* create(USystemTimeZoneType type, const char* region, const int32_t* rawOffset, UErrorCode& ec) { 1.773 + if (U_FAILURE(ec)) { 1.774 + return NULL; 1.775 + } 1.776 + 1.777 + int32_t baseLen; 1.778 + int32_t *baseMap = getMap(type, baseLen, ec); 1.779 + 1.780 + if (U_FAILURE(ec)) { 1.781 + return NULL; 1.782 + } 1.783 + 1.784 + // If any additional conditions are available, 1.785 + // create instance local map filtered by the conditions. 1.786 + 1.787 + int32_t *filteredMap = NULL; 1.788 + int32_t numEntries = 0; 1.789 + 1.790 + if (region != NULL || rawOffset != NULL) { 1.791 + int32_t filteredMapSize = DEFAULT_FILTERED_MAP_SIZE; 1.792 + filteredMap = (int32_t *)uprv_malloc(filteredMapSize * sizeof(int32_t)); 1.793 + if (filteredMap == NULL) { 1.794 + ec = U_MEMORY_ALLOCATION_ERROR; 1.795 + return NULL; 1.796 + } 1.797 + 1.798 + // Walk through the base map 1.799 + UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec); 1.800 + res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section 1.801 + for (int32_t i = 0; i < baseLen; i++) { 1.802 + int32_t zidx = baseMap[i]; 1.803 + UnicodeString id = ures_getUnicodeStringByIndex(res, zidx, &ec); 1.804 + if (U_FAILURE(ec)) { 1.805 + break; 1.806 + } 1.807 + if (region != NULL) { 1.808 + // Filter by region 1.809 + char tzregion[4]; // max 3 letters + null term 1.810 + TimeZone::getRegion(id, tzregion, sizeof(tzregion), ec); 1.811 + if (U_FAILURE(ec)) { 1.812 + break; 1.813 + } 1.814 + if (uprv_stricmp(tzregion, region) != 0) { 1.815 + // region does not match 1.816 + continue; 1.817 + } 1.818 + } 1.819 + if (rawOffset != NULL) { 1.820 + // Filter by raw offset 1.821 + // Note: This is VERY inefficient 1.822 + TimeZone *z = createSystemTimeZone(id, ec); 1.823 + if (U_FAILURE(ec)) { 1.824 + break; 1.825 + } 1.826 + int32_t tzoffset = z->getRawOffset(); 1.827 + delete z; 1.828 + 1.829 + if (tzoffset != *rawOffset) { 1.830 + continue; 1.831 + } 1.832 + } 1.833 + 1.834 + if (filteredMapSize <= numEntries) { 1.835 + filteredMapSize += MAP_INCREMENT_SIZE; 1.836 + int32_t *tmp = (int32_t *)uprv_realloc(filteredMap, filteredMapSize * sizeof(int32_t)); 1.837 + if (tmp == NULL) { 1.838 + ec = U_MEMORY_ALLOCATION_ERROR; 1.839 + break; 1.840 + } else { 1.841 + filteredMap = tmp; 1.842 + } 1.843 + } 1.844 + 1.845 + filteredMap[numEntries++] = zidx; 1.846 + } 1.847 + 1.848 + if (U_FAILURE(ec)) { 1.849 + uprv_free(filteredMap); 1.850 + filteredMap = NULL; 1.851 + } 1.852 + 1.853 + ures_close(res); 1.854 + } 1.855 + 1.856 + TZEnumeration *result = NULL; 1.857 + if (U_SUCCESS(ec)) { 1.858 + // Finally, create a new enumeration instance 1.859 + if (filteredMap == NULL) { 1.860 + result = new TZEnumeration(baseMap, baseLen, FALSE); 1.861 + } else { 1.862 + result = new TZEnumeration(filteredMap, numEntries, TRUE); 1.863 + filteredMap = NULL; 1.864 + } 1.865 + if (result == NULL) { 1.866 + ec = U_MEMORY_ALLOCATION_ERROR; 1.867 + } 1.868 + } 1.869 + 1.870 + if (filteredMap != NULL) { 1.871 + uprv_free(filteredMap); 1.872 + } 1.873 + 1.874 + return result; 1.875 + } 1.876 + 1.877 + TZEnumeration(const TZEnumeration &other) : StringEnumeration(), map(NULL), localMap(NULL), len(0), pos(0) { 1.878 + if (other.localMap != NULL) { 1.879 + localMap = (int32_t *)uprv_malloc(other.len * sizeof(int32_t)); 1.880 + if (localMap != NULL) { 1.881 + len = other.len; 1.882 + uprv_memcpy(localMap, other.localMap, len * sizeof(int32_t)); 1.883 + pos = other.pos; 1.884 + map = localMap; 1.885 + } else { 1.886 + len = 0; 1.887 + pos = 0; 1.888 + map = NULL; 1.889 + } 1.890 + } else { 1.891 + map = other.map; 1.892 + localMap = NULL; 1.893 + len = other.len; 1.894 + pos = other.pos; 1.895 + } 1.896 + } 1.897 + 1.898 + virtual ~TZEnumeration(); 1.899 + 1.900 + virtual StringEnumeration *clone() const { 1.901 + return new TZEnumeration(*this); 1.902 + } 1.903 + 1.904 + virtual int32_t count(UErrorCode& status) const { 1.905 + return U_FAILURE(status) ? 0 : len; 1.906 + } 1.907 + 1.908 + virtual const UnicodeString* snext(UErrorCode& status) { 1.909 + if (U_SUCCESS(status) && map != NULL && pos < len) { 1.910 + getID(map[pos]); 1.911 + ++pos; 1.912 + return &unistr; 1.913 + } 1.914 + return 0; 1.915 + } 1.916 + 1.917 + virtual void reset(UErrorCode& /*status*/) { 1.918 + pos = 0; 1.919 + } 1.920 + 1.921 +public: 1.922 + static UClassID U_EXPORT2 getStaticClassID(void); 1.923 + virtual UClassID getDynamicClassID(void) const; 1.924 +}; 1.925 + 1.926 +TZEnumeration::~TZEnumeration() { 1.927 + if (localMap != NULL) { 1.928 + uprv_free(localMap); 1.929 + } 1.930 +} 1.931 + 1.932 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(TZEnumeration) 1.933 + 1.934 +StringEnumeration* U_EXPORT2 1.935 +TimeZone::createTimeZoneIDEnumeration( 1.936 + USystemTimeZoneType zoneType, 1.937 + const char* region, 1.938 + const int32_t* rawOffset, 1.939 + UErrorCode& ec) { 1.940 + return TZEnumeration::create(zoneType, region, rawOffset, ec); 1.941 +} 1.942 + 1.943 +StringEnumeration* U_EXPORT2 1.944 +TimeZone::createEnumeration() { 1.945 + UErrorCode ec = U_ZERO_ERROR; 1.946 + return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, NULL, NULL, ec); 1.947 +} 1.948 + 1.949 +StringEnumeration* U_EXPORT2 1.950 +TimeZone::createEnumeration(int32_t rawOffset) { 1.951 + UErrorCode ec = U_ZERO_ERROR; 1.952 + return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, NULL, &rawOffset, ec); 1.953 +} 1.954 + 1.955 +StringEnumeration* U_EXPORT2 1.956 +TimeZone::createEnumeration(const char* country) { 1.957 + UErrorCode ec = U_ZERO_ERROR; 1.958 + return TZEnumeration::create(UCAL_ZONE_TYPE_ANY, country, NULL, ec); 1.959 +} 1.960 + 1.961 +// --------------------------------------- 1.962 + 1.963 +int32_t U_EXPORT2 1.964 +TimeZone::countEquivalentIDs(const UnicodeString& id) { 1.965 + int32_t result = 0; 1.966 + UErrorCode ec = U_ZERO_ERROR; 1.967 + UResourceBundle res; 1.968 + ures_initStackObject(&res); 1.969 + U_DEBUG_TZ_MSG(("countEquivalentIDs..\n")); 1.970 + UResourceBundle *top = openOlsonResource(id, res, ec); 1.971 + if (U_SUCCESS(ec)) { 1.972 + UResourceBundle r; 1.973 + ures_initStackObject(&r); 1.974 + ures_getByKey(&res, kLINKS, &r, &ec); 1.975 + ures_getIntVector(&r, &result, &ec); 1.976 + ures_close(&r); 1.977 + } 1.978 + ures_close(&res); 1.979 + ures_close(top); 1.980 + return result; 1.981 +} 1.982 + 1.983 +// --------------------------------------- 1.984 + 1.985 +const UnicodeString U_EXPORT2 1.986 +TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) { 1.987 + U_DEBUG_TZ_MSG(("gEI(%d)\n", index)); 1.988 + UnicodeString result; 1.989 + UErrorCode ec = U_ZERO_ERROR; 1.990 + UResourceBundle res; 1.991 + ures_initStackObject(&res); 1.992 + UResourceBundle *top = openOlsonResource(id, res, ec); 1.993 + int32_t zone = -1; 1.994 + if (U_SUCCESS(ec)) { 1.995 + UResourceBundle r; 1.996 + ures_initStackObject(&r); 1.997 + int32_t size; 1.998 + ures_getByKey(&res, kLINKS, &r, &ec); 1.999 + const int32_t* v = ures_getIntVector(&r, &size, &ec); 1.1000 + if (U_SUCCESS(ec)) { 1.1001 + if (index >= 0 && index < size) { 1.1002 + zone = v[index]; 1.1003 + } 1.1004 + } 1.1005 + ures_close(&r); 1.1006 + } 1.1007 + ures_close(&res); 1.1008 + if (zone >= 0) { 1.1009 + UResourceBundle *ares = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Zones section 1.1010 + if (U_SUCCESS(ec)) { 1.1011 + int32_t idLen = 0; 1.1012 + const UChar* id = ures_getStringByIndex(ares, zone, &idLen, &ec); 1.1013 + result.fastCopyFrom(UnicodeString(TRUE, id, idLen)); 1.1014 + U_DEBUG_TZ_MSG(("gei(%d) -> %d, len%d, %s\n", index, zone, result.length(), u_errorName(ec))); 1.1015 + } 1.1016 + ures_close(ares); 1.1017 + } 1.1018 + ures_close(top); 1.1019 +#if defined(U_DEBUG_TZ) 1.1020 + if(result.length() ==0) { 1.1021 + U_DEBUG_TZ_MSG(("equiv [__, #%d] -> 0 (%s)\n", index, u_errorName(ec))); 1.1022 + } 1.1023 +#endif 1.1024 + return result; 1.1025 +} 1.1026 + 1.1027 +// --------------------------------------- 1.1028 + 1.1029 +// These methods are used by ZoneMeta class only. 1.1030 + 1.1031 +const UChar* 1.1032 +TimeZone::findID(const UnicodeString& id) { 1.1033 + const UChar *result = NULL; 1.1034 + UErrorCode ec = U_ZERO_ERROR; 1.1035 + UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec); 1.1036 + 1.1037 + // resolve zone index by name 1.1038 + UResourceBundle *names = ures_getByKey(rb, kNAMES, NULL, &ec); 1.1039 + int32_t idx = findInStringArray(names, id, ec); 1.1040 + result = ures_getStringByIndex(names, idx, NULL, &ec); 1.1041 + if (U_FAILURE(ec)) { 1.1042 + result = NULL; 1.1043 + } 1.1044 + ures_close(names); 1.1045 + ures_close(rb); 1.1046 + return result; 1.1047 +} 1.1048 + 1.1049 + 1.1050 +const UChar* 1.1051 +TimeZone::dereferOlsonLink(const UnicodeString& id) { 1.1052 + const UChar *result = NULL; 1.1053 + UErrorCode ec = U_ZERO_ERROR; 1.1054 + UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec); 1.1055 + 1.1056 + // resolve zone index by name 1.1057 + UResourceBundle *names = ures_getByKey(rb, kNAMES, NULL, &ec); 1.1058 + int32_t idx = findInStringArray(names, id, ec); 1.1059 + result = ures_getStringByIndex(names, idx, NULL, &ec); 1.1060 + 1.1061 + // open the zone bundle by index 1.1062 + ures_getByKey(rb, kZONES, rb, &ec); 1.1063 + ures_getByIndex(rb, idx, rb, &ec); 1.1064 + 1.1065 + if (U_SUCCESS(ec)) { 1.1066 + if (ures_getType(rb) == URES_INT) { 1.1067 + // this is a link - dereference the link 1.1068 + int32_t deref = ures_getInt(rb, &ec); 1.1069 + const UChar* tmp = ures_getStringByIndex(names, deref, NULL, &ec); 1.1070 + if (U_SUCCESS(ec)) { 1.1071 + result = tmp; 1.1072 + } 1.1073 + } 1.1074 + } 1.1075 + 1.1076 + ures_close(names); 1.1077 + ures_close(rb); 1.1078 + 1.1079 + return result; 1.1080 +} 1.1081 + 1.1082 +const UChar* 1.1083 +TimeZone::getRegion(const UnicodeString& id) { 1.1084 + UErrorCode status = U_ZERO_ERROR; 1.1085 + return getRegion(id, status); 1.1086 +} 1.1087 + 1.1088 +const UChar* 1.1089 +TimeZone::getRegion(const UnicodeString& id, UErrorCode& status) { 1.1090 + if (U_FAILURE(status)) { 1.1091 + return NULL; 1.1092 + } 1.1093 + const UChar *result = NULL; 1.1094 + UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &status); 1.1095 + 1.1096 + // resolve zone index by name 1.1097 + UResourceBundle *res = ures_getByKey(rb, kNAMES, NULL, &status); 1.1098 + int32_t idx = findInStringArray(res, id, status); 1.1099 + 1.1100 + // get region mapping 1.1101 + ures_getByKey(rb, kREGIONS, res, &status); 1.1102 + const UChar *tmp = ures_getStringByIndex(res, idx, NULL, &status); 1.1103 + if (U_SUCCESS(status)) { 1.1104 + result = tmp; 1.1105 + } 1.1106 + 1.1107 + ures_close(res); 1.1108 + ures_close(rb); 1.1109 + 1.1110 + return result; 1.1111 +} 1.1112 + 1.1113 + 1.1114 +// --------------------------------------- 1.1115 +int32_t 1.1116 +TimeZone::getRegion(const UnicodeString& id, char *region, int32_t capacity, UErrorCode& status) 1.1117 +{ 1.1118 + int32_t resultLen = 0; 1.1119 + *region = 0; 1.1120 + if (U_FAILURE(status)) { 1.1121 + return 0; 1.1122 + } 1.1123 + 1.1124 + const UChar *uregion = NULL; 1.1125 + // "Etc/Unknown" is not a system zone ID, 1.1126 + // but in the zone data 1.1127 + if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) != 0) { 1.1128 + uregion = getRegion(id); 1.1129 + } 1.1130 + if (uregion == NULL) { 1.1131 + status = U_ILLEGAL_ARGUMENT_ERROR; 1.1132 + return 0; 1.1133 + } 1.1134 + resultLen = u_strlen(uregion); 1.1135 + // A region code is represented by invariant characters 1.1136 + u_UCharsToChars(uregion, region, uprv_min(resultLen, capacity)); 1.1137 + 1.1138 + if (capacity < resultLen) { 1.1139 + status = U_BUFFER_OVERFLOW_ERROR; 1.1140 + return resultLen; 1.1141 + } 1.1142 + 1.1143 + return u_terminateChars(region, capacity, resultLen, &status); 1.1144 +} 1.1145 + 1.1146 +// --------------------------------------- 1.1147 + 1.1148 + 1.1149 +UnicodeString& 1.1150 +TimeZone::getDisplayName(UnicodeString& result) const 1.1151 +{ 1.1152 + return getDisplayName(FALSE,LONG,Locale::getDefault(), result); 1.1153 +} 1.1154 + 1.1155 +UnicodeString& 1.1156 +TimeZone::getDisplayName(const Locale& locale, UnicodeString& result) const 1.1157 +{ 1.1158 + return getDisplayName(FALSE, LONG, locale, result); 1.1159 +} 1.1160 + 1.1161 +UnicodeString& 1.1162 +TimeZone::getDisplayName(UBool daylight, EDisplayType style, UnicodeString& result) const 1.1163 +{ 1.1164 + return getDisplayName(daylight,style, Locale::getDefault(), result); 1.1165 +} 1.1166 +//-------------------------------------- 1.1167 +int32_t 1.1168 +TimeZone::getDSTSavings()const { 1.1169 + if (useDaylightTime()) { 1.1170 + return 3600000; 1.1171 + } 1.1172 + return 0; 1.1173 +} 1.1174 +//--------------------------------------- 1.1175 +UnicodeString& 1.1176 +TimeZone::getDisplayName(UBool daylight, EDisplayType style, const Locale& locale, UnicodeString& result) const 1.1177 +{ 1.1178 + UErrorCode status = U_ZERO_ERROR; 1.1179 + UDate date = Calendar::getNow(); 1.1180 + UTimeZoneFormatTimeType timeType; 1.1181 + int32_t offset; 1.1182 + 1.1183 + if (style == GENERIC_LOCATION || style == LONG_GENERIC || style == SHORT_GENERIC) { 1.1184 + LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status)); 1.1185 + if (U_FAILURE(status)) { 1.1186 + result.remove(); 1.1187 + return result; 1.1188 + } 1.1189 + // Generic format 1.1190 + switch (style) { 1.1191 + case GENERIC_LOCATION: 1.1192 + tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, *this, date, result, &timeType); 1.1193 + break; 1.1194 + case LONG_GENERIC: 1.1195 + tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, *this, date, result, &timeType); 1.1196 + break; 1.1197 + case SHORT_GENERIC: 1.1198 + tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, *this, date, result, &timeType); 1.1199 + break; 1.1200 + default: 1.1201 + U_ASSERT(FALSE); 1.1202 + } 1.1203 + // Generic format many use Localized GMT as the final fallback. 1.1204 + // When Localized GMT format is used, the result might not be 1.1205 + // appropriate for the requested daylight value. 1.1206 + if ((daylight && timeType == UTZFMT_TIME_TYPE_STANDARD) || (!daylight && timeType == UTZFMT_TIME_TYPE_DAYLIGHT)) { 1.1207 + offset = daylight ? getRawOffset() + getDSTSavings() : getRawOffset(); 1.1208 + if (style == SHORT_GENERIC) { 1.1209 + tzfmt->formatOffsetShortLocalizedGMT(offset, result, status); 1.1210 + } else { 1.1211 + tzfmt->formatOffsetLocalizedGMT(offset, result, status); 1.1212 + } 1.1213 + } 1.1214 + } else if (style == LONG_GMT || style == SHORT_GMT) { 1.1215 + LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status)); 1.1216 + if (U_FAILURE(status)) { 1.1217 + result.remove(); 1.1218 + return result; 1.1219 + } 1.1220 + offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset(); 1.1221 + switch (style) { 1.1222 + case LONG_GMT: 1.1223 + tzfmt->formatOffsetLocalizedGMT(offset, result, status); 1.1224 + break; 1.1225 + case SHORT_GMT: 1.1226 + tzfmt->formatOffsetISO8601Basic(offset, FALSE, FALSE, FALSE, result, status); 1.1227 + break; 1.1228 + default: 1.1229 + U_ASSERT(FALSE); 1.1230 + } 1.1231 + 1.1232 + } else { 1.1233 + U_ASSERT(style == LONG || style == SHORT || style == SHORT_COMMONLY_USED); 1.1234 + UTimeZoneNameType nameType = UTZNM_UNKNOWN; 1.1235 + switch (style) { 1.1236 + case LONG: 1.1237 + nameType = daylight ? UTZNM_LONG_DAYLIGHT : UTZNM_LONG_STANDARD; 1.1238 + break; 1.1239 + case SHORT: 1.1240 + case SHORT_COMMONLY_USED: 1.1241 + nameType = daylight ? UTZNM_SHORT_DAYLIGHT : UTZNM_SHORT_STANDARD; 1.1242 + break; 1.1243 + default: 1.1244 + U_ASSERT(FALSE); 1.1245 + } 1.1246 + LocalPointer<TimeZoneNames> tznames(TimeZoneNames::createInstance(locale, status)); 1.1247 + if (U_FAILURE(status)) { 1.1248 + result.remove(); 1.1249 + return result; 1.1250 + } 1.1251 + UnicodeString canonicalID(ZoneMeta::getCanonicalCLDRID(*this)); 1.1252 + tznames->getDisplayName(canonicalID, nameType, date, result); 1.1253 + if (result.isEmpty()) { 1.1254 + // Fallback to localized GMT 1.1255 + LocalPointer<TimeZoneFormat> tzfmt(TimeZoneFormat::createInstance(locale, status)); 1.1256 + offset = daylight && useDaylightTime() ? getRawOffset() + getDSTSavings() : getRawOffset(); 1.1257 + if (style == LONG) { 1.1258 + tzfmt->formatOffsetLocalizedGMT(offset, result, status); 1.1259 + } else { 1.1260 + tzfmt->formatOffsetShortLocalizedGMT(offset, result, status); 1.1261 + } 1.1262 + } 1.1263 + } 1.1264 + if (U_FAILURE(status)) { 1.1265 + result.remove(); 1.1266 + } 1.1267 + return result; 1.1268 +} 1.1269 + 1.1270 +/** 1.1271 + * Parse a custom time zone identifier and return a corresponding zone. 1.1272 + * @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or 1.1273 + * GMT[+-]hh. 1.1274 + * @return a newly created SimpleTimeZone with the given offset and 1.1275 + * no Daylight Savings Time, or null if the id cannot be parsed. 1.1276 +*/ 1.1277 +TimeZone* 1.1278 +TimeZone::createCustomTimeZone(const UnicodeString& id) 1.1279 +{ 1.1280 + int32_t sign, hour, min, sec; 1.1281 + if (parseCustomID(id, sign, hour, min, sec)) { 1.1282 + UnicodeString customID; 1.1283 + formatCustomID(hour, min, sec, (sign < 0), customID); 1.1284 + int32_t offset = sign * ((hour * 60 + min) * 60 + sec) * 1000; 1.1285 + return new SimpleTimeZone(offset, customID); 1.1286 + } 1.1287 + return NULL; 1.1288 +} 1.1289 + 1.1290 +UnicodeString& 1.1291 +TimeZone::getCustomID(const UnicodeString& id, UnicodeString& normalized, UErrorCode& status) { 1.1292 + normalized.remove(); 1.1293 + if (U_FAILURE(status)) { 1.1294 + return normalized; 1.1295 + } 1.1296 + int32_t sign, hour, min, sec; 1.1297 + if (parseCustomID(id, sign, hour, min, sec)) { 1.1298 + formatCustomID(hour, min, sec, (sign < 0), normalized); 1.1299 + } 1.1300 + return normalized; 1.1301 +} 1.1302 + 1.1303 +UBool 1.1304 +TimeZone::parseCustomID(const UnicodeString& id, int32_t& sign, 1.1305 + int32_t& hour, int32_t& min, int32_t& sec) { 1.1306 + static const int32_t kParseFailed = -99999; 1.1307 + 1.1308 + NumberFormat* numberFormat = 0; 1.1309 + UnicodeString idUppercase = id; 1.1310 + idUppercase.toUpper(""); 1.1311 + 1.1312 + if (id.length() > GMT_ID_LENGTH && 1.1313 + idUppercase.startsWith(GMT_ID, GMT_ID_LENGTH)) 1.1314 + { 1.1315 + ParsePosition pos(GMT_ID_LENGTH); 1.1316 + sign = 1; 1.1317 + hour = 0; 1.1318 + min = 0; 1.1319 + sec = 0; 1.1320 + 1.1321 + if (id[pos.getIndex()] == MINUS /*'-'*/) { 1.1322 + sign = -1; 1.1323 + } else if (id[pos.getIndex()] != PLUS /*'+'*/) { 1.1324 + return FALSE; 1.1325 + } 1.1326 + pos.setIndex(pos.getIndex() + 1); 1.1327 + 1.1328 + UErrorCode success = U_ZERO_ERROR; 1.1329 + numberFormat = NumberFormat::createInstance(success); 1.1330 + if(U_FAILURE(success)){ 1.1331 + return FALSE; 1.1332 + } 1.1333 + numberFormat->setParseIntegerOnly(TRUE); 1.1334 + //numberFormat->setLenient(TRUE); // TODO: May need to set this, depends on latest timezone parsing 1.1335 + 1.1336 + // Look for either hh:mm, hhmm, or hh 1.1337 + int32_t start = pos.getIndex(); 1.1338 + Formattable n(kParseFailed); 1.1339 + numberFormat->parse(id, n, pos); 1.1340 + if (pos.getIndex() == start) { 1.1341 + delete numberFormat; 1.1342 + return FALSE; 1.1343 + } 1.1344 + hour = n.getLong(); 1.1345 + 1.1346 + if (pos.getIndex() < id.length()) { 1.1347 + if (pos.getIndex() - start > 2 1.1348 + || id[pos.getIndex()] != COLON) { 1.1349 + delete numberFormat; 1.1350 + return FALSE; 1.1351 + } 1.1352 + // hh:mm 1.1353 + pos.setIndex(pos.getIndex() + 1); 1.1354 + int32_t oldPos = pos.getIndex(); 1.1355 + n.setLong(kParseFailed); 1.1356 + numberFormat->parse(id, n, pos); 1.1357 + if ((pos.getIndex() - oldPos) != 2) { 1.1358 + // must be 2 digits 1.1359 + delete numberFormat; 1.1360 + return FALSE; 1.1361 + } 1.1362 + min = n.getLong(); 1.1363 + if (pos.getIndex() < id.length()) { 1.1364 + if (id[pos.getIndex()] != COLON) { 1.1365 + delete numberFormat; 1.1366 + return FALSE; 1.1367 + } 1.1368 + // [:ss] 1.1369 + pos.setIndex(pos.getIndex() + 1); 1.1370 + oldPos = pos.getIndex(); 1.1371 + n.setLong(kParseFailed); 1.1372 + numberFormat->parse(id, n, pos); 1.1373 + if (pos.getIndex() != id.length() 1.1374 + || (pos.getIndex() - oldPos) != 2) { 1.1375 + delete numberFormat; 1.1376 + return FALSE; 1.1377 + } 1.1378 + sec = n.getLong(); 1.1379 + } 1.1380 + } else { 1.1381 + // Supported formats are below - 1.1382 + // 1.1383 + // HHmmss 1.1384 + // Hmmss 1.1385 + // HHmm 1.1386 + // Hmm 1.1387 + // HH 1.1388 + // H 1.1389 + 1.1390 + int32_t length = pos.getIndex() - start; 1.1391 + if (length <= 0 || 6 < length) { 1.1392 + // invalid length 1.1393 + delete numberFormat; 1.1394 + return FALSE; 1.1395 + } 1.1396 + switch (length) { 1.1397 + case 1: 1.1398 + case 2: 1.1399 + // already set to hour 1.1400 + break; 1.1401 + case 3: 1.1402 + case 4: 1.1403 + min = hour % 100; 1.1404 + hour /= 100; 1.1405 + break; 1.1406 + case 5: 1.1407 + case 6: 1.1408 + sec = hour % 100; 1.1409 + min = (hour/100) % 100; 1.1410 + hour /= 10000; 1.1411 + break; 1.1412 + } 1.1413 + } 1.1414 + 1.1415 + delete numberFormat; 1.1416 + 1.1417 + if (hour > kMAX_CUSTOM_HOUR || min > kMAX_CUSTOM_MIN || sec > kMAX_CUSTOM_SEC) { 1.1418 + return FALSE; 1.1419 + } 1.1420 + return TRUE; 1.1421 + } 1.1422 + return FALSE; 1.1423 +} 1.1424 + 1.1425 +UnicodeString& 1.1426 +TimeZone::formatCustomID(int32_t hour, int32_t min, int32_t sec, 1.1427 + UBool negative, UnicodeString& id) { 1.1428 + // Create time zone ID - GMT[+|-]hhmm[ss] 1.1429 + id.setTo(GMT_ID, GMT_ID_LENGTH); 1.1430 + if (hour | min | sec) { 1.1431 + if (negative) { 1.1432 + id += (UChar)MINUS; 1.1433 + } else { 1.1434 + id += (UChar)PLUS; 1.1435 + } 1.1436 + 1.1437 + if (hour < 10) { 1.1438 + id += (UChar)ZERO_DIGIT; 1.1439 + } else { 1.1440 + id += (UChar)(ZERO_DIGIT + hour/10); 1.1441 + } 1.1442 + id += (UChar)(ZERO_DIGIT + hour%10); 1.1443 + id += (UChar)COLON; 1.1444 + if (min < 10) { 1.1445 + id += (UChar)ZERO_DIGIT; 1.1446 + } else { 1.1447 + id += (UChar)(ZERO_DIGIT + min/10); 1.1448 + } 1.1449 + id += (UChar)(ZERO_DIGIT + min%10); 1.1450 + 1.1451 + if (sec) { 1.1452 + id += (UChar)COLON; 1.1453 + if (sec < 10) { 1.1454 + id += (UChar)ZERO_DIGIT; 1.1455 + } else { 1.1456 + id += (UChar)(ZERO_DIGIT + sec/10); 1.1457 + } 1.1458 + id += (UChar)(ZERO_DIGIT + sec%10); 1.1459 + } 1.1460 + } 1.1461 + return id; 1.1462 +} 1.1463 + 1.1464 + 1.1465 +UBool 1.1466 +TimeZone::hasSameRules(const TimeZone& other) const 1.1467 +{ 1.1468 + return (getRawOffset() == other.getRawOffset() && 1.1469 + useDaylightTime() == other.useDaylightTime()); 1.1470 +} 1.1471 + 1.1472 +static void U_CALLCONV initTZDataVersion(UErrorCode &status) { 1.1473 + ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup); 1.1474 + int32_t len = 0; 1.1475 + UResourceBundle *bundle = ures_openDirect(NULL, kZONEINFO, &status); 1.1476 + const UChar *tzver = ures_getStringByKey(bundle, kTZVERSION, &len, &status); 1.1477 + 1.1478 + if (U_SUCCESS(status)) { 1.1479 + if (len >= (int32_t)sizeof(TZDATA_VERSION)) { 1.1480 + // Ensure that there is always space for a trailing nul in TZDATA_VERSION 1.1481 + len = sizeof(TZDATA_VERSION) - 1; 1.1482 + } 1.1483 + u_UCharsToChars(tzver, TZDATA_VERSION, len); 1.1484 + } 1.1485 + ures_close(bundle); 1.1486 + 1.1487 +} 1.1488 + 1.1489 +const char* 1.1490 +TimeZone::getTZDataVersion(UErrorCode& status) 1.1491 +{ 1.1492 + umtx_initOnce(gTZDataVersionInitOnce, &initTZDataVersion, status); 1.1493 + return (const char*)TZDATA_VERSION; 1.1494 +} 1.1495 + 1.1496 +UnicodeString& 1.1497 +TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UErrorCode& status) 1.1498 +{ 1.1499 + UBool isSystemID = FALSE; 1.1500 + return getCanonicalID(id, canonicalID, isSystemID, status); 1.1501 +} 1.1502 + 1.1503 +UnicodeString& 1.1504 +TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UBool& isSystemID, 1.1505 + UErrorCode& status) 1.1506 +{ 1.1507 + canonicalID.remove(); 1.1508 + isSystemID = FALSE; 1.1509 + if (U_FAILURE(status)) { 1.1510 + return canonicalID; 1.1511 + } 1.1512 + if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) == 0) { 1.1513 + // special case - Etc/Unknown is a canonical ID, but not system ID 1.1514 + canonicalID.fastCopyFrom(id); 1.1515 + isSystemID = FALSE; 1.1516 + } else { 1.1517 + ZoneMeta::getCanonicalCLDRID(id, canonicalID, status); 1.1518 + if (U_SUCCESS(status)) { 1.1519 + isSystemID = TRUE; 1.1520 + } else { 1.1521 + // Not a system ID 1.1522 + status = U_ZERO_ERROR; 1.1523 + getCustomID(id, canonicalID, status); 1.1524 + } 1.1525 + } 1.1526 + return canonicalID; 1.1527 +} 1.1528 + 1.1529 +#ifndef U_HIDE_DRAFT_API 1.1530 +UnicodeString& 1.1531 +TimeZone::getWindowsID(const UnicodeString& id, UnicodeString& winid, UErrorCode& status) { 1.1532 + winid.remove(); 1.1533 + if (U_FAILURE(status)) { 1.1534 + return winid; 1.1535 + } 1.1536 + 1.1537 + // canonicalize the input ID 1.1538 + UnicodeString canonicalID; 1.1539 + UBool isSystemID = FALSE; 1.1540 + 1.1541 + getCanonicalID(id, canonicalID, isSystemID, status); 1.1542 + if (U_FAILURE(status) || !isSystemID) { 1.1543 + // mapping data is only applicable to tz database IDs 1.1544 + return winid; 1.1545 + } 1.1546 + 1.1547 + UResourceBundle *mapTimezones = ures_openDirect(NULL, "windowsZones", &status); 1.1548 + ures_getByKey(mapTimezones, "mapTimezones", mapTimezones, &status); 1.1549 + 1.1550 + if (U_FAILURE(status)) { 1.1551 + return winid; 1.1552 + } 1.1553 + 1.1554 + UResourceBundle *winzone = NULL; 1.1555 + UBool found = FALSE; 1.1556 + while (ures_hasNext(mapTimezones) && !found) { 1.1557 + winzone = ures_getNextResource(mapTimezones, winzone, &status); 1.1558 + if (U_FAILURE(status)) { 1.1559 + break; 1.1560 + } 1.1561 + if (ures_getType(winzone) != URES_TABLE) { 1.1562 + continue; 1.1563 + } 1.1564 + UResourceBundle *regionalData = NULL; 1.1565 + while (ures_hasNext(winzone) && !found) { 1.1566 + regionalData = ures_getNextResource(winzone, regionalData, &status); 1.1567 + if (U_FAILURE(status)) { 1.1568 + break; 1.1569 + } 1.1570 + if (ures_getType(regionalData) != URES_STRING) { 1.1571 + continue; 1.1572 + } 1.1573 + int32_t len; 1.1574 + const UChar *tzids = ures_getString(regionalData, &len, &status); 1.1575 + if (U_FAILURE(status)) { 1.1576 + break; 1.1577 + } 1.1578 + 1.1579 + const UChar *start = tzids; 1.1580 + UBool hasNext = TRUE; 1.1581 + while (hasNext) { 1.1582 + const UChar *end = u_strchr(start, (UChar)0x20); 1.1583 + if (end == NULL) { 1.1584 + end = tzids + len; 1.1585 + hasNext = FALSE; 1.1586 + } 1.1587 + if (canonicalID.compare(start, end - start) == 0) { 1.1588 + winid = UnicodeString(ures_getKey(winzone), -1 , US_INV); 1.1589 + found = TRUE; 1.1590 + break; 1.1591 + } 1.1592 + start = end + 1; 1.1593 + } 1.1594 + } 1.1595 + ures_close(regionalData); 1.1596 + } 1.1597 + ures_close(winzone); 1.1598 + ures_close(mapTimezones); 1.1599 + 1.1600 + return winid; 1.1601 +} 1.1602 + 1.1603 +#define MAX_WINDOWS_ID_SIZE 128 1.1604 + 1.1605 +UnicodeString& 1.1606 +TimeZone::getIDForWindowsID(const UnicodeString& winid, const char* region, UnicodeString& id, UErrorCode& status) { 1.1607 + id.remove(); 1.1608 + if (U_FAILURE(status)) { 1.1609 + return id; 1.1610 + } 1.1611 + 1.1612 + UResourceBundle *zones = ures_openDirect(NULL, "windowsZones", &status); 1.1613 + ures_getByKey(zones, "mapTimezones", zones, &status); 1.1614 + if (U_FAILURE(status)) { 1.1615 + ures_close(zones); 1.1616 + return id; 1.1617 + } 1.1618 + 1.1619 + UErrorCode tmperr = U_ZERO_ERROR; 1.1620 + char winidKey[MAX_WINDOWS_ID_SIZE]; 1.1621 + int32_t winKeyLen = winid.extract(0, winid.length(), winidKey, sizeof(winidKey) - 1, US_INV); 1.1622 + 1.1623 + if (winKeyLen == 0 || winKeyLen >= (int32_t)sizeof(winidKey)) { 1.1624 + ures_close(zones); 1.1625 + return id; 1.1626 + } 1.1627 + winidKey[winKeyLen] = 0; 1.1628 + 1.1629 + ures_getByKey(zones, winidKey, zones, &tmperr); // use tmperr, because windows mapping might not 1.1630 + // be avaiable by design 1.1631 + if (U_FAILURE(tmperr)) { 1.1632 + ures_close(zones); 1.1633 + return id; 1.1634 + } 1.1635 + 1.1636 + const UChar *tzid = NULL; 1.1637 + int32_t len = 0; 1.1638 + UBool gotID = FALSE; 1.1639 + if (region) { 1.1640 + const UChar *tzids = ures_getStringByKey(zones, region, &len, &tmperr); // use tmperr, because 1.1641 + // regional mapping is optional 1.1642 + if (U_SUCCESS(tmperr)) { 1.1643 + // first ID delimited by space is the defasult one 1.1644 + const UChar *end = u_strchr(tzids, (UChar)0x20); 1.1645 + if (end == NULL) { 1.1646 + id.setTo(tzids, -1); 1.1647 + } else { 1.1648 + id.setTo(tzids, end - tzids); 1.1649 + } 1.1650 + gotID = TRUE; 1.1651 + } 1.1652 + } 1.1653 + 1.1654 + if (!gotID) { 1.1655 + tzid = ures_getStringByKey(zones, "001", &len, &status); // using status, because "001" must be 1.1656 + // available at this point 1.1657 + if (U_SUCCESS(status)) { 1.1658 + id.setTo(tzid, len); 1.1659 + } 1.1660 + } 1.1661 + 1.1662 + ures_close(zones); 1.1663 + return id; 1.1664 +} 1.1665 +#endif /* U_HIDE_DRAFT_API */ 1.1666 + 1.1667 + 1.1668 +U_NAMESPACE_END 1.1669 + 1.1670 +#endif /* #if !UCONFIG_NO_FORMATTING */ 1.1671 + 1.1672 +//eof