]>
Commit | Line | Data |
---|---|---|
9ce05555 | 1 | /* |
d8925383 | 2 | * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. |
9ce05555 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
9ce05555 A |
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> | |
d8925383 | 30 | #include "CFUtilitiesPriv.h" |
9ce05555 A |
31 | #include "CFInternal.h" |
32 | #include <math.h> | |
33 | #include <limits.h> | |
34 | #include <sys/stat.h> | |
35 | #if !defined(__WIN32__) | |
36 | #include <dirent.h> | |
37 | #else | |
38 | #include <windows.h> | |
39 | #include <winreg.h> | |
40 | #include <tchar.h> | |
41 | #include <time.h> | |
42 | #endif | |
43 | #include <fcntl.h> | |
44 | #include <stdlib.h> | |
45 | #include <string.h> | |
46 | ||
47 | #if defined(__WIN32__) | |
48 | #include <io.h> | |
49 | #endif | |
50 | ||
51 | // For Windows(TM) time zone information, see registry key: | |
52 | // HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones | |
53 | ||
54 | #if defined(__WIN32__) | |
55 | #define TZZONEINFO "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones" | |
56 | #else | |
57 | #define TZZONELINK "/etc/localtime" | |
58 | #define TZZONEINFO "/usr/share/zoneinfo/" | |
59 | #endif | |
60 | ||
61 | static CFTimeZoneRef __CFTimeZoneSystem = NULL; | |
62 | static CFTimeZoneRef __CFTimeZoneDefault = NULL; | |
63 | static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL; | |
64 | static CFSpinLock_t __CFTimeZoneAbbreviationLock = 0; | |
d8925383 A |
65 | static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL; |
66 | static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict2 = NULL; | |
9ce05555 A |
67 | static CFSpinLock_t __CFTimeZoneCompatibilityMappingLock = 0; |
68 | static CFArrayRef __CFKnownTimeZoneList = NULL; | |
69 | static CFMutableDictionaryRef __CFTimeZoneCache = NULL; | |
70 | static CFSpinLock_t __CFTimeZoneGlobalLock = 0; | |
71 | ||
72 | CF_INLINE void __CFTimeZoneLockGlobal(void) { | |
73 | __CFSpinLock(&__CFTimeZoneGlobalLock); | |
74 | } | |
75 | ||
76 | CF_INLINE void __CFTimeZoneUnlockGlobal(void) { | |
77 | __CFSpinUnlock(&__CFTimeZoneGlobalLock); | |
78 | } | |
79 | ||
80 | CF_INLINE void __CFTimeZoneLockAbbreviations(void) { | |
81 | __CFSpinLock(&__CFTimeZoneAbbreviationLock); | |
82 | } | |
83 | ||
84 | CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) { | |
85 | __CFSpinUnlock(&__CFTimeZoneAbbreviationLock); | |
86 | } | |
87 | ||
88 | CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) { | |
89 | __CFSpinLock(&__CFTimeZoneCompatibilityMappingLock); | |
90 | } | |
91 | ||
92 | CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) { | |
93 | __CFSpinUnlock(&__CFTimeZoneCompatibilityMappingLock); | |
94 | } | |
95 | ||
96 | /* This function should be used for WIN32 instead of | |
97 | * __CFCopyRecursiveDirectoryList function. | |
98 | * It takes TimeZone names from the registry | |
99 | * (Aleksey Dukhnyakov) | |
100 | */ | |
101 | #if defined(__WIN32__) | |
102 | static CFMutableArrayRef __CFCopyWindowsTimeZoneList() { | |
103 | CFMutableArrayRef result = NULL; | |
104 | HKEY hkResult; | |
105 | TCHAR lpName[MAX_PATH+1]; | |
106 | DWORD dwIndex, retCode; | |
107 | ||
108 | if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) != | |
109 | ERROR_SUCCESS ) | |
110 | return NULL; | |
111 | ||
112 | result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); | |
113 | ||
114 | for (dwIndex=0; (retCode = RegEnumKey(hkResult,dwIndex,lpName,MAX_PATH)) != ERROR_NO_MORE_ITEMS ; dwIndex++) { | |
115 | ||
116 | if (retCode != ERROR_SUCCESS) { | |
117 | RegCloseKey(hkResult); | |
118 | CFRelease(result); | |
119 | return NULL; | |
120 | } | |
121 | else { | |
122 | #if defined(UNICODE) | |
123 | CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, lpName, _tcslen(lpName), kCFStringEncodingUnicode, false); | |
124 | #else | |
125 | CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, lpName, _tcslen(lpName), CFStringGetSystemEncoding(), false); | |
126 | #endif | |
127 | CFArrayAppendValue(result, string); | |
128 | CFRelease(string); | |
129 | } | |
130 | } | |
131 | ||
132 | RegCloseKey(hkResult); | |
133 | return result; | |
134 | } | |
135 | #endif | |
136 | ||
d8925383 | 137 | #if !defined(__WIN32__) |
9ce05555 A |
138 | static CFMutableArrayRef __CFCopyRecursiveDirectoryList(const char *topDir) { |
139 | CFMutableArrayRef result = NULL, temp; | |
140 | long fd, numread, plen, basep = 0; | |
141 | CFIndex idx, cnt, usedLen; | |
142 | char *dirge, path[CFMaxPathSize]; | |
143 | ||
9ce05555 A |
144 | // No d_namlen in dirent struct on Linux |
145 | #if defined(__LINUX__) | |
146 | #define dentDNameLen strlen(dent->d_name) | |
147 | #else | |
148 | #define dentDNameLen dent->d_namlen | |
149 | #endif | |
150 | fd = open(topDir, O_RDONLY, 0); | |
151 | if (fd < 0) { | |
152 | return NULL; | |
153 | } | |
154 | dirge = malloc(8192); | |
155 | result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); | |
156 | numread = getdirentries(fd, dirge, 8192, &basep); | |
157 | while (0 < numread) { | |
158 | struct dirent *dent = (struct dirent *)dirge; | |
159 | for (; dent < (struct dirent *)(dirge + numread); dent = (struct dirent *)((char *)dent + dent->d_reclen)) { | |
160 | if (0 == dent->d_fileno) continue; | |
161 | if (1 == dentDNameLen && '.' == dent->d_name[0]) continue; | |
162 | if (2 == dentDNameLen && '.' == dent->d_name[0] && '.' == dent->d_name[1]) continue; | |
163 | if (dent->d_type == DT_UNKNOWN) { | |
164 | struct stat statbuf; | |
165 | strcpy(path, topDir); | |
166 | strcat(path, "/"); | |
167 | plen = strlen(path); | |
168 | memmove(path + plen, dent->d_name, dentDNameLen); | |
169 | path[plen + dentDNameLen] = '\0'; | |
170 | if (0 <= stat(path, &statbuf) && (statbuf.st_mode & S_IFMT) == S_IFDIR) { | |
171 | dent->d_type = DT_DIR; | |
172 | } | |
173 | } | |
174 | if (DT_DIR == dent->d_type) { | |
175 | strcpy(path, topDir); | |
176 | strcat(path, "/"); | |
177 | plen = strlen(path); | |
178 | memmove(path + plen, dent->d_name, dentDNameLen); | |
179 | path[plen + dentDNameLen] = '\0'; | |
180 | temp = __CFCopyRecursiveDirectoryList(path); | |
181 | for (idx = 0, cnt = CFArrayGetCount(temp); idx < cnt; idx++) { | |
182 | CFStringRef string, item = CFArrayGetValueAtIndex(temp, idx); | |
183 | memmove(path, dent->d_name, dentDNameLen); | |
184 | path[dentDNameLen] = '/'; | |
185 | CFStringGetBytes(item, CFRangeMake(0, CFStringGetLength(item)), kCFStringEncodingUTF8, 0, false, path + dentDNameLen + 1, CFMaxPathLength - dentDNameLen - 2, &usedLen); | |
186 | string = CFStringCreateWithBytes(kCFAllocatorDefault, path, dentDNameLen + 1 + usedLen, kCFStringEncodingUTF8, false); | |
187 | CFArrayAppendValue(result, string); | |
188 | CFRelease(string); | |
189 | } | |
190 | CFRelease(temp); | |
191 | } else { | |
192 | CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, dent->d_name, dentDNameLen, kCFStringEncodingUTF8, false); | |
193 | CFArrayAppendValue(result, string); | |
194 | CFRelease(string); | |
195 | } | |
196 | } | |
197 | numread = getdirentries(fd, dirge, 8192, &basep); | |
198 | } | |
199 | close(fd); | |
200 | free(dirge); | |
201 | if (-1 == numread) { | |
202 | CFRelease(result); | |
203 | return NULL; | |
204 | } | |
9ce05555 A |
205 | return result; |
206 | } | |
d8925383 | 207 | #endif |
9ce05555 A |
208 | |
209 | typedef struct _CFTZPeriod { | |
210 | int32_t startSec; | |
211 | CFStringRef abbrev; | |
212 | uint32_t info; | |
213 | } CFTZPeriod; | |
214 | ||
215 | struct __CFTimeZone { | |
216 | CFRuntimeBase _base; | |
217 | CFStringRef _name; /* immutable */ | |
218 | CFDataRef _data; /* immutable */ | |
219 | CFTZPeriod *_periods; /* immutable */ | |
220 | int32_t _periodCnt; /* immutable */ | |
221 | }; | |
222 | ||
223 | /* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates | |
224 | * between 1933 and 2069; info outside these years is discarded on read-in */ | |
225 | /* Bits 31-18 of the info are unused */ | |
226 | /* Bit 17 of the info is used for the is-DST state */ | |
227 | /* Bit 16 of the info is used for the sign of the offset (1 == negative) */ | |
228 | /* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */ | |
229 | ||
230 | CF_INLINE void __CFTZPeriodInit(CFTZPeriod *period, int32_t startTime, CFStringRef abbrev, int32_t offset, Boolean isDST) { | |
231 | period->startSec = startTime; | |
232 | period->abbrev = abbrev ? CFRetain(abbrev) : NULL; | |
233 | __CFBitfieldSetValue(period->info, 15, 0, abs(offset)); | |
234 | __CFBitfieldSetValue(period->info, 16, 16, (offset < 0 ? 1 : 0)); | |
235 | __CFBitfieldSetValue(period->info, 17, 17, (isDST ? 1 : 0)); | |
236 | } | |
237 | ||
238 | CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) { | |
239 | return period->startSec; | |
240 | } | |
241 | ||
242 | CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) { | |
243 | return period->abbrev; | |
244 | } | |
245 | ||
246 | CF_INLINE int32_t __CFTZPeriodGMTOffset(const CFTZPeriod *period) { | |
247 | int32_t v = __CFBitfieldGetValue(period->info, 15, 0); | |
248 | if (__CFBitfieldGetValue(period->info, 16, 16)) v = -v; | |
249 | return v; | |
250 | } | |
251 | ||
252 | CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) { | |
253 | return (Boolean)__CFBitfieldGetValue(period->info, 17, 17); | |
254 | } | |
255 | ||
256 | static CFComparisonResult __CFCompareTZPeriods(const void *val1, const void *val2, void *context) { | |
257 | CFTZPeriod *tzp1 = (CFTZPeriod *)val1; | |
258 | CFTZPeriod *tzp2 = (CFTZPeriod *)val2; | |
259 | // we treat equal as less than, as the code which uses the | |
260 | // result of the bsearch doesn't expect exact matches | |
261 | // (they're pretty rare, so no point in over-coding for them) | |
262 | if (__CFTZPeriodStartSeconds(tzp1) <= __CFTZPeriodStartSeconds(tzp2)) return kCFCompareLessThan; | |
263 | return kCFCompareGreaterThan; | |
264 | } | |
265 | ||
d8925383 | 266 | static CFIndex __CFBSearchTZPeriods(CFTimeZoneRef tz, CFAbsoluteTime at) { |
9ce05555 A |
267 | CFTZPeriod elem; |
268 | CFIndex idx; | |
269 | __CFTZPeriodInit(&elem, (int32_t)(float)floor(at), NULL, 0, false); | |
270 | idx = CFBSearch(&elem, sizeof(CFTZPeriod), tz->_periods, tz->_periodCnt, __CFCompareTZPeriods, NULL); | |
271 | if (tz->_periodCnt <= idx) { | |
272 | idx = tz->_periodCnt; | |
273 | } else if (0 == idx) { | |
274 | // We want anything before the time zone records start to be not in DST; | |
275 | // we assume that if period[0] is DST, then period[1] is not; could do a search instead. | |
276 | idx = __CFTZPeriodIsDST(&(tz->_periods[0])) ? 2 : 1; | |
277 | } | |
278 | return idx - 1; | |
279 | } | |
280 | ||
281 | /* | |
282 | ** Each time zone data file begins with. . . | |
283 | */ | |
284 | ||
285 | struct tzhead { | |
286 | char tzh_reserved[20]; /* reserved for future use */ | |
287 | char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ | |
288 | char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ | |
289 | char tzh_leapcnt[4]; /* coded number of leap seconds */ | |
290 | char tzh_timecnt[4]; /* coded number of transition times */ | |
291 | char tzh_typecnt[4]; /* coded number of local time types */ | |
292 | char tzh_charcnt[4]; /* coded number of abbr. chars */ | |
293 | }; | |
294 | ||
295 | /* | |
296 | ** . . .followed by. . . | |
297 | ** | |
298 | ** tzh_timecnt (char [4])s coded transition times a la time(2) | |
299 | ** tzh_timecnt (UInt8)s types of local time starting at above | |
300 | ** tzh_typecnt repetitions of | |
301 | ** one (char [4]) coded GMT offset in seconds | |
302 | ** one (UInt8) used to set tm_isdst | |
303 | ** one (UInt8) that's an abbreviation list index | |
304 | ** tzh_charcnt (char)s '\0'-terminated zone abbreviations | |
305 | ** tzh_leapcnt repetitions of | |
306 | ** one (char [4]) coded leap second transition times | |
307 | ** one (char [4]) total correction after above | |
308 | ** tzh_ttisstdcnt (char)s indexed by type; if 1, transition | |
309 | ** time is standard time, if 0, | |
310 | ** transition time is wall clock time | |
311 | ** if absent, transition times are | |
312 | ** assumed to be wall clock time | |
313 | ** tzh_ttisgmtcnt (char)s indexed by type; if 1, transition | |
314 | ** time is GMT, if 0, | |
315 | ** transition time is local time | |
316 | ** if absent, transition times are | |
317 | ** assumed to be local time | |
318 | */ | |
319 | ||
320 | CF_INLINE int32_t __CFDetzcode(const unsigned char *bufp) { | |
321 | int32_t result = (bufp[0] & 0x80) ? ~0L : 0L; | |
322 | result = (result << 8) | (bufp[0] & 0xff); | |
323 | result = (result << 8) | (bufp[1] & 0xff); | |
324 | result = (result << 8) | (bufp[2] & 0xff); | |
325 | result = (result << 8) | (bufp[3] & 0xff); | |
326 | return result; | |
327 | } | |
328 | ||
329 | CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) { | |
330 | bufp[0] = (value >> 24) & 0xff; | |
331 | bufp[1] = (value >> 16) & 0xff; | |
332 | bufp[2] = (value >> 8) & 0xff; | |
333 | bufp[3] = (value >> 0) & 0xff; | |
334 | } | |
335 | ||
336 | static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) { | |
337 | #if !defined(__WIN32__) | |
338 | int32_t len, timecnt, typecnt, charcnt, idx, cnt; | |
339 | const char *p, *timep, *typep, *ttisp, *charp; | |
340 | CFStringRef *abbrs; | |
341 | Boolean result = true; | |
342 | ||
343 | p = CFDataGetBytePtr(data); | |
344 | len = CFDataGetLength(data); | |
345 | if (len < (int32_t)sizeof(struct tzhead)) { | |
346 | return false; | |
347 | } | |
47a9ab1f A |
348 | |
349 | if (!(p[0] == 'T' && p[1] == 'Z' && p[2] == 'i' && p[3] == 'f')) return false; /* Don't parse without TZif at head of file */ | |
350 | ||
9ce05555 A |
351 | p += 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */ |
352 | timecnt = __CFDetzcode(p); | |
353 | p += 4; | |
354 | typecnt = __CFDetzcode(p); | |
355 | p += 4; | |
356 | charcnt = __CFDetzcode(p); | |
357 | p += 4; | |
358 | if (typecnt <= 0 || timecnt < 0 || charcnt < 0) { | |
359 | return false; | |
360 | } | |
361 | if (len - (int32_t)sizeof(struct tzhead) < (4 + 1) * timecnt + (4 + 1 + 1) * typecnt + charcnt) { | |
362 | return false; | |
363 | } | |
364 | timep = p; | |
365 | typep = timep + 4 * timecnt; | |
366 | ttisp = typep + timecnt; | |
367 | charp = ttisp + (4 + 1 + 1) * typecnt; | |
368 | cnt = (0 < timecnt) ? timecnt : 1; | |
369 | *tzpp = CFAllocatorAllocate(allocator, cnt * sizeof(CFTZPeriod), 0); | |
370 | if (__CFOASafe) __CFSetLastAllocationEventName(*tzpp, "CFTimeZone (store)"); | |
371 | memset(*tzpp, 0, cnt * sizeof(CFTZPeriod)); | |
372 | abbrs = CFAllocatorAllocate(allocator, (charcnt + 1) * sizeof(CFStringRef), 0); | |
d8925383 | 373 | if (__CFOASafe) __CFSetLastAllocationEventName(abbrs, "CFTimeZone (temp)"); |
9ce05555 A |
374 | for (idx = 0; idx < charcnt + 1; idx++) { |
375 | abbrs[idx] = NULL; | |
376 | } | |
377 | for (idx = 0; idx < cnt; idx++) { | |
378 | CFAbsoluteTime at; | |
379 | int32_t itime, offset; | |
380 | uint8_t type, dst, abbridx; | |
381 | ||
382 | at = (CFAbsoluteTime)(__CFDetzcode(timep) + 0.0) - kCFAbsoluteTimeIntervalSince1970; | |
383 | if (0 == timecnt) itime = INT_MIN; | |
384 | else if (at < (CFAbsoluteTime)INT_MIN) itime = INT_MIN; | |
385 | else if ((CFAbsoluteTime)INT_MAX < at) itime = INT_MAX; | |
386 | else itime = (int32_t)at; | |
387 | timep += 4; /* harmless if 0 == timecnt */ | |
388 | type = (0 < timecnt) ? (uint8_t)*typep++ : 0; | |
389 | if (typecnt <= type) { | |
390 | result = false; | |
391 | break; | |
392 | } | |
393 | offset = __CFDetzcode(ttisp + 6 * type); | |
394 | dst = (uint8_t)*(ttisp + 6 * type + 4); | |
395 | if (0 != dst && 1 != dst) { | |
396 | result = false; | |
397 | break; | |
398 | } | |
399 | abbridx = (uint8_t)*(ttisp + 6 * type + 5); | |
400 | if (charcnt < abbridx) { | |
401 | result = false; | |
402 | break; | |
403 | } | |
404 | if (NULL == abbrs[abbridx]) { | |
405 | abbrs[abbridx] = CFStringCreateWithCString(allocator, &charp[abbridx], kCFStringEncodingASCII); | |
406 | } | |
407 | __CFTZPeriodInit(*tzpp + idx, itime, abbrs[abbridx], offset, (dst ? true : false)); | |
408 | } | |
409 | for (idx = 0; idx < charcnt + 1; idx++) { | |
410 | if (NULL != abbrs[idx]) { | |
411 | CFRelease(abbrs[idx]); | |
412 | } | |
413 | } | |
414 | CFAllocatorDeallocate(allocator, abbrs); | |
415 | if (result) { | |
416 | // dump all but the last INT_MIN and the first INT_MAX | |
417 | for (idx = 0; idx < cnt; idx++) { | |
418 | if (((*tzpp + idx)->startSec == INT_MIN) && (idx + 1 < cnt) && (((*tzpp + idx + 1)->startSec == INT_MIN))) { | |
d8925383 | 419 | if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); |
9ce05555 A |
420 | cnt--; |
421 | memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); | |
422 | idx--; | |
423 | } | |
424 | } | |
425 | // Don't combine these loops! Watch the idx decrementing... | |
426 | for (idx = 0; idx < cnt; idx++) { | |
427 | if (((*tzpp + idx)->startSec == INT_MAX) && (0 < idx) && (((*tzpp + idx - 1)->startSec == INT_MAX))) { | |
d8925383 | 428 | if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); |
9ce05555 A |
429 | cnt--; |
430 | memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); | |
431 | idx--; | |
432 | } | |
433 | } | |
434 | CFQSortArray(*tzpp, cnt, sizeof(CFTZPeriod), __CFCompareTZPeriods, NULL); | |
435 | *cntp = cnt; | |
436 | } else { | |
437 | CFAllocatorDeallocate(allocator, *tzpp); | |
438 | *tzpp = NULL; | |
439 | } | |
440 | return result; | |
441 | #else | |
442 | /* We use Win32 function to find TimeZone | |
443 | * (Aleksey Dukhnyakov) | |
444 | */ | |
445 | *tzpp = CFAllocatorAllocate(allocator, sizeof(CFTZPeriod), 0); | |
446 | __CFTZPeriodInit(*tzpp, 0, NULL, 0, false); | |
447 | *cntp = 1; | |
448 | return TRUE; | |
449 | #endif | |
450 | } | |
451 | ||
452 | static Boolean __CFTimeZoneEqual(CFTypeRef cf1, CFTypeRef cf2) { | |
453 | CFTimeZoneRef tz1 = (CFTimeZoneRef)cf1; | |
454 | CFTimeZoneRef tz2 = (CFTimeZoneRef)cf2; | |
455 | if (!CFEqual(CFTimeZoneGetName(tz1), CFTimeZoneGetName(tz2))) return false; | |
456 | if (!CFEqual(CFTimeZoneGetData(tz1), CFTimeZoneGetData(tz2))) return false; | |
457 | return true; | |
458 | } | |
459 | ||
460 | static CFHashCode __CFTimeZoneHash(CFTypeRef cf) { | |
461 | CFTimeZoneRef tz = (CFTimeZoneRef)cf; | |
462 | return CFHash(CFTimeZoneGetName(tz)); | |
463 | } | |
464 | ||
465 | static CFStringRef __CFTimeZoneCopyDescription(CFTypeRef cf) { | |
466 | CFTimeZoneRef tz = (CFTimeZoneRef)cf; | |
467 | CFStringRef result, abbrev; | |
468 | CFAbsoluteTime at; | |
469 | at = CFAbsoluteTimeGetCurrent(); | |
470 | abbrev = CFTimeZoneCopyAbbreviation(tz, at); | |
471 | result = CFStringCreateWithFormat(kCFAllocatorDefault, 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"); | |
472 | CFRelease(abbrev); | |
473 | return result; | |
474 | } | |
475 | ||
476 | static void __CFTimeZoneDeallocate(CFTypeRef cf) { | |
477 | CFTimeZoneRef tz = (CFTimeZoneRef)cf; | |
478 | CFAllocatorRef allocator = CFGetAllocator(tz); | |
479 | CFIndex idx; | |
480 | if (tz->_name) CFRelease(tz->_name); | |
481 | if (tz->_data) CFRelease(tz->_data); | |
482 | for (idx = 0; idx < tz->_periodCnt; idx++) { | |
483 | if (NULL != tz->_periods[idx].abbrev) CFRelease(tz->_periods[idx].abbrev); | |
484 | } | |
485 | if (NULL != tz->_periods) CFAllocatorDeallocate(allocator, tz->_periods); | |
486 | } | |
487 | ||
488 | static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID; | |
489 | ||
490 | static const CFRuntimeClass __CFTimeZoneClass = { | |
491 | 0, | |
492 | "CFTimeZone", | |
493 | NULL, // init | |
494 | NULL, // copy | |
495 | __CFTimeZoneDeallocate, | |
496 | __CFTimeZoneEqual, | |
497 | __CFTimeZoneHash, | |
498 | NULL, // | |
499 | __CFTimeZoneCopyDescription | |
500 | }; | |
501 | ||
502 | __private_extern__ void __CFTimeZoneInitialize(void) { | |
503 | __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass); | |
504 | } | |
505 | ||
506 | CFTypeID CFTimeZoneGetTypeID(void) { | |
507 | return __kCFTimeZoneTypeID; | |
508 | } | |
509 | ||
510 | static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { | |
511 | CFTimeZoneRef result = NULL; | |
512 | #if defined(__WIN32__) | |
513 | /* The GetTimeZoneInformation function retrieves the current | |
514 | * time-zone parameters for Win32 | |
515 | * (Aleksey Dukhnyakov) | |
516 | */ | |
517 | CFDataRef data; | |
518 | TIME_ZONE_INFORMATION tz; | |
519 | DWORD dw_result; | |
520 | dw_result=GetTimeZoneInformation(&tz); | |
521 | ||
522 | if ( dw_result == TIME_ZONE_ID_STANDARD || | |
523 | dw_result == TIME_ZONE_ID_DAYLIGHT ) { | |
524 | CFStringRef name = CFStringCreateWithCharacters(kCFAllocatorDefault, tz.StandardName, wcslen(tz.StandardName)); | |
525 | data = CFDataCreate(kCFAllocatorDefault, (UInt8*)&tz, sizeof(tz)); | |
526 | result = CFTimeZoneCreate(kCFAllocatorSystemDefault, name, data); | |
527 | CFRelease(name); | |
528 | CFRelease(data); | |
529 | if (result) return result; | |
530 | } | |
531 | #else | |
532 | char *tzenv; | |
533 | int ret; | |
534 | char linkbuf[CFMaxPathSize]; | |
535 | ||
536 | tzenv = getenv("TZFILE"); | |
537 | if (NULL != tzenv) { | |
538 | CFStringRef name = CFStringCreateWithBytes(kCFAllocatorDefault, tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); | |
539 | result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); | |
540 | CFRelease(name); | |
541 | if (result) return result; | |
542 | } | |
543 | tzenv = getenv("TZ"); | |
544 | if (NULL != tzenv) { | |
545 | CFStringRef name = CFStringCreateWithBytes(kCFAllocatorDefault, tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); | |
546 | result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true); | |
547 | CFRelease(name); | |
548 | if (result) return result; | |
549 | } | |
550 | ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf)); | |
551 | if (0 < ret) { | |
552 | CFStringRef name; | |
553 | linkbuf[ret] = '\0'; | |
554 | if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) { | |
555 | name = CFStringCreateWithBytes(kCFAllocatorDefault, linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false); | |
556 | } else { | |
557 | name = CFStringCreateWithBytes(kCFAllocatorDefault, linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false); | |
558 | } | |
559 | result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); | |
560 | CFRelease(name); | |
561 | if (result) return result; | |
562 | } | |
563 | #endif | |
564 | return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); | |
565 | } | |
566 | ||
567 | CFTimeZoneRef CFTimeZoneCopySystem(void) { | |
568 | CFTimeZoneRef tz; | |
569 | __CFTimeZoneLockGlobal(); | |
570 | if (NULL == __CFTimeZoneSystem) { | |
571 | __CFTimeZoneUnlockGlobal(); | |
572 | tz = __CFTimeZoneCreateSystem(); | |
573 | __CFTimeZoneLockGlobal(); | |
574 | if (NULL == __CFTimeZoneSystem) { | |
575 | __CFTimeZoneSystem = tz; | |
576 | } else { | |
577 | if (tz) CFRelease(tz); | |
578 | } | |
579 | } | |
580 | tz = __CFTimeZoneSystem ? CFRetain(__CFTimeZoneSystem) : NULL; | |
581 | __CFTimeZoneUnlockGlobal(); | |
582 | return tz; | |
583 | } | |
584 | ||
585 | void CFTimeZoneResetSystem(void) { | |
586 | __CFTimeZoneLockGlobal(); | |
587 | if (__CFTimeZoneDefault == __CFTimeZoneSystem) { | |
588 | if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); | |
589 | __CFTimeZoneDefault = NULL; | |
590 | } | |
591 | if (__CFTimeZoneSystem) CFRelease(__CFTimeZoneSystem); | |
592 | __CFTimeZoneSystem = NULL; | |
593 | __CFTimeZoneUnlockGlobal(); | |
594 | } | |
595 | ||
596 | CFTimeZoneRef CFTimeZoneCopyDefault(void) { | |
597 | CFTimeZoneRef tz; | |
598 | __CFTimeZoneLockGlobal(); | |
599 | if (NULL == __CFTimeZoneDefault) { | |
600 | __CFTimeZoneUnlockGlobal(); | |
601 | tz = CFTimeZoneCopySystem(); | |
602 | __CFTimeZoneLockGlobal(); | |
603 | if (NULL == __CFTimeZoneDefault) { | |
604 | __CFTimeZoneDefault = tz; | |
605 | } else { | |
606 | if (tz) CFRelease(tz); | |
607 | } | |
608 | } | |
609 | tz = __CFTimeZoneDefault ? CFRetain(__CFTimeZoneDefault) : NULL; | |
610 | __CFTimeZoneUnlockGlobal(); | |
611 | return tz; | |
612 | } | |
613 | ||
614 | void CFTimeZoneSetDefault(CFTimeZoneRef tz) { | |
615 | __CFGenericValidateType(tz, __kCFTimeZoneTypeID); | |
616 | __CFTimeZoneLockGlobal(); | |
617 | if (tz != __CFTimeZoneDefault) { | |
618 | if (tz) CFRetain(tz); | |
619 | if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); | |
620 | __CFTimeZoneDefault = tz; | |
621 | } | |
622 | __CFTimeZoneUnlockGlobal(); | |
623 | } | |
624 | ||
625 | static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void); | |
626 | ||
627 | CFArrayRef CFTimeZoneCopyKnownNames(void) { | |
628 | CFArrayRef tzs; | |
629 | __CFTimeZoneLockGlobal(); | |
630 | if (NULL == __CFKnownTimeZoneList) { | |
631 | CFMutableArrayRef list; | |
632 | /* TimeZone information locate in the registry for Win32 | |
633 | * (Aleksey Dukhnyakov) | |
634 | */ | |
635 | #if !defined(__WIN32__) | |
636 | list = __CFCopyRecursiveDirectoryList(TZZONEINFO); | |
637 | #else | |
638 | list = __CFCopyWindowsTimeZoneList(); | |
639 | #endif | |
640 | // Remove undesirable ancient cruft | |
641 | CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); | |
642 | CFIndex idx; | |
643 | for (idx = CFArrayGetCount(list); idx--; ) { | |
644 | CFStringRef item = CFArrayGetValueAtIndex(list, idx); | |
645 | if (CFDictionaryContainsKey(dict, item)) { | |
646 | CFArrayRemoveValueAtIndex(list, idx); | |
647 | } | |
648 | } | |
649 | __CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list); | |
650 | CFRelease(list); | |
651 | } | |
652 | tzs = __CFKnownTimeZoneList ? CFRetain(__CFKnownTimeZoneList) : NULL; | |
653 | __CFTimeZoneUnlockGlobal(); | |
654 | return tzs; | |
655 | } | |
656 | ||
657 | static const unsigned char *__CFTimeZoneAbbreviationDefaults = | |
658 | #if defined(__WIN32__) | |
659 | /* | |
660 | * TimeZone abbreviations for Win32 | |
661 | * (Andrew Dzubandovsky) | |
662 | * | |
663 | */ | |
664 | "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | |
665 | " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">" | |
666 | " <plist version=\"1.0\">" | |
667 | " <dict>" | |
668 | " <key>AFG</key> <string>Afghanistan Standard Time</string>" | |
669 | " <key>ALS</key> <string>Alaskan Standard Time</string>" | |
670 | " <key>ARA</key> <string>Arab Standard Time</string>" | |
671 | " <key>ARB</key> <string>Arabian Standard Time</string>" | |
672 | " <key>ARC</key> <string>Arabic Standard Time</string>" | |
673 | " <key>ATL</key> <string>Atlantic Standard Time</string>" | |
674 | " <key>ASC</key> <string>AUS Central Standard Time</string>" | |
675 | " <key>ASE</key> <string>AUS Eastern Standard Time</string>" | |
676 | " <key>AZS</key> <string>Azores Standard Time</string>" | |
677 | " <key>CND</key> <string>Canada Central Standard Time</string>" | |
678 | " <key>CPV</key> <string>Cape Verde Standard Time</string>" | |
679 | " <key>CCS</key> <string>Caucasus Standard Time</string>" | |
680 | " <key>CNAS</key> <string>Cen. Australia Standard Time</string>" | |
681 | " <key>CAMR</key> <string>Central America Standard Time</string>" | |
682 | " <key>CAS</key> <string>Central Asia Standard Time</string>" | |
683 | " <key>CER</key> <string>Central Europe Standard Time</string>" | |
684 | " <key>CEPN</key> <string>Central European Standard Time</string>" | |
685 | " <key>CPC</key> <string>Central Pacific Standard Time</string>" | |
686 | " <key>CSTD</key> <string>Central Standard Time</string>" | |
687 | " <key>CHN</key> <string>China Standard Time</string>" | |
688 | " <key>DTLN</key> <string>Dateline Standard Time</string>" | |
689 | " <key>EAFR</key> <string>E. Africa Standard Time</string>" | |
690 | " <key>EAS</key> <string>E. Australia Standard Time</string>" | |
691 | " <key>ERP</key> <string>E. Europe Standard Time</string>" | |
692 | " <key>ESTH</key> <string>E. South America Standard Time</string>" | |
693 | " <key>ESTM</key> <string>Eastern Standard Time</string>" | |
694 | " <key>EGP</key> <string>Egypt Standard Time</string>" | |
695 | " <key>EKT</key> <string>Ekaterinburg Standard Time</string>" | |
696 | " <key>FST</key> <string>Fiji Standard Time</string>" | |
697 | " <key>FLE</key> <string>FLE Standard Time</string>" | |
698 | " <key>GMT</key> <string>GMT Standard Time</string>" | |
699 | " <key>GRLD</key> <string>Greenland Standard Time</string>" | |
700 | " <key>GRW</key> <string>Greenwich Standard Time</string>" | |
701 | " <key>GTB</key> <string>GTB Standard Time</string>" | |
702 | " <key>HWT</key> <string>Hawaiian Standard Time</string>" | |
703 | " <key>INT</key> <string>India Standard Time</string>" | |
704 | " <key>IRT</key> <string>Iran Standard Time</string>" | |
705 | " <key>ISL</key> <string>Israel Standard Time</string>" | |
706 | " <key>KRT</key> <string>Korea Standard Time</string>" | |
707 | " <key>MXST</key> <string>Mexico Standard Time</string>" | |
708 | " <key>MTL</key> <string>Mid-Atlantic Standard Time</string>" | |
709 | " <key>MNT</key> <string>Mountain Standard Time</string>" | |
710 | " <key>MNM</key> <string>Myanmar Standard Time</string>" | |
711 | " <key>NCNA</key> <string>N. Central Asia Standard Time</string>" | |
712 | " <key>MPL</key> <string>Nepal Standard Time</string>" | |
713 | " <key>NWZ</key> <string>New Zealand Standard Time</string>" | |
714 | " <key>NWF</key> <string>Newfoundland Standard Time</string>" | |
715 | " <key>NTAE</key> <string>North Asia East Standard Time</string>" | |
716 | " <key>NTAS</key> <string>North Asia Standard Time</string>" | |
717 | " <key>HSAT</key> <string>Pacific SA Standard Time</string>" | |
718 | " <key>PST</key> <string>Pacific Standard Time</string>" | |
719 | " <key>RMC</key> <string>Romance Standard Time</string>" | |
720 | " <key>MSK</key> <string>Russian Standard Time</string>" | |
721 | " <key>SSS</key> <string>SA Eastern Standard Time</string>" | |
722 | " <key>SPS</key> <string>SA Pacific Standard Time</string>" | |
723 | " <key>SWS</key> <string>SA Western Standard Time</string>" | |
724 | " <key>SMS</key> <string>Samoa Standard Time</string>" | |
725 | " <key>SAS</key> <string>SE Asia Standard Time</string>" | |
726 | " <key>SNG</key> <string>Singapore Standard Time</string>" | |
727 | " <key>STAF</key> <string>South Africa Standard Time</string>" | |
728 | " <key>SRLK</key> <string>Sri Lanka Standard Time</string>" | |
729 | " <key>TPS</key> <string>Taipei Standard Time</string>" | |
730 | " <key>TSM</key> <string>Tasmania Standard Time</string>" | |
731 | " <key>JPN</key> <string>Tokyo Standard Time</string>" | |
732 | " <key>TNG</key> <string>Tonga Standard Time</string>" | |
733 | " <key>AEST</key> <string>US Eastern Standard Time</string>" | |
734 | " <key>AMST</key> <string>US Mountain Standard Time</string>" | |
735 | " <key>VLD</key> <string>Vladivostok Standard Time</string>" | |
736 | " <key>AUSW</key> <string>W. Australia Standard Time</string>" | |
737 | " <key>AFCW</key> <string>W. Central Africa Standard Time</string>" | |
738 | " <key>EWS</key> <string>W. Europe Standard Time</string>" | |
739 | " <key>ASW</key> <string>West Asia Standard Time</string>" | |
740 | " <key>PWS</key> <string>West Pacific Standard Time</string>" | |
741 | " <key>RKS</key> <string>Yakutsk Standard Time</string>" | |
742 | " </dict>" | |
743 | " </plist>"; | |
744 | #else | |
745 | "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" | |
746 | " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">" | |
747 | " <plist version=\"1.0\">" | |
748 | " <dict>" | |
749 | " <key>ADT</key> <string>America/Halifax</string>" | |
750 | " <key>AFT</key> <string>Asia/Kabul</string>" | |
751 | " <key>AKDT</key> <string>America/Juneau</string>" | |
752 | " <key>AKST</key> <string>America/Juneau</string>" | |
753 | " <key>AST</key> <string>America/Halifax</string>" | |
754 | " <key>CDT</key> <string>America/Chicago</string>" | |
755 | " <key>CEST</key> <string>Europe/Rome</string>" | |
756 | " <key>CET</key> <string>Europe/Rome</string>" | |
757 | " <key>CST</key> <string>America/Chicago</string>" | |
758 | " <key>EDT</key> <string>America/New_York</string>" | |
759 | " <key>EEST</key> <string>Europe/Warsaw</string>" | |
760 | " <key>EET</key> <string>Europe/Warsaw</string>" | |
761 | " <key>EST</key> <string>America/New_York</string>" | |
762 | " <key>GMT</key> <string>GMT</string>" | |
763 | " <key>HKST</key> <string>Asia/Hong_Kong</string>" | |
764 | " <key>HST</key> <string>Pacific/Honolulu</string>" | |
765 | " <key>JST</key> <string>Asia/Tokyo</string>" | |
766 | " <key>MDT</key> <string>America/Denver</string>" | |
767 | " <key>MSD</key> <string>Europe/Moscow</string>" | |
768 | " <key>MSK</key> <string>Europe/Moscow</string>" | |
769 | " <key>MST</key> <string>America/Denver</string>" | |
770 | " <key>NZDT</key> <string>Pacific/Auckland</string>" | |
771 | " <key>NZST</key> <string>Pacific/Auckland</string>" | |
772 | " <key>PDT</key> <string>America/Los_Angeles</string>" | |
773 | " <key>PST</key> <string>America/Los_Angeles</string>" | |
774 | " <key>UTC</key> <string>UTC</string>" | |
775 | " <key>WEST</key> <string>Europe/Paris</string>" | |
776 | " <key>WET</key> <string>Europe/Paris</string>" | |
777 | " <key>YDT</key> <string>America/Yakutat</string>" | |
778 | " <key>YST</key> <string>America/Yakutat</string>" | |
779 | " </dict>" | |
780 | " </plist>"; | |
781 | #endif | |
782 | ||
783 | CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) { | |
784 | CFDictionaryRef dict; | |
785 | __CFTimeZoneLockAbbreviations(); | |
786 | if (NULL == __CFTimeZoneAbbreviationDict) { | |
787 | CFDataRef data = CFDataCreate(kCFAllocatorDefault, __CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults)); | |
788 | __CFTimeZoneAbbreviationDict = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL); | |
789 | CFRelease(data); | |
790 | } | |
791 | if (NULL == __CFTimeZoneAbbreviationDict) { | |
792 | __CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, NULL, NULL); | |
793 | } | |
794 | dict = __CFTimeZoneAbbreviationDict ? CFRetain(__CFTimeZoneAbbreviationDict) : NULL; | |
795 | __CFTimeZoneUnlockAbbreviations(); | |
796 | return dict; | |
797 | } | |
798 | ||
799 | void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) { | |
800 | __CFGenericValidateType(dict, CFDictionaryGetTypeID()); | |
801 | __CFTimeZoneLockGlobal(); | |
802 | if (dict != __CFTimeZoneAbbreviationDict) { | |
803 | if (dict) CFRetain(dict); | |
804 | if (__CFTimeZoneAbbreviationDict) CFRelease(__CFTimeZoneAbbreviationDict); | |
805 | __CFTimeZoneAbbreviationDict = dict; | |
806 | } | |
807 | __CFTimeZoneUnlockGlobal(); | |
808 | } | |
809 | ||
810 | CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) { | |
811 | // assert: (NULL != name && NULL != data); | |
812 | CFTimeZoneRef memory; | |
813 | uint32_t size; | |
814 | CFTZPeriod *tzp; | |
815 | CFIndex idx, cnt; | |
816 | ||
817 | if (allocator == NULL) allocator = __CFGetDefaultAllocator(); | |
818 | __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); | |
819 | __CFGenericValidateType(name, CFStringGetTypeID()); | |
820 | __CFGenericValidateType(data, CFDataGetTypeID()); | |
821 | __CFTimeZoneLockGlobal(); | |
822 | if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) { | |
823 | __CFTimeZoneUnlockGlobal(); | |
824 | return (CFTimeZoneRef)CFRetain(memory); | |
825 | } | |
826 | if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) { | |
827 | __CFTimeZoneUnlockGlobal(); | |
828 | return NULL; | |
829 | } | |
830 | size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase); | |
831 | memory = _CFRuntimeCreateInstance(allocator, __kCFTimeZoneTypeID, size, NULL); | |
832 | if (NULL == memory) { | |
833 | __CFTimeZoneUnlockGlobal(); | |
834 | for (idx = 0; idx < cnt; idx++) { | |
835 | if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev); | |
836 | } | |
837 | if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp); | |
838 | return NULL; | |
839 | } | |
d8925383 A |
840 | ((struct __CFTimeZone *)memory)->_name = CFStringCreateCopy(allocator, name); |
841 | ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data); | |
9ce05555 A |
842 | ((struct __CFTimeZone *)memory)->_periods = tzp; |
843 | ((struct __CFTimeZone *)memory)->_periodCnt = cnt; | |
844 | if (NULL == __CFTimeZoneCache) { | |
d8925383 A |
845 | CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks; |
846 | kcb.retain = kcb.release = NULL; | |
847 | __CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kcb, &kCFTypeDictionaryValueCallBacks); | |
9ce05555 | 848 | } |
d8925383 | 849 | CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory); |
9ce05555 A |
850 | __CFTimeZoneUnlockGlobal(); |
851 | return memory; | |
852 | } | |
853 | ||
d8925383 | 854 | #if !defined(__WIN32__) |
9ce05555 A |
855 | static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { |
856 | CFTimeZoneRef result; | |
857 | CFDataRef data; | |
858 | int32_t nameLen = CFStringGetLength(name); | |
859 | #if defined(__WIN32__) | |
860 | unsigned char *dataBytes = CFAllocatorAllocate(allocator, 52 + nameLen + 1, 0); | |
861 | if (!dataBytes) return NULL; | |
d8925383 | 862 | if (__CFOASafe) __CFSetLastAllocationEventName(dataBytes, "CFTimeZone (temp)"); |
9ce05555 A |
863 | #else |
864 | unsigned char dataBytes[52 + nameLen + 1]; | |
865 | #endif | |
866 | memset(dataBytes, 0, sizeof(dataBytes)); | |
47a9ab1f A |
867 | |
868 | // Put in correct magic bytes for timezone structures | |
869 | dataBytes[0] = 'T'; | |
870 | dataBytes[1] = 'Z'; | |
871 | dataBytes[2] = 'i'; | |
872 | dataBytes[3] = 'f'; | |
873 | ||
9ce05555 A |
874 | __CFEntzcode(1, dataBytes + 20); |
875 | __CFEntzcode(1, dataBytes + 24); | |
876 | __CFEntzcode(1, dataBytes + 36); | |
877 | __CFEntzcode(nameLen + 1, dataBytes + 40); | |
878 | __CFEntzcode(seconds, dataBytes + 44); | |
879 | dataBytes[48] = isDST ? 1 : 0; | |
880 | CFStringGetCString(name, dataBytes + 50, nameLen + 1, kCFStringEncodingASCII); | |
881 | data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1); | |
882 | result = CFTimeZoneCreate(allocator, name, data); | |
883 | CFRelease(data); | |
884 | #if defined(__WIN32__) | |
885 | CFAllocatorDeallocate(allocator, dataBytes); | |
886 | #endif | |
887 | return result; | |
888 | } | |
d8925383 | 889 | #endif |
9ce05555 A |
890 | |
891 | // rounds offset to nearest minute | |
892 | CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) { | |
893 | CFTimeZoneRef result; | |
894 | CFStringRef name; | |
895 | int32_t seconds, minute, hour; | |
896 | if (allocator == NULL) allocator = __CFGetDefaultAllocator(); | |
897 | __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); | |
898 | if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL; | |
899 | ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0; | |
900 | seconds = (int32_t)ti; | |
901 | hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600); | |
902 | seconds -= ((ti < 0) ? -hour : hour) * 3600; | |
903 | minute = (ti < 0) ? (-seconds / 60) : (seconds / 60); | |
904 | if (fabs(ti) < 1.0) { | |
905 | name = CFRetain(CFSTR("GMT")); | |
906 | } else { | |
907 | name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute); | |
908 | } | |
909 | #if !defined(__WIN32__) | |
910 | result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0); | |
911 | #else | |
912 | /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure | |
913 | * to find current timezone | |
914 | * (Aleksey Dukhnyakov) | |
915 | */ | |
916 | { | |
917 | TIME_ZONE_INFORMATION tzi; | |
918 | CFDataRef data; | |
919 | CFIndex length = CFStringGetLength(name); | |
920 | ||
921 | memset(&tzi,0,sizeof(tzi)); | |
922 | tzi.Bias=(long)(-ti/60); | |
923 | CFStringGetCharacters(name, CFRangeMake(0, length < 31 ? length : 31 ), tzi.StandardName); | |
924 | data = CFDataCreate(allocator,(UInt8*)&tzi, sizeof(tzi)); | |
925 | result = CFTimeZoneCreate(allocator, name, data); | |
926 | CFRelease(data); | |
927 | } | |
928 | #endif | |
929 | CFRelease(name); | |
930 | return result; | |
931 | } | |
932 | ||
933 | CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) { | |
934 | CFTimeZoneRef result = NULL; | |
935 | CFStringRef tzName = NULL; | |
936 | CFDataRef data = NULL; | |
9ce05555 A |
937 | |
938 | if (allocator == NULL) allocator = __CFGetDefaultAllocator(); | |
939 | __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); | |
940 | __CFGenericValidateType(name, CFStringGetTypeID()); | |
941 | if (CFEqual(CFSTR(""), name)) { | |
942 | // empty string is not a time zone name, just abort now, | |
943 | // following stuff will fail anyway | |
944 | return NULL; | |
945 | } | |
946 | __CFTimeZoneLockGlobal(); | |
947 | if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) { | |
948 | __CFTimeZoneUnlockGlobal(); | |
949 | return (CFTimeZoneRef)CFRetain(result); | |
950 | } | |
951 | __CFTimeZoneUnlockGlobal(); | |
952 | #if !defined(__WIN32__) | |
d8925383 A |
953 | CFURLRef baseURL, tempURL; |
954 | void *bytes; | |
955 | CFIndex length; | |
956 | ||
9ce05555 A |
957 | baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true); |
958 | if (tryAbbrev) { | |
959 | CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); | |
960 | tzName = CFDictionaryGetValue(abbrevs, name); | |
961 | if (NULL != tzName) { | |
962 | tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, baseURL, tzName, false); | |
963 | if (NULL != tempURL) { | |
964 | if (_CFReadBytesFromFile(kCFAllocatorDefault, tempURL, &bytes, &length, 0)) { | |
965 | data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorDefault); | |
966 | } | |
967 | CFRelease(tempURL); | |
968 | } | |
969 | } | |
970 | CFRelease(abbrevs); | |
971 | } | |
972 | if (NULL == data) { | |
973 | CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); | |
974 | CFStringRef mapping = CFDictionaryGetValue(dict, name); | |
975 | if (mapping) { | |
976 | name = mapping; | |
977 | } else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) { | |
978 | CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(name), name); | |
979 | CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO))); | |
980 | mapping = CFDictionaryGetValue(dict, unprefixed); | |
981 | if (mapping) { | |
982 | name = mapping; | |
983 | } | |
984 | CFRelease(unprefixed); | |
985 | } | |
986 | CFRelease(dict); | |
987 | if (CFEqual(CFSTR(""), name)) { | |
988 | return NULL; | |
989 | } | |
990 | } | |
991 | if (NULL == data) { | |
992 | tzName = name; | |
993 | tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, baseURL, tzName, false); | |
994 | if (NULL != tempURL) { | |
995 | if (_CFReadBytesFromFile(kCFAllocatorDefault, tempURL, &bytes, &length, 0)) { | |
996 | data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorDefault); | |
997 | } | |
998 | CFRelease(tempURL); | |
999 | } | |
1000 | } | |
1001 | CFRelease(baseURL); | |
1002 | if (NULL == data) { | |
1003 | tzName = name; | |
1004 | tempURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, tzName, kCFURLPOSIXPathStyle, false); | |
1005 | if (NULL != tempURL) { | |
1006 | if (_CFReadBytesFromFile(kCFAllocatorDefault, tempURL, &bytes, &length, 0)) { | |
1007 | data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorDefault); | |
1008 | } | |
1009 | CFRelease(tempURL); | |
1010 | } | |
1011 | } | |
1012 | if (NULL != data) { | |
1013 | result = CFTimeZoneCreate(allocator, tzName, data); | |
1014 | CFRelease(data); | |
1015 | } | |
1016 | #else | |
1017 | /* Reading GMT offset and daylight flag from the registry | |
1018 | * for TimeZone name | |
1019 | * (Aleksey Dukhnyakov) | |
1020 | */ | |
1021 | { | |
1022 | CFStringRef safeName = name; | |
1023 | struct { | |
1024 | LONG Bias; | |
1025 | LONG StandardBias; | |
1026 | LONG DaylightBias; | |
1027 | SYSTEMTIME StandardDate; | |
1028 | SYSTEMTIME DaylightDate; | |
1029 | } tzi; | |
1030 | TIME_ZONE_INFORMATION tzi_system; | |
1031 | ||
1032 | HKEY hkResult; | |
1033 | DWORD dwType, dwSize=sizeof(tzi), | |
1034 | dwSize_name1=sizeof(tzi_system.StandardName), | |
1035 | dwSize_name2=sizeof(tzi_system.DaylightName); | |
1036 | ||
1037 | if (tryAbbrev) { | |
1038 | CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); | |
1039 | tzName = CFDictionaryGetValue(abbrevs, name); | |
1040 | if (NULL == tzName) { | |
1041 | return NULL; | |
1042 | } | |
1043 | name = tzName; | |
1044 | CFRelease(abbrevs); | |
1045 | } | |
1046 | ||
1047 | /* Open regestry and move down to the TimeZone information | |
1048 | */ | |
1049 | if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) != | |
1050 | ERROR_SUCCESS ) { | |
1051 | return NULL; | |
1052 | } | |
1053 | /* Move down to specific TimeZone name | |
1054 | */ | |
1055 | #if defined(UNICODE) | |
1056 | if (RegOpenKey(hkResult,CFStringGetCharactersPtr(name) ,&hkResult) != | |
1057 | ERROR_SUCCESS ) { | |
1058 | #else | |
1059 | if (RegOpenKey(hkResult,CFStringGetCStringPtr(name, CFStringGetSystemEncoding()),&hkResult) != ERROR_SUCCESS ) { | |
1060 | #endif | |
1061 | return NULL; | |
1062 | } | |
1063 | /* TimeZone information(offsets, daylight flag, ...) assign to tzi structure | |
1064 | */ | |
1065 | if ( RegQueryValueEx(hkResult,_T("TZI"),NULL,&dwType,(LPBYTE)&tzi,&dwSize) != ERROR_SUCCESS && | |
1066 | RegQueryValueEx(hkResult,_T("Std"),NULL,&dwType,(LPBYTE)&tzi_system.StandardName,&dwSize_name1) != ERROR_SUCCESS && | |
1067 | RegQueryValueEx(hkResult,_T("Dlt"),NULL,&dwType,(LPBYTE)&tzi_system.DaylightName,&dwSize_name2) != ERROR_SUCCESS ) | |
1068 | { | |
1069 | return NULL; | |
1070 | } | |
1071 | ||
1072 | tzi_system.Bias=tzi.Bias; | |
1073 | tzi_system.StandardBias=tzi.StandardBias; | |
1074 | tzi_system.DaylightBias=tzi.DaylightBias; | |
1075 | tzi_system.StandardDate=tzi.StandardDate; | |
1076 | tzi_system.DaylightDate=tzi.DaylightDate; | |
1077 | ||
1078 | /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure | |
1079 | * to find current timezone | |
1080 | * (Aleksey Dukhnyakov) | |
1081 | */ | |
1082 | data = CFDataCreate(allocator,(UInt8*)&tzi_system, sizeof(tzi_system)); | |
1083 | ||
1084 | RegCloseKey(hkResult); | |
1085 | result = CFTimeZoneCreate(allocator, name, data); | |
1086 | if (result) { | |
1087 | if (tryAbbrev) | |
1088 | result->_periods->abbrev = CFStringCreateCopy(allocator,safeName); | |
1089 | else { | |
1090 | } | |
1091 | } | |
1092 | CFRelease(data); | |
1093 | } | |
1094 | #endif | |
1095 | return result; | |
1096 | } | |
1097 | ||
1098 | CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) { | |
1099 | CF_OBJC_FUNCDISPATCH0(__kCFTimeZoneTypeID, CFStringRef, tz, "name"); | |
1100 | __CFGenericValidateType(tz, __kCFTimeZoneTypeID); | |
1101 | return tz->_name; | |
1102 | } | |
1103 | ||
1104 | CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) { | |
1105 | CF_OBJC_FUNCDISPATCH0(__kCFTimeZoneTypeID, CFDataRef, tz, "data"); | |
1106 | __CFGenericValidateType(tz, __kCFTimeZoneTypeID); | |
1107 | return tz->_data; | |
1108 | } | |
1109 | ||
1110 | /* This function converts CFAbsoluteTime to (Win32) SYSTEMTIME | |
1111 | * (Aleksey Dukhnyakov) | |
1112 | */ | |
1113 | #if defined(__WIN32__) | |
1114 | BOOL __CFTimeZoneGetWin32SystemTime(SYSTEMTIME * sys_time, CFAbsoluteTime time) | |
1115 | { | |
1116 | LONGLONG l; | |
1117 | FILETIME * ftime=(FILETIME*)&l; | |
1118 | ||
1119 | /* seconds between 1601 and 1970 : 11644473600, | |
1120 | * seconds between 1970 and 2001 : 978307200, | |
1121 | * FILETIME - number of 100-nanosecond intervals since January 1, 1601 | |
1122 | */ | |
d8925383 | 1123 | l=(time+11644473600LL+978307200)*10000000; |
9ce05555 A |
1124 | if (FileTimeToSystemTime(ftime,sys_time)) |
1125 | return TRUE; | |
1126 | else | |
1127 | return FALSE; | |
1128 | } | |
1129 | #endif | |
1130 | ||
d8925383 A |
1131 | CFTimeInterval _CFTimeZoneGetDSTOffset(CFTimeZoneRef tz, CFAbsoluteTime at) { |
1132 | #if !defined(__WIN32__) | |
1133 | // #warning this does not work for non-CFTimeZoneRefs | |
1134 | CFIndex idx; | |
1135 | idx = __CFBSearchTZPeriods(tz, at); | |
1136 | // idx 0 is never returned if it is in DST | |
1137 | if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) { | |
1138 | return __CFTZPeriodGMTOffset(&(tz->_periods[idx])) - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1])); | |
1139 | } | |
1140 | #endif | |
1141 | return 0.0; | |
1142 | } | |
1143 | ||
1144 | // returns 0.0 if there is no data for the next switch after 'at' | |
1145 | CFAbsoluteTime _CFTimeZoneGetNextDSTSwitch(CFTimeZoneRef tz, CFAbsoluteTime at) { | |
1146 | #if !defined(__WIN32__) | |
1147 | // #warning this does not work for non-CFTimeZoneRefs | |
1148 | CFIndex idx; | |
1149 | idx = __CFBSearchTZPeriods(tz, at); | |
1150 | if (tz->_periodCnt <= idx + 1) { | |
1151 | return 0.0; | |
1152 | } | |
1153 | return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1])); | |
1154 | #endif | |
1155 | return 0.0; | |
1156 | } | |
1157 | ||
9ce05555 A |
1158 | CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) { |
1159 | #if !defined(__WIN32__) | |
1160 | CFIndex idx; | |
1161 | CF_OBJC_FUNCDISPATCH1(__kCFTimeZoneTypeID, CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at); | |
1162 | __CFGenericValidateType(tz, __kCFTimeZoneTypeID); | |
1163 | idx = __CFBSearchTZPeriods(tz, at); | |
1164 | return __CFTZPeriodGMTOffset(&(tz->_periods[idx])); | |
1165 | #else | |
1166 | /* To calculate seconds from GMT, calculate current timezone time and | |
1167 | * subtract GMT timnezone time | |
1168 | * (Aleksey Dukhnyakov) | |
1169 | */ | |
1170 | TIME_ZONE_INFORMATION tzi; | |
1171 | FILETIME ftime1,ftime2; | |
1172 | SYSTEMTIME stime0,stime1,stime2; | |
1173 | LONGLONG * l1= (LONGLONG*)&ftime1; | |
1174 | LONGLONG * l2= (LONGLONG*)&ftime2; | |
1175 | CFRange range={0,sizeof(TIME_ZONE_INFORMATION)}; | |
1176 | double result; | |
1177 | ||
1178 | CF_OBJC_FUNCDISPATCH1(__kCFTimeZoneTypeID, CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at); | |
1179 | ||
1180 | CFDataGetBytes(tz->_data,range,(UInt8*)&tzi); | |
1181 | ||
1182 | if (!__CFTimeZoneGetWin32SystemTime(&stime0,at) || | |
1183 | !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime1) || | |
1184 | !SystemTimeToFileTime(&stime1,&ftime1) ) | |
1185 | { | |
1186 | CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); | |
1187 | return 0; | |
1188 | } | |
1189 | ||
1190 | tzi.DaylightDate.wMonth=0; | |
1191 | tzi.StandardDate.wMonth=0; | |
1192 | tzi.StandardBias=0; | |
1193 | tzi.DaylightBias=0; | |
1194 | tzi.Bias=0; | |
1195 | ||
1196 | if ( !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime2) || | |
1197 | !SystemTimeToFileTime(&stime2,&ftime2)) | |
1198 | { | |
1199 | CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); | |
1200 | return 0; | |
1201 | } | |
1202 | result=(double)((*l1-*l2)/10000000); | |
1203 | return result; | |
1204 | #endif | |
1205 | } | |
1206 | ||
1207 | #if defined(__WIN32__) | |
1208 | /* | |
1209 | * Get abbreviation for name for WIN32 platform | |
1210 | * (Aleksey Dukhnyakov) | |
1211 | */ | |
1212 | ||
1213 | typedef struct { | |
1214 | CFStringRef tzName; | |
1215 | CFStringRef tzAbbr; | |
1216 | } _CFAbbrFind; | |
1217 | ||
1218 | static void _CFFindKeyForValue(const void *key, const void *value, void *context) { | |
1219 | if ( ((_CFAbbrFind *)context)->tzAbbr != NULL ) { | |
1220 | if ( ((_CFAbbrFind *)context)->tzName == (CFStringRef) value ) { | |
1221 | ((_CFAbbrFind *)context)->tzAbbr = key ; | |
1222 | } | |
1223 | } | |
1224 | } | |
1225 | ||
1226 | CFIndex __CFTimeZoneInitAbbrev(CFTimeZoneRef tz) { | |
1227 | ||
1228 | if ( tz->_periods->abbrev == NULL ) { | |
1229 | _CFAbbrFind abbr = { NULL, NULL }; | |
1230 | CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); | |
1231 | ||
1232 | CFDictionaryApplyFunction(abbrevs, _CFFindKeyForValue, &abbr); | |
1233 | ||
1234 | if ( abbr.tzAbbr != NULL) | |
1235 | tz->_periods->abbrev = CFStringCreateCopy(kCFAllocatorDefault, abbr.tzAbbr); | |
1236 | else | |
1237 | tz->_periods->abbrev = CFStringCreateCopy(kCFAllocatorDefault, tz->_name); | |
1238 | /* We should return name of TimeZone if couldn't find abbrevation. | |
1239 | * (Ala on MACOSX) | |
1240 | * | |
1241 | * old line : tz->_periods->abbrev = | |
1242 | * CFStringCreateWithCString(kCFAllocatorDefault,"UNKNOWN", | |
1243 | * CFStringGetSystemEncoding()); | |
1244 | * | |
1245 | * (Aleksey Dukhnyakov) | |
1246 | */ | |
1247 | CFRelease( abbrevs ); | |
1248 | } | |
1249 | ||
1250 | return 0; | |
1251 | } | |
1252 | #endif | |
1253 | ||
1254 | CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) { | |
1255 | CFStringRef result; | |
1256 | CFIndex idx; | |
1257 | CF_OBJC_FUNCDISPATCH1(__kCFTimeZoneTypeID, CFStringRef, tz, "_abbreviationForAbsoluteTime:", at); | |
1258 | __CFGenericValidateType(tz, __kCFTimeZoneTypeID); | |
1259 | #if !defined(__WIN32__) | |
1260 | idx = __CFBSearchTZPeriods(tz, at); | |
1261 | #else | |
1262 | /* | |
1263 | * Initialize abbreviation for this TimeZone | |
1264 | * (Aleksey Dukhnyakov) | |
1265 | */ | |
1266 | idx = __CFTimeZoneInitAbbrev(tz); | |
1267 | #endif | |
1268 | result = __CFTZPeriodAbbreviation(&(tz->_periods[idx])); | |
1269 | return result ? CFRetain(result) : NULL; | |
1270 | } | |
1271 | ||
1272 | Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) { | |
1273 | #if !defined(__WIN32__) | |
1274 | CFIndex idx; | |
1275 | CF_OBJC_FUNCDISPATCH1(__kCFTimeZoneTypeID, Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at); | |
1276 | __CFGenericValidateType(tz, __kCFTimeZoneTypeID); | |
1277 | idx = __CFBSearchTZPeriods(tz, at); | |
1278 | return __CFTZPeriodIsDST(&(tz->_periods[idx])); | |
1279 | #else | |
1280 | /* Compare current timezone time and current timezone time without | |
1281 | * transition to day light saving time | |
1282 | * (Aleskey Dukhnyakov) | |
1283 | */ | |
1284 | TIME_ZONE_INFORMATION tzi; | |
1285 | SYSTEMTIME stime0,stime1,stime2; | |
1286 | CFRange range={0,sizeof(TIME_ZONE_INFORMATION)}; | |
1287 | ||
1288 | CF_OBJC_FUNCDISPATCH1(__kCFTimeZoneTypeID, Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at); | |
1289 | ||
1290 | CFDataGetBytes(tz->_data,range,(UInt8*)&tzi); | |
1291 | ||
1292 | if ( !__CFTimeZoneGetWin32SystemTime(&stime0,at) || | |
1293 | !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime1)) { | |
1294 | CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); | |
1295 | return FALSE; | |
1296 | } | |
1297 | ||
1298 | tzi.DaylightDate.wMonth=0; | |
1299 | tzi.StandardDate.wMonth=0; | |
1300 | ||
1301 | if ( !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime2)) { | |
1302 | CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); | |
1303 | return FALSE; | |
1304 | } | |
1305 | ||
1306 | if ( !memcmp(&stime1,&stime2,sizeof(stime1)) ) | |
1307 | return FALSE; | |
1308 | ||
1309 | return TRUE; | |
1310 | #endif | |
1311 | } | |
1312 | ||
1313 | CFTimeInterval _CFTimeZoneGetDSTDelta(CFTimeZoneRef tz, CFAbsoluteTime at) { | |
1314 | CFIndex idx; | |
1315 | __CFGenericValidateType(tz, __kCFTimeZoneTypeID); | |
1316 | idx = __CFBSearchTZPeriods(tz, at); | |
1317 | CFTimeInterval delta = __CFTZPeriodGMTOffset(&(tz->_periods[idx])); | |
1318 | if (idx + 1 < tz->_periodCnt) { | |
1319 | return fabs(delta - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1]))); | |
1320 | } else if (0 < idx) { | |
1321 | return fabs(delta - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1]))); | |
1322 | } | |
1323 | return 0.0; | |
1324 | } | |
1325 | ||
9ce05555 A |
1326 | static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) { |
1327 | CFDictionaryRef dict; | |
1328 | __CFTimeZoneLockCompatibilityMapping(); | |
1329 | if (NULL == __CFTimeZoneCompatibilityMappingDict) { | |
d8925383 A |
1330 | __CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
1331 | ||
1332 | // Empty string means delete/ignore these | |
1333 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Factory"), CFSTR("")); | |
1334 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Pacific-New"), CFSTR("")); | |
1335 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mideast/Riyadh87"), CFSTR("")); | |
1336 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mideast/Riyadh88"), CFSTR("")); | |
1337 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mideast/Riyadh89"), CFSTR("")); | |
1338 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/AST4"), CFSTR("")); | |
1339 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/AST4ADT"), CFSTR("")); | |
1340 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/CST6"), CFSTR("")); | |
1341 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/CST6CDT"), CFSTR("")); | |
1342 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/EST5"), CFSTR("")); | |
1343 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/EST5EDT"), CFSTR("")); | |
1344 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/HST10"), CFSTR("")); | |
1345 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/MST7"), CFSTR("")); | |
1346 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/MST7MDT"), CFSTR("")); | |
1347 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/PST8"), CFSTR("")); | |
1348 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/PST8PDT"), CFSTR("")); | |
1349 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/YST9"), CFSTR("")); | |
1350 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/YST9YDT"), CFSTR("")); | |
1351 | ||
1352 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Atka"), CFSTR("America/Adak")); | |
1353 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Ensenada"), CFSTR("America/Tijuana")); | |
1354 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Fort_Wayne"), CFSTR("America/Indianapolis")); | |
1355 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Indiana/Indianapolis"), CFSTR("America/Indianapolis")); | |
1356 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Kentucky/Louisville"), CFSTR("America/Louisville")); | |
1357 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Knox_IN"), CFSTR("America/Indiana/Knox")); | |
1358 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Porto_Acre"), CFSTR("America/Rio_Branco")); | |
1359 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Rosario"), CFSTR("America/Cordoba")); | |
1360 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Shiprock"), CFSTR("America/Denver")); | |
1361 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Virgin"), CFSTR("America/St_Thomas")); | |
1362 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Antarctica/South_Pole"), CFSTR("Antarctica/McMurdo")); | |
1363 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Ashkhabad"), CFSTR("Asia/Ashgabat")); | |
1364 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Chungking"), CFSTR("Asia/Chongqing")); | |
1365 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Macao"), CFSTR("Asia/Macau")); | |
1366 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Tel_Aviv"), CFSTR("Asia/Jerusalem")); | |
1367 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Thimbu"), CFSTR("Asia/Thimphu")); | |
1368 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Ujung_Pandang"), CFSTR("Asia/Makassar")); | |
1369 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Ulan_Bator"), CFSTR("Asia/Ulaanbaatar")); | |
1370 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/ACT"), CFSTR("Australia/Sydney")); | |
1371 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/LHI"), CFSTR("Australia/Lord_Howe")); | |
1372 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/NSW"), CFSTR("Australia/Sydney")); | |
1373 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/North"), CFSTR("Australia/Darwin")); | |
1374 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/Queensland"), CFSTR("Australia/Brisbane")); | |
1375 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/South"), CFSTR("Australia/Adelaide")); | |
1376 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/Tasmania"), CFSTR("Australia/Hobart")); | |
1377 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/Victoria"), CFSTR("Australia/Melbourne")); | |
1378 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/West"), CFSTR("Australia/Perth")); | |
1379 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/Yancowinna"), CFSTR("Australia/Broken_Hill")); | |
1380 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Brazil/Acre"), CFSTR("America/Porto_Acre")); | |
1381 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Brazil/DeNoronha"), CFSTR("America/Noronha")); | |
1382 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Brazil/West"), CFSTR("America/Manaus")); | |
1383 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("CST6CDT"), CFSTR("America/Chicago")); | |
1384 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Canada/Central"), CFSTR("America/Winnipeg")); | |
1385 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Canada/East-Saskatchewan"), CFSTR("America/Regina")); | |
1386 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Canada/Pacific"), CFSTR("America/Vancouver")); | |
1387 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Canada/Yukon"), CFSTR("America/Whitehorse")); | |
1388 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Chile/Continental"), CFSTR("America/Santiago")); | |
1389 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Chile/EasterIsland"), CFSTR("Pacific/Easter")); | |
1390 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Cuba"), CFSTR("America/Havana")); | |
1391 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("EST5EDT"), CFSTR("America/New_York")); | |
1392 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Egypt"), CFSTR("Africa/Cairo")); | |
1393 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Eire"), CFSTR("Europe/Dublin")); | |
1394 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/GMT+0"), CFSTR("GMT")); | |
1395 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/GMT-0"), CFSTR("GMT")); | |
1396 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/GMT0"), CFSTR("GMT")); | |
1397 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/Greenwich"), CFSTR("GMT")); | |
1398 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/Universal"), CFSTR("UTC")); | |
1399 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/Zulu"), CFSTR("UTC")); | |
1400 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Europe/Nicosia"), CFSTR("Asia/Nicosia")); | |
1401 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Europe/Tiraspol"), CFSTR("Europe/Chisinau")); | |
1402 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GB-Eire"), CFSTR("Europe/London")); | |
1403 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GB"), CFSTR("Europe/London")); | |
1404 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GMT+0"), CFSTR("GMT")); | |
1405 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GMT-0"), CFSTR("GMT")); | |
1406 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GMT0"), CFSTR("GMT")); | |
1407 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Greenwich"), CFSTR("GMT")); | |
1408 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Hongkong"), CFSTR("Asia/Hong_Kong")); | |
1409 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Iceland"), CFSTR("Atlantic/Reykjavik")); | |
1410 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Iran"), CFSTR("Asia/Tehran")); | |
1411 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Israel"), CFSTR("Asia/Jerusalem")); | |
1412 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Jamaica"), CFSTR("America/Jamaica")); | |
1413 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Kwajalein"), CFSTR("Pacific/Kwajalein")); | |
1414 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Libya"), CFSTR("Africa/Tripoli")); | |
1415 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("MST7MDT"), CFSTR("America/Denver")); | |
1416 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mexico/BajaNorte"), CFSTR("America/Tijuana")); | |
1417 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mexico/BajaSur"), CFSTR("America/Mazatlan")); | |
1418 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mexico/General"), CFSTR("America/Mexico_City")); | |
1419 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("NZ-CHAT"), CFSTR("Pacific/Chatham")); | |
1420 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("NZ"), CFSTR("Pacific/Auckland")); | |
1421 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Navajo"), CFSTR("America/Denver")); | |
1422 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("PRC"), CFSTR("Asia/Shanghai")); | |
1423 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("PST8PDT"), CFSTR("America/Los_Angeles")); | |
1424 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Pacific/Samoa"), CFSTR("Pacific/Pago_Pago")); | |
1425 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Poland"), CFSTR("Europe/Warsaw")); | |
1426 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Portugal"), CFSTR("Europe/Lisbon")); | |
1427 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("ROC"), CFSTR("Asia/Taipei")); | |
1428 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("ROK"), CFSTR("Asia/Seoul")); | |
1429 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Singapore"), CFSTR("Asia/Singapore")); | |
1430 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Turkey"), CFSTR("Europe/Istanbul")); | |
1431 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("UCT"), CFSTR("UTC")); | |
1432 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Alaska"), CFSTR("America/Anchorage")); | |
1433 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Aleutian"), CFSTR("America/Adak")); | |
1434 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Arizona"), CFSTR("America/Phoenix")); | |
1435 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/East-Indiana"), CFSTR("America/Indianapolis")); | |
1436 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Hawaii"), CFSTR("Pacific/Honolulu")); | |
1437 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Indiana-Starke"), CFSTR("America/Indiana/Knox")); | |
1438 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Michigan"), CFSTR("America/Detroit")); | |
1439 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Samoa"), CFSTR("Pacific/Pago_Pago")); | |
1440 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Universal"), CFSTR("UTC")); | |
1441 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("W-SU"), CFSTR("Europe/Moscow")); | |
1442 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Zulu"), CFSTR("UTC")); | |
9ce05555 A |
1443 | } |
1444 | dict = __CFTimeZoneCompatibilityMappingDict ? CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL; | |
1445 | __CFTimeZoneUnlockCompatibilityMapping(); | |
1446 | return dict; | |
1447 | } | |
1448 | ||
9ce05555 A |
1449 | __private_extern__ CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary2(void) { |
1450 | CFDictionaryRef dict; | |
1451 | __CFTimeZoneLockCompatibilityMapping(); | |
1452 | if (NULL == __CFTimeZoneCompatibilityMappingDict2) { | |
d8925383 A |
1453 | __CFTimeZoneCompatibilityMappingDict2 = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 16, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); |
1454 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Asia/Dacca"), CFSTR("Asia/Dhaka")); | |
1455 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Asia/Istanbul"), CFSTR("Europe/Istanbul")); | |
1456 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Australia/Canberra"), CFSTR("Australia/Sydney")); | |
1457 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Brazil/East"), CFSTR("America/Sao_Paulo")); | |
1458 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Atlantic"), CFSTR("America/Halifax")); | |
1459 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Eastern"), CFSTR("America/Montreal")); | |
1460 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Mountain"), CFSTR("America/Edmonton")); | |
1461 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Newfoundland"), CFSTR("America/St_Johns")); | |
1462 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Saskatchewan"), CFSTR("America/Regina")); | |
1463 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Japan"), CFSTR("Asia/Tokyo")); | |
1464 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("US/Central"), CFSTR("America/Chicago")); | |
1465 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("US/Eastern"), CFSTR("America/New_York")); | |
1466 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("US/Mountain"), CFSTR("America/Denver")); | |
1467 | CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("US/Pacific"), CFSTR("America/Los_Angeles")); | |
1468 | } | |
9ce05555 A |
1469 | dict = __CFTimeZoneCompatibilityMappingDict2 ? CFRetain(__CFTimeZoneCompatibilityMappingDict2) : NULL; |
1470 | __CFTimeZoneUnlockCompatibilityMapping(); | |
1471 | return dict; | |
1472 | } | |
1473 | ||
1474 |