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