1/* 2 * Copyright (c) 2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* CFTimeZone.c 25 Copyright (c) 1998-2013, Apple Inc. All rights reserved. 26 Responsibility: Christopher Kane 27*/ 28 29 30#include <CoreFoundation/CFTimeZone.h> 31#include <CoreFoundation/CFPropertyList.h> 32#include <CoreFoundation/CFDateFormatter.h> 33#include <CoreFoundation/CFPriv.h> 34#include "CFInternal.h" 35#include <math.h> 36#include <limits.h> 37#include <sys/stat.h> 38#include <fcntl.h> 39#include <stdlib.h> 40#include <string.h> 41#include <unicode/ucal.h> 42#include <CoreFoundation/CFDateFormatter.h> 43#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX 44#include <dirent.h> 45#include <unistd.h> 46#include <sys/fcntl.h> 47#endif 48#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 49#include <tzfile.h> 50#elif DEPLOYMENT_TARGET_LINUX 51#ifndef TZDIR 52#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */ 53#endif /* !defined TZDIR */ 54 55#ifndef TZDEFAULT 56#define TZDEFAULT "/etc/localtime" 57#endif /* !defined TZDEFAULT */ 58 59struct tzhead { 60 char tzh_magic[4]; /* TZ_MAGIC */ 61 char tzh_reserved[16]; /* reserved for future use */ 62 char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ 63 char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ 64 char tzh_leapcnt[4]; /* coded number of leap seconds */ 65 char tzh_timecnt[4]; /* coded number of transition times */ 66 char tzh_typecnt[4]; /* coded number of local time types */ 67 char tzh_charcnt[4]; /* coded number of abbr. chars */ 68}; 69#endif 70 71#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX 72#define TZZONELINK TZDEFAULT 73#define TZZONEINFO TZDIR "/" 74#elif DEPLOYMENT_TARGET_WINDOWS 75static CFStringRef __tzZoneInfo = NULL; 76static char *__tzDir = NULL; 77static void __InitTZStrings(void); 78#else 79#error Unknown or unspecified DEPLOYMENT_TARGET 80#endif 81 82#if DEPLOYMENT_TARGET_LINUX 83// Symbol aliases 84CF_EXPORT CFStringRef const kCFDateFormatterTimeZone __attribute__((weak, alias ("kCFDateFormatterTimeZoneKey"))); 85#endif 86 87CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification") 88 89static CFTimeZoneRef __CFTimeZoneSystem = NULL; 90static CFTimeZoneRef __CFTimeZoneDefault = NULL; 91static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL; 92static CFSpinLock_t __CFTimeZoneAbbreviationLock = CFSpinLockInit; 93static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL; 94static CFSpinLock_t __CFTimeZoneCompatibilityMappingLock = CFSpinLockInit; 95static CFArrayRef __CFKnownTimeZoneList = NULL; 96static CFMutableDictionaryRef __CFTimeZoneCache = NULL; 97static CFSpinLock_t __CFTimeZoneGlobalLock = CFSpinLockInit; 98 99#if DEPLOYMENT_TARGET_WINDOWS 100static CFDictionaryRef __CFTimeZoneWinToOlsonDict = NULL; 101static CFSpinLock_t __CFTimeZoneWinToOlsonLock = CFSpinLockInit; 102#endif 103 104CF_INLINE void __CFTimeZoneLockGlobal(void) { 105 __CFSpinLock(&__CFTimeZoneGlobalLock); 106} 107 108CF_INLINE void __CFTimeZoneUnlockGlobal(void) { 109 __CFSpinUnlock(&__CFTimeZoneGlobalLock); 110} 111 112CF_INLINE void __CFTimeZoneLockAbbreviations(void) { 113 __CFSpinLock(&__CFTimeZoneAbbreviationLock); 114} 115 116CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) { 117 __CFSpinUnlock(&__CFTimeZoneAbbreviationLock); 118} 119 120CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) { 121 __CFSpinLock(&__CFTimeZoneCompatibilityMappingLock); 122} 123 124CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) { 125 __CFSpinUnlock(&__CFTimeZoneCompatibilityMappingLock); 126} 127 128#if DEPLOYMENT_TARGET_WINDOWS 129/* This function should be used for WIN32 instead of 130 * __CFCopyRecursiveDirectoryList function. 131 * It takes TimeZone names from the registry 132 * (Aleksey Dukhnyakov) 133 */ 134static CFMutableArrayRef __CFCopyWindowsTimeZoneList() { 135 CFMutableArrayRef result = NULL; 136 HKEY hkResult; 137 TCHAR lpName[MAX_PATH+1]; 138 DWORD dwIndex, retCode; 139 140 if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) != 141 ERROR_SUCCESS ) 142 return NULL; 143 144 result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 145 for (dwIndex=0; (retCode = RegEnumKey(hkResult,dwIndex,lpName,MAX_PATH)) != ERROR_NO_MORE_ITEMS ; dwIndex++) { 146 if (retCode != ERROR_SUCCESS) { 147 RegCloseKey(hkResult); 148 CFRelease(result); 149 return NULL; 150 } else { 151#if defined(UNICODE) 152 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const UInt8 *)lpName, (_tcslen(lpName) * sizeof(UniChar)), kCFStringEncodingUnicode, false); 153#else 154 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, lpName, _tcslen(lpName), CFStringGetSystemEncoding(), false); 155#endif 156 CFArrayAppendValue(result, string); 157 CFRelease(string); 158 } 159 } 160 161 RegCloseKey(hkResult); 162 return result; 163} 164#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX 165static CFMutableArrayRef __CFCopyRecursiveDirectoryList() { 166 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 167#if DEPLOYMENT_TARGET_WINDOWS 168 if (!__tzDir) __InitTZStrings(); 169 if (!__tzDir) return result; 170 int fd = open(__tzDir, O_RDONLY); 171#else 172 int fd = open(TZDIR "/zone.tab", O_RDONLY); 173#endif 174 175 for (; 0 <= fd;) { 176 uint8_t buffer[4096]; 177 ssize_t len = read(fd, buffer, sizeof(buffer)); 178 if (len <= 0) break; 179 if (len < sizeof(buffer)) { 180 // assumes that partial read only occurs at the end of the file 181 buffer[len] = '\n'; 182 len++; 183 } 184 const uint8_t *bytes = buffer; 185 for (;;) { 186 const uint8_t *nextl = memchr(bytes, '\n', len); 187 if (!nextl) break; 188 nextl++; 189 if ('#' == *bytes) { 190 len -= (nextl - bytes); 191 bytes = nextl; 192 continue; 193 } 194 const uint8_t *tab1 = memchr(bytes, '\t', (nextl - bytes)); 195 if (!tab1) { 196 len -= (nextl - bytes); 197 bytes = nextl; 198 continue; 199 } 200 tab1++; 201 len -= (tab1 - bytes); 202 bytes = tab1; 203 const uint8_t *tab2 = memchr(bytes, '\t', (nextl - bytes)); 204 if (!tab2) { 205 len -= (nextl - bytes); 206 bytes = nextl; 207 continue; 208 } 209 tab2++; 210 len -= (tab2 - bytes); 211 bytes = tab2; 212 const uint8_t *tab3 = memchr(bytes, '\t', (nextl - bytes)); 213 int nmlen = tab3 ? (tab3 - bytes) : (nextl - 1 - bytes); 214 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, bytes, nmlen, kCFStringEncodingUTF8, false); 215 CFArrayAppendValue(result, string); 216 CFRelease(string); 217 len -= (nextl - bytes); 218 bytes = nextl; 219 } 220 lseek(fd, -len, SEEK_CUR); 221 } 222 close(fd); 223 return result; 224} 225#else 226#error Unknown or unspecified DEPLOYMENT_TARGET 227#endif 228 229typedef struct _CFTZPeriod { 230 int32_t startSec; 231 CFStringRef abbrev; 232 uint32_t info; 233} CFTZPeriod; 234 235struct __CFTimeZone { 236 CFRuntimeBase _base; 237 CFStringRef _name; /* immutable */ 238 CFDataRef _data; /* immutable */ 239 CFTZPeriod *_periods; /* immutable */ 240 int32_t _periodCnt; /* immutable */ 241}; 242 243/* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates 244 * between 1933 and 2069; info outside these years is discarded on read-in */ 245/* Bits 31-18 of the info are unused */ 246/* Bit 17 of the info is used for the is-DST state */ 247/* Bit 16 of the info is used for the sign of the offset (1 == negative) */ 248/* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */ 249 250CF_INLINE void __CFTZPeriodInit(CFTZPeriod *period, int32_t startTime, CFStringRef abbrev, int32_t offset, Boolean isDST) { 251 period->startSec = startTime; 252 period->abbrev = abbrev ? (CFStringRef)CFRetain(abbrev) : NULL; 253 __CFBitfieldSetValue(period->info, 15, 0, abs(offset)); 254 __CFBitfieldSetValue(period->info, 16, 16, (offset < 0 ? 1 : 0)); 255 __CFBitfieldSetValue(period->info, 17, 17, (isDST ? 1 : 0)); 256} 257 258CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) { 259 return period->startSec; 260} 261 262CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) { 263 return period->abbrev; 264} 265 266CF_INLINE int32_t __CFTZPeriodGMTOffset(const CFTZPeriod *period) { 267 int32_t v = __CFBitfieldGetValue(period->info, 15, 0); 268 if (__CFBitfieldGetValue(period->info, 16, 16)) v = -v; 269 return v; 270} 271 272CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) { 273 return (Boolean)__CFBitfieldGetValue(period->info, 17, 17); 274} 275 276static CFComparisonResult __CFCompareTZPeriods(const void *val1, const void *val2, void *context) { 277 CFTZPeriod *tzp1 = (CFTZPeriod *)val1; 278 CFTZPeriod *tzp2 = (CFTZPeriod *)val2; 279 // we treat equal as less than, as the code which uses the 280 // result of the bsearch doesn't expect exact matches 281 // (they're pretty rare, so no point in over-coding for them) 282 if (__CFTZPeriodStartSeconds(tzp1) <= __CFTZPeriodStartSeconds(tzp2)) return kCFCompareLessThan; 283 return kCFCompareGreaterThan; 284} 285 286static CFIndex __CFBSearchTZPeriods(CFTimeZoneRef tz, CFAbsoluteTime at) { 287 CFTZPeriod elem; 288 __CFTZPeriodInit(&elem, (int32_t)floor(at + 1.0), NULL, 0, false); 289 CFIndex idx = CFBSearch(&elem, sizeof(CFTZPeriod), tz->_periods, tz->_periodCnt, __CFCompareTZPeriods, NULL); 290 if (tz->_periodCnt <= idx) { 291 idx = tz->_periodCnt; 292 } else if (0 == idx) { 293 idx = 1; 294 } 295 return idx - 1; 296} 297 298 299CF_INLINE int32_t __CFDetzcode(const unsigned char *bufp) { 300 int32_t result = (bufp[0] & 0x80) ? ~0L : 0L; 301 result = (result << 8) | (bufp[0] & 0xff); 302 result = (result << 8) | (bufp[1] & 0xff); 303 result = (result << 8) | (bufp[2] & 0xff); 304 result = (result << 8) | (bufp[3] & 0xff); 305 return result; 306} 307 308CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) { 309 bufp[0] = (value >> 24) & 0xff; 310 bufp[1] = (value >> 16) & 0xff; 311 bufp[2] = (value >> 8) & 0xff; 312 bufp[3] = (value >> 0) & 0xff; 313} 314 315static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) { 316 int32_t len, timecnt, typecnt, charcnt, idx, cnt; 317 const uint8_t *p, *timep, *typep, *ttisp, *charp; 318 CFStringRef *abbrs; 319 Boolean result = true; 320 321 p = CFDataGetBytePtr(data); 322 len = CFDataGetLength(data); 323 if (len < (int32_t)sizeof(struct tzhead)) { 324 return false; 325 } 326 327 if (!(p[0] == 'T' && p[1] == 'Z' && p[2] == 'i' && p[3] == 'f')) return false; /* Don't parse without TZif at head of file */ 328 329 p += 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */ 330 timecnt = __CFDetzcode(p); 331 p += 4; 332 typecnt = __CFDetzcode(p); 333 p += 4; 334 charcnt = __CFDetzcode(p); 335 p += 4; 336 if (typecnt <= 0 || timecnt < 0 || charcnt < 0) { 337 return false; 338 } 339 if (1024 < timecnt || 32 < typecnt || 128 < charcnt) { 340 // reject excessive timezones to avoid arithmetic overflows for 341 // security reasons and to reject potentially corrupt files 342 return false; 343 } 344 if (len - (int32_t)sizeof(struct tzhead) < (4 + 1) * timecnt + (4 + 1 + 1) * typecnt + charcnt) { 345 return false; 346 } 347 timep = p; 348 typep = timep + 4 * timecnt; 349 ttisp = typep + timecnt; 350 charp = ttisp + (4 + 1 + 1) * typecnt; 351 cnt = (0 < timecnt) ? timecnt : 1; 352 *tzpp = CFAllocatorAllocate(allocator, cnt * sizeof(CFTZPeriod), 0); 353 if (__CFOASafe) __CFSetLastAllocationEventName(*tzpp, "CFTimeZone (store)"); 354 memset(*tzpp, 0, cnt * sizeof(CFTZPeriod)); 355 abbrs = CFAllocatorAllocate(allocator, (charcnt + 1) * sizeof(CFStringRef), 0); 356 if (__CFOASafe) __CFSetLastAllocationEventName(abbrs, "CFTimeZone (temp)"); 357 for (idx = 0; idx < charcnt + 1; idx++) { 358 abbrs[idx] = NULL; 359 } 360 for (idx = 0; idx < cnt; idx++) { 361 CFAbsoluteTime at; 362 int32_t itime, offset; 363 uint8_t type, dst, abbridx; 364 365 at = (CFAbsoluteTime)(__CFDetzcode(timep) + 0.0) - kCFAbsoluteTimeIntervalSince1970; 366 if (0 == timecnt) itime = INT_MIN; 367 else if (at < (CFAbsoluteTime)INT_MIN) itime = INT_MIN; 368 else if ((CFAbsoluteTime)INT_MAX < at) itime = INT_MAX; 369 else itime = (int32_t)at; 370 timep += 4; /* harmless if 0 == timecnt */ 371 type = (0 < timecnt) ? (uint8_t)*typep++ : 0; 372 if (typecnt <= type) { 373 result = false; 374 break; 375 } 376 offset = __CFDetzcode(ttisp + 6 * type); 377 dst = (uint8_t)*(ttisp + 6 * type + 4); 378 if (0 != dst && 1 != dst) { 379 result = false; 380 break; 381 } 382 abbridx = (uint8_t)*(ttisp + 6 * type + 5); 383 if (charcnt < abbridx) { 384 result = false; 385 break; 386 } 387 if (NULL == abbrs[abbridx]) { 388 abbrs[abbridx] = CFStringCreateWithCString(allocator, (char *)&charp[abbridx], kCFStringEncodingASCII); 389 } 390 __CFTZPeriodInit(*tzpp + idx, itime, abbrs[abbridx], offset, (dst ? true : false)); 391 } 392 for (idx = 0; idx < charcnt + 1; idx++) { 393 if (NULL != abbrs[idx]) { 394 CFRelease(abbrs[idx]); 395 } 396 } 397 CFAllocatorDeallocate(allocator, abbrs); 398 if (result) { 399 // dump all but the last INT_MIN and the first INT_MAX 400 for (idx = 0; idx < cnt; idx++) { 401 if (((*tzpp + idx)->startSec == INT_MIN) && (idx + 1 < cnt) && (((*tzpp + idx + 1)->startSec == INT_MIN))) { 402 if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); 403 cnt--; 404 memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); 405 idx--; 406 } 407 } 408 // Don't combine these loops! Watch the idx decrementing... 409 for (idx = 0; idx < cnt; idx++) { 410 if (((*tzpp + idx)->startSec == INT_MAX) && (0 < idx) && (((*tzpp + idx - 1)->startSec == INT_MAX))) { 411 if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); 412 cnt--; 413 memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); 414 idx--; 415 } 416 } 417 CFQSortArray(*tzpp, cnt, sizeof(CFTZPeriod), __CFCompareTZPeriods, NULL); 418 // if the first period is in DST and there is more than one period, drop it 419 if (1 < cnt && __CFTZPeriodIsDST(*tzpp + 0)) { 420 if (NULL != (*tzpp + 0)->abbrev) CFRelease((*tzpp + 0)->abbrev); 421 cnt--; 422 memmove((*tzpp + 0), (*tzpp + 0 + 1), sizeof(CFTZPeriod) * (cnt - 0)); 423 } 424 *cntp = cnt; 425 } else { 426 CFAllocatorDeallocate(allocator, *tzpp); 427 *tzpp = NULL; 428 } 429 return result; 430} 431 432static Boolean __CFTimeZoneEqual(CFTypeRef cf1, CFTypeRef cf2) { 433 CFTimeZoneRef tz1 = (CFTimeZoneRef)cf1; 434 CFTimeZoneRef tz2 = (CFTimeZoneRef)cf2; 435 if (!CFEqual(CFTimeZoneGetName(tz1), CFTimeZoneGetName(tz2))) return false; 436 if (!CFEqual(CFTimeZoneGetData(tz1), CFTimeZoneGetData(tz2))) return false; 437 return true; 438} 439 440static CFHashCode __CFTimeZoneHash(CFTypeRef cf) { 441 CFTimeZoneRef tz = (CFTimeZoneRef)cf; 442 return CFHash(CFTimeZoneGetName(tz)); 443} 444 445static CFStringRef __CFTimeZoneCopyDescription(CFTypeRef cf) { 446 CFTimeZoneRef tz = (CFTimeZoneRef)cf; 447 CFStringRef result, abbrev; 448 CFAbsoluteTime at; 449 at = CFAbsoluteTimeGetCurrent(); 450 abbrev = CFTimeZoneCopyAbbreviation(tz, at); 451 result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFTimeZone %p [%p]>{name = %@; abbreviation = %@; GMT offset = %g; is DST = %s}"), cf, CFGetAllocator(tz), tz->_name, abbrev, CFTimeZoneGetSecondsFromGMT(tz, at), CFTimeZoneIsDaylightSavingTime(tz, at) ? "true" : "false"); 452 CFRelease(abbrev); 453 return result; 454} 455 456static void __CFTimeZoneDeallocate(CFTypeRef cf) { 457 CFTimeZoneRef tz = (CFTimeZoneRef)cf; 458 CFAllocatorRef allocator = CFGetAllocator(tz); 459 CFIndex idx; 460 if (tz->_name) CFRelease(tz->_name); 461 if (tz->_data) CFRelease(tz->_data); 462 for (idx = 0; idx < tz->_periodCnt; idx++) { 463 if (NULL != tz->_periods[idx].abbrev) CFRelease(tz->_periods[idx].abbrev); 464 } 465 if (NULL != tz->_periods) CFAllocatorDeallocate(allocator, tz->_periods); 466} 467 468static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID; 469 470static const CFRuntimeClass __CFTimeZoneClass = { 471 0, 472 "CFTimeZone", 473 NULL, // init 474 NULL, // copy 475 __CFTimeZoneDeallocate, 476 __CFTimeZoneEqual, 477 __CFTimeZoneHash, 478 NULL, // 479 __CFTimeZoneCopyDescription 480}; 481 482CF_PRIVATE void __CFTimeZoneInitialize(void) { 483 __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass); 484} 485 486CFTypeID CFTimeZoneGetTypeID(void) { 487 return __kCFTimeZoneTypeID; 488} 489 490#if DEPLOYMENT_TARGET_WINDOWS 491static const char *__CFTimeZoneWinToOlsonDefaults = 492/* Mappings to time zones in Windows Registry are best-guess */ 493"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 494" <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">" 495" <plist version=\"1.0\">" 496" <dict>" 497" <key>Afghanistan</key> <string>Asia/Kabul</string>" 498" <key>Afghanistan Standard Time</key> <string>Asia/Kabul</string>" 499" <key>Alaskan</key> <string>America/Anchorage</string>" 500" <key>Alaskan Standard Time</key> <string>America/Anchorage</string>" 501" <key>Arab</key> <string>Asia/Riyadh</string>" 502" <key>Arab Standard Time</key> <string>Asia/Riyadh</string>" 503" <key>Arabian</key> <string>Asia/Muscat</string>" 504" <key>Arabian Standard Time</key> <string>Asia/Muscat</string>" 505" <key>Arabic Standard Time</key> <string>Asia/Baghdad</string>" 506" <key>Atlantic</key> <string>America/Halifax</string>" 507" <key>Atlantic Standard Time</key> <string>America/Halifax</string>" 508" <key>AUS Central</key> <string>Australia/Darwin</string>" 509" <key>AUS Central Standard Time</key> <string>Australia/Darwin</string>" 510" <key>AUS Eastern</key> <string>Australia/Sydney</string>" 511" <key>AUS Eastern Standard Time</key> <string>Australia/Sydney</string>" 512" <key>Azerbaijan Standard Time</key> <string>Asia/Baku</string>" 513" <key>Azores</key> <string>Atlantic/Azores</string>" 514" <key>Azores Standard Time</key> <string>Atlantic/Azores</string>" 515" <key>Bangkok</key> <string>Asia/Bangkok</string>" 516" <key>Bangkok Standard Time</key> <string>Asia/Bangkok</string>" 517" <key>Beijing</key> <string>Asia/Shanghai</string>" 518" <key>Canada Central</key> <string>America/Regina</string>" 519" <key>Canada Central Standard Time</key> <string>America/Regina</string>" 520" <key>Cape Verde Standard Time</key> <string>Atlantic/Cape_Verde</string>" 521" <key>Caucasus</key> <string>Asia/Yerevan</string>" 522" <key>Caucasus Standard Time</key> <string>Asia/Yerevan</string>" 523" <key>Cen. Australia</key> <string>Australia/Adelaide</string>" 524" <key>Cen. Australia Standard Time</key> <string>Australia/Adelaide</string>" 525" <key>Central</key> <string>America/Chicago</string>" 526" <key>Central America Standard Time</key> <string>America/Regina</string>" 527" <key>Central Asia</key> <string>Asia/Dhaka</string>" 528" <key>Central Asia Standard Time</key> <string>Asia/Dhaka</string>" 529" <key>Central Brazilian Standard Time</key> <string>America/Manaus</string>" 530" <key>Central Europe</key> <string>Europe/Prague</string>" 531" <key>Central Europe Standard Time</key> <string>Europe/Prague</string>" 532" <key>Central European</key> <string>Europe/Belgrade</string>" 533" <key>Central European Standard Time</key> <string>Europe/Belgrade</string>" 534" <key>Central Pacific</key> <string>Pacific/Guadalcanal</string>" 535" <key>Central Pacific Standard Time</key> <string>Pacific/Guadalcanal</string>" 536" <key>Central Standard Time</key> <string>America/Chicago</string>" 537" <key>Central Standard Time (Mexico)</key> <string>America/Mexico_City</string>" 538" <key>China</key> <string>Asia/Shanghai</string>" 539" <key>China Standard Time</key> <string>Asia/Shanghai</string>" 540" <key>Dateline</key> <string>GMT-1200</string>" 541" <key>Dateline Standard Time</key> <string>GMT-1200</string>" 542" <key>E. Africa</key> <string>Africa/Nairobi</string>" 543" <key>E. Africa Standard Time</key> <string>Africa/Nairobi</string>" 544" <key>E. Australia</key> <string>Australia/Brisbane</string>" 545" <key>E. Australia Standard Time</key> <string>Australia/Brisbane</string>" 546" <key>E. Europe</key> <string>Europe/Minsk</string>" 547" <key>E. Europe Standard Time</key> <string>Europe/Minsk</string>" 548" <key>E. South America</key> <string>America/Sao_Paulo</string>" 549" <key>E. South America Standard Time</key> <string>America/Sao_Paulo</string>" 550" <key>Eastern</key> <string>America/New_York</string>" 551" <key>Eastern Standard Time</key> <string>America/New_York</string>" 552" <key>Egypt</key> <string>Africa/Cairo</string>" 553" <key>Egypt Standard Time</key> <string>Africa/Cairo</string>" 554" <key>Ekaterinburg</key> <string>Asia/Yekaterinburg</string>" 555" <key>Ekaterinburg Standard Time</key> <string>Asia/Yekaterinburg</string>" 556" <key>Fiji</key> <string>Pacific/Fiji</string>" 557" <key>Fiji Standard Time</key> <string>Pacific/Fiji</string>" 558" <key>FLE</key> <string>Europe/Helsinki</string>" 559" <key>FLE Standard Time</key> <string>Europe/Helsinki</string>" 560" <key>Georgian Standard Time</key> <string>Asia/Tbilisi</string>" 561" <key>GFT</key> <string>Europe/Athens</string>" 562" <key>GFT Standard Time</key> <string>Europe/Athens</string>" 563" <key>GMT</key> <string>Europe/London</string>" 564" <key>GMT Standard Time</key> <string>Europe/London</string>" 565" <key>Greenland Standard Time</key> <string>America/Godthab</string>" 566" <key>Greenwich</key> <string>GMT</string>" 567" <key>Greenwich Standard Time</key> <string>GMT</string>" 568" <key>GTB</key> <string>Europe/Athens</string>" 569" <key>GTB Standard Time</key> <string>Europe/Athens</string>" 570" <key>Hawaiian</key> <string>Pacific/Honolulu</string>" 571" <key>Hawaiian Standard Time</key> <string>Pacific/Honolulu</string>" 572" <key>India</key> <string>Asia/Calcutta</string>" 573" <key>India Standard Time</key> <string>Asia/Calcutta</string>" 574" <key>Iran</key> <string>Asia/Tehran</string>" 575" <key>Iran Standard Time</key> <string>Asia/Tehran</string>" 576" <key>Israel</key> <string>Asia/Jerusalem</string>" 577" <key>Israel Standard Time</key> <string>Asia/Jerusalem</string>" 578" <key>Jordan Standard Time</key> <string>Asia/Amman</string>" 579" <key>Korea</key> <string>Asia/Seoul</string>" 580" <key>Korea Standard Time</key> <string>Asia/Seoul</string>" 581" <key>Mexico</key> <string>America/Mexico_City</string>" 582" <key>Mexico Standard Time</key> <string>America/Mexico_City</string>" 583" <key>Mexico Standard Time 2</key> <string>America/Chihuahua</string>" 584" <key>Mid-Atlantic</key> <string>Atlantic/South_Georgia</string>" 585" <key>Mid-Atlantic Standard Time</key> <string>Atlantic/South_Georgia</string>" 586" <key>Middle East Standard Time</key> <string>Asia/Beirut</string>" 587" <key>Mountain</key> <string>America/Denver</string>" 588" <key>Mountain Standard Time</key> <string>America/Denver</string>" 589" <key>Mountain Standard Time (Mexico)</key> <string>America/Chihuahua</string>" 590" <key>Myanmar Standard Time</key> <string>Asia/Rangoon</string>" 591" <key>N. Central Asia Standard Time</key> <string>Asia/Novosibirsk</string>" 592" <key>Namibia Standard Time</key> <string>Africa/Windhoek</string>" 593" <key>Nepal Standard Time</key> <string>Asia/Katmandu</string>" 594" <key>New Zealand</key> <string>Pacific/Auckland</string>" 595" <key>New Zealand Standard Time</key> <string>Pacific/Auckland</string>" 596" <key>Newfoundland</key> <string>America/St_Johns</string>" 597" <key>Newfoundland Standard Time</key> <string>America/St_Johns</string>" 598" <key>North Asia East Standard Time</key> <string>Asia/Ulaanbaatar</string>" 599" <key>North Asia Standard Time</key> <string>Asia/Krasnoyarsk</string>" 600" <key>Pacific</key> <string>America/Los_Angeles</string>" 601" <key>Pacific SA</key> <string>America/Santiago</string>" 602" <key>Pacific SA Standard Time</key> <string>America/Santiago</string>" 603" <key>Pacific Standard Time</key> <string>America/Los_Angeles</string>" 604" <key>Pacific Standard Time (Mexico)</key> <string>America/Tijuana</string>" 605" <key>Prague Bratislava</key> <string>Europe/Prague</string>" 606" <key>Romance</key> <string>Europe/Paris</string>" 607" <key>Romance Standard Time</key> <string>Europe/Paris</string>" 608" <key>Russian</key> <string>Europe/Moscow</string>" 609" <key>Russian Standard Time</key> <string>Europe/Moscow</string>" 610" <key>SA Eastern</key> <string>America/Buenos_Aires</string>" 611" <key>SA Eastern Standard Time</key> <string>America/Buenos_Aires</string>" 612" <key>SA Pacific</key> <string>America/Bogota</string>" 613" <key>SA Pacific Standard Time</key> <string>America/Bogota</string>" 614" <key>SA Western</key> <string>America/Caracas</string>" 615" <key>SA Western Standard Time</key> <string>America/Caracas</string>" 616" <key>Samoa</key> <string>Pacific/Apia</string>" 617" <key>Samoa Standard Time</key> <string>Pacific/Apia</string>" 618" <key>Saudi Arabia</key> <string>Asia/Riyadh</string>" 619" <key>Saudi Arabia Standard Time</key> <string>Asia/Riyadh</string>" 620" <key>SE Asia Standard Time</key> <string>Asia/Bangkok</string>" 621" <key>Singapore</key> <string>Asia/Singapore</string>" 622" <key>Singapore Standard Time</key> <string>Asia/Singapore</string>" 623" <key>South Africa</key> <string>Africa/Harare</string>" 624" <key>South Africa Standard Time</key> <string>Africa/Harare</string>" 625" <key>Sri Lanka</key> <string>Asia/Colombo</string>" 626" <key>Sri Lanka Standard Time</key> <string>Asia/Colombo</string>" 627" <key>Sydney Standard Time</key> <string>Australia/Sydney</string>" 628" <key>Taipei</key> <string>Asia/Taipei</string>" 629" <key>Taipei Standard Time</key> <string>Asia/Taipei</string>" 630" <key>Tasmania</key> <string>Australia/Hobart</string>" 631" <key>Tasmania Standard Time</key> <string>Australia/Hobart</string>" 632" <key>Tasmania Standard Time</key> <string>Australia/Hobart</string>" 633" <key>Tokyo</key> <string>Asia/Tokyo</string>" 634" <key>Tokyo Standard Time</key> <string>Asia/Tokyo</string>" 635" <key>Tonga Standard Time</key> <string>Pacific/Tongatapu</string>" 636" <key>US Eastern</key> <string>America/Indianapolis</string>" 637" <key>US Eastern Standard Time</key> <string>America/Indianapolis</string>" 638" <key>US Mountain</key> <string>America/Phoenix</string>" 639" <key>US Mountain Standard Time</key> <string>America/Phoenix</string>" 640" <key>Vladivostok</key> <string>Asia/Vladivostok</string>" 641" <key>Vladivostok Standard Time</key> <string>Asia/Vladivostok</string>" 642" <key>W. Australia</key> <string>Australia/Perth</string>" 643" <key>W. Australia Standard Time</key> <string>Australia/Perth</string>" 644" <key>W. Central Africa Standard Time</key> <string>Africa/Luanda</string>" 645" <key>W. Europe</key> <string>Europe/Berlin</string>" 646" <key>W. Europe Standard Time</key> <string>Europe/Berlin</string>" 647" <key>Warsaw</key> <string>Europe/Warsaw</string>" 648" <key>West Asia</key> <string>Asia/Karachi</string>" 649" <key>West Asia Standard Time</key> <string>Asia/Karachi</string>" 650" <key>West Pacific</key> <string>Pacific/Guam</string>" 651" <key>West Pacific Standard Time</key> <string>Pacific/Guam</string>" 652" <key>Western Brazilian Standard Time</key> <string>America/Rio_Branco</string>" 653" <key>Yakutsk</key> <string>Asia/Yakutsk</string>" 654" </dict>" 655" </plist>"; 656 657CF_INLINE void __CFTimeZoneLockWinToOlson(void) { 658 __CFSpinLock(&__CFTimeZoneWinToOlsonLock); 659} 660 661CF_INLINE void __CFTimeZoneUnlockWinToOlson(void) { 662 __CFSpinUnlock(&__CFTimeZoneWinToOlsonLock); 663} 664 665CFDictionaryRef CFTimeZoneCopyWinToOlsonDictionary(void) { 666 CFDictionaryRef dict; 667 __CFTimeZoneLockWinToOlson(); 668 if (NULL == __CFTimeZoneWinToOlsonDict) { 669 CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneWinToOlsonDefaults, strlen(__CFTimeZoneWinToOlsonDefaults)); 670 __CFTimeZoneWinToOlsonDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); 671 CFRelease(data); 672 } 673 if (NULL == __CFTimeZoneWinToOlsonDict) { 674 __CFTimeZoneWinToOlsonDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL); 675 } 676 dict = __CFTimeZoneWinToOlsonDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneWinToOlsonDict) : NULL; 677 __CFTimeZoneUnlockWinToOlson(); 678 return dict; 679} 680 681void CFTimeZoneSetWinToOlsonDictionary(CFDictionaryRef dict) { 682 __CFGenericValidateType(dict, CFDictionaryGetTypeID()); 683 __CFTimeZoneLockWinToOlson(); 684 if (dict != __CFTimeZoneWinToOlsonDict) { 685 if (dict) CFRetain(dict); 686 if (__CFTimeZoneWinToOlsonDict) CFRelease(__CFTimeZoneWinToOlsonDict); 687 __CFTimeZoneWinToOlsonDict = dict; 688 } 689 __CFTimeZoneUnlockWinToOlson(); 690} 691 692CFTimeZoneRef CFTimeZoneCreateWithWindowsName(CFAllocatorRef allocator, CFStringRef winName) { 693 if (!winName) return NULL; 694 695 CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary(); 696 if (!winToOlson) return NULL; 697 698 CFStringRef olsonName = CFDictionaryGetValue(winToOlson, winName); 699 CFTimeZoneRef retval = NULL; 700 if (olsonName) { 701 retval = CFTimeZoneCreateWithName(allocator, olsonName, false); 702 } 703 CFRelease(winToOlson); 704 return retval; 705} 706 707extern CFStringRef _CFGetWindowsAppleSystemLibraryDirectory(void); 708void __InitTZStrings(void) { 709 static CFSpinLock_t __CFTZDirLock = CFSpinLockInit; 710 __CFSpinLock(&__CFTZDirLock); 711 if (!__tzZoneInfo) { 712 CFStringRef winDir = _CFGetWindowsAppleSystemLibraryDirectory(); 713 __tzZoneInfo = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\\etc\\zoneinfo"), winDir); 714 } 715 if (!__tzDir && __tzZoneInfo) { 716 int length = CFStringGetLength(__tzZoneInfo) + sizeof("\\zone.tab") + 1; 717 __tzDir = malloc(length); // If we don't use ascii, we'll need to malloc more space 718 if (!__tzDir || !CFStringGetCString(__tzZoneInfo, __tzDir, length, kCFStringEncodingASCII)) { 719 free(__tzDir); 720 } else { 721 strcat(__tzDir, "\\zone.tab"); 722 } 723 } 724 __CFSpinUnlock(&__CFTZDirLock); 725} 726#endif 727 728static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { 729 CFTimeZoneRef result = NULL; 730 731#if DEPLOYMENT_TARGET_WINDOWS 732 CFStringRef name = NULL; 733 TIME_ZONE_INFORMATION tzi = { 0 }; 734 DWORD rval = GetTimeZoneInformation(&tzi); 735 if (rval != TIME_ZONE_ID_INVALID) { 736 LPWSTR standardName = (LPWSTR)&tzi.StandardName; 737 CFStringRef cfStandardName = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (UInt8 *)standardName, wcslen(standardName)*sizeof(WCHAR), kCFStringEncodingUTF16LE, false); 738 if (cfStandardName) { 739 CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary(); 740 if (winToOlson) { 741 name = CFDictionaryGetValue(winToOlson, cfStandardName); 742 if (name) CFRetain(name); 743 CFRelease(winToOlson); 744 } 745 CFRelease(cfStandardName); 746 } 747 } else { 748 CFLog(kCFLogLevelError, CFSTR("Couldn't get time zone information error %d"), GetLastError()); 749 } 750 if (name) { 751#else 752 const char *tzenv; 753 int ret; 754 char linkbuf[CFMaxPathSize]; 755 756 tzenv = __CFgetenv("TZFILE"); 757 if (NULL != tzenv) { 758 CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); 759 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); 760 CFRelease(name); 761 if (result) return result; 762 } 763 tzenv = __CFgetenv("TZ"); 764 if (NULL != tzenv) { 765 CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); 766 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true); 767 CFRelease(name); 768 if (result) return result; 769 } 770 ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf)); 771 if (0 < ret) { 772 CFStringRef name; 773 linkbuf[ret] = '\0'; 774 if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) { 775 name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false); 776 } else { 777 name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false); 778 } 779#endif 780 781 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); 782 CFRelease(name); 783 if (result) return result; 784 } 785 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); 786} 787 788CFTimeZoneRef CFTimeZoneCopySystem(void) { 789 CFTimeZoneRef tz; 790 __CFTimeZoneLockGlobal(); 791 if (NULL == __CFTimeZoneSystem) { 792 __CFTimeZoneUnlockGlobal(); 793 tz = __CFTimeZoneCreateSystem(); 794 __CFTimeZoneLockGlobal(); 795 if (NULL == __CFTimeZoneSystem) { 796 __CFTimeZoneSystem = tz; 797 } else { 798 if (tz) CFRelease(tz); 799 } 800 } 801 tz = __CFTimeZoneSystem ? (CFTimeZoneRef)CFRetain(__CFTimeZoneSystem) : NULL; 802 __CFTimeZoneUnlockGlobal(); 803 return tz; 804} 805 806static CFIndex __noteCount = 0; 807 808void CFTimeZoneResetSystem(void) { 809 __CFTimeZoneLockGlobal(); 810 if (__CFTimeZoneDefault == __CFTimeZoneSystem) { 811 if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); 812 __CFTimeZoneDefault = NULL; 813 } 814 CFTimeZoneRef tz = __CFTimeZoneSystem; 815 __CFTimeZoneSystem = NULL; 816 __CFTimeZoneUnlockGlobal(); 817 if (tz) CFRelease(tz); 818} 819 820CFIndex _CFTimeZoneGetNoteCount(void) { 821 return __noteCount; 822} 823 824CFTimeZoneRef CFTimeZoneCopyDefault(void) { 825 CFTimeZoneRef tz; 826 __CFTimeZoneLockGlobal(); 827 if (NULL == __CFTimeZoneDefault) { 828 __CFTimeZoneUnlockGlobal(); 829 tz = CFTimeZoneCopySystem(); 830 __CFTimeZoneLockGlobal(); 831 if (NULL == __CFTimeZoneDefault) { 832 __CFTimeZoneDefault = tz; 833 } else { 834 if (tz) CFRelease(tz); 835 } 836 } 837 tz = __CFTimeZoneDefault ? (CFTimeZoneRef)CFRetain(__CFTimeZoneDefault) : NULL; 838 __CFTimeZoneUnlockGlobal(); 839 return tz; 840} 841 842void CFTimeZoneSetDefault(CFTimeZoneRef tz) { 843 if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 844 __CFTimeZoneLockGlobal(); 845 if (tz != __CFTimeZoneDefault) { 846 if (tz) CFRetain(tz); 847 if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); 848 __CFTimeZoneDefault = tz; 849 } 850 __CFTimeZoneUnlockGlobal(); 851} 852 853static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void); 854 855CFArrayRef CFTimeZoneCopyKnownNames(void) { 856 CFArrayRef tzs; 857 __CFTimeZoneLockGlobal(); 858 if (NULL == __CFKnownTimeZoneList) { 859 CFMutableArrayRef list; 860/* TimeZone information locate in the registry for Win32 861 * (Aleksey Dukhnyakov) 862 */ 863 list = __CFCopyRecursiveDirectoryList(); 864 // Remove undesirable ancient cruft 865 CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); 866 CFIndex idx; 867 for (idx = CFArrayGetCount(list); idx--; ) { 868 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(list, idx); 869 if (CFDictionaryContainsKey(dict, item)) { 870 CFArrayRemoveValueAtIndex(list, idx); 871 } 872 } 873 __CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list); 874 CFRelease(list); 875 } 876 tzs = __CFKnownTimeZoneList ? (CFArrayRef)CFRetain(__CFKnownTimeZoneList) : NULL; 877 __CFTimeZoneUnlockGlobal(); 878 return tzs; 879} 880 881/* The criteria here are sort of: coverage for the U.S. and Europe, 882 * large cities, abbreviation uniqueness, and perhaps a few others. 883 * But do not make the list too large with obscure information. 884 */ 885static const char *__CFTimeZoneAbbreviationDefaults = 886"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 887" <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">" 888" <plist version=\"1.0\">" 889" <dict>" 890" <key>ADT</key> <string>America/Halifax</string>" 891" <key>AKDT</key> <string>America/Juneau</string>" 892" <key>AKST</key> <string>America/Juneau</string>" 893" <key>ART</key> <string>America/Argentina/Buenos_Aires</string>" 894" <key>AST</key> <string>America/Halifax</string>" 895" <key>BDT</key> <string>Asia/Dhaka</string>" 896" <key>BRST</key> <string>America/Sao_Paulo</string>" 897" <key>BRT</key> <string>America/Sao_Paulo</string>" 898" <key>BST</key> <string>Europe/London</string>" 899" <key>CAT</key> <string>Africa/Harare</string>" 900" <key>CDT</key> <string>America/Chicago</string>" 901" <key>CEST</key> <string>Europe/Paris</string>" 902" <key>CET</key> <string>Europe/Paris</string>" 903" <key>CLST</key> <string>America/Santiago</string>" 904" <key>CLT</key> <string>America/Santiago</string>" 905" <key>COT</key> <string>America/Bogota</string>" 906" <key>CST</key> <string>America/Chicago</string>" 907" <key>EAT</key> <string>Africa/Addis_Ababa</string>" 908" <key>EDT</key> <string>America/New_York</string>" 909" <key>EEST</key> <string>Europe/Istanbul</string>" 910" <key>EET</key> <string>Europe/Istanbul</string>" 911" <key>EST</key> <string>America/New_York</string>" 912" <key>GMT</key> <string>GMT</string>" 913" <key>GST</key> <string>Asia/Dubai</string>" 914" <key>HKT</key> <string>Asia/Hong_Kong</string>" 915" <key>HST</key> <string>Pacific/Honolulu</string>" 916" <key>ICT</key> <string>Asia/Bangkok</string>" 917" <key>IRST</key> <string>Asia/Tehran</string>" 918" <key>IST</key> <string>Asia/Calcutta</string>" 919" <key>JST</key> <string>Asia/Tokyo</string>" 920" <key>KST</key> <string>Asia/Seoul</string>" 921" <key>MDT</key> <string>America/Denver</string>" 922" <key>MSD</key> <string>Europe/Moscow</string>" 923" <key>MSK</key> <string>Europe/Moscow</string>" 924" <key>MST</key> <string>America/Denver</string>" 925" <key>NZDT</key> <string>Pacific/Auckland</string>" 926" <key>NZST</key> <string>Pacific/Auckland</string>" 927" <key>PDT</key> <string>America/Los_Angeles</string>" 928" <key>PET</key> <string>America/Lima</string>" 929" <key>PHT</key> <string>Asia/Manila</string>" 930" <key>PKT</key> <string>Asia/Karachi</string>" 931" <key>PST</key> <string>America/Los_Angeles</string>" 932" <key>SGT</key> <string>Asia/Singapore</string>" 933" <key>UTC</key> <string>UTC</string>" 934" <key>WAT</key> <string>Africa/Lagos</string>" 935" <key>WEST</key> <string>Europe/Lisbon</string>" 936" <key>WET</key> <string>Europe/Lisbon</string>" 937" <key>WIT</key> <string>Asia/Jakarta</string>" 938" </dict>" 939" </plist>"; 940 941CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) { 942 CFDictionaryRef dict; 943 __CFTimeZoneLockAbbreviations(); 944 if (NULL == __CFTimeZoneAbbreviationDict) { 945 CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults)); 946 __CFTimeZoneAbbreviationDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); 947 CFRelease(data); 948 } 949 if (NULL == __CFTimeZoneAbbreviationDict) { 950 __CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL); 951 } 952 dict = __CFTimeZoneAbbreviationDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneAbbreviationDict) : NULL; 953 __CFTimeZoneUnlockAbbreviations(); 954 return dict; 955} 956 957void _removeFromCache(const void *key, const void *value, void *context) { 958 CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)key); 959} 960 961void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) { 962 __CFGenericValidateType(dict, CFDictionaryGetTypeID()); 963 __CFTimeZoneLockGlobal(); 964 if (dict != __CFTimeZoneAbbreviationDict) { 965 if (dict) CFRetain(dict); 966 if (__CFTimeZoneAbbreviationDict) { 967 CFDictionaryApplyFunction(__CFTimeZoneAbbreviationDict, _removeFromCache, NULL); 968 CFRelease(__CFTimeZoneAbbreviationDict); 969 } 970 __CFTimeZoneAbbreviationDict = dict; 971 } 972 __CFTimeZoneUnlockGlobal(); 973} 974 975CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) { 976// assert: (NULL != name && NULL != data); 977 CFTimeZoneRef memory; 978 uint32_t size; 979 CFTZPeriod *tzp = NULL; 980 CFIndex idx, cnt = 0; 981 982 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 983 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 984 __CFGenericValidateType(name, CFStringGetTypeID()); 985 __CFGenericValidateType(data, CFDataGetTypeID()); 986 __CFTimeZoneLockGlobal(); 987 if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) { 988 __CFTimeZoneUnlockGlobal(); 989 return (CFTimeZoneRef)CFRetain(memory); 990 } 991 if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) { 992 __CFTimeZoneUnlockGlobal(); 993 return NULL; 994 } 995 size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase); 996 memory = (CFTimeZoneRef)_CFRuntimeCreateInstance(allocator, CFTimeZoneGetTypeID(), size, NULL); 997 if (NULL == memory) { 998 __CFTimeZoneUnlockGlobal(); 999 for (idx = 0; idx < cnt; idx++) { 1000 if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev); 1001 } 1002 if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp); 1003 return NULL; 1004 } 1005 ((struct __CFTimeZone *)memory)->_name = (CFStringRef)CFStringCreateCopy(allocator, name); 1006 ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data); 1007 ((struct __CFTimeZone *)memory)->_periods = tzp; 1008 ((struct __CFTimeZone *)memory)->_periodCnt = cnt; 1009 if (NULL == __CFTimeZoneCache) { 1010 __CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1011 } 1012 CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory); 1013 __CFTimeZoneUnlockGlobal(); 1014 return memory; 1015} 1016 1017static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { 1018 CFTimeZoneRef result; 1019 CFDataRef data; 1020 int32_t nameLen = CFStringGetLength(name); 1021 unsigned char dataBytes[52 + nameLen + 1]; 1022 memset(dataBytes, 0, sizeof(dataBytes)); 1023 1024 // Put in correct magic bytes for timezone structures 1025 dataBytes[0] = 'T'; 1026 dataBytes[1] = 'Z'; 1027 dataBytes[2] = 'i'; 1028 dataBytes[3] = 'f'; 1029 1030 __CFEntzcode(1, dataBytes + 20); 1031 __CFEntzcode(1, dataBytes + 24); 1032 __CFEntzcode(1, dataBytes + 36); 1033 __CFEntzcode(nameLen + 1, dataBytes + 40); 1034 __CFEntzcode(seconds, dataBytes + 44); 1035 dataBytes[48] = isDST ? 1 : 0; 1036 CFStringGetCString(name, (char *)dataBytes + 50, nameLen + 1, kCFStringEncodingASCII); 1037 data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1); 1038 result = CFTimeZoneCreate(allocator, name, data); 1039 CFRelease(data); 1040 return result; 1041} 1042 1043 1044// rounds offset to nearest minute 1045CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) { 1046 CFTimeZoneRef result; 1047 CFStringRef name; 1048 int32_t seconds, minute, hour; 1049 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 1050 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 1051 if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL; 1052 ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0; 1053 seconds = (int32_t)ti; 1054 hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600); 1055 seconds -= ((ti < 0) ? -hour : hour) * 3600; 1056 minute = (ti < 0) ? (-seconds / 60) : (seconds / 60); 1057 if (fabs(ti) < 1.0) { 1058 name = (CFStringRef)CFRetain(CFSTR("GMT")); 1059 } else { 1060 name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute); 1061 } 1062 result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0); 1063 CFRelease(name); 1064 return result; 1065} 1066 1067CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) { 1068 CFTimeZoneRef result = NULL; 1069 CFStringRef tzName = NULL; 1070 CFDataRef data = NULL; 1071 1072 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 1073 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 1074 __CFGenericValidateType(name, CFStringGetTypeID()); 1075 if (CFEqual(CFSTR(""), name)) { 1076 // empty string is not a time zone name, just abort now, 1077 // following stuff will fail anyway 1078 return NULL; 1079 } 1080 __CFTimeZoneLockGlobal(); 1081 if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) { 1082 __CFTimeZoneUnlockGlobal(); 1083 return (CFTimeZoneRef)CFRetain(result); 1084 } 1085 __CFTimeZoneUnlockGlobal(); 1086 CFIndex len = CFStringGetLength(name); 1087 if (6 == len || 8 == len) { 1088 UniChar buffer[8]; 1089 CFStringGetCharacters(name, CFRangeMake(0, len), buffer); 1090 if ('G' == buffer[0] && 'M' == buffer[1] && 'T' == buffer[2] && ('+' == buffer[3] || '-' == buffer[3])) { 1091 if (('0' <= buffer[4] && buffer[4] <= '9') && ('0' <= buffer[5] && buffer[5] <= '9')) { 1092 int32_t hours = (buffer[4] - '0') * 10 + (buffer[5] - '0'); 1093 if (-14 <= hours && hours <= 14) { 1094 CFTimeInterval ti = hours * 3600.0; 1095 if (6 == len) { 1096 return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti); 1097 } else { 1098 if (('0' <= buffer[6] && buffer[6] <= '9') && ('0' <= buffer[7] && buffer[7] <= '9')) { 1099 int32_t minutes = (buffer[6] - '0') * 10 + (buffer[7] - '0'); 1100 if ((-14 == hours && 0 == minutes) || (14 == hours && 0 == minutes) || (0 <= minutes && minutes <= 59)) { 1101 ti = ti + minutes * 60.0; 1102 return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti); 1103 } 1104 } 1105 } 1106 } 1107 } 1108 } 1109 } 1110 CFURLRef baseURL, tempURL; 1111 void *bytes; 1112 CFIndex length; 1113 1114#if DEPLOYMENT_TARGET_WINDOWS 1115 if (!__tzZoneInfo) __InitTZStrings(); 1116 if (!__tzZoneInfo) return NULL; 1117 baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLWindowsPathStyle, true); 1118#else 1119 baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true); 1120#endif 1121 if (tryAbbrev) { 1122 CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); 1123 tzName = CFDictionaryGetValue(abbrevs, name); 1124 if (NULL != tzName) { 1125 tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false); 1126 if (NULL != tempURL) { 1127 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0, 0)) { 1128 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault); 1129 } 1130 CFRelease(tempURL); 1131 } 1132 } 1133 CFRelease(abbrevs); 1134 } 1135 if (NULL == data) { 1136 CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); 1137 CFStringRef mapping = CFDictionaryGetValue(dict, name); 1138 if (mapping) { 1139 name = mapping; 1140#if DEPLOYMENT_TARGET_WINDOWS 1141 } else if (CFStringHasPrefix(name, __tzZoneInfo)) { 1142 CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name); 1143 CFStringDelete(unprefixed, CFRangeMake(0, CFStringGetLength(__tzZoneInfo))); 1144#else 1145 } else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) { 1146 CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name); 1147 CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO))); 1148#endif 1149 mapping = CFDictionaryGetValue(dict, unprefixed); 1150 if (mapping) { 1151 name = mapping; 1152 } 1153 CFRelease(unprefixed); 1154 } 1155 CFRelease(dict); 1156 if (CFEqual(CFSTR(""), name)) { 1157 return NULL; 1158 } 1159 } 1160 if (NULL == data) { 1161 tzName = name; 1162 tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false); 1163 if (NULL != tempURL) { 1164 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0, 0)) { 1165 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault); 1166 } 1167 CFRelease(tempURL); 1168 } 1169 } 1170 CFRelease(baseURL); 1171 if (NULL != data) { 1172 result = CFTimeZoneCreate(allocator, tzName, data); 1173 if (name != tzName) { 1174 CFStringRef nameCopy = (CFStringRef)CFStringCreateCopy(allocator, name); 1175 __CFTimeZoneLockGlobal(); 1176 CFDictionaryAddValue(__CFTimeZoneCache, nameCopy, result); 1177 __CFTimeZoneUnlockGlobal(); 1178 CFRelease(nameCopy); 1179 } 1180 CFRelease(data); 1181 } 1182 return result; 1183} 1184 1185CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) { 1186 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFStringRef, (NSTimeZone *)tz, name); 1187 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1188 return tz->_name; 1189} 1190 1191CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) { 1192 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFDataRef, (NSTimeZone *)tz, data); 1193 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1194 return tz->_data; 1195} 1196 1197/* This function converts CFAbsoluteTime to (Win32) SYSTEMTIME 1198 * (Aleksey Dukhnyakov) 1199 */ 1200#if DEPLOYMENT_TARGET_WINDOWS 1201BOOL __CFTimeZoneGetWin32SystemTime(SYSTEMTIME * sys_time, CFAbsoluteTime time) 1202{ 1203 LONGLONG l; 1204 FILETIME * ftime=(FILETIME*)&l; 1205 1206 /* seconds between 1601 and 1970 : 11644473600, 1207 * seconds between 1970 and 2001 : 978307200, 1208 * FILETIME - number of 100-nanosecond intervals since January 1, 1601 1209 */ 1210 l=(LONGLONG)(time+11644473600LL+978307200)*10000000; 1211 if (FileTimeToSystemTime(ftime,sys_time)) 1212 return TRUE; 1213 else 1214 return FALSE; 1215} 1216#endif 1217 1218CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) { 1219 CFIndex idx; 1220 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1221 idx = __CFBSearchTZPeriods(tz, at); 1222 return __CFTZPeriodGMTOffset(&(tz->_periods[idx])); 1223} 1224 1225CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) { 1226 CFStringRef result; 1227 CFIndex idx; 1228 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1229 idx = __CFBSearchTZPeriods(tz, at); 1230 result = __CFTZPeriodAbbreviation(&(tz->_periods[idx])); 1231 return result ? (CFStringRef)CFRetain(result) : NULL; 1232} 1233 1234Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) { 1235 CFIndex idx; 1236 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1237 idx = __CFBSearchTZPeriods(tz, at); 1238 return __CFTZPeriodIsDST(&(tz->_periods[idx])); 1239} 1240 1241CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) { 1242 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval, (NSTimeZone *)tz, _daylightSavingTimeOffsetForAbsoluteTime:at); 1243 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1244 CFIndex idx = __CFBSearchTZPeriods(tz, at); 1245 if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) { 1246 CFTimeInterval offset = __CFTZPeriodGMTOffset(&(tz->_periods[idx])); 1247 if (idx + 1 < tz->_periodCnt) { 1248 return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1])); 1249 } else if (0 < idx) { 1250 return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1])); 1251 } 1252 } 1253 return 0.0; 1254} 1255 1256CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) { 1257 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval, (NSTimeZone *)tz, _nextDaylightSavingTimeTransitionAfterAbsoluteTime:at); 1258 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1259 CFIndex idx = __CFBSearchTZPeriods(tz, at); 1260 if (tz->_periodCnt <= idx + 1) { 1261 return 0.0; 1262 } 1263 return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1])); 1264} 1265 1266extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); 1267 1268#define BUFFER_SIZE 768 1269 1270CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) { 1271 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFStringRef, (NSTimeZone *)tz, localizedName:(NSTimeZoneNameStyle)style locale:(NSLocale *)locale); 1272 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1273 __CFGenericValidateType(locale, CFLocaleGetTypeID()); 1274 1275 if (style == kCFTimeZoneNameStyleGeneric || style == kCFTimeZoneNameStyleShortGeneric) { 1276 CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorSystemDefault, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); 1277 CFDateFormatterSetProperty(df, kCFDateFormatterTimeZone, tz); 1278 CFDateFormatterSetFormat(df, (style == kCFTimeZoneNameStyleGeneric) ? CFSTR("vvvv") : CFSTR("v")); 1279 CFStringRef str = CFDateFormatterCreateStringWithAbsoluteTime(CFGetAllocator(tz), df, 0.0); 1280 CFRelease(df); 1281 return str; 1282 } 1283 1284 CFStringRef localeID = CFLocaleGetIdentifier(locale); 1285 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, localeID, tz); 1286 if (NULL == cal) { 1287 return NULL; 1288 } 1289 1290 char buffer[BUFFER_SIZE]; 1291 const char *cstr = CFStringGetCStringPtr(localeID, kCFStringEncodingASCII); 1292 if (NULL == cstr) { 1293 if (CFStringGetCString(localeID, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; 1294 } 1295 if (NULL == cstr) { 1296 ucal_close(cal); 1297 return NULL; 1298 } 1299 1300 UChar ubuffer[BUFFER_SIZE]; 1301 UErrorCode status = U_ZERO_ERROR; 1302 int32_t cnt = ucal_getTimeZoneDisplayName(cal, (UCalendarDisplayNameType)style, cstr, ubuffer, BUFFER_SIZE, &status); 1303 ucal_close(cal); 1304 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { 1305 return CFStringCreateWithCharacters(CFGetAllocator(tz), (const UniChar *)ubuffer, cnt); 1306 } 1307 return NULL; 1308} 1309 1310static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) { 1311 CFDictionaryRef dict; 1312 __CFTimeZoneLockCompatibilityMapping(); 1313 if (NULL == __CFTimeZoneCompatibilityMappingDict) { 1314 __CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1315 1316 // Empty string means delete/ignore these 1317 } 1318 dict = __CFTimeZoneCompatibilityMappingDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL; 1319 __CFTimeZoneUnlockCompatibilityMapping(); 1320 return dict; 1321} 1322 1323#undef TZZONEINFO 1324#undef TZZONELINK 1325 1326