/ CFTimeZone.c
CFTimeZone.c
1 /* 2 * Copyright (c) 2015 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-2014, 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 59 struct 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 75 static CFStringRef __tzZoneInfo = NULL; 76 static char *__tzDir = NULL; 77 static void __InitTZStrings(void); 78 #else 79 #error Unknown or unspecified DEPLOYMENT_TARGET 80 #endif 81 82 #if DEPLOYMENT_TARGET_LINUX 83 // Symbol aliases 84 CF_EXPORT CFStringRef const kCFDateFormatterTimeZone __attribute__((weak, alias ("kCFDateFormatterTimeZoneKey"))); 85 #endif 86 87 CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification") 88 89 static CFTimeZoneRef __CFTimeZoneSystem = NULL; 90 static CFTimeZoneRef __CFTimeZoneDefault = NULL; 91 static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL; 92 static CFLock_t __CFTimeZoneAbbreviationLock = CFLockInit; 93 static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL; 94 static CFLock_t __CFTimeZoneCompatibilityMappingLock = CFLockInit; 95 static CFArrayRef __CFKnownTimeZoneList = NULL; 96 static CFMutableDictionaryRef __CFTimeZoneCache = NULL; 97 static CFLock_t __CFTimeZoneGlobalLock = CFLockInit; 98 99 #if DEPLOYMENT_TARGET_WINDOWS 100 static CFDictionaryRef __CFTimeZoneWinToOlsonDict = NULL; 101 static CFLock_t __CFTimeZoneWinToOlsonLock = CFLockInit; 102 #endif 103 104 CF_INLINE void __CFTimeZoneLockGlobal(void) { 105 __CFLock(&__CFTimeZoneGlobalLock); 106 } 107 108 CF_INLINE void __CFTimeZoneUnlockGlobal(void) { 109 __CFUnlock(&__CFTimeZoneGlobalLock); 110 } 111 112 CF_INLINE void __CFTimeZoneLockAbbreviations(void) { 113 __CFLock(&__CFTimeZoneAbbreviationLock); 114 } 115 116 CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) { 117 __CFUnlock(&__CFTimeZoneAbbreviationLock); 118 } 119 120 CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) { 121 __CFLock(&__CFTimeZoneCompatibilityMappingLock); 122 } 123 124 CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) { 125 __CFUnlock(&__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 */ 134 static 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 165 static 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 229 typedef struct _CFTZPeriod { 230 int32_t startSec; 231 CFStringRef abbrev; 232 uint32_t info; 233 } CFTZPeriod; 234 235 struct __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 250 CF_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 258 CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) { 259 return period->startSec; 260 } 261 262 CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) { 263 return period->abbrev; 264 } 265 266 CF_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 272 CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) { 273 return (Boolean)__CFBitfieldGetValue(period->info, 17, 17); 274 } 275 276 static 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 286 static 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 299 CF_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 308 CF_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 315 static 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 432 static 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 440 static CFHashCode __CFTimeZoneHash(CFTypeRef cf) { 441 CFTimeZoneRef tz = (CFTimeZoneRef)cf; 442 return CFHash(CFTimeZoneGetName(tz)); 443 } 444 445 static 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 456 static 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 468 static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID; 469 470 static 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 482 CFTypeID CFTimeZoneGetTypeID(void) { 483 static dispatch_once_t initOnce; 484 dispatch_once(&initOnce, ^{ __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass); }); 485 return __kCFTimeZoneTypeID; 486 } 487 488 #if DEPLOYMENT_TARGET_WINDOWS 489 static const char *__CFTimeZoneWinToOlsonDefaults = 490 /* Mappings to time zones in Windows Registry are best-guess */ 491 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 492 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">" 493 " <plist version=\"1.0\">" 494 " <dict>" 495 " <key>Afghanistan</key> <string>Asia/Kabul</string>" 496 " <key>Afghanistan Standard Time</key> <string>Asia/Kabul</string>" 497 " <key>Alaskan</key> <string>America/Anchorage</string>" 498 " <key>Alaskan Standard Time</key> <string>America/Anchorage</string>" 499 " <key>Arab</key> <string>Asia/Riyadh</string>" 500 " <key>Arab Standard Time</key> <string>Asia/Riyadh</string>" 501 " <key>Arabian</key> <string>Asia/Muscat</string>" 502 " <key>Arabian Standard Time</key> <string>Asia/Muscat</string>" 503 " <key>Arabic Standard Time</key> <string>Asia/Baghdad</string>" 504 " <key>Atlantic</key> <string>America/Halifax</string>" 505 " <key>Atlantic Standard Time</key> <string>America/Halifax</string>" 506 " <key>AUS Central</key> <string>Australia/Darwin</string>" 507 " <key>AUS Central Standard Time</key> <string>Australia/Darwin</string>" 508 " <key>AUS Eastern</key> <string>Australia/Sydney</string>" 509 " <key>AUS Eastern Standard Time</key> <string>Australia/Sydney</string>" 510 " <key>Azerbaijan Standard Time</key> <string>Asia/Baku</string>" 511 " <key>Azores</key> <string>Atlantic/Azores</string>" 512 " <key>Azores Standard Time</key> <string>Atlantic/Azores</string>" 513 " <key>Bangkok</key> <string>Asia/Bangkok</string>" 514 " <key>Bangkok Standard Time</key> <string>Asia/Bangkok</string>" 515 " <key>Beijing</key> <string>Asia/Shanghai</string>" 516 " <key>Canada Central</key> <string>America/Regina</string>" 517 " <key>Canada Central Standard Time</key> <string>America/Regina</string>" 518 " <key>Cape Verde Standard Time</key> <string>Atlantic/Cape_Verde</string>" 519 " <key>Caucasus</key> <string>Asia/Yerevan</string>" 520 " <key>Caucasus Standard Time</key> <string>Asia/Yerevan</string>" 521 " <key>Cen. Australia</key> <string>Australia/Adelaide</string>" 522 " <key>Cen. Australia Standard Time</key> <string>Australia/Adelaide</string>" 523 " <key>Central</key> <string>America/Chicago</string>" 524 " <key>Central America Standard Time</key> <string>America/Regina</string>" 525 " <key>Central Asia</key> <string>Asia/Dhaka</string>" 526 " <key>Central Asia Standard Time</key> <string>Asia/Dhaka</string>" 527 " <key>Central Brazilian Standard Time</key> <string>America/Manaus</string>" 528 " <key>Central Europe</key> <string>Europe/Prague</string>" 529 " <key>Central Europe Standard Time</key> <string>Europe/Prague</string>" 530 " <key>Central European</key> <string>Europe/Belgrade</string>" 531 " <key>Central European Standard Time</key> <string>Europe/Belgrade</string>" 532 " <key>Central Pacific</key> <string>Pacific/Guadalcanal</string>" 533 " <key>Central Pacific Standard Time</key> <string>Pacific/Guadalcanal</string>" 534 " <key>Central Standard Time</key> <string>America/Chicago</string>" 535 " <key>Central Standard Time (Mexico)</key> <string>America/Mexico_City</string>" 536 " <key>China</key> <string>Asia/Shanghai</string>" 537 " <key>China Standard Time</key> <string>Asia/Shanghai</string>" 538 " <key>Dateline</key> <string>GMT-1200</string>" 539 " <key>Dateline Standard Time</key> <string>GMT-1200</string>" 540 " <key>E. Africa</key> <string>Africa/Nairobi</string>" 541 " <key>E. Africa Standard Time</key> <string>Africa/Nairobi</string>" 542 " <key>E. Australia</key> <string>Australia/Brisbane</string>" 543 " <key>E. Australia Standard Time</key> <string>Australia/Brisbane</string>" 544 " <key>E. Europe</key> <string>Europe/Minsk</string>" 545 " <key>E. Europe Standard Time</key> <string>Europe/Minsk</string>" 546 " <key>E. South America</key> <string>America/Sao_Paulo</string>" 547 " <key>E. South America Standard Time</key> <string>America/Sao_Paulo</string>" 548 " <key>Eastern</key> <string>America/New_York</string>" 549 " <key>Eastern Standard Time</key> <string>America/New_York</string>" 550 " <key>Egypt</key> <string>Africa/Cairo</string>" 551 " <key>Egypt Standard Time</key> <string>Africa/Cairo</string>" 552 " <key>Ekaterinburg</key> <string>Asia/Yekaterinburg</string>" 553 " <key>Ekaterinburg Standard Time</key> <string>Asia/Yekaterinburg</string>" 554 " <key>Fiji</key> <string>Pacific/Fiji</string>" 555 " <key>Fiji Standard Time</key> <string>Pacific/Fiji</string>" 556 " <key>FLE</key> <string>Europe/Helsinki</string>" 557 " <key>FLE Standard Time</key> <string>Europe/Helsinki</string>" 558 " <key>Georgian Standard Time</key> <string>Asia/Tbilisi</string>" 559 " <key>GFT</key> <string>Europe/Athens</string>" 560 " <key>GFT Standard Time</key> <string>Europe/Athens</string>" 561 " <key>GMT</key> <string>Europe/London</string>" 562 " <key>GMT Standard Time</key> <string>Europe/London</string>" 563 " <key>Greenland Standard Time</key> <string>America/Godthab</string>" 564 " <key>Greenwich</key> <string>GMT</string>" 565 " <key>Greenwich Standard Time</key> <string>GMT</string>" 566 " <key>GTB</key> <string>Europe/Athens</string>" 567 " <key>GTB Standard Time</key> <string>Europe/Athens</string>" 568 " <key>Hawaiian</key> <string>Pacific/Honolulu</string>" 569 " <key>Hawaiian Standard Time</key> <string>Pacific/Honolulu</string>" 570 " <key>India</key> <string>Asia/Calcutta</string>" 571 " <key>India Standard Time</key> <string>Asia/Calcutta</string>" 572 " <key>Iran</key> <string>Asia/Tehran</string>" 573 " <key>Iran Standard Time</key> <string>Asia/Tehran</string>" 574 " <key>Israel</key> <string>Asia/Jerusalem</string>" 575 " <key>Israel Standard Time</key> <string>Asia/Jerusalem</string>" 576 " <key>Jordan Standard Time</key> <string>Asia/Amman</string>" 577 " <key>Korea</key> <string>Asia/Seoul</string>" 578 " <key>Korea Standard Time</key> <string>Asia/Seoul</string>" 579 " <key>Mexico</key> <string>America/Mexico_City</string>" 580 " <key>Mexico Standard Time</key> <string>America/Mexico_City</string>" 581 " <key>Mexico Standard Time 2</key> <string>America/Chihuahua</string>" 582 " <key>Mid-Atlantic</key> <string>Atlantic/South_Georgia</string>" 583 " <key>Mid-Atlantic Standard Time</key> <string>Atlantic/South_Georgia</string>" 584 " <key>Middle East Standard Time</key> <string>Asia/Beirut</string>" 585 " <key>Mountain</key> <string>America/Denver</string>" 586 " <key>Mountain Standard Time</key> <string>America/Denver</string>" 587 " <key>Mountain Standard Time (Mexico)</key> <string>America/Chihuahua</string>" 588 " <key>Myanmar Standard Time</key> <string>Asia/Rangoon</string>" 589 " <key>N. Central Asia Standard Time</key> <string>Asia/Novosibirsk</string>" 590 " <key>Namibia Standard Time</key> <string>Africa/Windhoek</string>" 591 " <key>Nepal Standard Time</key> <string>Asia/Katmandu</string>" 592 " <key>New Zealand</key> <string>Pacific/Auckland</string>" 593 " <key>New Zealand Standard Time</key> <string>Pacific/Auckland</string>" 594 " <key>Newfoundland</key> <string>America/St_Johns</string>" 595 " <key>Newfoundland Standard Time</key> <string>America/St_Johns</string>" 596 " <key>North Asia East Standard Time</key> <string>Asia/Ulaanbaatar</string>" 597 " <key>North Asia Standard Time</key> <string>Asia/Krasnoyarsk</string>" 598 " <key>Pacific</key> <string>America/Los_Angeles</string>" 599 " <key>Pacific SA</key> <string>America/Santiago</string>" 600 " <key>Pacific SA Standard Time</key> <string>America/Santiago</string>" 601 " <key>Pacific Standard Time</key> <string>America/Los_Angeles</string>" 602 " <key>Pacific Standard Time (Mexico)</key> <string>America/Tijuana</string>" 603 " <key>Prague Bratislava</key> <string>Europe/Prague</string>" 604 " <key>Romance</key> <string>Europe/Paris</string>" 605 " <key>Romance Standard Time</key> <string>Europe/Paris</string>" 606 " <key>Russian</key> <string>Europe/Moscow</string>" 607 " <key>Russian Standard Time</key> <string>Europe/Moscow</string>" 608 " <key>SA Eastern</key> <string>America/Buenos_Aires</string>" 609 " <key>SA Eastern Standard Time</key> <string>America/Buenos_Aires</string>" 610 " <key>SA Pacific</key> <string>America/Bogota</string>" 611 " <key>SA Pacific Standard Time</key> <string>America/Bogota</string>" 612 " <key>SA Western</key> <string>America/Caracas</string>" 613 " <key>SA Western Standard Time</key> <string>America/Caracas</string>" 614 " <key>Samoa</key> <string>Pacific/Apia</string>" 615 " <key>Samoa Standard Time</key> <string>Pacific/Apia</string>" 616 " <key>Saudi Arabia</key> <string>Asia/Riyadh</string>" 617 " <key>Saudi Arabia Standard Time</key> <string>Asia/Riyadh</string>" 618 " <key>SE Asia Standard Time</key> <string>Asia/Bangkok</string>" 619 " <key>Singapore</key> <string>Asia/Singapore</string>" 620 " <key>Singapore Standard Time</key> <string>Asia/Singapore</string>" 621 " <key>South Africa</key> <string>Africa/Harare</string>" 622 " <key>South Africa Standard Time</key> <string>Africa/Harare</string>" 623 " <key>Sri Lanka</key> <string>Asia/Colombo</string>" 624 " <key>Sri Lanka Standard Time</key> <string>Asia/Colombo</string>" 625 " <key>Sydney Standard Time</key> <string>Australia/Sydney</string>" 626 " <key>Taipei</key> <string>Asia/Taipei</string>" 627 " <key>Taipei Standard Time</key> <string>Asia/Taipei</string>" 628 " <key>Tasmania</key> <string>Australia/Hobart</string>" 629 " <key>Tasmania Standard Time</key> <string>Australia/Hobart</string>" 630 " <key>Tasmania Standard Time</key> <string>Australia/Hobart</string>" 631 " <key>Tokyo</key> <string>Asia/Tokyo</string>" 632 " <key>Tokyo Standard Time</key> <string>Asia/Tokyo</string>" 633 " <key>Tonga Standard Time</key> <string>Pacific/Tongatapu</string>" 634 " <key>US Eastern</key> <string>America/Indianapolis</string>" 635 " <key>US Eastern Standard Time</key> <string>America/Indianapolis</string>" 636 " <key>US Mountain</key> <string>America/Phoenix</string>" 637 " <key>US Mountain Standard Time</key> <string>America/Phoenix</string>" 638 " <key>Vladivostok</key> <string>Asia/Vladivostok</string>" 639 " <key>Vladivostok Standard Time</key> <string>Asia/Vladivostok</string>" 640 " <key>W. Australia</key> <string>Australia/Perth</string>" 641 " <key>W. Australia Standard Time</key> <string>Australia/Perth</string>" 642 " <key>W. Central Africa Standard Time</key> <string>Africa/Luanda</string>" 643 " <key>W. Europe</key> <string>Europe/Berlin</string>" 644 " <key>W. Europe Standard Time</key> <string>Europe/Berlin</string>" 645 " <key>Warsaw</key> <string>Europe/Warsaw</string>" 646 " <key>West Asia</key> <string>Asia/Karachi</string>" 647 " <key>West Asia Standard Time</key> <string>Asia/Karachi</string>" 648 " <key>West Pacific</key> <string>Pacific/Guam</string>" 649 " <key>West Pacific Standard Time</key> <string>Pacific/Guam</string>" 650 " <key>Western Brazilian Standard Time</key> <string>America/Rio_Branco</string>" 651 " <key>Yakutsk</key> <string>Asia/Yakutsk</string>" 652 " </dict>" 653 " </plist>"; 654 655 CF_INLINE void __CFTimeZoneLockWinToOlson(void) { 656 __CFLock(&__CFTimeZoneWinToOlsonLock); 657 } 658 659 CF_INLINE void __CFTimeZoneUnlockWinToOlson(void) { 660 __CFUnlock(&__CFTimeZoneWinToOlsonLock); 661 } 662 663 CFDictionaryRef CFTimeZoneCopyWinToOlsonDictionary(void) { 664 CFDictionaryRef dict; 665 __CFTimeZoneLockWinToOlson(); 666 if (NULL == __CFTimeZoneWinToOlsonDict) { 667 CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneWinToOlsonDefaults, strlen(__CFTimeZoneWinToOlsonDefaults)); 668 __CFTimeZoneWinToOlsonDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); 669 CFRelease(data); 670 } 671 if (NULL == __CFTimeZoneWinToOlsonDict) { 672 __CFTimeZoneWinToOlsonDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL); 673 } 674 dict = __CFTimeZoneWinToOlsonDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneWinToOlsonDict) : NULL; 675 __CFTimeZoneUnlockWinToOlson(); 676 return dict; 677 } 678 679 void CFTimeZoneSetWinToOlsonDictionary(CFDictionaryRef dict) { 680 __CFGenericValidateType(dict, CFDictionaryGetTypeID()); 681 __CFTimeZoneLockWinToOlson(); 682 if (dict != __CFTimeZoneWinToOlsonDict) { 683 if (dict) CFRetain(dict); 684 if (__CFTimeZoneWinToOlsonDict) CFRelease(__CFTimeZoneWinToOlsonDict); 685 __CFTimeZoneWinToOlsonDict = dict; 686 } 687 __CFTimeZoneUnlockWinToOlson(); 688 } 689 690 CFTimeZoneRef CFTimeZoneCreateWithWindowsName(CFAllocatorRef allocator, CFStringRef winName) { 691 if (!winName) return NULL; 692 693 CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary(); 694 if (!winToOlson) return NULL; 695 696 CFStringRef olsonName = CFDictionaryGetValue(winToOlson, winName); 697 CFTimeZoneRef retval = NULL; 698 if (olsonName) { 699 retval = CFTimeZoneCreateWithName(allocator, olsonName, false); 700 } 701 CFRelease(winToOlson); 702 return retval; 703 } 704 705 extern CFStringRef _CFGetWindowsAppleSystemLibraryDirectory(void); 706 void __InitTZStrings(void) { 707 static CFLock_t __CFTZDirLock = CFLockInit; 708 __CFLock(&__CFTZDirLock); 709 if (!__tzZoneInfo) { 710 CFStringRef winDir = _CFGetWindowsAppleSystemLibraryDirectory(); 711 __tzZoneInfo = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\\etc\\zoneinfo"), winDir); 712 } 713 if (!__tzDir && __tzZoneInfo) { 714 int length = CFStringGetLength(__tzZoneInfo) + sizeof("\\zone.tab") + 1; 715 __tzDir = malloc(length); // If we don't use ascii, we'll need to malloc more space 716 if (!__tzDir || !CFStringGetCString(__tzZoneInfo, __tzDir, length, kCFStringEncodingASCII)) { 717 free(__tzDir); 718 } else { 719 strcat(__tzDir, "\\zone.tab"); 720 } 721 } 722 __CFUnlock(&__CFTZDirLock); 723 } 724 #endif 725 726 static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { 727 CFTimeZoneRef result = NULL; 728 729 #if DEPLOYMENT_TARGET_WINDOWS 730 CFStringRef name = NULL; 731 TIME_ZONE_INFORMATION tzi = { 0 }; 732 DWORD rval = GetTimeZoneInformation(&tzi); 733 if (rval != TIME_ZONE_ID_INVALID) { 734 LPWSTR standardName = (LPWSTR)&tzi.StandardName; 735 CFStringRef cfStandardName = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (UInt8 *)standardName, wcslen(standardName)*sizeof(WCHAR), kCFStringEncodingUTF16LE, false); 736 if (cfStandardName) { 737 CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary(); 738 if (winToOlson) { 739 name = CFDictionaryGetValue(winToOlson, cfStandardName); 740 if (name) CFRetain(name); 741 CFRelease(winToOlson); 742 } 743 CFRelease(cfStandardName); 744 } 745 } else { 746 CFLog(kCFLogLevelError, CFSTR("Couldn't get time zone information error %d"), GetLastError()); 747 } 748 if (name) { 749 #else 750 const char *tzenv; 751 int ret; 752 char linkbuf[CFMaxPathSize]; 753 754 tzenv = __CFgetenv("TZFILE"); 755 if (NULL != tzenv) { 756 CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); 757 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); 758 CFRelease(name); 759 if (result) return result; 760 } 761 tzenv = __CFgetenv("TZ"); 762 if (NULL != tzenv) { 763 CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); 764 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true); 765 CFRelease(name); 766 if (result) return result; 767 } 768 ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf)); 769 if (0 < ret) { 770 CFStringRef name; 771 linkbuf[ret] = '\0'; 772 if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) { 773 name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false); 774 } else { 775 name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false); 776 } 777 #endif 778 779 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); 780 CFRelease(name); 781 if (result) return result; 782 } 783 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); 784 } 785 786 CFTimeZoneRef CFTimeZoneCopySystem(void) { 787 CFTimeZoneRef tz; 788 __CFTimeZoneLockGlobal(); 789 if (NULL == __CFTimeZoneSystem) { 790 __CFTimeZoneUnlockGlobal(); 791 tz = __CFTimeZoneCreateSystem(); 792 __CFTimeZoneLockGlobal(); 793 if (NULL == __CFTimeZoneSystem) { 794 __CFTimeZoneSystem = tz; 795 } else { 796 if (tz) CFRelease(tz); 797 } 798 } 799 tz = __CFTimeZoneSystem ? (CFTimeZoneRef)CFRetain(__CFTimeZoneSystem) : NULL; 800 __CFTimeZoneUnlockGlobal(); 801 return tz; 802 } 803 804 static CFIndex __noteCount = 0; 805 806 void CFTimeZoneResetSystem(void) { 807 __CFTimeZoneLockGlobal(); 808 if (__CFTimeZoneDefault == __CFTimeZoneSystem) { 809 if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); 810 __CFTimeZoneDefault = NULL; 811 } 812 CFTimeZoneRef tz = __CFTimeZoneSystem; 813 __CFTimeZoneSystem = NULL; 814 __CFTimeZoneUnlockGlobal(); 815 if (tz) CFRelease(tz); 816 } 817 818 CFIndex _CFTimeZoneGetNoteCount(void) { 819 return __noteCount; 820 } 821 822 CFTimeZoneRef CFTimeZoneCopyDefault(void) { 823 CFTimeZoneRef tz; 824 __CFTimeZoneLockGlobal(); 825 if (NULL == __CFTimeZoneDefault) { 826 __CFTimeZoneUnlockGlobal(); 827 tz = CFTimeZoneCopySystem(); 828 __CFTimeZoneLockGlobal(); 829 if (NULL == __CFTimeZoneDefault) { 830 __CFTimeZoneDefault = tz; 831 } else { 832 if (tz) CFRelease(tz); 833 } 834 } 835 tz = __CFTimeZoneDefault ? (CFTimeZoneRef)CFRetain(__CFTimeZoneDefault) : NULL; 836 __CFTimeZoneUnlockGlobal(); 837 return tz; 838 } 839 840 void CFTimeZoneSetDefault(CFTimeZoneRef tz) { 841 if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 842 __CFTimeZoneLockGlobal(); 843 if (tz != __CFTimeZoneDefault) { 844 if (tz) CFRetain(tz); 845 if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); 846 __CFTimeZoneDefault = tz; 847 } 848 __CFTimeZoneUnlockGlobal(); 849 } 850 851 static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void); 852 853 CFArrayRef CFTimeZoneCopyKnownNames(void) { 854 CFArrayRef tzs; 855 __CFTimeZoneLockGlobal(); 856 if (NULL == __CFKnownTimeZoneList) { 857 CFMutableArrayRef list; 858 /* TimeZone information locate in the registry for Win32 859 * (Aleksey Dukhnyakov) 860 */ 861 list = __CFCopyRecursiveDirectoryList(); 862 // Remove undesirable ancient cruft 863 CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); 864 CFIndex idx; 865 for (idx = CFArrayGetCount(list); idx--; ) { 866 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(list, idx); 867 if (CFDictionaryContainsKey(dict, item)) { 868 CFArrayRemoveValueAtIndex(list, idx); 869 } 870 } 871 __CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list); 872 CFRelease(list); 873 } 874 tzs = __CFKnownTimeZoneList ? (CFArrayRef)CFRetain(__CFKnownTimeZoneList) : NULL; 875 __CFTimeZoneUnlockGlobal(); 876 return tzs; 877 } 878 879 /* The criteria here are sort of: coverage for the U.S. and Europe, 880 * large cities, abbreviation uniqueness, and perhaps a few others. 881 * But do not make the list too large with obscure information. 882 */ 883 static const char *__CFTimeZoneAbbreviationDefaults = 884 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 885 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">" 886 " <plist version=\"1.0\">" 887 " <dict>" 888 " <key>ADT</key> <string>America/Halifax</string>" 889 " <key>AKDT</key> <string>America/Juneau</string>" 890 " <key>AKST</key> <string>America/Juneau</string>" 891 " <key>ART</key> <string>America/Argentina/Buenos_Aires</string>" 892 " <key>AST</key> <string>America/Halifax</string>" 893 " <key>BDT</key> <string>Asia/Dhaka</string>" 894 " <key>BRST</key> <string>America/Sao_Paulo</string>" 895 " <key>BRT</key> <string>America/Sao_Paulo</string>" 896 " <key>BST</key> <string>Europe/London</string>" 897 " <key>CAT</key> <string>Africa/Harare</string>" 898 " <key>CDT</key> <string>America/Chicago</string>" 899 " <key>CEST</key> <string>Europe/Paris</string>" 900 " <key>CET</key> <string>Europe/Paris</string>" 901 " <key>CLST</key> <string>America/Santiago</string>" 902 " <key>CLT</key> <string>America/Santiago</string>" 903 " <key>COT</key> <string>America/Bogota</string>" 904 " <key>CST</key> <string>America/Chicago</string>" 905 " <key>EAT</key> <string>Africa/Addis_Ababa</string>" 906 " <key>EDT</key> <string>America/New_York</string>" 907 " <key>EEST</key> <string>Europe/Istanbul</string>" 908 " <key>EET</key> <string>Europe/Istanbul</string>" 909 " <key>EST</key> <string>America/New_York</string>" 910 " <key>GMT</key> <string>GMT</string>" 911 " <key>GST</key> <string>Asia/Dubai</string>" 912 " <key>HKT</key> <string>Asia/Hong_Kong</string>" 913 " <key>HST</key> <string>Pacific/Honolulu</string>" 914 " <key>ICT</key> <string>Asia/Bangkok</string>" 915 " <key>IRST</key> <string>Asia/Tehran</string>" 916 " <key>IST</key> <string>Asia/Calcutta</string>" 917 " <key>JST</key> <string>Asia/Tokyo</string>" 918 " <key>KST</key> <string>Asia/Seoul</string>" 919 " <key>MDT</key> <string>America/Denver</string>" 920 " <key>MSD</key> <string>Europe/Moscow</string>" 921 " <key>MSK</key> <string>Europe/Moscow</string>" 922 " <key>MST</key> <string>America/Denver</string>" 923 " <key>NZDT</key> <string>Pacific/Auckland</string>" 924 " <key>NZST</key> <string>Pacific/Auckland</string>" 925 " <key>PDT</key> <string>America/Los_Angeles</string>" 926 " <key>PET</key> <string>America/Lima</string>" 927 " <key>PHT</key> <string>Asia/Manila</string>" 928 " <key>PKT</key> <string>Asia/Karachi</string>" 929 " <key>PST</key> <string>America/Los_Angeles</string>" 930 " <key>SGT</key> <string>Asia/Singapore</string>" 931 " <key>UTC</key> <string>UTC</string>" 932 " <key>WAT</key> <string>Africa/Lagos</string>" 933 " <key>WEST</key> <string>Europe/Lisbon</string>" 934 " <key>WET</key> <string>Europe/Lisbon</string>" 935 " <key>WIT</key> <string>Asia/Jakarta</string>" 936 " </dict>" 937 " </plist>"; 938 939 CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) { 940 CFDictionaryRef dict; 941 __CFTimeZoneLockAbbreviations(); 942 if (NULL == __CFTimeZoneAbbreviationDict) { 943 CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults)); 944 __CFTimeZoneAbbreviationDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); 945 CFRelease(data); 946 } 947 if (NULL == __CFTimeZoneAbbreviationDict) { 948 __CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL); 949 } 950 dict = __CFTimeZoneAbbreviationDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneAbbreviationDict) : NULL; 951 __CFTimeZoneUnlockAbbreviations(); 952 return dict; 953 } 954 955 void _removeFromCache(const void *key, const void *value, void *context) { 956 CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)key); 957 } 958 959 void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) { 960 __CFGenericValidateType(dict, CFDictionaryGetTypeID()); 961 __CFTimeZoneLockGlobal(); 962 if (dict != __CFTimeZoneAbbreviationDict) { 963 if (dict) CFRetain(dict); 964 if (__CFTimeZoneAbbreviationDict) { 965 CFDictionaryApplyFunction(__CFTimeZoneAbbreviationDict, _removeFromCache, NULL); 966 CFRelease(__CFTimeZoneAbbreviationDict); 967 } 968 __CFTimeZoneAbbreviationDict = dict; 969 } 970 __CFTimeZoneUnlockGlobal(); 971 } 972 973 CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) { 974 // assert: (NULL != name && NULL != data); 975 CFTimeZoneRef memory; 976 uint32_t size; 977 CFTZPeriod *tzp = NULL; 978 CFIndex idx, cnt = 0; 979 980 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 981 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 982 __CFGenericValidateType(name, CFStringGetTypeID()); 983 __CFGenericValidateType(data, CFDataGetTypeID()); 984 __CFTimeZoneLockGlobal(); 985 if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) { 986 __CFTimeZoneUnlockGlobal(); 987 return (CFTimeZoneRef)CFRetain(memory); 988 } 989 if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) { 990 __CFTimeZoneUnlockGlobal(); 991 return NULL; 992 } 993 size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase); 994 memory = (CFTimeZoneRef)_CFRuntimeCreateInstance(allocator, CFTimeZoneGetTypeID(), size, NULL); 995 if (NULL == memory) { 996 __CFTimeZoneUnlockGlobal(); 997 for (idx = 0; idx < cnt; idx++) { 998 if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev); 999 } 1000 if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp); 1001 return NULL; 1002 } 1003 ((struct __CFTimeZone *)memory)->_name = (CFStringRef)CFStringCreateCopy(allocator, name); 1004 ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data); 1005 ((struct __CFTimeZone *)memory)->_periods = tzp; 1006 ((struct __CFTimeZone *)memory)->_periodCnt = cnt; 1007 if (NULL == __CFTimeZoneCache) { 1008 __CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1009 } 1010 CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory); 1011 __CFTimeZoneUnlockGlobal(); 1012 return memory; 1013 } 1014 1015 static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { 1016 CFTimeZoneRef result; 1017 CFDataRef data; 1018 int32_t nameLen = CFStringGetLength(name); 1019 unsigned char dataBytes[52 + nameLen + 1]; 1020 memset(dataBytes, 0, sizeof(dataBytes)); 1021 1022 // Put in correct magic bytes for timezone structures 1023 dataBytes[0] = 'T'; 1024 dataBytes[1] = 'Z'; 1025 dataBytes[2] = 'i'; 1026 dataBytes[3] = 'f'; 1027 1028 __CFEntzcode(1, dataBytes + 20); 1029 __CFEntzcode(1, dataBytes + 24); 1030 __CFEntzcode(1, dataBytes + 36); 1031 __CFEntzcode(nameLen + 1, dataBytes + 40); 1032 __CFEntzcode(seconds, dataBytes + 44); 1033 dataBytes[48] = isDST ? 1 : 0; 1034 CFStringGetCString(name, (char *)dataBytes + 50, nameLen + 1, kCFStringEncodingASCII); 1035 data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1); 1036 result = CFTimeZoneCreate(allocator, name, data); 1037 CFRelease(data); 1038 return result; 1039 } 1040 1041 1042 // rounds offset to nearest minute 1043 CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) { 1044 CFTimeZoneRef result; 1045 CFStringRef name; 1046 int32_t seconds, minute, hour; 1047 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 1048 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 1049 if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL; 1050 ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0; 1051 seconds = (int32_t)ti; 1052 hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600); 1053 seconds -= ((ti < 0) ? -hour : hour) * 3600; 1054 minute = (ti < 0) ? (-seconds / 60) : (seconds / 60); 1055 if (fabs(ti) < 1.0) { 1056 name = (CFStringRef)CFRetain(CFSTR("GMT")); 1057 } else { 1058 name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute); 1059 } 1060 result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0); 1061 CFRelease(name); 1062 return result; 1063 } 1064 1065 CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) { 1066 CFTimeZoneRef result = NULL; 1067 CFStringRef tzName = NULL; 1068 CFDataRef data = NULL; 1069 1070 if (allocator == NULL) allocator = __CFGetDefaultAllocator(); 1071 __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); 1072 __CFGenericValidateType(name, CFStringGetTypeID()); 1073 if (CFEqual(CFSTR(""), name)) { 1074 // empty string is not a time zone name, just abort now, 1075 // following stuff will fail anyway 1076 return NULL; 1077 } 1078 __CFTimeZoneLockGlobal(); 1079 if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) { 1080 __CFTimeZoneUnlockGlobal(); 1081 return (CFTimeZoneRef)CFRetain(result); 1082 } 1083 __CFTimeZoneUnlockGlobal(); 1084 CFIndex len = CFStringGetLength(name); 1085 if (6 == len || 8 == len) { 1086 UniChar buffer[8]; 1087 CFStringGetCharacters(name, CFRangeMake(0, len), buffer); 1088 if ('G' == buffer[0] && 'M' == buffer[1] && 'T' == buffer[2] && ('+' == buffer[3] || '-' == buffer[3])) { 1089 if (('0' <= buffer[4] && buffer[4] <= '9') && ('0' <= buffer[5] && buffer[5] <= '9')) { 1090 int32_t hours = (buffer[4] - '0') * 10 + (buffer[5] - '0'); 1091 if (-14 <= hours && hours <= 14) { 1092 CFTimeInterval ti = hours * 3600.0; 1093 if (6 == len) { 1094 return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti); 1095 } else { 1096 if (('0' <= buffer[6] && buffer[6] <= '9') && ('0' <= buffer[7] && buffer[7] <= '9')) { 1097 int32_t minutes = (buffer[6] - '0') * 10 + (buffer[7] - '0'); 1098 if ((-14 == hours && 0 == minutes) || (14 == hours && 0 == minutes) || (0 <= minutes && minutes <= 59)) { 1099 ti = ti + minutes * 60.0; 1100 return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti); 1101 } 1102 } 1103 } 1104 } 1105 } 1106 } 1107 } 1108 CFURLRef baseURL, tempURL; 1109 void *bytes; 1110 CFIndex length; 1111 1112 #if DEPLOYMENT_TARGET_WINDOWS 1113 if (!__tzZoneInfo) __InitTZStrings(); 1114 if (!__tzZoneInfo) return NULL; 1115 baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLWindowsPathStyle, true); 1116 #else 1117 baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true); 1118 #endif 1119 if (tryAbbrev) { 1120 CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); 1121 tzName = CFDictionaryGetValue(abbrevs, name); 1122 if (NULL != tzName) { 1123 tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false); 1124 if (NULL != tempURL) { 1125 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0, 0)) { 1126 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault); 1127 } 1128 CFRelease(tempURL); 1129 } 1130 } 1131 CFRelease(abbrevs); 1132 } 1133 if (NULL == data) { 1134 CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); 1135 CFStringRef mapping = CFDictionaryGetValue(dict, name); 1136 if (mapping) { 1137 name = mapping; 1138 #if DEPLOYMENT_TARGET_WINDOWS 1139 } else if (CFStringHasPrefix(name, __tzZoneInfo)) { 1140 CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name); 1141 CFStringDelete(unprefixed, CFRangeMake(0, CFStringGetLength(__tzZoneInfo))); 1142 #else 1143 } else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) { 1144 CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name); 1145 CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO))); 1146 #endif 1147 mapping = CFDictionaryGetValue(dict, unprefixed); 1148 if (mapping) { 1149 name = mapping; 1150 } 1151 CFRelease(unprefixed); 1152 } 1153 CFRelease(dict); 1154 if (CFEqual(CFSTR(""), name)) { 1155 return NULL; 1156 } 1157 } 1158 if (NULL == data) { 1159 tzName = name; 1160 tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false); 1161 if (NULL != tempURL) { 1162 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0, 0)) { 1163 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault); 1164 } 1165 CFRelease(tempURL); 1166 } 1167 } 1168 CFRelease(baseURL); 1169 if (NULL != data) { 1170 result = CFTimeZoneCreate(allocator, tzName, data); 1171 if (name != tzName) { 1172 CFStringRef nameCopy = (CFStringRef)CFStringCreateCopy(allocator, name); 1173 __CFTimeZoneLockGlobal(); 1174 CFDictionaryAddValue(__CFTimeZoneCache, nameCopy, result); 1175 __CFTimeZoneUnlockGlobal(); 1176 CFRelease(nameCopy); 1177 } 1178 CFRelease(data); 1179 } 1180 return result; 1181 } 1182 1183 CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) { 1184 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFStringRef, (NSTimeZone *)tz, name); 1185 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1186 return tz->_name; 1187 } 1188 1189 CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) { 1190 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFDataRef, (NSTimeZone *)tz, data); 1191 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1192 return tz->_data; 1193 } 1194 1195 /* This function converts CFAbsoluteTime to (Win32) SYSTEMTIME 1196 * (Aleksey Dukhnyakov) 1197 */ 1198 #if DEPLOYMENT_TARGET_WINDOWS 1199 BOOL __CFTimeZoneGetWin32SystemTime(SYSTEMTIME * sys_time, CFAbsoluteTime time) 1200 { 1201 LONGLONG l; 1202 FILETIME * ftime=(FILETIME*)&l; 1203 1204 /* seconds between 1601 and 1970 : 11644473600, 1205 * seconds between 1970 and 2001 : 978307200, 1206 * FILETIME - number of 100-nanosecond intervals since January 1, 1601 1207 */ 1208 l=(LONGLONG)(time+11644473600LL+978307200)*10000000; 1209 if (FileTimeToSystemTime(ftime,sys_time)) 1210 return TRUE; 1211 else 1212 return FALSE; 1213 } 1214 #endif 1215 1216 CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) { 1217 CFIndex idx; 1218 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1219 idx = __CFBSearchTZPeriods(tz, at); 1220 return __CFTZPeriodGMTOffset(&(tz->_periods[idx])); 1221 } 1222 1223 CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) { 1224 CFStringRef result; 1225 CFIndex idx; 1226 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1227 idx = __CFBSearchTZPeriods(tz, at); 1228 result = __CFTZPeriodAbbreviation(&(tz->_periods[idx])); 1229 return result ? (CFStringRef)CFRetain(result) : NULL; 1230 } 1231 1232 Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) { 1233 CFIndex idx; 1234 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1235 idx = __CFBSearchTZPeriods(tz, at); 1236 return __CFTZPeriodIsDST(&(tz->_periods[idx])); 1237 } 1238 1239 CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) { 1240 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval, (NSTimeZone *)tz, _daylightSavingTimeOffsetForAbsoluteTime:at); 1241 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1242 CFIndex idx = __CFBSearchTZPeriods(tz, at); 1243 if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) { 1244 CFTimeInterval offset = __CFTZPeriodGMTOffset(&(tz->_periods[idx])); 1245 if (idx + 1 < tz->_periodCnt) { 1246 return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1])); 1247 } else if (0 < idx) { 1248 return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1])); 1249 } 1250 } 1251 return 0.0; 1252 } 1253 1254 CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) { 1255 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval, (NSTimeZone *)tz, _nextDaylightSavingTimeTransitionAfterAbsoluteTime:at); 1256 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1257 CFIndex idx = __CFBSearchTZPeriods(tz, at); 1258 if (tz->_periodCnt <= idx + 1) { 1259 return 0.0; 1260 } 1261 return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1])); 1262 } 1263 1264 extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); 1265 1266 #define BUFFER_SIZE 768 1267 1268 CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) { 1269 CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFStringRef, (NSTimeZone *)tz, localizedName:(NSTimeZoneNameStyle)style locale:(NSLocale *)locale); 1270 __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); 1271 __CFGenericValidateType(locale, CFLocaleGetTypeID()); 1272 1273 if (style == kCFTimeZoneNameStyleGeneric || style == kCFTimeZoneNameStyleShortGeneric) { 1274 CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorSystemDefault, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); 1275 CFDateFormatterSetProperty(df, kCFDateFormatterTimeZone, tz); 1276 CFDateFormatterSetFormat(df, (style == kCFTimeZoneNameStyleGeneric) ? CFSTR("vvvv") : CFSTR("v")); 1277 CFStringRef str = CFDateFormatterCreateStringWithAbsoluteTime(CFGetAllocator(tz), df, 0.0); 1278 CFRelease(df); 1279 return str; 1280 } 1281 1282 CFStringRef localeID = CFLocaleGetIdentifier(locale); 1283 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, localeID, tz); 1284 if (NULL == cal) { 1285 return NULL; 1286 } 1287 1288 char buffer[BUFFER_SIZE]; 1289 const char *cstr = CFStringGetCStringPtr(localeID, kCFStringEncodingASCII); 1290 if (NULL == cstr) { 1291 if (CFStringGetCString(localeID, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; 1292 } 1293 if (NULL == cstr) { 1294 ucal_close(cal); 1295 return NULL; 1296 } 1297 1298 UChar ubuffer[BUFFER_SIZE]; 1299 UErrorCode status = U_ZERO_ERROR; 1300 int32_t cnt = ucal_getTimeZoneDisplayName(cal, (UCalendarDisplayNameType)style, cstr, ubuffer, BUFFER_SIZE, &status); 1301 ucal_close(cal); 1302 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { 1303 return CFStringCreateWithCharacters(CFGetAllocator(tz), (const UniChar *)ubuffer, cnt); 1304 } 1305 return NULL; 1306 } 1307 1308 static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) { 1309 CFDictionaryRef dict; 1310 __CFTimeZoneLockCompatibilityMapping(); 1311 if (NULL == __CFTimeZoneCompatibilityMappingDict) { 1312 __CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1313 1314 // Empty string means delete/ignore these 1315 } 1316 dict = __CFTimeZoneCompatibilityMappingDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL; 1317 __CFTimeZoneUnlockCompatibilityMapping(); 1318 return dict; 1319 } 1320 1321 #undef TZZONEINFO 1322 #undef TZZONELINK 1323