]> git.saurik.com Git - apple/cf.git/blob - CFTimeZone.c
CF-1152.14.tar.gz
[apple/cf.git] / 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