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