]> git.saurik.com Git - apple/cf.git/blob - CFTimeZone.c
3af1cc9dcb8764f1012a1aec6261c30964c92b5d
[apple/cf.git] / CFTimeZone.c
1 /*
2 * Copyright (c) 2009 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 /* CFTimeZone.c
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
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_WINDOWS
44 #include <dirent.h>
45 #include <unistd.h>
46 #include <sys/fcntl.h>
47 #include <tzfile.h>
48 #else
49 #error Unknown or unspecified DEPLOYMENT_TARGET
50 #endif
51
52
53 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
54 #define TZZONELINK TZDEFAULT
55 #define TZZONEINFO TZDIR "/"
56 #elif DEPLOYMENT_TARGET_WINDOWS
57 static CFStringRef __tzZoneInfo = NULL;
58 static char *__tzDir = NULL;
59 static void __InitTZStrings(void);
60 #else
61 #error Unknown or unspecified DEPLOYMENT_TARGET
62 #endif
63
64 CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification")
65
66 static CFTimeZoneRef __CFTimeZoneSystem = NULL;
67 static CFTimeZoneRef __CFTimeZoneDefault = NULL;
68 static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL;
69 static CFSpinLock_t __CFTimeZoneAbbreviationLock = CFSpinLockInit;
70 static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL;
71 static CFSpinLock_t __CFTimeZoneCompatibilityMappingLock = CFSpinLockInit;
72 static CFArrayRef __CFKnownTimeZoneList = NULL;
73 static CFMutableDictionaryRef __CFTimeZoneCache = NULL;
74 static CFSpinLock_t __CFTimeZoneGlobalLock = CFSpinLockInit;
75
76 #if DEPLOYMENT_TARGET_WINDOWS
77 static CFDictionaryRef __CFTimeZoneWinToOlsonDict = NULL;
78 static CFSpinLock_t __CFTimeZoneWinToOlsonLock = CFSpinLockInit;
79 #endif
80
81 CF_INLINE void __CFTimeZoneLockGlobal(void) {
82 __CFSpinLock(&__CFTimeZoneGlobalLock);
83 }
84
85 CF_INLINE void __CFTimeZoneUnlockGlobal(void) {
86 __CFSpinUnlock(&__CFTimeZoneGlobalLock);
87 }
88
89 CF_INLINE void __CFTimeZoneLockAbbreviations(void) {
90 __CFSpinLock(&__CFTimeZoneAbbreviationLock);
91 }
92
93 CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) {
94 __CFSpinUnlock(&__CFTimeZoneAbbreviationLock);
95 }
96
97 CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) {
98 __CFSpinLock(&__CFTimeZoneCompatibilityMappingLock);
99 }
100
101 CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) {
102 __CFSpinUnlock(&__CFTimeZoneCompatibilityMappingLock);
103 }
104
105 #if DEPLOYMENT_TARGET_WINDOWS
106 /* This function should be used for WIN32 instead of
107 * __CFCopyRecursiveDirectoryList function.
108 * It takes TimeZone names from the registry
109 * (Aleksey Dukhnyakov)
110 */
111 static CFMutableArrayRef __CFCopyWindowsTimeZoneList() {
112 CFMutableArrayRef result = NULL;
113 HKEY hkResult;
114 TCHAR lpName[MAX_PATH+1];
115 DWORD dwIndex, retCode;
116
117 if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) !=
118 ERROR_SUCCESS )
119 return NULL;
120
121 result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
122 for (dwIndex=0; (retCode = RegEnumKey(hkResult,dwIndex,lpName,MAX_PATH)) != ERROR_NO_MORE_ITEMS ; dwIndex++) {
123 if (retCode != ERROR_SUCCESS) {
124 RegCloseKey(hkResult);
125 CFRelease(result);
126 return NULL;
127 } else {
128 #if defined(UNICODE)
129 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const UInt8 *)lpName, (_tcslen(lpName) * sizeof(UniChar)), kCFStringEncodingUnicode, false);
130 #else
131 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, lpName, _tcslen(lpName), CFStringGetSystemEncoding(), false);
132 #endif
133 CFArrayAppendValue(result, string);
134 CFRelease(string);
135 }
136 }
137
138 RegCloseKey(hkResult);
139 return result;
140 }
141 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
142 static CFMutableArrayRef __CFCopyRecursiveDirectoryList() {
143 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
144 #if DEPLOYMENT_TARGET_WINDOWS
145 if (!__tzDir) __InitTZStrings();
146 if (!__tzDir) return result;
147 int fd = open(__tzDir, O_RDONLY);
148 #else
149 int fd = open(TZDIR "/zone.tab", O_RDONLY);
150 #endif
151
152 for (; 0 <= fd;) {
153 uint8_t buffer[4096];
154 ssize_t len = read(fd, buffer, sizeof(buffer));
155 if (len <= 0) break;
156 if (len < sizeof(buffer)) {
157 // assumes that partial read only occurs at the end of the file
158 buffer[len] = '\n';
159 len++;
160 }
161 const uint8_t *bytes = buffer;
162 for (;;) {
163 const uint8_t *nextl = memchr(bytes, '\n', len);
164 if (!nextl) break;
165 nextl++;
166 if ('#' == *bytes) {
167 len -= (nextl - bytes);
168 bytes = nextl;
169 continue;
170 }
171 const uint8_t *tab1 = memchr(bytes, '\t', (nextl - bytes));
172 if (!tab1) {
173 len -= (nextl - bytes);
174 bytes = nextl;
175 continue;
176 }
177 tab1++;
178 len -= (tab1 - bytes);
179 bytes = tab1;
180 const uint8_t *tab2 = memchr(bytes, '\t', (nextl - bytes));
181 if (!tab2) {
182 len -= (nextl - bytes);
183 bytes = nextl;
184 continue;
185 }
186 tab2++;
187 len -= (tab2 - bytes);
188 bytes = tab2;
189 const uint8_t *tab3 = memchr(bytes, '\t', (nextl - bytes));
190 int nmlen = tab3 ? (tab3 - bytes) : (nextl - 1 - bytes);
191 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, bytes, nmlen, kCFStringEncodingUTF8, false);
192 CFArrayAppendValue(result, string);
193 CFRelease(string);
194 len -= (nextl - bytes);
195 bytes = nextl;
196 }
197 lseek(fd, -len, SEEK_CUR);
198 }
199 close(fd);
200 return result;
201 }
202 #else
203 #error Unknown or unspecified DEPLOYMENT_TARGET
204 #endif
205
206 typedef struct _CFTZPeriod {
207 int32_t startSec;
208 CFStringRef abbrev;
209 uint32_t info;
210 } CFTZPeriod;
211
212 struct __CFTimeZone {
213 CFRuntimeBase _base;
214 CFStringRef _name; /* immutable */
215 CFDataRef _data; /* immutable */
216 CFTZPeriod *_periods; /* immutable */
217 int32_t _periodCnt; /* immutable */
218 };
219
220 /* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates
221 * between 1933 and 2069; info outside these years is discarded on read-in */
222 /* Bits 31-18 of the info are unused */
223 /* Bit 17 of the info is used for the is-DST state */
224 /* Bit 16 of the info is used for the sign of the offset (1 == negative) */
225 /* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */
226
227 CF_INLINE void __CFTZPeriodInit(CFTZPeriod *period, int32_t startTime, CFStringRef abbrev, int32_t offset, Boolean isDST) {
228 period->startSec = startTime;
229 period->abbrev = abbrev ? (CFStringRef)CFRetain(abbrev) : NULL;
230 __CFBitfieldSetValue(period->info, 15, 0, abs(offset));
231 __CFBitfieldSetValue(period->info, 16, 16, (offset < 0 ? 1 : 0));
232 __CFBitfieldSetValue(period->info, 17, 17, (isDST ? 1 : 0));
233 }
234
235 CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) {
236 return period->startSec;
237 }
238
239 CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) {
240 return period->abbrev;
241 }
242
243 CF_INLINE int32_t __CFTZPeriodGMTOffset(const CFTZPeriod *period) {
244 int32_t v = __CFBitfieldGetValue(period->info, 15, 0);
245 if (__CFBitfieldGetValue(period->info, 16, 16)) v = -v;
246 return v;
247 }
248
249 CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) {
250 return (Boolean)__CFBitfieldGetValue(period->info, 17, 17);
251 }
252
253 static CFComparisonResult __CFCompareTZPeriods(const void *val1, const void *val2, void *context) {
254 CFTZPeriod *tzp1 = (CFTZPeriod *)val1;
255 CFTZPeriod *tzp2 = (CFTZPeriod *)val2;
256 // we treat equal as less than, as the code which uses the
257 // result of the bsearch doesn't expect exact matches
258 // (they're pretty rare, so no point in over-coding for them)
259 if (__CFTZPeriodStartSeconds(tzp1) <= __CFTZPeriodStartSeconds(tzp2)) return kCFCompareLessThan;
260 return kCFCompareGreaterThan;
261 }
262
263 static CFIndex __CFBSearchTZPeriods(CFTimeZoneRef tz, CFAbsoluteTime at) {
264 CFTZPeriod elem;
265 __CFTZPeriodInit(&elem, (int32_t)floor(at + 1.0), NULL, 0, false);
266 CFIndex idx = CFBSearch(&elem, sizeof(CFTZPeriod), tz->_periods, tz->_periodCnt, __CFCompareTZPeriods, NULL);
267 if (tz->_periodCnt <= idx) {
268 idx = tz->_periodCnt;
269 } else if (0 == idx) {
270 idx = 1;
271 }
272 return idx - 1;
273 }
274
275
276 CF_INLINE int32_t __CFDetzcode(const unsigned char *bufp) {
277 int32_t result = (bufp[0] & 0x80) ? ~0L : 0L;
278 result = (result << 8) | (bufp[0] & 0xff);
279 result = (result << 8) | (bufp[1] & 0xff);
280 result = (result << 8) | (bufp[2] & 0xff);
281 result = (result << 8) | (bufp[3] & 0xff);
282 return result;
283 }
284
285 CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) {
286 bufp[0] = (value >> 24) & 0xff;
287 bufp[1] = (value >> 16) & 0xff;
288 bufp[2] = (value >> 8) & 0xff;
289 bufp[3] = (value >> 0) & 0xff;
290 }
291
292 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
293 static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) {
294 int32_t len, timecnt, typecnt, charcnt, idx, cnt;
295 const uint8_t *p, *timep, *typep, *ttisp, *charp;
296 CFStringRef *abbrs;
297 Boolean result = true;
298
299 p = CFDataGetBytePtr(data);
300 len = CFDataGetLength(data);
301 if (len < (int32_t)sizeof(struct tzhead)) {
302 return false;
303 }
304
305 if (!(p[0] == 'T' && p[1] == 'Z' && p[2] == 'i' && p[3] == 'f')) return false; /* Don't parse without TZif at head of file */
306
307 p += 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */
308 timecnt = __CFDetzcode(p);
309 p += 4;
310 typecnt = __CFDetzcode(p);
311 p += 4;
312 charcnt = __CFDetzcode(p);
313 p += 4;
314 if (typecnt <= 0 || timecnt < 0 || charcnt < 0) {
315 return false;
316 }
317 if (1024 < timecnt || 32 < typecnt || 128 < charcnt) {
318 // reject excessive timezones to avoid arithmetic overflows for
319 // security reasons and to reject potentially corrupt files
320 return false;
321 }
322 if (len - (int32_t)sizeof(struct tzhead) < (4 + 1) * timecnt + (4 + 1 + 1) * typecnt + charcnt) {
323 return false;
324 }
325 timep = p;
326 typep = timep + 4 * timecnt;
327 ttisp = typep + timecnt;
328 charp = ttisp + (4 + 1 + 1) * typecnt;
329 cnt = (0 < timecnt) ? timecnt : 1;
330 *tzpp = CFAllocatorAllocate(allocator, cnt * sizeof(CFTZPeriod), 0);
331 if (__CFOASafe) __CFSetLastAllocationEventName(*tzpp, "CFTimeZone (store)");
332 memset(*tzpp, 0, cnt * sizeof(CFTZPeriod));
333 abbrs = CFAllocatorAllocate(allocator, (charcnt + 1) * sizeof(CFStringRef), 0);
334 if (__CFOASafe) __CFSetLastAllocationEventName(abbrs, "CFTimeZone (temp)");
335 for (idx = 0; idx < charcnt + 1; idx++) {
336 abbrs[idx] = NULL;
337 }
338 for (idx = 0; idx < cnt; idx++) {
339 CFAbsoluteTime at;
340 int32_t itime, offset;
341 uint8_t type, dst, abbridx;
342
343 at = (CFAbsoluteTime)(__CFDetzcode(timep) + 0.0) - kCFAbsoluteTimeIntervalSince1970;
344 if (0 == timecnt) itime = INT_MIN;
345 else if (at < (CFAbsoluteTime)INT_MIN) itime = INT_MIN;
346 else if ((CFAbsoluteTime)INT_MAX < at) itime = INT_MAX;
347 else itime = (int32_t)at;
348 timep += 4; /* harmless if 0 == timecnt */
349 type = (0 < timecnt) ? (uint8_t)*typep++ : 0;
350 if (typecnt <= type) {
351 result = false;
352 break;
353 }
354 offset = __CFDetzcode(ttisp + 6 * type);
355 dst = (uint8_t)*(ttisp + 6 * type + 4);
356 if (0 != dst && 1 != dst) {
357 result = false;
358 break;
359 }
360 abbridx = (uint8_t)*(ttisp + 6 * type + 5);
361 if (charcnt < abbridx) {
362 result = false;
363 break;
364 }
365 if (NULL == abbrs[abbridx]) {
366 abbrs[abbridx] = CFStringCreateWithCString(allocator, (char *)&charp[abbridx], kCFStringEncodingASCII);
367 }
368 __CFTZPeriodInit(*tzpp + idx, itime, abbrs[abbridx], offset, (dst ? true : false));
369 }
370 for (idx = 0; idx < charcnt + 1; idx++) {
371 if (NULL != abbrs[idx]) {
372 CFRelease(abbrs[idx]);
373 }
374 }
375 CFAllocatorDeallocate(allocator, abbrs);
376 if (result) {
377 // dump all but the last INT_MIN and the first INT_MAX
378 for (idx = 0; idx < cnt; idx++) {
379 if (((*tzpp + idx)->startSec == INT_MIN) && (idx + 1 < cnt) && (((*tzpp + idx + 1)->startSec == INT_MIN))) {
380 if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev);
381 cnt--;
382 memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx));
383 idx--;
384 }
385 }
386 // Don't combine these loops! Watch the idx decrementing...
387 for (idx = 0; idx < cnt; idx++) {
388 if (((*tzpp + idx)->startSec == INT_MAX) && (0 < idx) && (((*tzpp + idx - 1)->startSec == INT_MAX))) {
389 if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev);
390 cnt--;
391 memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx));
392 idx--;
393 }
394 }
395 CFQSortArray(*tzpp, cnt, sizeof(CFTZPeriod), __CFCompareTZPeriods, NULL);
396 // if the first period is in DST and there is more than one period, drop it
397 if (1 < cnt && __CFTZPeriodIsDST(*tzpp + 0)) {
398 if (NULL != (*tzpp + 0)->abbrev) CFRelease((*tzpp + 0)->abbrev);
399 cnt--;
400 memmove((*tzpp + 0), (*tzpp + 0 + 1), sizeof(CFTZPeriod) * (cnt - 0));
401 }
402 *cntp = cnt;
403 } else {
404 CFAllocatorDeallocate(allocator, *tzpp);
405 *tzpp = NULL;
406 }
407 return result;
408 }
409 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
410 static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) {
411 /* We use Win32 function to find TimeZone
412 * (Aleksey Dukhnyakov)
413 */
414 *tzpp = (CFTZPeriod *)CFAllocatorAllocate(allocator, sizeof(CFTZPeriod), 0);
415 memset(*tzpp, 0, sizeof(CFTZPeriod));
416 __CFTZPeriodInit(*tzpp, 0, NULL, 0, false);
417 *cntp = 1;
418 return TRUE;
419 }
420 #else
421 #error Unknown or unspecified DEPLOYMENT_TARGET
422 #endif
423
424 static Boolean __CFTimeZoneEqual(CFTypeRef cf1, CFTypeRef cf2) {
425 CFTimeZoneRef tz1 = (CFTimeZoneRef)cf1;
426 CFTimeZoneRef tz2 = (CFTimeZoneRef)cf2;
427 if (!CFEqual(CFTimeZoneGetName(tz1), CFTimeZoneGetName(tz2))) return false;
428 if (!CFEqual(CFTimeZoneGetData(tz1), CFTimeZoneGetData(tz2))) return false;
429 return true;
430 }
431
432 static CFHashCode __CFTimeZoneHash(CFTypeRef cf) {
433 CFTimeZoneRef tz = (CFTimeZoneRef)cf;
434 return CFHash(CFTimeZoneGetName(tz));
435 }
436
437 static CFStringRef __CFTimeZoneCopyDescription(CFTypeRef cf) {
438 CFTimeZoneRef tz = (CFTimeZoneRef)cf;
439 CFStringRef result, abbrev;
440 CFAbsoluteTime at;
441 at = CFAbsoluteTimeGetCurrent();
442 abbrev = CFTimeZoneCopyAbbreviation(tz, at);
443 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");
444 CFRelease(abbrev);
445 return result;
446 }
447
448 static void __CFTimeZoneDeallocate(CFTypeRef cf) {
449 CFTimeZoneRef tz = (CFTimeZoneRef)cf;
450 CFAllocatorRef allocator = CFGetAllocator(tz);
451 CFIndex idx;
452 if (tz->_name) CFRelease(tz->_name);
453 if (tz->_data) CFRelease(tz->_data);
454 for (idx = 0; idx < tz->_periodCnt; idx++) {
455 if (NULL != tz->_periods[idx].abbrev) CFRelease(tz->_periods[idx].abbrev);
456 }
457 if (NULL != tz->_periods) CFAllocatorDeallocate(allocator, tz->_periods);
458 }
459
460 static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID;
461
462 static const CFRuntimeClass __CFTimeZoneClass = {
463 0,
464 "CFTimeZone",
465 NULL, // init
466 NULL, // copy
467 __CFTimeZoneDeallocate,
468 __CFTimeZoneEqual,
469 __CFTimeZoneHash,
470 NULL, //
471 __CFTimeZoneCopyDescription
472 };
473
474 __private_extern__ void __CFTimeZoneInitialize(void) {
475 __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass);
476 }
477
478 CFTypeID CFTimeZoneGetTypeID(void) {
479 return __kCFTimeZoneTypeID;
480 }
481
482
483 #if DEPLOYMENT_TARGET_WINDOWS_SYNC
484 static const char *__CFTimeZoneWinToOlsonDefaults =
485 /* Mappings to time zones in Windows Registry are best-guess */
486 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
487 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
488 " <plist version=\"1.0\">"
489 " <dict>"
490 " <key>Afghanistan</key> <string>Asia/Kabul</string>"
491 " <key>Afghanistan Standard Time</key> <string>Asia/Kabul</string>"
492 " <key>Alaskan</key> <string>America/Anchorage</string>"
493 " <key>Alaskan Standard Time</key> <string>America/Anchorage</string>"
494 " <key>Arab</key> <string>Asia/Riyadh</string>"
495 " <key>Arab Standard Time</key> <string>Asia/Riyadh</string>"
496 " <key>Arabian</key> <string>Asia/Muscat</string>"
497 " <key>Arabian Standard Time</key> <string>Asia/Muscat</string>"
498 " <key>Arabic Standard Time</key> <string>Asia/Baghdad</string>"
499 " <key>Atlantic</key> <string>America/Halifax</string>"
500 " <key>Atlantic Standard Time</key> <string>America/Halifax</string>"
501 " <key>AUS Central</key> <string>Australia/Darwin</string>"
502 " <key>AUS Central Standard Time</key> <string>Australia/Darwin</string>"
503 " <key>AUS Eastern</key> <string>Australia/Sydney</string>"
504 " <key>AUS Eastern Standard Time</key> <string>Australia/Sydney</string>"
505 " <key>Azerbaijan Standard Time</key> <string>Asia/Baku</string>"
506 " <key>Azores</key> <string>Atlantic/Azores</string>"
507 " <key>Azores Standard Time</key> <string>Atlantic/Azores</string>"
508 " <key>Bangkok</key> <string>Asia/Bangkok</string>"
509 " <key>Bangkok Standard Time</key> <string>Asia/Bangkok</string>"
510 " <key>Beijing</key> <string>Asia/Shanghai</string>"
511 " <key>Canada Central</key> <string>America/Regina</string>"
512 " <key>Canada Central Standard Time</key> <string>America/Regina</string>"
513 " <key>Cape Verde Standard Time</key> <string>Atlantic/Cape_Verde</string>"
514 " <key>Caucasus</key> <string>Asia/Yerevan</string>"
515 " <key>Caucasus Standard Time</key> <string>Asia/Yerevan</string>"
516 " <key>Cen. Australia</key> <string>Australia/Adelaide</string>"
517 " <key>Cen. Australia Standard Time</key> <string>Australia/Adelaide</string>"
518 " <key>Central</key> <string>America/Chicago</string>"
519 " <key>Central America Standard Time</key> <string>America/Regina</string>"
520 " <key>Central Asia</key> <string>Asia/Dhaka</string>"
521 " <key>Central Asia Standard Time</key> <string>Asia/Dhaka</string>"
522 " <key>Central Brazilian Standard Time</key> <string>America/Manaus</string>"
523 " <key>Central Europe</key> <string>Europe/Prague</string>"
524 " <key>Central Europe Standard Time</key> <string>Europe/Prague</string>"
525 " <key>Central European</key> <string>Europe/Belgrade</string>"
526 " <key>Central European Standard Time</key> <string>Europe/Belgrade</string>"
527 " <key>Central Pacific</key> <string>Pacific/Guadalcanal</string>"
528 " <key>Central Pacific Standard Time</key> <string>Pacific/Guadalcanal</string>"
529 " <key>Central Standard Time</key> <string>America/Chicago</string>"
530 " <key>Central Standard Time (Mexico)</key> <string>America/Mexico_City</string>"
531 " <key>China</key> <string>Asia/Shanghai</string>"
532 " <key>China Standard Time</key> <string>Asia/Shanghai</string>"
533 " <key>Dateline</key> <string>GMT-1200</string>"
534 " <key>Dateline Standard Time</key> <string>GMT-1200</string>"
535 " <key>E. Africa</key> <string>Africa/Nairobi</string>"
536 " <key>E. Africa Standard Time</key> <string>Africa/Nairobi</string>"
537 " <key>E. Australia</key> <string>Australia/Brisbane</string>"
538 " <key>E. Australia Standard Time</key> <string>Australia/Brisbane</string>"
539 " <key>E. Europe</key> <string>Europe/Minsk</string>"
540 " <key>E. Europe Standard Time</key> <string>Europe/Minsk</string>"
541 " <key>E. South America</key> <string>America/Sao_Paulo</string>"
542 " <key>E. South America Standard Time</key> <string>America/Sao_Paulo</string>"
543 " <key>Eastern</key> <string>America/New_York</string>"
544 " <key>Eastern Standard Time</key> <string>America/New_York</string>"
545 " <key>Egypt</key> <string>Africa/Cairo</string>"
546 " <key>Egypt Standard Time</key> <string>Africa/Cairo</string>"
547 " <key>Ekaterinburg</key> <string>Asia/Yekaterinburg</string>"
548 " <key>Ekaterinburg Standard Time</key> <string>Asia/Yekaterinburg</string>"
549 " <key>Fiji</key> <string>Pacific/Fiji</string>"
550 " <key>Fiji Standard Time</key> <string>Pacific/Fiji</string>"
551 " <key>FLE</key> <string>Europe/Helsinki</string>"
552 " <key>FLE Standard Time</key> <string>Europe/Helsinki</string>"
553 " <key>Georgian Standard Time</key> <string>Asia/Tbilisi</string>"
554 " <key>GFT</key> <string>Europe/Athens</string>"
555 " <key>GFT Standard Time</key> <string>Europe/Athens</string>"
556 " <key>GMT</key> <string>Europe/London</string>"
557 " <key>GMT Standard Time</key> <string>Europe/London</string>"
558 " <key>Greenland Standard Time</key> <string>America/Godthab</string>"
559 " <key>Greenwich</key> <string>GMT</string>"
560 " <key>Greenwich Standard Time</key> <string>GMT</string>"
561 " <key>GTB</key> <string>Europe/Athens</string>"
562 " <key>GTB Standard Time</key> <string>Europe/Athens</string>"
563 " <key>Hawaiian</key> <string>Pacific/Honolulu</string>"
564 " <key>Hawaiian Standard Time</key> <string>Pacific/Honolulu</string>"
565 " <key>India</key> <string>Asia/Calcutta</string>"
566 " <key>India Standard Time</key> <string>Asia/Calcutta</string>"
567 " <key>Iran</key> <string>Asia/Tehran</string>"
568 " <key>Iran Standard Time</key> <string>Asia/Tehran</string>"
569 " <key>Israel</key> <string>Asia/Jerusalem</string>"
570 " <key>Israel Standard Time</key> <string>Asia/Jerusalem</string>"
571 " <key>Jordan Standard Time</key> <string>Asia/Amman</string>"
572 " <key>Korea</key> <string>Asia/Seoul</string>"
573 " <key>Korea Standard Time</key> <string>Asia/Seoul</string>"
574 " <key>Mexico</key> <string>America/Mexico_City</string>"
575 " <key>Mexico Standard Time</key> <string>America/Mexico_City</string>"
576 " <key>Mexico Standard Time 2</key> <string>America/Chihuahua</string>"
577 " <key>Mid-Atlantic</key> <string>Atlantic/South_Georgia</string>"
578 " <key>Mid-Atlantic Standard Time</key> <string>Atlantic/South_Georgia</string>"
579 " <key>Middle East Standard Time</key> <string>Asia/Beirut</string>"
580 " <key>Mountain</key> <string>America/Denver</string>"
581 " <key>Mountain Standard Time</key> <string>America/Denver</string>"
582 " <key>Mountain Standard Time (Mexico)</key> <string>America/Chihuahua</string>"
583 " <key>Myanmar Standard Time</key> <string>Asia/Rangoon</string>"
584 " <key>N. Central Asia Standard Time</key> <string>Asia/Novosibirsk</string>"
585 " <key>Namibia Standard Time</key> <string>Africa/Windhoek</string>"
586 " <key>Nepal Standard Time</key> <string>Asia/Katmandu</string>"
587 " <key>New Zealand</key> <string>Pacific/Auckland</string>"
588 " <key>New Zealand Standard Time</key> <string>Pacific/Auckland</string>"
589 " <key>Newfoundland</key> <string>America/St_Johns</string>"
590 " <key>Newfoundland Standard Time</key> <string>America/St_Johns</string>"
591 " <key>North Asia East Standard Time</key> <string>Asia/Ulaanbaatar</string>"
592 " <key>North Asia Standard Time</key> <string>Asia/Krasnoyarsk</string>"
593 " <key>Pacific</key> <string>America/Los_Angeles</string>"
594 " <key>Pacific SA</key> <string>America/Santiago</string>"
595 " <key>Pacific SA Standard Time</key> <string>America/Santiago</string>"
596 " <key>Pacific Standard Time</key> <string>America/Los_Angeles</string>"
597 " <key>Pacific Standard Time (Mexico)</key> <string>America/Tijuana</string>"
598 " <key>Prague Bratislava</key> <string>Europe/Prague</string>"
599 " <key>Romance</key> <string>Europe/Paris</string>"
600 " <key>Romance Standard Time</key> <string>Europe/Paris</string>"
601 " <key>Russian</key> <string>Europe/Moscow</string>"
602 " <key>Russian Standard Time</key> <string>Europe/Moscow</string>"
603 " <key>SA Eastern</key> <string>America/Buenos_Aires</string>"
604 " <key>SA Eastern Standard Time</key> <string>America/Buenos_Aires</string>"
605 " <key>SA Pacific</key> <string>America/Bogota</string>"
606 " <key>SA Pacific Standard Time</key> <string>America/Bogota</string>"
607 " <key>SA Western</key> <string>America/Caracas</string>"
608 " <key>SA Western Standard Time</key> <string>America/Caracas</string>"
609 " <key>Samoa</key> <string>Pacific/Apia</string>"
610 " <key>Samoa Standard Time</key> <string>Pacific/Apia</string>"
611 " <key>Saudi Arabia</key> <string>Asia/Riyadh</string>"
612 " <key>Saudi Arabia Standard Time</key> <string>Asia/Riyadh</string>"
613 " <key>SE Asia Standard Time</key> <string>Asia/Bangkok</string>"
614 " <key>Singapore</key> <string>Asia/Singapore</string>"
615 " <key>Singapore Standard Time</key> <string>Asia/Singapore</string>"
616 " <key>South Africa</key> <string>Africa/Harare</string>"
617 " <key>South Africa Standard Time</key> <string>Africa/Harare</string>"
618 " <key>Sri Lanka</key> <string>Asia/Colombo</string>"
619 " <key>Sri Lanka Standard Time</key> <string>Asia/Colombo</string>"
620 " <key>Sydney Standard Time</key> <string>Australia/Sydney</string>"
621 " <key>Taipei</key> <string>Asia/Taipei</string>"
622 " <key>Taipei Standard Time</key> <string>Asia/Taipei</string>"
623 " <key>Tasmania</key> <string>Australia/Hobart</string>"
624 " <key>Tasmania Standard Time</key> <string>Australia/Hobart</string>"
625 " <key>Tasmania Standard Time</key> <string>Australia/Hobart</string>"
626 " <key>Tokyo</key> <string>Asia/Tokyo</string>"
627 " <key>Tokyo Standard Time</key> <string>Asia/Tokyo</string>"
628 " <key>Tonga Standard Time</key> <string>Pacific/Tongatapu</string>"
629 " <key>US Eastern</key> <string>America/Indianapolis</string>"
630 " <key>US Eastern Standard Time</key> <string>America/Indianapolis</string>"
631 " <key>US Mountain</key> <string>America/Phoenix</string>"
632 " <key>US Mountain Standard Time</key> <string>America/Phoenix</string>"
633 " <key>Vladivostok</key> <string>Asia/Vladivostok</string>"
634 " <key>Vladivostok Standard Time</key> <string>Asia/Vladivostok</string>"
635 " <key>W. Australia</key> <string>Australia/Perth</string>"
636 " <key>W. Australia Standard Time</key> <string>Australia/Perth</string>"
637 " <key>W. Central Africa Standard Time</key> <string>Africa/Luanda</string>"
638 " <key>W. Europe</key> <string>Europe/Berlin</string>"
639 " <key>W. Europe Standard Time</key> <string>Europe/Berlin</string>"
640 " <key>Warsaw</key> <string>Europe/Warsaw</string>"
641 " <key>West Asia</key> <string>Asia/Karachi</string>"
642 " <key>West Asia Standard Time</key> <string>Asia/Karachi</string>"
643 " <key>West Pacific</key> <string>Pacific/Guam</string>"
644 " <key>West Pacific Standard Time</key> <string>Pacific/Guam</string>"
645 " <key>Western Brazilian Standard Time</key> <string>America/Rio_Branco</string>"
646 " <key>Yakutsk</key> <string>Asia/Yakutsk</string>"
647 " </dict>"
648 " </plist>";
649
650 CF_INLINE void __CFTimeZoneLockWinToOlson(void) {
651 __CFSpinLock(&__CFTimeZoneWinToOlsonLock);
652 }
653
654 CF_INLINE void __CFTimeZoneUnlockWinToOlson(void) {
655 __CFSpinUnlock(&__CFTimeZoneWinToOlsonLock);
656 }
657
658 CFDictionaryRef CFTimeZoneCopyWinToOlsonDictionary(void) {
659 CFDictionaryRef dict;
660 __CFTimeZoneLockWinToOlson();
661 if (NULL == __CFTimeZoneWinToOlsonDict) {
662 CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneWinToOlsonDefaults, strlen(__CFTimeZoneWinToOlsonDefaults));
663 __CFTimeZoneWinToOlsonDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL);
664 CFRelease(data);
665 }
666 if (NULL == __CFTimeZoneWinToOlsonDict) {
667 __CFTimeZoneWinToOlsonDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL);
668 }
669 dict = __CFTimeZoneWinToOlsonDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneWinToOlsonDict) : NULL;
670 __CFTimeZoneUnlockWinToOlson();
671 return dict;
672 }
673
674 void CFTimeZoneSetWinToOlsonDictionary(CFDictionaryRef dict) {
675 __CFGenericValidateType(dict, CFDictionaryGetTypeID());
676 __CFTimeZoneLockWinToOlson();
677 if (dict != __CFTimeZoneWinToOlsonDict) {
678 if (dict) CFRetain(dict);
679 if (__CFTimeZoneWinToOlsonDict) CFRelease(__CFTimeZoneWinToOlsonDict);
680 __CFTimeZoneWinToOlsonDict = dict;
681 }
682 __CFTimeZoneUnlockWinToOlson();
683 }
684
685 CFTimeZoneRef CFTimeZoneCreateWithWindowsName(CFAllocatorRef allocator, CFStringRef winName) {
686 if (!winName) return NULL;
687
688 CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary();
689 if (!winToOlson) return NULL;
690
691 CFStringRef olsonName = CFDictionaryGetValue(winToOlson, winName);
692 CFTimeZoneRef retval = NULL;
693 if (olsonName) {
694 retval = CFTimeZoneCreateWithName(allocator, olsonName, false);
695 }
696 CFRelease(winToOlson);
697 return retval;
698 }
699
700 extern CFStringRef _CFGetWindowsAppleSystemLibraryDirectory(void);
701 void __InitTZStrings(void) {
702 static CFSpinLock_t __CFTZDirLock = CFSpinLockInit;
703 __CFSpinLock(&__CFTZDirLock);
704 if (!__tzZoneInfo) {
705 CFStringRef winDir = _CFGetWindowsAppleSystemLibraryDirectory();
706 __tzZoneInfo = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\\etc\\zoneinfo"), winDir);
707 }
708 if (!__tzDir && __tzZoneInfo) {
709 int length = CFStringGetLength(__tzZoneInfo) + sizeof("\\zone.tab") + 1;
710 __tzDir = malloc(length); // If we don't use ascii, we'll need to malloc more space
711 if (!__tzDir || !CFStringGetCString(__tzZoneInfo, __tzDir, length, kCFStringEncodingASCII)) {
712 free(__tzDir);
713 } else {
714 strcat(__tzDir, "\\zone.tab");
715 }
716 }
717 __CFSpinUnlock(&__CFTZDirLock);
718 }
719 #endif
720
721 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
722 static CFTimeZoneRef __CFTimeZoneCreateSystem(void) {
723 CFTimeZoneRef result = NULL;
724
725 #if DEPLOYMENT_TARGET_WINDOWS_SYNC
726 CFStringRef name = NULL;
727 TIME_ZONE_INFORMATION tzi = { 0 };
728 DWORD rval = GetTimeZoneInformation(&tzi);
729 if (rval != TIME_ZONE_ID_INVALID) {
730 LPWSTR standardName = (LPWSTR)&tzi.StandardName;
731 CFStringRef cfStandardName = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (UInt8 *)standardName, wcslen(standardName)*sizeof(WCHAR), kCFStringEncodingUTF16LE, false);
732 if (cfStandardName) {
733 CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary();
734 if (winToOlson) {
735 name = CFDictionaryGetValue(winToOlson, cfStandardName);
736 if (name) CFRetain(name);
737 CFRelease(winToOlson);
738 }
739 CFRelease(cfStandardName);
740 }
741 } else {
742 CFLog(kCFLogLevelError, CFSTR("Couldn't get time zone information error %d"), GetLastError());
743 }
744 if (name) {
745 #else
746 const char *tzenv;
747 int ret;
748 char linkbuf[CFMaxPathSize];
749
750 tzenv = __CFgetenv("TZFILE");
751 if (NULL != tzenv) {
752 CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false);
753 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false);
754 CFRelease(name);
755 if (result) return result;
756 }
757 tzenv = __CFgetenv("TZ");
758 if (NULL != tzenv) {
759 CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false);
760 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true);
761 CFRelease(name);
762 if (result) return result;
763 }
764 ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf));
765 if (0 < ret) {
766 CFStringRef name;
767 linkbuf[ret] = '\0';
768 if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) {
769 name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false);
770 } else {
771 name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false);
772 }
773 #endif
774
775 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false);
776 CFRelease(name);
777 if (result) return result;
778 }
779 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0);
780 }
781 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
782 static CFTimeZoneRef __CFTimeZoneCreateSystem(void) {
783 CFTimeZoneRef result = NULL;
784 /* The GetTimeZoneInformation function retrieves the current
785 * time-zone parameters for Win32
786 * (Aleksey Dukhnyakov)
787 */
788 CFDataRef data;
789 TIME_ZONE_INFORMATION tz;
790 DWORD dw_result;
791 dw_result=GetTimeZoneInformation(&tz);
792
793 if ( dw_result == TIME_ZONE_ID_STANDARD ||
794 dw_result == TIME_ZONE_ID_DAYLIGHT ) {
795 CFStringRef name = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)tz.StandardName, wcslen(tz.StandardName));
796 data = CFDataCreate(kCFAllocatorSystemDefault, (UInt8 *)&tz, sizeof(tz));
797 result = CFTimeZoneCreate(kCFAllocatorSystemDefault, name, data);
798 CFRelease(name);
799 CFRelease(data);
800 if (result) return result;
801 }
802 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0);
803 }
804 #else
805 #error Unknown or unspecified DEPLOYMENT_TARGET
806 #endif
807
808 CFTimeZoneRef CFTimeZoneCopySystem(void) {
809 CFTimeZoneRef tz;
810 __CFTimeZoneLockGlobal();
811 if (NULL == __CFTimeZoneSystem) {
812 __CFTimeZoneUnlockGlobal();
813 tz = __CFTimeZoneCreateSystem();
814 __CFTimeZoneLockGlobal();
815 if (NULL == __CFTimeZoneSystem) {
816 __CFTimeZoneSystem = tz;
817 } else {
818 if (tz) CFRelease(tz);
819 }
820 }
821 tz = __CFTimeZoneSystem ? (CFTimeZoneRef)CFRetain(__CFTimeZoneSystem) : NULL;
822 __CFTimeZoneUnlockGlobal();
823 return tz;
824 }
825
826 static CFIndex __noteCount = 0;
827
828 void CFTimeZoneResetSystem(void) {
829 __CFTimeZoneLockGlobal();
830 if (__CFTimeZoneDefault == __CFTimeZoneSystem) {
831 if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault);
832 __CFTimeZoneDefault = NULL;
833 }
834 CFTimeZoneRef tz = __CFTimeZoneSystem;
835 __CFTimeZoneSystem = NULL;
836 __CFTimeZoneUnlockGlobal();
837 if (tz) CFRelease(tz);
838 }
839
840 CFIndex _CFTimeZoneGetNoteCount(void) {
841 return __noteCount;
842 }
843
844 CFTimeZoneRef CFTimeZoneCopyDefault(void) {
845 CFTimeZoneRef tz;
846 __CFTimeZoneLockGlobal();
847 if (NULL == __CFTimeZoneDefault) {
848 __CFTimeZoneUnlockGlobal();
849 tz = CFTimeZoneCopySystem();
850 __CFTimeZoneLockGlobal();
851 if (NULL == __CFTimeZoneDefault) {
852 __CFTimeZoneDefault = tz;
853 } else {
854 if (tz) CFRelease(tz);
855 }
856 }
857 tz = __CFTimeZoneDefault ? (CFTimeZoneRef)CFRetain(__CFTimeZoneDefault) : NULL;
858 __CFTimeZoneUnlockGlobal();
859 return tz;
860 }
861
862 void CFTimeZoneSetDefault(CFTimeZoneRef tz) {
863 if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
864 __CFTimeZoneLockGlobal();
865 if (tz != __CFTimeZoneDefault) {
866 if (tz) CFRetain(tz);
867 if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault);
868 __CFTimeZoneDefault = tz;
869 }
870 __CFTimeZoneUnlockGlobal();
871 }
872
873 static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void);
874
875 CFArrayRef CFTimeZoneCopyKnownNames(void) {
876 CFArrayRef tzs;
877 __CFTimeZoneLockGlobal();
878 if (NULL == __CFKnownTimeZoneList) {
879 CFMutableArrayRef list;
880 /* TimeZone information locate in the registry for Win32
881 * (Aleksey Dukhnyakov)
882 */
883 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
884 list = __CFCopyRecursiveDirectoryList();
885 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
886 list = __CFCopyWindowsTimeZoneList();
887 #else
888 #error Unknown or unspecified DEPLOYMENT_TARGET
889 #endif
890 // Remove undesirable ancient cruft
891 CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary();
892 CFIndex idx;
893 for (idx = CFArrayGetCount(list); idx--; ) {
894 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(list, idx);
895 if (CFDictionaryContainsKey(dict, item)) {
896 CFArrayRemoveValueAtIndex(list, idx);
897 }
898 }
899 __CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list);
900 CFRelease(list);
901 }
902 tzs = __CFKnownTimeZoneList ? (CFArrayRef)CFRetain(__CFKnownTimeZoneList) : NULL;
903 __CFTimeZoneUnlockGlobal();
904 return tzs;
905 }
906
907 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
908 /* The criteria here are sort of: coverage for the U.S. and Europe,
909 * large cities, abbreviation uniqueness, and perhaps a few others.
910 * But do not make the list too large with obscure information.
911 */
912 static const char *__CFTimeZoneAbbreviationDefaults =
913 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
914 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
915 " <plist version=\"1.0\">"
916 " <dict>"
917 " <key>ADT</key> <string>America/Halifax</string>"
918 " <key>AKDT</key> <string>America/Juneau</string>"
919 " <key>AKST</key> <string>America/Juneau</string>"
920 " <key>ART</key> <string>America/Argentina/Buenos_Aires</string>"
921 " <key>AST</key> <string>America/Halifax</string>"
922 " <key>BDT</key> <string>Asia/Dhaka</string>"
923 " <key>BRST</key> <string>America/Sao_Paulo</string>"
924 " <key>BRT</key> <string>America/Sao_Paulo</string>"
925 " <key>BST</key> <string>Europe/London</string>"
926 " <key>CAT</key> <string>Africa/Harare</string>"
927 " <key>CDT</key> <string>America/Chicago</string>"
928 " <key>CEST</key> <string>Europe/Paris</string>"
929 " <key>CET</key> <string>Europe/Paris</string>"
930 " <key>CLST</key> <string>America/Santiago</string>"
931 " <key>CLT</key> <string>America/Santiago</string>"
932 " <key>COT</key> <string>America/Bogota</string>"
933 " <key>CST</key> <string>America/Chicago</string>"
934 " <key>EAT</key> <string>Africa/Addis_Ababa</string>"
935 " <key>EDT</key> <string>America/New_York</string>"
936 " <key>EEST</key> <string>Europe/Istanbul</string>"
937 " <key>EET</key> <string>Europe/Istanbul</string>"
938 " <key>EST</key> <string>America/New_York</string>"
939 " <key>GMT</key> <string>GMT</string>"
940 " <key>GST</key> <string>Asia/Dubai</string>"
941 " <key>HKT</key> <string>Asia/Hong_Kong</string>"
942 " <key>HST</key> <string>Pacific/Honolulu</string>"
943 " <key>ICT</key> <string>Asia/Bangkok</string>"
944 " <key>IRST</key> <string>Asia/Tehran</string>"
945 " <key>IST</key> <string>Asia/Calcutta</string>"
946 " <key>JST</key> <string>Asia/Tokyo</string>"
947 " <key>KST</key> <string>Asia/Seoul</string>"
948 " <key>MDT</key> <string>America/Denver</string>"
949 " <key>MSD</key> <string>Europe/Moscow</string>"
950 " <key>MSK</key> <string>Europe/Moscow</string>"
951 " <key>MST</key> <string>America/Denver</string>"
952 " <key>NZDT</key> <string>Pacific/Auckland</string>"
953 " <key>NZST</key> <string>Pacific/Auckland</string>"
954 " <key>PDT</key> <string>America/Los_Angeles</string>"
955 " <key>PET</key> <string>America/Lima</string>"
956 " <key>PHT</key> <string>Asia/Manila</string>"
957 " <key>PKT</key> <string>Asia/Karachi</string>"
958 " <key>PST</key> <string>America/Los_Angeles</string>"
959 " <key>SGT</key> <string>Asia/Singapore</string>"
960 " <key>UTC</key> <string>UTC</string>"
961 " <key>WAT</key> <string>Africa/Lagos</string>"
962 " <key>WEST</key> <string>Europe/Lisbon</string>"
963 " <key>WET</key> <string>Europe/Lisbon</string>"
964 " <key>WIT</key> <string>Asia/Jakarta</string>"
965 " </dict>"
966 " </plist>";
967 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
968 static const char *__CFTimeZoneAbbreviationDefaults =
969 /* Mappings to time zones in Windows Registry are best-guess */
970 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
971 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
972 " <plist version=\"1.0\">"
973 " <dict>"
974 " <key>ADT</key> <string>Atlantic Standard Time</string>"
975 " <key>AKDT</key> <string>Alaskan Standard Time</string>"
976 " <key>AKST</key> <string>Alaskan Standard Time</string>"
977 " <key>ART</key> <string>SA Eastern Standard Time</string>"
978 " <key>AST</key> <string>Atlantic Standard Time</string>"
979 " <key>BDT</key> <string>Central Asia Standard Time</string>"
980 " <key>BRST</key> <string>SA Eastern Standard Time</string>"
981 " <key>BRT</key> <string>SA Eastern Standard Time</string>"
982 " <key>BST</key> <string>GMT Standard Time</string>"
983 " <key>CAT</key> <string>South Africa Standard Time</string>"
984 " <key>CDT</key> <string>Central Standard Time</string>"
985 " <key>CEST</key> <string>Central Europe Standard Time</string>"
986 " <key>CET</key> <string>Central Europe Standard Time</string>"
987 " <key>CLST</key> <string>SA Western Standard Time</string>"
988 " <key>CLT</key> <string>SA Western Standard Time</string>"
989 " <key>COT</key> <string>Central Standard Time</string>"
990 " <key>CST</key> <string>Central Standard Time</string>"
991 " <key>EAT</key> <string>E. Africa Standard Time</string>"
992 " <key>EDT</key> <string>Eastern Standard Time</string>"
993 " <key>EEST</key> <string>E. Europe Standard Time</string>"
994 " <key>EET</key> <string>E. Europe Standard Time</string>"
995 " <key>EST</key> <string>Eastern Standard Time</string>"
996 " <key>GMT</key> <string>Greenwich Standard Time</string>"
997 " <key>GST</key> <string>Arabian Standard Time</string>"
998 " <key>HKT</key> <string>China Standard Time</string>"
999 " <key>HST</key> <string>Hawaiian Standard Time</string>"
1000 " <key>ICT</key> <string>SE Asia Standard Time</string>"
1001 " <key>IRST</key> <string>Iran Standard Time</string>"
1002 " <key>IST</key> <string>India Standard Time</string>"
1003 " <key>JST</key> <string>Tokyo Standard Time</string>"
1004 " <key>KST</key> <string>Korea Standard Time</string>"
1005 " <key>MDT</key> <string>Mountain Standard Time</string>"
1006 " <key>MSD</key> <string>E. Europe Standard Time</string>"
1007 " <key>MSK</key> <string>E. Europe Standard Time</string>"
1008 " <key>MST</key> <string>Mountain Standard Time</string>"
1009 " <key>NZDT</key> <string>New Zealand Standard Time</string>"
1010 " <key>NZST</key> <string>New Zealand Standard Time</string>"
1011 " <key>PDT</key> <string>Pacific Standard Time</string>"
1012 " <key>PET</key> <string>SA Pacific Standard Time</string>"
1013 " <key>PHT</key> <string>Taipei Standard Time</string>"
1014 " <key>PKT</key> <string>West Asia Standard Time</string>"
1015 " <key>PST</key> <string>Pacific Standard Time</string>"
1016 " <key>SGT</key> <string>Singapore Standard Time</string>"
1017 " <key>UTC</key> <string>Greenwich Standard Time</string>"
1018 " <key>WAT</key> <string>W. Central Africa Standard Time</string>"
1019 " <key>WEST</key> <string>W. Europe Standard Time</string>"
1020 " <key>WET</key> <string>W. Europe Standard Time</string>"
1021 " <key>WIT</key> <string>SE Asia Standard Time</string>"
1022 " </dict>"
1023 " </plist>";
1024 #else
1025 #error Unknown or unspecified DEPLOYMENT_TARGET
1026 #endif
1027
1028 CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) {
1029 CFDictionaryRef dict;
1030 __CFTimeZoneLockAbbreviations();
1031 if (NULL == __CFTimeZoneAbbreviationDict) {
1032 CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults));
1033 __CFTimeZoneAbbreviationDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL);
1034 CFRelease(data);
1035 }
1036 if (NULL == __CFTimeZoneAbbreviationDict) {
1037 __CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL);
1038 }
1039 dict = __CFTimeZoneAbbreviationDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneAbbreviationDict) : NULL;
1040 __CFTimeZoneUnlockAbbreviations();
1041 return dict;
1042 }
1043
1044 void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) {
1045 __CFGenericValidateType(dict, CFDictionaryGetTypeID());
1046 __CFTimeZoneLockGlobal();
1047 if (dict != __CFTimeZoneAbbreviationDict) {
1048 if (dict) CFRetain(dict);
1049 if (__CFTimeZoneAbbreviationDict) {
1050 for (id key in (id)__CFTimeZoneAbbreviationDict) {
1051 CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)key);
1052 }
1053 CFRelease(__CFTimeZoneAbbreviationDict);
1054 }
1055 __CFTimeZoneAbbreviationDict = dict;
1056 }
1057 __CFTimeZoneUnlockGlobal();
1058 }
1059
1060 CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) {
1061 // assert: (NULL != name && NULL != data);
1062 CFTimeZoneRef memory;
1063 uint32_t size;
1064 CFTZPeriod *tzp = NULL;
1065 CFIndex idx, cnt = 0;
1066
1067 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
1068 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
1069 __CFGenericValidateType(name, CFStringGetTypeID());
1070 __CFGenericValidateType(data, CFDataGetTypeID());
1071 __CFTimeZoneLockGlobal();
1072 if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) {
1073 __CFTimeZoneUnlockGlobal();
1074 return (CFTimeZoneRef)CFRetain(memory);
1075 }
1076 if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) {
1077 __CFTimeZoneUnlockGlobal();
1078 return NULL;
1079 }
1080 size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase);
1081 memory = (CFTimeZoneRef)_CFRuntimeCreateInstance(allocator, CFTimeZoneGetTypeID(), size, NULL);
1082 if (NULL == memory) {
1083 __CFTimeZoneUnlockGlobal();
1084 for (idx = 0; idx < cnt; idx++) {
1085 if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev);
1086 }
1087 if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp);
1088 return NULL;
1089 }
1090 ((struct __CFTimeZone *)memory)->_name = (CFStringRef)CFStringCreateCopy(allocator, name);
1091 ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data);
1092 ((struct __CFTimeZone *)memory)->_periods = tzp;
1093 ((struct __CFTimeZone *)memory)->_periodCnt = cnt;
1094 if (NULL == __CFTimeZoneCache) {
1095 __CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1096 }
1097 CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory);
1098 __CFTimeZoneUnlockGlobal();
1099 return memory;
1100 }
1101
1102 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
1103 static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) {
1104 CFTimeZoneRef result;
1105 CFDataRef data;
1106 int32_t nameLen = CFStringGetLength(name);
1107 unsigned char dataBytes[52 + nameLen + 1];
1108 memset(dataBytes, 0, sizeof(dataBytes));
1109
1110 // Put in correct magic bytes for timezone structures
1111 dataBytes[0] = 'T';
1112 dataBytes[1] = 'Z';
1113 dataBytes[2] = 'i';
1114 dataBytes[3] = 'f';
1115
1116 __CFEntzcode(1, dataBytes + 20);
1117 __CFEntzcode(1, dataBytes + 24);
1118 __CFEntzcode(1, dataBytes + 36);
1119 __CFEntzcode(nameLen + 1, dataBytes + 40);
1120 __CFEntzcode(seconds, dataBytes + 44);
1121 dataBytes[48] = isDST ? 1 : 0;
1122 CFStringGetCString(name, (char *)dataBytes + 50, nameLen + 1, kCFStringEncodingASCII);
1123 data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1);
1124 result = CFTimeZoneCreate(allocator, name, data);
1125 CFRelease(data);
1126 return result;
1127 }
1128 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
1129 static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) {
1130 /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure
1131 * to find current timezone
1132 * (Aleksey Dukhnyakov)
1133 */
1134 CFTimeZoneRef result;
1135 TIME_ZONE_INFORMATION tzi;
1136 CFDataRef data;
1137 CFIndex length = CFStringGetLength(name);
1138
1139 memset(&tzi,0,sizeof(tzi));
1140 tzi.Bias=(long)(-seconds/60);
1141 CFStringGetCharacters(name, CFRangeMake(0, length < 31 ? length : 31 ), (UniChar *)tzi.StandardName);
1142 data = CFDataCreate(allocator,(UInt8 *)&tzi, sizeof(tzi));
1143 result = CFTimeZoneCreate(allocator, name, data);
1144 CFRelease(data);
1145 return result;
1146 }
1147 #else
1148 #error Unknown or unspecified DEPLOYMENT_TARGET
1149 #endif
1150
1151 // rounds offset to nearest minute
1152 CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) {
1153 CFTimeZoneRef result;
1154 CFStringRef name;
1155 int32_t seconds, minute, hour;
1156 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
1157 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
1158 if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL;
1159 ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0;
1160 seconds = (int32_t)ti;
1161 hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600);
1162 seconds -= ((ti < 0) ? -hour : hour) * 3600;
1163 minute = (ti < 0) ? (-seconds / 60) : (seconds / 60);
1164 if (fabs(ti) < 1.0) {
1165 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
1166 name = (CFStringRef)CFRetain(CFSTR("GMT"));
1167 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
1168 name = (CFStringRef)CFRetain(CFSTR("Greenwich Standard Time"));
1169 #else
1170 #error Unknown or unspecified DEPLOYMENT_TARGET
1171 #endif
1172 } else {
1173 name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute);
1174 }
1175 result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0);
1176 CFRelease(name);
1177 return result;
1178 }
1179
1180 CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) {
1181 CFTimeZoneRef result = NULL;
1182 CFStringRef tzName = NULL;
1183 CFDataRef data = NULL;
1184
1185 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
1186 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
1187 __CFGenericValidateType(name, CFStringGetTypeID());
1188 if (CFEqual(CFSTR(""), name)) {
1189 // empty string is not a time zone name, just abort now,
1190 // following stuff will fail anyway
1191 return NULL;
1192 }
1193 __CFTimeZoneLockGlobal();
1194 if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) {
1195 __CFTimeZoneUnlockGlobal();
1196 return (CFTimeZoneRef)CFRetain(result);
1197 }
1198 __CFTimeZoneUnlockGlobal();
1199 CFIndex len = CFStringGetLength(name);
1200 if (6 == len || 8 == len) {
1201 UniChar buffer[8];
1202 CFStringGetCharacters(name, CFRangeMake(0, len), buffer);
1203 if ('G' == buffer[0] && 'M' == buffer[1] && 'T' == buffer[2] && ('+' == buffer[3] || '-' == buffer[3])) {
1204 if (('0' <= buffer[4] && buffer[4] <= '9') && ('0' <= buffer[5] && buffer[5] <= '9')) {
1205 int32_t hours = (buffer[4] - '0') * 10 + (buffer[5] - '0');
1206 if (-14 <= hours && hours <= 14) {
1207 CFTimeInterval ti = hours * 3600.0;
1208 if (6 == len) {
1209 return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti);
1210 } else {
1211 if (('0' <= buffer[6] && buffer[6] <= '9') && ('0' <= buffer[7] && buffer[7] <= '9')) {
1212 int32_t minutes = (buffer[6] - '0') * 10 + (buffer[7] - '0');
1213 if ((-14 == hours && 0 == minutes) || (14 == hours && 0 == minutes) || (0 <= minutes && minutes <= 59)) {
1214 ti = ti + minutes * 60.0;
1215 return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti);
1216 }
1217 }
1218 }
1219 }
1220 }
1221 }
1222 }
1223 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
1224 CFURLRef baseURL, tempURL;
1225 void *bytes;
1226 CFIndex length;
1227
1228 #if DEPLOYMENT_TARGET_WINDOWS_SYNC
1229 if (!__tzZoneInfo) __InitTZStrings();
1230 if (!__tzZoneInfo) return NULL;
1231 baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLWindowsPathStyle, true);
1232 #else
1233 baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true);
1234 #endif
1235 if (tryAbbrev) {
1236 CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
1237 tzName = CFDictionaryGetValue(abbrevs, name);
1238 if (NULL != tzName) {
1239 tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false);
1240 if (NULL != tempURL) {
1241 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0)) {
1242 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault);
1243 }
1244 CFRelease(tempURL);
1245 }
1246 }
1247 CFRelease(abbrevs);
1248 }
1249 if (NULL == data) {
1250 CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary();
1251 CFStringRef mapping = CFDictionaryGetValue(dict, name);
1252 if (mapping) {
1253 name = mapping;
1254 #if DEPLOYMENT_TARGET_WINDOWS_SYNC
1255 } else if (CFStringHasPrefix(name, __tzZoneInfo)) {
1256 CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name);
1257 CFStringDelete(unprefixed, CFRangeMake(0, CFStringGetLength(__tzZoneInfo)));
1258 #else
1259 } else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) {
1260 CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name);
1261 CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO)));
1262 #endif
1263 mapping = CFDictionaryGetValue(dict, unprefixed);
1264 if (mapping) {
1265 name = mapping;
1266 }
1267 CFRelease(unprefixed);
1268 }
1269 CFRelease(dict);
1270 if (CFEqual(CFSTR(""), name)) {
1271 return NULL;
1272 }
1273 }
1274 if (NULL == data) {
1275 tzName = name;
1276 tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false);
1277 if (NULL != tempURL) {
1278 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0)) {
1279 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault);
1280 }
1281 CFRelease(tempURL);
1282 }
1283 }
1284 CFRelease(baseURL);
1285 if (NULL != data) {
1286 result = CFTimeZoneCreate(allocator, tzName, data);
1287 if (name != tzName) {
1288 CFStringRef nameCopy = (CFStringRef)CFStringCreateCopy(allocator, name);
1289 __CFTimeZoneLockGlobal();
1290 CFDictionaryAddValue(__CFTimeZoneCache, nameCopy, result);
1291 __CFTimeZoneUnlockGlobal();
1292 CFRelease(nameCopy);
1293 }
1294 CFRelease(data);
1295 }
1296 return result;
1297 }
1298 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
1299 /* Reading GMT offset and daylight flag from the registry
1300 * for TimeZone name
1301 * (Aleksey Dukhnyakov)
1302 */
1303 {
1304 CFStringRef safeName = name;
1305 struct {
1306 LONG Bias;
1307 LONG StandardBias;
1308 LONG DaylightBias;
1309 SYSTEMTIME StandardDate;
1310 SYSTEMTIME DaylightDate;
1311 } tzi;
1312 TIME_ZONE_INFORMATION tzi_system;
1313
1314 HKEY hkResult;
1315 DWORD dwType, dwSize=sizeof(tzi),
1316 dwSize_name1=sizeof(tzi_system.StandardName),
1317 dwSize_name2=sizeof(tzi_system.DaylightName);
1318
1319 if (tryAbbrev) {
1320 CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
1321 tzName = (CFStringRef)CFDictionaryGetValue(abbrevs, name);
1322 if (NULL == tzName) {
1323 CFRelease(abbrevs);
1324 return NULL;
1325 }
1326 name = tzName;
1327 CFRelease(abbrevs);
1328 }
1329
1330 /* Open regestry and move down to the TimeZone information
1331 */
1332 if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) !=
1333 ERROR_SUCCESS ) {
1334 return NULL;
1335 }
1336 /* Move down to specific TimeZone name
1337 */
1338 #if defined(UNICODE)
1339 UniChar *uniTimeZone = (UniChar*)CFStringGetCharactersPtr(name);
1340 if (uniTimeZone == NULL) {
1341 // We need to extract the bytes out of the CFStringRef and create our own
1342 // UNICODE string to pass to the Win32 API - RegOpenKey.
1343 UInt8 uniBuff[MAX_PATH+2]; // adding +2 to handle Unicode-null termination /0/0.
1344 CFIndex usedBuff = 0;
1345 CFIndex numChars = CFStringGetBytes(name, CFRangeMake(0, CFStringGetLength(name)), kCFStringEncodingUnicode, 0, FALSE, uniBuff, MAX_PATH, &usedBuff);
1346 if (numChars == 0) {
1347 return NULL;
1348 } else {
1349 // NULL-terminate the newly created Unicode string.
1350 uniBuff[usedBuff] = '\0';
1351 uniBuff[usedBuff+1] = '\0';
1352 }
1353
1354 if (RegOpenKey(hkResult, (LPCWSTR)uniBuff ,&hkResult) != ERROR_SUCCESS ) {
1355 return NULL;
1356 }
1357 } else {
1358 if (RegOpenKey(hkResult, (LPCWSTR)uniTimeZone ,&hkResult) != ERROR_SUCCESS ) {
1359 return NULL;
1360 }
1361 }
1362 #else
1363 if (RegOpenKey(hkResult,CFStringGetCStringPtr(name, CFStringGetSystemEncoding()),&hkResult) != ERROR_SUCCESS ) {
1364 return NULL;
1365 }
1366 #endif
1367
1368 /* TimeZone information(offsets, daylight flag, ...) assign to tzi structure
1369 */
1370 if ( RegQueryValueEx(hkResult,_T("TZI"),NULL,&dwType,(LPBYTE)&tzi,&dwSize) != ERROR_SUCCESS &&
1371 RegQueryValueEx(hkResult,_T("Std"),NULL,&dwType,(LPBYTE)&tzi_system.StandardName,&dwSize_name1) != ERROR_SUCCESS &&
1372 RegQueryValueEx(hkResult,_T("Dlt"),NULL,&dwType,(LPBYTE)&tzi_system.DaylightName,&dwSize_name2) != ERROR_SUCCESS )
1373 {
1374 return NULL;
1375 }
1376
1377 tzi_system.Bias=tzi.Bias;
1378 tzi_system.StandardBias=tzi.StandardBias;
1379 tzi_system.DaylightBias=tzi.DaylightBias;
1380 tzi_system.StandardDate=tzi.StandardDate;
1381 tzi_system.DaylightDate=tzi.DaylightDate;
1382
1383 /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure
1384 * to find current timezone
1385 * (Aleksey Dukhnyakov)
1386 */
1387 data = CFDataCreate(allocator,(UInt8 *)&tzi_system, sizeof(tzi_system));
1388
1389 RegCloseKey(hkResult);
1390 result = CFTimeZoneCreate(allocator, name, data);
1391 if (result) {
1392 if (tryAbbrev)
1393 result->_periods->abbrev = (CFStringRef)CFStringCreateCopy(allocator,safeName);
1394 else {
1395 }
1396 }
1397 CFRelease(data);
1398 }
1399 return result;
1400 }
1401 #else
1402 #error Unknown or unspecified DEPLOYMENT_TARGET
1403 #endif
1404
1405 CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) {
1406 CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFStringRef, tz, "name");
1407 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1408 return tz->_name;
1409 }
1410
1411 CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) {
1412 CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFDataRef, tz, "data");
1413 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1414 return tz->_data;
1415 }
1416
1417 /* This function converts CFAbsoluteTime to (Win32) SYSTEMTIME
1418 * (Aleksey Dukhnyakov)
1419 */
1420 #if DEPLOYMENT_TARGET_WINDOWS
1421 BOOL __CFTimeZoneGetWin32SystemTime(SYSTEMTIME * sys_time, CFAbsoluteTime time)
1422 {
1423 LONGLONG l;
1424 FILETIME * ftime=(FILETIME*)&l;
1425
1426 /* seconds between 1601 and 1970 : 11644473600,
1427 * seconds between 1970 and 2001 : 978307200,
1428 * FILETIME - number of 100-nanosecond intervals since January 1, 1601
1429 */
1430 l=(LONGLONG)(time+11644473600LL+978307200)*10000000;
1431 if (FileTimeToSystemTime(ftime,sys_time))
1432 return TRUE;
1433 else
1434 return FALSE;
1435 }
1436 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1437 #else
1438 #error Unknown or unspecified DEPLOYMENT_TARGET
1439 #endif
1440
1441 CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) {
1442 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
1443 CFIndex idx;
1444 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at);
1445 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1446 idx = __CFBSearchTZPeriods(tz, at);
1447 return __CFTZPeriodGMTOffset(&(tz->_periods[idx]));
1448 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
1449 /* To calculate seconds from GMT, calculate current timezone time and
1450 * subtract GMT timnezone time
1451 * (Aleksey Dukhnyakov)
1452 */
1453 TIME_ZONE_INFORMATION tzi;
1454 FILETIME ftime1,ftime2;
1455 SYSTEMTIME stime0,stime1,stime2;
1456 LONGLONG * l1= (LONGLONG*)&ftime1;
1457 LONGLONG * l2= (LONGLONG*)&ftime2;
1458 CFRange range={0,sizeof(TIME_ZONE_INFORMATION)};
1459 double result;
1460
1461 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at);
1462
1463 CFDataGetBytes(tz->_data,range,(UInt8 *)&tzi);
1464
1465 if (!__CFTimeZoneGetWin32SystemTime(&stime0,at) ||
1466 !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime1) ||
1467 !SystemTimeToFileTime(&stime1,&ftime1) )
1468 {
1469 CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n");
1470 return 0;
1471 }
1472
1473 tzi.DaylightDate.wMonth=0;
1474 tzi.StandardDate.wMonth=0;
1475 tzi.StandardBias=0;
1476 tzi.DaylightBias=0;
1477 tzi.Bias=0;
1478
1479 if ( !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime2) ||
1480 !SystemTimeToFileTime(&stime2,&ftime2))
1481 {
1482 CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n");
1483 return 0;
1484 }
1485 result=(double)((*l1-*l2)/10000000);
1486 return result;
1487 #else
1488 #error Unknown or unspecified DEPLOYMENT_TARGET
1489 #endif
1490 }
1491
1492 #if DEPLOYMENT_TARGET_WINDOWS_SAFARI
1493 /*
1494 * Get abbreviation for name for WIN32 platform
1495 * (Aleksey Dukhnyakov)
1496 */
1497
1498 typedef struct {
1499 CFStringRef tzName;
1500 CFStringRef tzAbbr;
1501 } _CFAbbrFind;
1502
1503 static void _CFFindKeyForValue(const void *key, const void *value, void *context) {
1504 if ( ((_CFAbbrFind *)context)->tzAbbr != NULL ) {
1505 if ( ((_CFAbbrFind *)context)->tzName == (CFStringRef) value ) {
1506 ((_CFAbbrFind *)context)->tzAbbr = (CFStringRef)key ;
1507 }
1508 }
1509 }
1510
1511 CFIndex __CFTimeZoneInitAbbrev(CFTimeZoneRef tz) {
1512
1513 if ( tz->_periods->abbrev == NULL ) {
1514 _CFAbbrFind abbr = { NULL, NULL };
1515 CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
1516
1517 CFDictionaryApplyFunction(abbrevs, _CFFindKeyForValue, &abbr);
1518
1519 if ( abbr.tzAbbr != NULL)
1520 tz->_periods->abbrev = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, abbr.tzAbbr);
1521 else
1522 tz->_periods->abbrev = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, tz->_name);
1523 /* We should return name of TimeZone if couldn't find abbrevation.
1524 * (Ala on MACOSX)
1525 *
1526 * (Aleksey Dukhnyakov)
1527 */
1528 CFRelease( abbrevs );
1529 }
1530
1531 return 0;
1532 }
1533 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
1534 #else
1535 #error Unknown or unspecified DEPLOYMENT_TARGET
1536 #endif
1537
1538 CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) {
1539 CFStringRef result;
1540 CFIndex idx;
1541 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFStringRef, tz, "_abbreviationForAbsoluteTime:", at);
1542 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1543 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
1544 idx = __CFBSearchTZPeriods(tz, at);
1545 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
1546 /*
1547 * Initialize abbreviation for this TimeZone
1548 * (Aleksey Dukhnyakov)
1549 */
1550 idx = __CFTimeZoneInitAbbrev(tz);
1551 #else
1552 #error Unknown or unspecified DEPLOYMENT_TARGET
1553 #endif
1554 result = __CFTZPeriodAbbreviation(&(tz->_periods[idx]));
1555 return result ? (CFStringRef)CFRetain(result) : NULL;
1556 }
1557
1558 Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) {
1559 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC
1560 CFIndex idx;
1561 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at);
1562 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1563 idx = __CFBSearchTZPeriods(tz, at);
1564 return __CFTZPeriodIsDST(&(tz->_periods[idx]));
1565 #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI
1566 /* Compare current timezone time and current timezone time without
1567 * transition to day light saving time
1568 * (Aleskey Dukhnyakov)
1569 */
1570 TIME_ZONE_INFORMATION tzi;
1571 SYSTEMTIME stime0,stime1,stime2;
1572 CFRange range={0,sizeof(TIME_ZONE_INFORMATION)};
1573
1574 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at);
1575
1576 CFDataGetBytes(tz->_data,range,(UInt8 *)&tzi);
1577
1578 if ( !__CFTimeZoneGetWin32SystemTime(&stime0,at) ||
1579 !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime1)) {
1580 CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n");
1581 return FALSE;
1582 }
1583
1584 tzi.DaylightDate.wMonth=0;
1585 tzi.StandardDate.wMonth=0;
1586
1587 if ( !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime2)) {
1588 CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n");
1589 return FALSE;
1590 }
1591
1592 if ( !memcmp(&stime1,&stime2,sizeof(stime1)) )
1593 return FALSE;
1594
1595 return TRUE;
1596 #else
1597 #error Unknown or unspecified DEPLOYMENT_TARGET
1598 #endif
1599 }
1600
1601 CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) {
1602 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_daylightSavingTimeOffsetForAbsoluteTime:", at);
1603 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1604 CFIndex idx = __CFBSearchTZPeriods(tz, at);
1605 if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) {
1606 CFTimeInterval offset = __CFTZPeriodGMTOffset(&(tz->_periods[idx]));
1607 if (idx + 1 < tz->_periodCnt) {
1608 return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1]));
1609 } else if (0 < idx) {
1610 return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1]));
1611 }
1612 }
1613 return 0.0;
1614 }
1615
1616 CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) {
1617 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_nextDaylightSavingTimeTransitionAfterAbsoluteTime:", at);
1618 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1619 CFIndex idx = __CFBSearchTZPeriods(tz, at);
1620 if (tz->_periodCnt <= idx + 1) {
1621 return 0.0;
1622 }
1623 return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1]));
1624 }
1625
1626 extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz);
1627
1628 #define BUFFER_SIZE 768
1629
1630 CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) {
1631 CF_OBJC_FUNCDISPATCH2(CFTimeZoneGetTypeID(), CFStringRef, tz, "localizedName:locale:", style, locale);
1632 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1633 __CFGenericValidateType(locale, CFLocaleGetTypeID());
1634
1635 if (style == kCFTimeZoneNameStyleGeneric || style == kCFTimeZoneNameStyleShortGeneric) {
1636 CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorSystemDefault, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle);
1637 CFDateFormatterSetProperty(df, kCFDateFormatterTimeZone, tz);
1638 CFDateFormatterSetFormat(df, (style == kCFTimeZoneNameStyleGeneric) ? CFSTR("vvvv") : CFSTR("v"));
1639 CFStringRef str = CFDateFormatterCreateStringWithAbsoluteTime(CFGetAllocator(tz), df, 0.0);
1640 CFRelease(df);
1641 return str;
1642 }
1643
1644 CFStringRef localeID = CFLocaleGetIdentifier(locale);
1645 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, localeID, tz);
1646 if (NULL == cal) {
1647 return NULL;
1648 }
1649
1650 char buffer[BUFFER_SIZE];
1651 const char *cstr = CFStringGetCStringPtr(localeID, kCFStringEncodingASCII);
1652 if (NULL == cstr) {
1653 if (CFStringGetCString(localeID, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
1654 }
1655 if (NULL == cstr) {
1656 ucal_close(cal);
1657 return NULL;
1658 }
1659
1660 UChar ubuffer[BUFFER_SIZE];
1661 UErrorCode status = U_ZERO_ERROR;
1662 int32_t cnt = ucal_getTimeZoneDisplayName(cal, (UCalendarDisplayNameType)style, cstr, ubuffer, BUFFER_SIZE, &status);
1663 ucal_close(cal);
1664 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1665 return CFStringCreateWithCharacters(CFGetAllocator(tz), (const UniChar *)ubuffer, cnt);
1666 }
1667 return NULL;
1668 }
1669
1670 static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) {
1671 CFDictionaryRef dict;
1672 __CFTimeZoneLockCompatibilityMapping();
1673 if (NULL == __CFTimeZoneCompatibilityMappingDict) {
1674 __CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1675
1676 // Empty string means delete/ignore these
1677 }
1678 dict = __CFTimeZoneCompatibilityMappingDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL;
1679 __CFTimeZoneUnlockCompatibilityMapping();
1680 return dict;
1681 }
1682
1683 #undef TZZONEINFO
1684 #undef TZZONELINK
1685