]> git.saurik.com Git - apple/cf.git/blob - CFTimeZone.c
CF-476.15.tar.gz
[apple/cf.git] / CFTimeZone.c
1 /*
2 * Copyright (c) 2008 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 #include <CoreFoundation/CFTimeZone.h>
29 #include <CoreFoundation/CFPropertyList.h>
30 #include "CFPriv.h"
31 #include "CFInternal.h"
32 #include <math.h>
33 #include <limits.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unicode/ucal.h>
39 #if DEPLOYMENT_TARGET_MACOSX
40 #include <dirent.h>
41 #include <unistd.h>
42 #include <sys/fcntl.h>
43 #include <tzfile.h>
44 #endif
45
46 #if DEPLOYMENT_TARGET_MACOSX
47 #define TZZONELINK TZDEFAULT
48 #define TZZONEINFO TZDIR "/"
49 #endif
50
51 CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification")
52
53 static CFTimeZoneRef __CFTimeZoneSystem = NULL;
54 static CFTimeZoneRef __CFTimeZoneDefault = NULL;
55 static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL;
56 static CFSpinLock_t __CFTimeZoneAbbreviationLock = CFSpinLockInit;
57 static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL;
58 static CFSpinLock_t __CFTimeZoneCompatibilityMappingLock = CFSpinLockInit;
59 static CFArrayRef __CFKnownTimeZoneList = NULL;
60 static CFMutableDictionaryRef __CFTimeZoneCache = NULL;
61 static CFSpinLock_t __CFTimeZoneGlobalLock = CFSpinLockInit;
62
63 CF_INLINE void __CFTimeZoneLockGlobal(void) {
64 __CFSpinLock(&__CFTimeZoneGlobalLock);
65 }
66
67 CF_INLINE void __CFTimeZoneUnlockGlobal(void) {
68 __CFSpinUnlock(&__CFTimeZoneGlobalLock);
69 }
70
71 CF_INLINE void __CFTimeZoneLockAbbreviations(void) {
72 __CFSpinLock(&__CFTimeZoneAbbreviationLock);
73 }
74
75 CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) {
76 __CFSpinUnlock(&__CFTimeZoneAbbreviationLock);
77 }
78
79 CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) {
80 __CFSpinLock(&__CFTimeZoneCompatibilityMappingLock);
81 }
82
83 CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) {
84 __CFSpinUnlock(&__CFTimeZoneCompatibilityMappingLock);
85 }
86
87 #if DEPLOYMENT_TARGET_MACOSX
88 static CFMutableArrayRef __CFCopyRecursiveDirectoryList() {
89 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
90 int fd = open(TZDIR "/zone.tab", O_RDONLY);
91 for (; 0 <= fd;) {
92 uint8_t buffer[4096];
93 ssize_t len = read(fd, buffer, sizeof(buffer));
94 if (len <= 0) break;
95 if (len < sizeof(buffer)) {
96 // assumes that partial read only occurs at the end of the file
97 buffer[len] = '\n';
98 len++;
99 }
100 const uint8_t *bytes = buffer;
101 for (;;) {
102 const uint8_t *nextl = memchr(bytes, '\n', len);
103 if (!nextl) break;
104 nextl++;
105 if ('#' == *bytes) {
106 len -= (nextl - bytes);
107 bytes = nextl;
108 continue;
109 }
110 const uint8_t *tab1 = memchr(bytes, '\t', (nextl - bytes));
111 if (!tab1) {
112 len -= (nextl - bytes);
113 bytes = nextl;
114 continue;
115 }
116 tab1++;
117 len -= (tab1 - bytes);
118 bytes = tab1;
119 const uint8_t *tab2 = memchr(bytes, '\t', (nextl - bytes));
120 if (!tab2) {
121 len -= (nextl - bytes);
122 bytes = nextl;
123 continue;
124 }
125 tab2++;
126 len -= (tab2 - bytes);
127 bytes = tab2;
128 const uint8_t *tab3 = memchr(bytes, '\t', (nextl - bytes));
129 int nmlen = tab3 ? (tab3 - bytes) : (nextl - 1 - bytes);
130 CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, bytes, nmlen, kCFStringEncodingUTF8, false);
131 CFArrayAppendValue(result, string);
132 CFRelease(string);
133 len -= (nextl - bytes);
134 bytes = nextl;
135 }
136 lseek(fd, -len, SEEK_CUR);
137 }
138 close(fd);
139 return result;
140 }
141 #else
142 #error Unknown or unspecified DEPLOYMENT_TARGET
143 #endif
144
145 typedef struct _CFTZPeriod {
146 int32_t startSec;
147 CFStringRef abbrev;
148 uint32_t info;
149 } CFTZPeriod;
150
151 struct __CFTimeZone {
152 CFRuntimeBase _base;
153 CFStringRef _name; /* immutable */
154 CFDataRef _data; /* immutable */
155 CFTZPeriod *_periods; /* immutable */
156 int32_t _periodCnt; /* immutable */
157 };
158
159 /* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates
160 * between 1933 and 2069; info outside these years is discarded on read-in */
161 /* Bits 31-18 of the info are unused */
162 /* Bit 17 of the info is used for the is-DST state */
163 /* Bit 16 of the info is used for the sign of the offset (1 == negative) */
164 /* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */
165
166 CF_INLINE void __CFTZPeriodInit(CFTZPeriod *period, int32_t startTime, CFStringRef abbrev, int32_t offset, Boolean isDST) {
167 period->startSec = startTime;
168 period->abbrev = abbrev ? (CFStringRef)CFRetain(abbrev) : NULL;
169 __CFBitfieldSetValue(period->info, 15, 0, abs(offset));
170 __CFBitfieldSetValue(period->info, 16, 16, (offset < 0 ? 1 : 0));
171 __CFBitfieldSetValue(period->info, 17, 17, (isDST ? 1 : 0));
172 }
173
174 CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) {
175 return period->startSec;
176 }
177
178 CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) {
179 return period->abbrev;
180 }
181
182 CF_INLINE int32_t __CFTZPeriodGMTOffset(const CFTZPeriod *period) {
183 int32_t v = __CFBitfieldGetValue(period->info, 15, 0);
184 if (__CFBitfieldGetValue(period->info, 16, 16)) v = -v;
185 return v;
186 }
187
188 CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) {
189 return (Boolean)__CFBitfieldGetValue(period->info, 17, 17);
190 }
191
192 static CFComparisonResult __CFCompareTZPeriods(const void *val1, const void *val2, void *context) {
193 CFTZPeriod *tzp1 = (CFTZPeriod *)val1;
194 CFTZPeriod *tzp2 = (CFTZPeriod *)val2;
195 // we treat equal as less than, as the code which uses the
196 // result of the bsearch doesn't expect exact matches
197 // (they're pretty rare, so no point in over-coding for them)
198 if (__CFTZPeriodStartSeconds(tzp1) <= __CFTZPeriodStartSeconds(tzp2)) return kCFCompareLessThan;
199 return kCFCompareGreaterThan;
200 }
201
202 static CFIndex __CFBSearchTZPeriods(CFTimeZoneRef tz, CFAbsoluteTime at) {
203 CFTZPeriod elem;
204 __CFTZPeriodInit(&elem, (int32_t)floor(at), NULL, 0, false);
205 CFIndex idx = CFBSearch(&elem, sizeof(CFTZPeriod), tz->_periods, tz->_periodCnt, __CFCompareTZPeriods, NULL);
206 if (tz->_periodCnt <= idx) {
207 idx = tz->_periodCnt;
208 } else if (0 == idx) {
209 idx = 1;
210 }
211 return idx - 1;
212 }
213
214
215 CF_INLINE int32_t __CFDetzcode(const unsigned char *bufp) {
216 int32_t result = (bufp[0] & 0x80) ? ~0L : 0L;
217 result = (result << 8) | (bufp[0] & 0xff);
218 result = (result << 8) | (bufp[1] & 0xff);
219 result = (result << 8) | (bufp[2] & 0xff);
220 result = (result << 8) | (bufp[3] & 0xff);
221 return result;
222 }
223
224 CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) {
225 bufp[0] = (value >> 24) & 0xff;
226 bufp[1] = (value >> 16) & 0xff;
227 bufp[2] = (value >> 8) & 0xff;
228 bufp[3] = (value >> 0) & 0xff;
229 }
230
231 #if DEPLOYMENT_TARGET_MACOSX
232 static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) {
233 int32_t len, timecnt, typecnt, charcnt, idx, cnt;
234 const uint8_t *p, *timep, *typep, *ttisp, *charp;
235 CFStringRef *abbrs;
236 Boolean result = true;
237
238 p = CFDataGetBytePtr(data);
239 len = CFDataGetLength(data);
240 if (len < (int32_t)sizeof(struct tzhead)) {
241 return false;
242 }
243
244 if (!(p[0] == 'T' && p[1] == 'Z' && p[2] == 'i' && p[3] == 'f')) return false; /* Don't parse without TZif at head of file */
245
246 p += 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */
247 timecnt = __CFDetzcode(p);
248 p += 4;
249 typecnt = __CFDetzcode(p);
250 p += 4;
251 charcnt = __CFDetzcode(p);
252 p += 4;
253 if (typecnt <= 0 || timecnt < 0 || charcnt < 0) {
254 return false;
255 }
256 if (1024 < timecnt || 32 < typecnt || 128 < charcnt) {
257 // reject excessive timezones to avoid arithmetic overflows for
258 // security reasons and to reject potentially corrupt files
259 return false;
260 }
261 if (len - (int32_t)sizeof(struct tzhead) < (4 + 1) * timecnt + (4 + 1 + 1) * typecnt + charcnt) {
262 return false;
263 }
264 timep = p;
265 typep = timep + 4 * timecnt;
266 ttisp = typep + timecnt;
267 charp = ttisp + (4 + 1 + 1) * typecnt;
268 cnt = (0 < timecnt) ? timecnt : 1;
269 *tzpp = CFAllocatorAllocate(allocator, cnt * sizeof(CFTZPeriod), 0);
270 if (__CFOASafe) __CFSetLastAllocationEventName(*tzpp, "CFTimeZone (store)");
271 memset(*tzpp, 0, cnt * sizeof(CFTZPeriod));
272 abbrs = CFAllocatorAllocate(allocator, (charcnt + 1) * sizeof(CFStringRef), 0);
273 if (__CFOASafe) __CFSetLastAllocationEventName(abbrs, "CFTimeZone (temp)");
274 for (idx = 0; idx < charcnt + 1; idx++) {
275 abbrs[idx] = NULL;
276 }
277 for (idx = 0; idx < cnt; idx++) {
278 CFAbsoluteTime at;
279 int32_t itime, offset;
280 uint8_t type, dst, abbridx;
281
282 at = (CFAbsoluteTime)(__CFDetzcode(timep) + 0.0) - kCFAbsoluteTimeIntervalSince1970;
283 if (0 == timecnt) itime = INT_MIN;
284 else if (at < (CFAbsoluteTime)INT_MIN) itime = INT_MIN;
285 else if ((CFAbsoluteTime)INT_MAX < at) itime = INT_MAX;
286 else itime = (int32_t)at;
287 timep += 4; /* harmless if 0 == timecnt */
288 type = (0 < timecnt) ? (uint8_t)*typep++ : 0;
289 if (typecnt <= type) {
290 result = false;
291 break;
292 }
293 offset = __CFDetzcode(ttisp + 6 * type);
294 dst = (uint8_t)*(ttisp + 6 * type + 4);
295 if (0 != dst && 1 != dst) {
296 result = false;
297 break;
298 }
299 abbridx = (uint8_t)*(ttisp + 6 * type + 5);
300 if (charcnt < abbridx) {
301 result = false;
302 break;
303 }
304 if (NULL == abbrs[abbridx]) {
305 abbrs[abbridx] = CFStringCreateWithCString(allocator, (char *)&charp[abbridx], kCFStringEncodingASCII);
306 }
307 __CFTZPeriodInit(*tzpp + idx, itime, abbrs[abbridx], offset, (dst ? true : false));
308 }
309 for (idx = 0; idx < charcnt + 1; idx++) {
310 if (NULL != abbrs[idx]) {
311 CFRelease(abbrs[idx]);
312 }
313 }
314 CFAllocatorDeallocate(allocator, abbrs);
315 if (result) {
316 // dump all but the last INT_MIN and the first INT_MAX
317 for (idx = 0; idx < cnt; idx++) {
318 if (((*tzpp + idx)->startSec == INT_MIN) && (idx + 1 < cnt) && (((*tzpp + idx + 1)->startSec == INT_MIN))) {
319 if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev);
320 cnt--;
321 memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx));
322 idx--;
323 }
324 }
325 // Don't combine these loops! Watch the idx decrementing...
326 for (idx = 0; idx < cnt; idx++) {
327 if (((*tzpp + idx)->startSec == INT_MAX) && (0 < idx) && (((*tzpp + idx - 1)->startSec == INT_MAX))) {
328 if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev);
329 cnt--;
330 memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx));
331 idx--;
332 }
333 }
334 CFQSortArray(*tzpp, cnt, sizeof(CFTZPeriod), __CFCompareTZPeriods, NULL);
335 // if the first period is in DST and there is more than one period, drop it
336 if (1 < cnt && __CFTZPeriodIsDST(*tzpp + 0)) {
337 if (NULL != (*tzpp + 0)->abbrev) CFRelease((*tzpp + 0)->abbrev);
338 cnt--;
339 memmove((*tzpp + 0), (*tzpp + 0 + 1), sizeof(CFTZPeriod) * (cnt - 0));
340 }
341 *cntp = cnt;
342 } else {
343 CFAllocatorDeallocate(allocator, *tzpp);
344 *tzpp = NULL;
345 }
346 return result;
347 }
348 #elif 0 || 0
349 static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) {
350 /* We use Win32 function to find TimeZone
351 * (Aleksey Dukhnyakov)
352 */
353 *tzpp = (CFTZPeriod *)CFAllocatorAllocate(allocator, sizeof(CFTZPeriod), 0);
354 memset(*tzpp, 0, sizeof(CFTZPeriod));
355 __CFTZPeriodInit(*tzpp, 0, NULL, 0, false);
356 *cntp = 1;
357 return TRUE;
358 }
359 #else
360 #error Unknown or unspecified DEPLOYMENT_TARGET
361 #endif
362
363 static Boolean __CFTimeZoneEqual(CFTypeRef cf1, CFTypeRef cf2) {
364 CFTimeZoneRef tz1 = (CFTimeZoneRef)cf1;
365 CFTimeZoneRef tz2 = (CFTimeZoneRef)cf2;
366 if (!CFEqual(CFTimeZoneGetName(tz1), CFTimeZoneGetName(tz2))) return false;
367 if (!CFEqual(CFTimeZoneGetData(tz1), CFTimeZoneGetData(tz2))) return false;
368 return true;
369 }
370
371 static CFHashCode __CFTimeZoneHash(CFTypeRef cf) {
372 CFTimeZoneRef tz = (CFTimeZoneRef)cf;
373 return CFHash(CFTimeZoneGetName(tz));
374 }
375
376 static CFStringRef __CFTimeZoneCopyDescription(CFTypeRef cf) {
377 CFTimeZoneRef tz = (CFTimeZoneRef)cf;
378 CFStringRef result, abbrev;
379 CFAbsoluteTime at;
380 at = CFAbsoluteTimeGetCurrent();
381 abbrev = CFTimeZoneCopyAbbreviation(tz, at);
382 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");
383 CFRelease(abbrev);
384 return result;
385 }
386
387 static void __CFTimeZoneDeallocate(CFTypeRef cf) {
388 CFTimeZoneRef tz = (CFTimeZoneRef)cf;
389 CFAllocatorRef allocator = CFGetAllocator(tz);
390 CFIndex idx;
391 if (tz->_name) CFRelease(tz->_name);
392 if (tz->_data) CFRelease(tz->_data);
393 for (idx = 0; idx < tz->_periodCnt; idx++) {
394 if (NULL != tz->_periods[idx].abbrev) CFRelease(tz->_periods[idx].abbrev);
395 }
396 if (NULL != tz->_periods) CFAllocatorDeallocate(allocator, tz->_periods);
397 }
398
399 static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID;
400
401 static const CFRuntimeClass __CFTimeZoneClass = {
402 0,
403 "CFTimeZone",
404 NULL, // init
405 NULL, // copy
406 __CFTimeZoneDeallocate,
407 __CFTimeZoneEqual,
408 __CFTimeZoneHash,
409 NULL, //
410 __CFTimeZoneCopyDescription
411 };
412
413 __private_extern__ void __CFTimeZoneInitialize(void) {
414 __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass);
415 }
416
417 CFTypeID CFTimeZoneGetTypeID(void) {
418 return __kCFTimeZoneTypeID;
419 }
420
421
422 #if DEPLOYMENT_TARGET_MACOSX
423 static CFTimeZoneRef __CFTimeZoneCreateSystem(void) {
424 CFTimeZoneRef result = NULL;
425
426
427 char *tzenv;
428 int ret;
429 char linkbuf[CFMaxPathSize];
430
431 tzenv = getenv("TZFILE");
432 if (NULL != tzenv) {
433 CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false);
434 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false);
435 CFRelease(name);
436 if (result) return result;
437 }
438 tzenv = getenv("TZ");
439 if (NULL != tzenv) {
440 CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false);
441 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true);
442 CFRelease(name);
443 if (result) return result;
444 }
445 ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf));
446 if (0 < ret) {
447 CFStringRef name;
448 linkbuf[ret] = '\0';
449 if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) {
450 name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false);
451 } else {
452 name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false);
453 }
454 result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false);
455 CFRelease(name);
456 if (result) return result;
457 }
458 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0);
459 }
460 #elif 0 || 0
461 static CFTimeZoneRef __CFTimeZoneCreateSystem(void) {
462 CFTimeZoneRef result = NULL;
463 /* The GetTimeZoneInformation function retrieves the current
464 * time-zone parameters for Win32
465 * (Aleksey Dukhnyakov)
466 */
467 CFDataRef data;
468 TIME_ZONE_INFORMATION tz;
469 DWORD dw_result;
470 dw_result=GetTimeZoneInformation(&tz);
471
472 if ( dw_result == TIME_ZONE_ID_STANDARD ||
473 dw_result == TIME_ZONE_ID_DAYLIGHT ) {
474 CFStringRef name = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)tz.StandardName, wcslen(tz.StandardName));
475 data = CFDataCreate(kCFAllocatorSystemDefault, (UInt8 *)&tz, sizeof(tz));
476 result = CFTimeZoneCreate(kCFAllocatorSystemDefault, name, data);
477 CFRelease(name);
478 CFRelease(data);
479 if (result) return result;
480 }
481 return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0);
482 }
483 #else
484 #error Unknown or unspecified DEPLOYMENT_TARGET
485 #endif
486
487 CFTimeZoneRef CFTimeZoneCopySystem(void) {
488 CFTimeZoneRef tz;
489 __CFTimeZoneLockGlobal();
490 if (NULL == __CFTimeZoneSystem) {
491 __CFTimeZoneUnlockGlobal();
492 tz = __CFTimeZoneCreateSystem();
493 __CFTimeZoneLockGlobal();
494 if (NULL == __CFTimeZoneSystem) {
495 __CFTimeZoneSystem = tz;
496 } else {
497 if (tz) CFRelease(tz);
498 }
499 }
500 tz = __CFTimeZoneSystem ? (CFTimeZoneRef)CFRetain(__CFTimeZoneSystem) : NULL;
501 __CFTimeZoneUnlockGlobal();
502 return tz;
503 }
504
505 static CFIndex __noteCount = 0;
506
507 void CFTimeZoneResetSystem(void) {
508 __CFTimeZoneLockGlobal();
509 if (__CFTimeZoneDefault == __CFTimeZoneSystem) {
510 if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault);
511 __CFTimeZoneDefault = NULL;
512 }
513 CFTimeZoneRef tz = __CFTimeZoneSystem;
514 __CFTimeZoneSystem = NULL;
515 __CFTimeZoneUnlockGlobal();
516 if (tz) CFRelease(tz);
517 }
518
519 CFIndex _CFTimeZoneGetNoteCount(void) {
520 return __noteCount;
521 }
522
523 CFTimeZoneRef CFTimeZoneCopyDefault(void) {
524 CFTimeZoneRef tz;
525 __CFTimeZoneLockGlobal();
526 if (NULL == __CFTimeZoneDefault) {
527 __CFTimeZoneUnlockGlobal();
528 tz = CFTimeZoneCopySystem();
529 __CFTimeZoneLockGlobal();
530 if (NULL == __CFTimeZoneDefault) {
531 __CFTimeZoneDefault = tz;
532 } else {
533 if (tz) CFRelease(tz);
534 }
535 }
536 tz = __CFTimeZoneDefault ? (CFTimeZoneRef)CFRetain(__CFTimeZoneDefault) : NULL;
537 __CFTimeZoneUnlockGlobal();
538 return tz;
539 }
540
541 void CFTimeZoneSetDefault(CFTimeZoneRef tz) {
542 if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
543 __CFTimeZoneLockGlobal();
544 if (tz != __CFTimeZoneDefault) {
545 if (tz) CFRetain(tz);
546 if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault);
547 __CFTimeZoneDefault = tz;
548 }
549 __CFTimeZoneUnlockGlobal();
550 }
551
552 static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void);
553
554 CFArrayRef CFTimeZoneCopyKnownNames(void) {
555 CFArrayRef tzs;
556 __CFTimeZoneLockGlobal();
557 if (NULL == __CFKnownTimeZoneList) {
558 CFMutableArrayRef list;
559 /* TimeZone information locate in the registry for Win32
560 * (Aleksey Dukhnyakov)
561 */
562 #if DEPLOYMENT_TARGET_MACOSX
563 list = __CFCopyRecursiveDirectoryList();
564 #else
565 #error Unknown or unspecified DEPLOYMENT_TARGET
566 #endif
567 // Remove undesirable ancient cruft
568 CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary();
569 CFIndex idx;
570 for (idx = CFArrayGetCount(list); idx--; ) {
571 CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(list, idx);
572 if (CFDictionaryContainsKey(dict, item)) {
573 CFArrayRemoveValueAtIndex(list, idx);
574 }
575 }
576 __CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list);
577 CFRelease(list);
578 }
579 tzs = __CFKnownTimeZoneList ? (CFArrayRef)CFRetain(__CFKnownTimeZoneList) : NULL;
580 __CFTimeZoneUnlockGlobal();
581 return tzs;
582 }
583
584 #if DEPLOYMENT_TARGET_MACOSX
585 /* The criteria here are sort of: coverage for the U.S. and Europe,
586 * large cities, abbreviation uniqueness, and perhaps a few others.
587 * But do not make the list too large with obscure information.
588 */
589 static const char *__CFTimeZoneAbbreviationDefaults =
590 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
591 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
592 " <plist version=\"1.0\">"
593 " <dict>"
594 " <key>ADT</key> <string>America/Halifax</string>"
595 " <key>AKDT</key> <string>America/Juneau</string>"
596 " <key>AKST</key> <string>America/Juneau</string>"
597 " <key>ART</key> <string>America/Argentina/Buenos_Aires</string>"
598 " <key>AST</key> <string>America/Halifax</string>"
599 " <key>BDT</key> <string>Asia/Dhaka</string>"
600 " <key>BRST</key> <string>America/Sao_Paulo</string>"
601 " <key>BRT</key> <string>America/Sao_Paulo</string>"
602 " <key>BST</key> <string>Europe/London</string>"
603 " <key>CAT</key> <string>Africa/Harare</string>"
604 " <key>CDT</key> <string>America/Chicago</string>"
605 " <key>CEST</key> <string>Europe/Paris</string>"
606 " <key>CET</key> <string>Europe/Paris</string>"
607 " <key>CLST</key> <string>America/Santiago</string>"
608 " <key>CLT</key> <string>America/Santiago</string>"
609 " <key>COT</key> <string>America/Bogota</string>"
610 " <key>CST</key> <string>America/Chicago</string>"
611 " <key>EAT</key> <string>Africa/Addis_Ababa</string>"
612 " <key>EDT</key> <string>America/New_York</string>"
613 " <key>EEST</key> <string>Europe/Istanbul</string>"
614 " <key>EET</key> <string>Europe/Istanbul</string>"
615 " <key>EST</key> <string>America/New_York</string>"
616 " <key>GMT</key> <string>GMT</string>"
617 " <key>GST</key> <string>Asia/Dubai</string>"
618 " <key>HKT</key> <string>Asia/Hong_Kong</string>"
619 " <key>HST</key> <string>Pacific/Honolulu</string>"
620 " <key>ICT</key> <string>Asia/Bangkok</string>"
621 " <key>IRST</key> <string>Asia/Tehran</string>"
622 " <key>IST</key> <string>Asia/Calcutta</string>"
623 " <key>JST</key> <string>Asia/Tokyo</string>"
624 " <key>KST</key> <string>Asia/Seoul</string>"
625 " <key>MDT</key> <string>America/Denver</string>"
626 " <key>MSD</key> <string>Europe/Moscow</string>"
627 " <key>MSK</key> <string>Europe/Moscow</string>"
628 " <key>MST</key> <string>America/Denver</string>"
629 " <key>NZDT</key> <string>Pacific/Auckland</string>"
630 " <key>NZST</key> <string>Pacific/Auckland</string>"
631 " <key>PDT</key> <string>America/Los_Angeles</string>"
632 " <key>PET</key> <string>America/Lima</string>"
633 " <key>PHT</key> <string>Asia/Manila</string>"
634 " <key>PKT</key> <string>Asia/Karachi</string>"
635 " <key>PST</key> <string>America/Los_Angeles</string>"
636 " <key>SGT</key> <string>Asia/Singapore</string>"
637 " <key>UTC</key> <string>UTC</string>"
638 " <key>WAT</key> <string>Africa/Lagos</string>"
639 " <key>WEST</key> <string>Europe/Lisbon</string>"
640 " <key>WET</key> <string>Europe/Lisbon</string>"
641 " <key>WIT</key> <string>Asia/Jakarta</string>"
642 " </dict>"
643 " </plist>";
644 #elif 0 || 0
645 static const char *__CFTimeZoneAbbreviationDefaults =
646 /* Mappings to time zones in Windows Registry are best-guess */
647 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
648 " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
649 " <plist version=\"1.0\">"
650 " <dict>"
651 " <key>ADT</key> <string>Atlantic Standard Time</string>"
652 " <key>AKDT</key> <string>Alaskan Standard Time</string>"
653 " <key>AKST</key> <string>Alaskan Standard Time</string>"
654 " <key>ART</key> <string>SA Eastern Standard Time</string>"
655 " <key>AST</key> <string>Atlantic Standard Time</string>"
656 " <key>BDT</key> <string>Central Asia Standard Time</string>"
657 " <key>BRST</key> <string>SA Eastern Standard Time</string>"
658 " <key>BRT</key> <string>SA Eastern Standard Time</string>"
659 " <key>BST</key> <string>GMT Standard Time</string>"
660 " <key>CAT</key> <string>South Africa Standard Time</string>"
661 " <key>CDT</key> <string>Central Standard Time</string>"
662 " <key>CEST</key> <string>Central Europe Standard Time</string>"
663 " <key>CET</key> <string>Central Europe Standard Time</string>"
664 " <key>CLST</key> <string>SA Western Standard Time</string>"
665 " <key>CLT</key> <string>SA Western Standard Time</string>"
666 " <key>COT</key> <string>Central Standard Time</string>"
667 " <key>CST</key> <string>Central Standard Time</string>"
668 " <key>EAT</key> <string>E. Africa Standard Time</string>"
669 " <key>EDT</key> <string>Eastern Standard Time</string>"
670 " <key>EEST</key> <string>E. Europe Standard Time</string>"
671 " <key>EET</key> <string>E. Europe Standard Time</string>"
672 " <key>EST</key> <string>Eastern Standard Time</string>"
673 " <key>GMT</key> <string>Greenwich Standard Time</string>"
674 " <key>GST</key> <string>Arabian Standard Time</string>"
675 " <key>HKT</key> <string>China Standard Time</string>"
676 " <key>HST</key> <string>Hawaiian Standard Time</string>"
677 " <key>ICT</key> <string>SE Asia Standard Time</string>"
678 " <key>IRST</key> <string>Iran Standard Time</string>"
679 " <key>IST</key> <string>India Standard Time</string>"
680 " <key>JST</key> <string>Tokyo Standard Time</string>"
681 " <key>KST</key> <string>Korea Standard Time</string>"
682 " <key>MDT</key> <string>Mountain Standard Time</string>"
683 " <key>MSD</key> <string>E. Europe Standard Time</string>"
684 " <key>MSK</key> <string>E. Europe Standard Time</string>"
685 " <key>MST</key> <string>Mountain Standard Time</string>"
686 " <key>NZDT</key> <string>New Zealand Standard Time</string>"
687 " <key>NZST</key> <string>New Zealand Standard Time</string>"
688 " <key>PDT</key> <string>Pacific Standard Time</string>"
689 " <key>PET</key> <string>SA Pacific Standard Time</string>"
690 " <key>PHT</key> <string>Taipei Standard Time</string>"
691 " <key>PKT</key> <string>West Asia Standard Time</string>"
692 " <key>PST</key> <string>Pacific Standard Time</string>"
693 " <key>SGT</key> <string>Singapore Standard Time</string>"
694 " <key>UTC</key> <string>Greenwich Standard Time</string>"
695 " <key>WAT</key> <string>W. Central Africa Standard Time</string>"
696 " <key>WEST</key> <string>W. Europe Standard Time</string>"
697 " <key>WET</key> <string>W. Europe Standard Time</string>"
698 " <key>WIT</key> <string>SE Asia Standard Time</string>"
699 " </dict>"
700 " </plist>";
701 #else
702 #error Unknown or unspecified DEPLOYMENT_TARGET
703 #endif
704
705 CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) {
706 CFDictionaryRef dict;
707 __CFTimeZoneLockAbbreviations();
708 if (NULL == __CFTimeZoneAbbreviationDict) {
709 CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults));
710 __CFTimeZoneAbbreviationDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL);
711 CFRelease(data);
712 }
713 if (NULL == __CFTimeZoneAbbreviationDict) {
714 __CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL);
715 }
716 dict = __CFTimeZoneAbbreviationDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneAbbreviationDict) : NULL;
717 __CFTimeZoneUnlockAbbreviations();
718 return dict;
719 }
720
721 void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) {
722 __CFGenericValidateType(dict, CFDictionaryGetTypeID());
723 __CFTimeZoneLockGlobal();
724 if (dict != __CFTimeZoneAbbreviationDict) {
725 if (dict) CFRetain(dict);
726 if (__CFTimeZoneAbbreviationDict) {
727 CFIndex count, idx;
728 count = CFDictionaryGetCount(__CFTimeZoneAbbreviationDict);
729 CFTypeRef *keys = (CFTypeRef *)malloc(sizeof(CFTypeRef *) * count);
730 for (idx = 0; idx < count; idx++) {
731 CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)keys[idx]);
732 }
733 free(keys);
734 CFRelease(__CFTimeZoneAbbreviationDict);
735 }
736 __CFTimeZoneAbbreviationDict = dict;
737 }
738 __CFTimeZoneUnlockGlobal();
739 }
740
741 CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) {
742 // assert: (NULL != name && NULL != data);
743 CFTimeZoneRef memory;
744 uint32_t size;
745 CFTZPeriod *tzp = NULL;
746 CFIndex idx, cnt = 0;
747
748 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
749 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
750 __CFGenericValidateType(name, CFStringGetTypeID());
751 __CFGenericValidateType(data, CFDataGetTypeID());
752 __CFTimeZoneLockGlobal();
753 if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) {
754 __CFTimeZoneUnlockGlobal();
755 return (CFTimeZoneRef)CFRetain(memory);
756 }
757 if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) {
758 __CFTimeZoneUnlockGlobal();
759 return NULL;
760 }
761 size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase);
762 memory = (CFTimeZoneRef)_CFRuntimeCreateInstance(allocator, CFTimeZoneGetTypeID(), size, NULL);
763 if (NULL == memory) {
764 __CFTimeZoneUnlockGlobal();
765 for (idx = 0; idx < cnt; idx++) {
766 if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev);
767 }
768 if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp);
769 return NULL;
770 }
771 ((struct __CFTimeZone *)memory)->_name = (CFStringRef)CFStringCreateCopy(allocator, name);
772 ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data);
773 ((struct __CFTimeZone *)memory)->_periods = tzp;
774 ((struct __CFTimeZone *)memory)->_periodCnt = cnt;
775 if (NULL == __CFTimeZoneCache) {
776 __CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
777 }
778 CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory);
779 __CFTimeZoneUnlockGlobal();
780 return memory;
781 }
782
783 #if DEPLOYMENT_TARGET_MACOSX
784 static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) {
785 CFTimeZoneRef result;
786 CFDataRef data;
787 int32_t nameLen = CFStringGetLength(name);
788 unsigned char dataBytes[52 + nameLen + 1];
789 memset(dataBytes, 0, sizeof(dataBytes));
790
791 // Put in correct magic bytes for timezone structures
792 dataBytes[0] = 'T';
793 dataBytes[1] = 'Z';
794 dataBytes[2] = 'i';
795 dataBytes[3] = 'f';
796
797 __CFEntzcode(1, dataBytes + 20);
798 __CFEntzcode(1, dataBytes + 24);
799 __CFEntzcode(1, dataBytes + 36);
800 __CFEntzcode(nameLen + 1, dataBytes + 40);
801 __CFEntzcode(seconds, dataBytes + 44);
802 dataBytes[48] = isDST ? 1 : 0;
803 CFStringGetCString(name, (char *)dataBytes + 50, nameLen + 1, kCFStringEncodingASCII);
804 data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1);
805 result = CFTimeZoneCreate(allocator, name, data);
806 CFRelease(data);
807 return result;
808 }
809 #elif 0 || 0
810 static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) {
811 /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure
812 * to find current timezone
813 * (Aleksey Dukhnyakov)
814 */
815 CFTimeZoneRef result;
816 TIME_ZONE_INFORMATION tzi;
817 CFDataRef data;
818 CFIndex length = CFStringGetLength(name);
819
820 memset(&tzi,0,sizeof(tzi));
821 tzi.Bias=(long)(-seconds/60);
822 CFStringGetCharacters(name, CFRangeMake(0, length < 31 ? length : 31 ), (UniChar *)tzi.StandardName);
823 data = CFDataCreate(allocator,(UInt8 *)&tzi, sizeof(tzi));
824 result = CFTimeZoneCreate(allocator, name, data);
825 CFRelease(data);
826 return result;
827 }
828 #else
829 #error Unknown or unspecified DEPLOYMENT_TARGET
830 #endif
831
832 // rounds offset to nearest minute
833 CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) {
834 CFTimeZoneRef result;
835 CFStringRef name;
836 int32_t seconds, minute, hour;
837 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
838 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
839 if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL;
840 ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0;
841 seconds = (int32_t)ti;
842 hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600);
843 seconds -= ((ti < 0) ? -hour : hour) * 3600;
844 minute = (ti < 0) ? (-seconds / 60) : (seconds / 60);
845 if (fabs(ti) < 1.0) {
846 name = (CFStringRef)CFRetain(CFSTR("GMT"));
847 } else {
848 name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute);
849 }
850 result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0);
851 CFRelease(name);
852 return result;
853 }
854
855 CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) {
856 CFTimeZoneRef result = NULL;
857 CFStringRef tzName = NULL;
858 CFDataRef data = NULL;
859
860 if (allocator == NULL) allocator = __CFGetDefaultAllocator();
861 __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
862 __CFGenericValidateType(name, CFStringGetTypeID());
863 if (CFEqual(CFSTR(""), name)) {
864 // empty string is not a time zone name, just abort now,
865 // following stuff will fail anyway
866 return NULL;
867 }
868 __CFTimeZoneLockGlobal();
869 if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) {
870 __CFTimeZoneUnlockGlobal();
871 return (CFTimeZoneRef)CFRetain(result);
872 }
873 __CFTimeZoneUnlockGlobal();
874 #if DEPLOYMENT_TARGET_MACOSX
875 CFURLRef baseURL, tempURL;
876 void *bytes;
877 CFIndex length;
878
879 baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true);
880 if (tryAbbrev) {
881 CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
882 tzName = CFDictionaryGetValue(abbrevs, name);
883 if (NULL != tzName) {
884 tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false);
885 if (NULL != tempURL) {
886 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0)) {
887 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault);
888 }
889 CFRelease(tempURL);
890 }
891 }
892 CFRelease(abbrevs);
893 }
894 if (NULL == data) {
895 CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary();
896 CFStringRef mapping = CFDictionaryGetValue(dict, name);
897 if (mapping) {
898 name = mapping;
899 } else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) {
900 CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name);
901 CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO)));
902 mapping = CFDictionaryGetValue(dict, unprefixed);
903 if (mapping) {
904 name = mapping;
905 }
906 CFRelease(unprefixed);
907 }
908 CFRelease(dict);
909 if (CFEqual(CFSTR(""), name)) {
910 return NULL;
911 }
912 }
913 if (NULL == data) {
914 tzName = name;
915 tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false);
916 if (NULL != tempURL) {
917 if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0)) {
918 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault);
919 }
920 CFRelease(tempURL);
921 }
922 }
923 CFRelease(baseURL);
924 if (NULL != data) {
925 result = CFTimeZoneCreate(allocator, tzName, data);
926 if (name != tzName) {
927 CFStringRef nameCopy = (CFStringRef)CFStringCreateCopy(allocator, name);
928 __CFTimeZoneLockGlobal();
929 CFDictionaryAddValue(__CFTimeZoneCache, nameCopy, result);
930 __CFTimeZoneUnlockGlobal();
931 CFRelease(nameCopy);
932 }
933 CFRelease(data);
934 }
935 return result;
936 }
937 #elif 0 || 0
938 /* Reading GMT offset and daylight flag from the registry
939 * for TimeZone name
940 * (Aleksey Dukhnyakov)
941 */
942 {
943 CFStringRef safeName = name;
944 struct {
945 LONG Bias;
946 LONG StandardBias;
947 LONG DaylightBias;
948 SYSTEMTIME StandardDate;
949 SYSTEMTIME DaylightDate;
950 } tzi;
951 TIME_ZONE_INFORMATION tzi_system;
952
953 HKEY hkResult;
954 DWORD dwType, dwSize=sizeof(tzi),
955 dwSize_name1=sizeof(tzi_system.StandardName),
956 dwSize_name2=sizeof(tzi_system.DaylightName);
957
958 if (tryAbbrev) {
959 CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
960 tzName = (CFStringRef)CFDictionaryGetValue(abbrevs, name);
961 if (NULL == tzName) {
962 CFRelease(abbrevs);
963 return NULL;
964 }
965 name = tzName;
966 CFRelease(abbrevs);
967 }
968
969 /* Open regestry and move down to the TimeZone information
970 */
971 if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) !=
972 ERROR_SUCCESS ) {
973 return NULL;
974 }
975 /* Move down to specific TimeZone name
976 */
977 #if defined(UNICODE)
978 UniChar *uniTimeZone = (UniChar*)CFStringGetCharactersPtr(name);
979 if (uniTimeZone == NULL) {
980 // We need to extract the bytes out of the CFStringRef and create our own
981 // UNICODE string to pass to the Win32 API - RegOpenKey.
982 UInt8 uniBuff[MAX_PATH+2]; // adding +2 to handle Unicode-null termination /0/0.
983 CFIndex usedBuff = 0;
984 CFIndex numChars = CFStringGetBytes(name, CFRangeMake(0, CFStringGetLength(name)), kCFStringEncodingUnicode, 0, FALSE, uniBuff, MAX_PATH, &usedBuff);
985 if (numChars == 0) {
986 return NULL;
987 } else {
988 // NULL-terminate the newly created Unicode string.
989 uniBuff[usedBuff] = '\0';
990 uniBuff[usedBuff+1] = '\0';
991 }
992
993 if (RegOpenKey(hkResult, (LPCWSTR)uniBuff ,&hkResult) != ERROR_SUCCESS ) {
994 return NULL;
995 }
996 } else {
997 if (RegOpenKey(hkResult, (LPCWSTR)uniTimeZone ,&hkResult) != ERROR_SUCCESS ) {
998 return NULL;
999 }
1000 }
1001 #else
1002 if (RegOpenKey(hkResult,CFStringGetCStringPtr(name, CFStringGetSystemEncoding()),&hkResult) != ERROR_SUCCESS ) {
1003 return NULL;
1004 }
1005 #endif
1006
1007 /* TimeZone information(offsets, daylight flag, ...) assign to tzi structure
1008 */
1009 if ( RegQueryValueEx(hkResult,_T("TZI"),NULL,&dwType,(LPBYTE)&tzi,&dwSize) != ERROR_SUCCESS &&
1010 RegQueryValueEx(hkResult,_T("Std"),NULL,&dwType,(LPBYTE)&tzi_system.StandardName,&dwSize_name1) != ERROR_SUCCESS &&
1011 RegQueryValueEx(hkResult,_T("Dlt"),NULL,&dwType,(LPBYTE)&tzi_system.DaylightName,&dwSize_name2) != ERROR_SUCCESS )
1012 {
1013 return NULL;
1014 }
1015
1016 tzi_system.Bias=tzi.Bias;
1017 tzi_system.StandardBias=tzi.StandardBias;
1018 tzi_system.DaylightBias=tzi.DaylightBias;
1019 tzi_system.StandardDate=tzi.StandardDate;
1020 tzi_system.DaylightDate=tzi.DaylightDate;
1021
1022 /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure
1023 * to find current timezone
1024 * (Aleksey Dukhnyakov)
1025 */
1026 data = CFDataCreate(allocator,(UInt8 *)&tzi_system, sizeof(tzi_system));
1027
1028 RegCloseKey(hkResult);
1029 result = CFTimeZoneCreate(allocator, name, data);
1030 if (result) {
1031 if (tryAbbrev)
1032 result->_periods->abbrev = (CFStringRef)CFStringCreateCopy(allocator,safeName);
1033 else {
1034 }
1035 }
1036 CFRelease(data);
1037 }
1038 return result;
1039 }
1040 #else
1041 #error Unknown or unspecified DEPLOYMENT_TARGET
1042 #endif
1043
1044 CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) {
1045 CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFStringRef, tz, "name");
1046 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1047 return tz->_name;
1048 }
1049
1050 CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) {
1051 CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFDataRef, tz, "data");
1052 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1053 return tz->_data;
1054 }
1055
1056 CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) {
1057 #if DEPLOYMENT_TARGET_MACOSX
1058 CFIndex idx;
1059 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at);
1060 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1061 idx = __CFBSearchTZPeriods(tz, at);
1062 return __CFTZPeriodGMTOffset(&(tz->_periods[idx]));
1063 #endif
1064 }
1065
1066 CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) {
1067 CFStringRef result;
1068 CFIndex idx;
1069 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFStringRef, tz, "_abbreviationForAbsoluteTime:", at);
1070 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1071 #if DEPLOYMENT_TARGET_MACOSX
1072 idx = __CFBSearchTZPeriods(tz, at);
1073 #endif
1074 result = __CFTZPeriodAbbreviation(&(tz->_periods[idx]));
1075 return result ? (CFStringRef)CFRetain(result) : NULL;
1076 }
1077
1078 Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) {
1079 #if DEPLOYMENT_TARGET_MACOSX
1080 CFIndex idx;
1081 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at);
1082 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1083 idx = __CFBSearchTZPeriods(tz, at);
1084 return __CFTZPeriodIsDST(&(tz->_periods[idx]));
1085 #endif
1086 }
1087
1088 CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) {
1089 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_daylightSavingTimeOffsetForAbsoluteTime:", at);
1090 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1091 CFIndex idx = __CFBSearchTZPeriods(tz, at);
1092 if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) {
1093 CFTimeInterval offset = __CFTZPeriodGMTOffset(&(tz->_periods[idx]));
1094 if (idx + 1 < tz->_periodCnt) {
1095 return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1]));
1096 } else if (0 < idx) {
1097 return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1]));
1098 }
1099 }
1100 return 0.0;
1101 }
1102
1103 CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) {
1104 CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_nextDaylightSavingTimeTransitionAfterAbsoluteTime:", at);
1105 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1106 CFIndex idx = __CFBSearchTZPeriods(tz, at);
1107 if (tz->_periodCnt <= idx + 1) {
1108 return 0.0;
1109 }
1110 return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1]));
1111 }
1112
1113 enum {
1114 kCFTimeZoneNameStyleGeneric = 4,
1115 kCFTimeZoneNameStyleShortGeneric = 5
1116 };
1117
1118 extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz);
1119
1120 #define BUFFER_SIZE 768
1121
1122 CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) {
1123 CF_OBJC_FUNCDISPATCH2(CFTimeZoneGetTypeID(), CFStringRef, tz, "localizedName:locale:", style, locale);
1124 __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1125 __CFGenericValidateType(locale, CFLocaleGetTypeID());
1126
1127
1128 CFStringRef localeID = CFLocaleGetIdentifier(locale);
1129 UCalendar *cal = __CFCalendarCreateUCalendar(NULL, localeID, tz);
1130 if (NULL == cal) {
1131 return NULL;
1132 }
1133
1134 char buffer[BUFFER_SIZE];
1135 const char *cstr = CFStringGetCStringPtr(localeID, kCFStringEncodingASCII);
1136 if (NULL == cstr) {
1137 if (CFStringGetCString(localeID, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
1138 }
1139 if (NULL == cstr) {
1140 ucal_close(cal);
1141 return NULL;
1142 }
1143
1144 UChar ubuffer[BUFFER_SIZE];
1145 UErrorCode status = U_ZERO_ERROR;
1146 int32_t cnt = ucal_getTimeZoneDisplayName(cal, (UCalendarDisplayNameType)style, cstr, ubuffer, BUFFER_SIZE, &status);
1147 ucal_close(cal);
1148 if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1149 return CFStringCreateWithCharacters(CFGetAllocator(tz), (const UniChar *)ubuffer, cnt);
1150 }
1151 return NULL;
1152 }
1153
1154 static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) {
1155 CFDictionaryRef dict;
1156 __CFTimeZoneLockCompatibilityMapping();
1157 if (NULL == __CFTimeZoneCompatibilityMappingDict) {
1158 __CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1159
1160 // Empty string means delete/ignore these
1161 }
1162 dict = __CFTimeZoneCompatibilityMappingDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL;
1163 __CFTimeZoneUnlockCompatibilityMapping();
1164 return dict;
1165 }
1166
1167 #undef TZZONEINFO
1168 #undef TZZONELINK
1169