/* * Copyright (c) 2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* CFTimeZone.c Copyright 1998-2002, Apple, Inc. All rights reserved. Responsibility: Christopher Kane */ #include #include #include #include #include "CFInternal.h" #include #include #include #include #include #include #include #include #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #include #include #include #include #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif #import #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #define TZZONELINK TZDEFAULT #define TZZONEINFO TZDIR "/" #elif DEPLOYMENT_TARGET_WINDOWS static CFStringRef __tzZoneInfo = NULL; static char *__tzDir = NULL; static void __InitTZStrings(void); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification") static CFTimeZoneRef __CFTimeZoneSystem = NULL; static CFTimeZoneRef __CFTimeZoneDefault = NULL; static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL; static CFSpinLock_t __CFTimeZoneAbbreviationLock = CFSpinLockInit; static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL; static CFSpinLock_t __CFTimeZoneCompatibilityMappingLock = CFSpinLockInit; static CFArrayRef __CFKnownTimeZoneList = NULL; static CFMutableDictionaryRef __CFTimeZoneCache = NULL; static CFSpinLock_t __CFTimeZoneGlobalLock = CFSpinLockInit; #if DEPLOYMENT_TARGET_WINDOWS static CFDictionaryRef __CFTimeZoneWinToOlsonDict = NULL; static CFSpinLock_t __CFTimeZoneWinToOlsonLock = CFSpinLockInit; #endif CF_INLINE void __CFTimeZoneLockGlobal(void) { __CFSpinLock(&__CFTimeZoneGlobalLock); } CF_INLINE void __CFTimeZoneUnlockGlobal(void) { __CFSpinUnlock(&__CFTimeZoneGlobalLock); } CF_INLINE void __CFTimeZoneLockAbbreviations(void) { __CFSpinLock(&__CFTimeZoneAbbreviationLock); } CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) { __CFSpinUnlock(&__CFTimeZoneAbbreviationLock); } CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) { __CFSpinLock(&__CFTimeZoneCompatibilityMappingLock); } CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) { __CFSpinUnlock(&__CFTimeZoneCompatibilityMappingLock); } #if DEPLOYMENT_TARGET_WINDOWS /* This function should be used for WIN32 instead of * __CFCopyRecursiveDirectoryList function. * It takes TimeZone names from the registry * (Aleksey Dukhnyakov) */ static CFMutableArrayRef __CFCopyWindowsTimeZoneList() { CFMutableArrayRef result = NULL; HKEY hkResult; TCHAR lpName[MAX_PATH+1]; DWORD dwIndex, retCode; if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) != ERROR_SUCCESS ) return NULL; result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); for (dwIndex=0; (retCode = RegEnumKey(hkResult,dwIndex,lpName,MAX_PATH)) != ERROR_NO_MORE_ITEMS ; dwIndex++) { if (retCode != ERROR_SUCCESS) { RegCloseKey(hkResult); CFRelease(result); return NULL; } else { #if defined(UNICODE) CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const UInt8 *)lpName, (_tcslen(lpName) * sizeof(UniChar)), kCFStringEncodingUnicode, false); #else CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, lpName, _tcslen(lpName), CFStringGetSystemEncoding(), false); #endif CFArrayAppendValue(result, string); CFRelease(string); } } RegCloseKey(hkResult); return result; } #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS static CFMutableArrayRef __CFCopyRecursiveDirectoryList() { CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); #if DEPLOYMENT_TARGET_WINDOWS if (!__tzDir) __InitTZStrings(); if (!__tzDir) return result; int fd = open(__tzDir, O_RDONLY); #else int fd = open(TZDIR "/zone.tab", O_RDONLY); #endif for (; 0 <= fd;) { uint8_t buffer[4096]; ssize_t len = read(fd, buffer, sizeof(buffer)); if (len <= 0) break; if (len < sizeof(buffer)) { // assumes that partial read only occurs at the end of the file buffer[len] = '\n'; len++; } const uint8_t *bytes = buffer; for (;;) { const uint8_t *nextl = memchr(bytes, '\n', len); if (!nextl) break; nextl++; if ('#' == *bytes) { len -= (nextl - bytes); bytes = nextl; continue; } const uint8_t *tab1 = memchr(bytes, '\t', (nextl - bytes)); if (!tab1) { len -= (nextl - bytes); bytes = nextl; continue; } tab1++; len -= (tab1 - bytes); bytes = tab1; const uint8_t *tab2 = memchr(bytes, '\t', (nextl - bytes)); if (!tab2) { len -= (nextl - bytes); bytes = nextl; continue; } tab2++; len -= (tab2 - bytes); bytes = tab2; const uint8_t *tab3 = memchr(bytes, '\t', (nextl - bytes)); int nmlen = tab3 ? (tab3 - bytes) : (nextl - 1 - bytes); CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, bytes, nmlen, kCFStringEncodingUTF8, false); CFArrayAppendValue(result, string); CFRelease(string); len -= (nextl - bytes); bytes = nextl; } lseek(fd, -len, SEEK_CUR); } close(fd); return result; } #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif typedef struct _CFTZPeriod { int32_t startSec; CFStringRef abbrev; uint32_t info; } CFTZPeriod; struct __CFTimeZone { CFRuntimeBase _base; CFStringRef _name; /* immutable */ CFDataRef _data; /* immutable */ CFTZPeriod *_periods; /* immutable */ int32_t _periodCnt; /* immutable */ }; /* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates * between 1933 and 2069; info outside these years is discarded on read-in */ /* Bits 31-18 of the info are unused */ /* Bit 17 of the info is used for the is-DST state */ /* Bit 16 of the info is used for the sign of the offset (1 == negative) */ /* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */ CF_INLINE void __CFTZPeriodInit(CFTZPeriod *period, int32_t startTime, CFStringRef abbrev, int32_t offset, Boolean isDST) { period->startSec = startTime; period->abbrev = abbrev ? (CFStringRef)CFRetain(abbrev) : NULL; __CFBitfieldSetValue(period->info, 15, 0, abs(offset)); __CFBitfieldSetValue(period->info, 16, 16, (offset < 0 ? 1 : 0)); __CFBitfieldSetValue(period->info, 17, 17, (isDST ? 1 : 0)); } CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) { return period->startSec; } CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) { return period->abbrev; } CF_INLINE int32_t __CFTZPeriodGMTOffset(const CFTZPeriod *period) { int32_t v = __CFBitfieldGetValue(period->info, 15, 0); if (__CFBitfieldGetValue(period->info, 16, 16)) v = -v; return v; } CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) { return (Boolean)__CFBitfieldGetValue(period->info, 17, 17); } static CFComparisonResult __CFCompareTZPeriods(const void *val1, const void *val2, void *context) { CFTZPeriod *tzp1 = (CFTZPeriod *)val1; CFTZPeriod *tzp2 = (CFTZPeriod *)val2; // we treat equal as less than, as the code which uses the // result of the bsearch doesn't expect exact matches // (they're pretty rare, so no point in over-coding for them) if (__CFTZPeriodStartSeconds(tzp1) <= __CFTZPeriodStartSeconds(tzp2)) return kCFCompareLessThan; return kCFCompareGreaterThan; } static CFIndex __CFBSearchTZPeriods(CFTimeZoneRef tz, CFAbsoluteTime at) { CFTZPeriod elem; __CFTZPeriodInit(&elem, (int32_t)floor(at + 1.0), NULL, 0, false); CFIndex idx = CFBSearch(&elem, sizeof(CFTZPeriod), tz->_periods, tz->_periodCnt, __CFCompareTZPeriods, NULL); if (tz->_periodCnt <= idx) { idx = tz->_periodCnt; } else if (0 == idx) { idx = 1; } return idx - 1; } CF_INLINE int32_t __CFDetzcode(const unsigned char *bufp) { int32_t result = (bufp[0] & 0x80) ? ~0L : 0L; result = (result << 8) | (bufp[0] & 0xff); result = (result << 8) | (bufp[1] & 0xff); result = (result << 8) | (bufp[2] & 0xff); result = (result << 8) | (bufp[3] & 0xff); return result; } CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) { bufp[0] = (value >> 24) & 0xff; bufp[1] = (value >> 16) & 0xff; bufp[2] = (value >> 8) & 0xff; bufp[3] = (value >> 0) & 0xff; } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) { int32_t len, timecnt, typecnt, charcnt, idx, cnt; const uint8_t *p, *timep, *typep, *ttisp, *charp; CFStringRef *abbrs; Boolean result = true; p = CFDataGetBytePtr(data); len = CFDataGetLength(data); if (len < (int32_t)sizeof(struct tzhead)) { return false; } if (!(p[0] == 'T' && p[1] == 'Z' && p[2] == 'i' && p[3] == 'f')) return false; /* Don't parse without TZif at head of file */ p += 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */ timecnt = __CFDetzcode(p); p += 4; typecnt = __CFDetzcode(p); p += 4; charcnt = __CFDetzcode(p); p += 4; if (typecnt <= 0 || timecnt < 0 || charcnt < 0) { return false; } if (1024 < timecnt || 32 < typecnt || 128 < charcnt) { // reject excessive timezones to avoid arithmetic overflows for // security reasons and to reject potentially corrupt files return false; } if (len - (int32_t)sizeof(struct tzhead) < (4 + 1) * timecnt + (4 + 1 + 1) * typecnt + charcnt) { return false; } timep = p; typep = timep + 4 * timecnt; ttisp = typep + timecnt; charp = ttisp + (4 + 1 + 1) * typecnt; cnt = (0 < timecnt) ? timecnt : 1; *tzpp = CFAllocatorAllocate(allocator, cnt * sizeof(CFTZPeriod), 0); if (__CFOASafe) __CFSetLastAllocationEventName(*tzpp, "CFTimeZone (store)"); memset(*tzpp, 0, cnt * sizeof(CFTZPeriod)); abbrs = CFAllocatorAllocate(allocator, (charcnt + 1) * sizeof(CFStringRef), 0); if (__CFOASafe) __CFSetLastAllocationEventName(abbrs, "CFTimeZone (temp)"); for (idx = 0; idx < charcnt + 1; idx++) { abbrs[idx] = NULL; } for (idx = 0; idx < cnt; idx++) { CFAbsoluteTime at; int32_t itime, offset; uint8_t type, dst, abbridx; at = (CFAbsoluteTime)(__CFDetzcode(timep) + 0.0) - kCFAbsoluteTimeIntervalSince1970; if (0 == timecnt) itime = INT_MIN; else if (at < (CFAbsoluteTime)INT_MIN) itime = INT_MIN; else if ((CFAbsoluteTime)INT_MAX < at) itime = INT_MAX; else itime = (int32_t)at; timep += 4; /* harmless if 0 == timecnt */ type = (0 < timecnt) ? (uint8_t)*typep++ : 0; if (typecnt <= type) { result = false; break; } offset = __CFDetzcode(ttisp + 6 * type); dst = (uint8_t)*(ttisp + 6 * type + 4); if (0 != dst && 1 != dst) { result = false; break; } abbridx = (uint8_t)*(ttisp + 6 * type + 5); if (charcnt < abbridx) { result = false; break; } if (NULL == abbrs[abbridx]) { abbrs[abbridx] = CFStringCreateWithCString(allocator, (char *)&charp[abbridx], kCFStringEncodingASCII); } __CFTZPeriodInit(*tzpp + idx, itime, abbrs[abbridx], offset, (dst ? true : false)); } for (idx = 0; idx < charcnt + 1; idx++) { if (NULL != abbrs[idx]) { CFRelease(abbrs[idx]); } } CFAllocatorDeallocate(allocator, abbrs); if (result) { // dump all but the last INT_MIN and the first INT_MAX for (idx = 0; idx < cnt; idx++) { if (((*tzpp + idx)->startSec == INT_MIN) && (idx + 1 < cnt) && (((*tzpp + idx + 1)->startSec == INT_MIN))) { if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); cnt--; memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); idx--; } } // Don't combine these loops! Watch the idx decrementing... for (idx = 0; idx < cnt; idx++) { if (((*tzpp + idx)->startSec == INT_MAX) && (0 < idx) && (((*tzpp + idx - 1)->startSec == INT_MAX))) { if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); cnt--; memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); idx--; } } CFQSortArray(*tzpp, cnt, sizeof(CFTZPeriod), __CFCompareTZPeriods, NULL); // if the first period is in DST and there is more than one period, drop it if (1 < cnt && __CFTZPeriodIsDST(*tzpp + 0)) { if (NULL != (*tzpp + 0)->abbrev) CFRelease((*tzpp + 0)->abbrev); cnt--; memmove((*tzpp + 0), (*tzpp + 0 + 1), sizeof(CFTZPeriod) * (cnt - 0)); } *cntp = cnt; } else { CFAllocatorDeallocate(allocator, *tzpp); *tzpp = NULL; } return result; } #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) { /* We use Win32 function to find TimeZone * (Aleksey Dukhnyakov) */ *tzpp = (CFTZPeriod *)CFAllocatorAllocate(allocator, sizeof(CFTZPeriod), 0); memset(*tzpp, 0, sizeof(CFTZPeriod)); __CFTZPeriodInit(*tzpp, 0, NULL, 0, false); *cntp = 1; return TRUE; } #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif static Boolean __CFTimeZoneEqual(CFTypeRef cf1, CFTypeRef cf2) { CFTimeZoneRef tz1 = (CFTimeZoneRef)cf1; CFTimeZoneRef tz2 = (CFTimeZoneRef)cf2; if (!CFEqual(CFTimeZoneGetName(tz1), CFTimeZoneGetName(tz2))) return false; if (!CFEqual(CFTimeZoneGetData(tz1), CFTimeZoneGetData(tz2))) return false; return true; } static CFHashCode __CFTimeZoneHash(CFTypeRef cf) { CFTimeZoneRef tz = (CFTimeZoneRef)cf; return CFHash(CFTimeZoneGetName(tz)); } static CFStringRef __CFTimeZoneCopyDescription(CFTypeRef cf) { CFTimeZoneRef tz = (CFTimeZoneRef)cf; CFStringRef result, abbrev; CFAbsoluteTime at; at = CFAbsoluteTimeGetCurrent(); abbrev = CFTimeZoneCopyAbbreviation(tz, at); result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{name = %@; abbreviation = %@; GMT offset = %g; is DST = %s}"), cf, CFGetAllocator(tz), tz->_name, abbrev, CFTimeZoneGetSecondsFromGMT(tz, at), CFTimeZoneIsDaylightSavingTime(tz, at) ? "true" : "false"); CFRelease(abbrev); return result; } static void __CFTimeZoneDeallocate(CFTypeRef cf) { CFTimeZoneRef tz = (CFTimeZoneRef)cf; CFAllocatorRef allocator = CFGetAllocator(tz); CFIndex idx; if (tz->_name) CFRelease(tz->_name); if (tz->_data) CFRelease(tz->_data); for (idx = 0; idx < tz->_periodCnt; idx++) { if (NULL != tz->_periods[idx].abbrev) CFRelease(tz->_periods[idx].abbrev); } if (NULL != tz->_periods) CFAllocatorDeallocate(allocator, tz->_periods); } static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __CFTimeZoneClass = { 0, "CFTimeZone", NULL, // init NULL, // copy __CFTimeZoneDeallocate, __CFTimeZoneEqual, __CFTimeZoneHash, NULL, // __CFTimeZoneCopyDescription }; __private_extern__ void __CFTimeZoneInitialize(void) { __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass); } CFTypeID CFTimeZoneGetTypeID(void) { return __kCFTimeZoneTypeID; } #if DEPLOYMENT_TARGET_WINDOWS_SYNC static const char *__CFTimeZoneWinToOlsonDefaults = /* Mappings to time zones in Windows Registry are best-guess */ "" " " " " " " " Afghanistan Asia/Kabul" " Afghanistan Standard Time Asia/Kabul" " Alaskan America/Anchorage" " Alaskan Standard Time America/Anchorage" " Arab Asia/Riyadh" " Arab Standard Time Asia/Riyadh" " Arabian Asia/Muscat" " Arabian Standard Time Asia/Muscat" " Arabic Standard Time Asia/Baghdad" " Atlantic America/Halifax" " Atlantic Standard Time America/Halifax" " AUS Central Australia/Darwin" " AUS Central Standard Time Australia/Darwin" " AUS Eastern Australia/Sydney" " AUS Eastern Standard Time Australia/Sydney" " Azerbaijan Standard Time Asia/Baku" " Azores Atlantic/Azores" " Azores Standard Time Atlantic/Azores" " Bangkok Asia/Bangkok" " Bangkok Standard Time Asia/Bangkok" " Beijing Asia/Shanghai" " Canada Central America/Regina" " Canada Central Standard Time America/Regina" " Cape Verde Standard Time Atlantic/Cape_Verde" " Caucasus Asia/Yerevan" " Caucasus Standard Time Asia/Yerevan" " Cen. Australia Australia/Adelaide" " Cen. Australia Standard Time Australia/Adelaide" " Central America/Chicago" " Central America Standard Time America/Regina" " Central Asia Asia/Dhaka" " Central Asia Standard Time Asia/Dhaka" " Central Brazilian Standard Time America/Manaus" " Central Europe Europe/Prague" " Central Europe Standard Time Europe/Prague" " Central European Europe/Belgrade" " Central European Standard Time Europe/Belgrade" " Central Pacific Pacific/Guadalcanal" " Central Pacific Standard Time Pacific/Guadalcanal" " Central Standard Time America/Chicago" " Central Standard Time (Mexico) America/Mexico_City" " China Asia/Shanghai" " China Standard Time Asia/Shanghai" " Dateline GMT-1200" " Dateline Standard Time GMT-1200" " E. Africa Africa/Nairobi" " E. Africa Standard Time Africa/Nairobi" " E. Australia Australia/Brisbane" " E. Australia Standard Time Australia/Brisbane" " E. Europe Europe/Minsk" " E. Europe Standard Time Europe/Minsk" " E. South America America/Sao_Paulo" " E. South America Standard Time America/Sao_Paulo" " Eastern America/New_York" " Eastern Standard Time America/New_York" " Egypt Africa/Cairo" " Egypt Standard Time Africa/Cairo" " Ekaterinburg Asia/Yekaterinburg" " Ekaterinburg Standard Time Asia/Yekaterinburg" " Fiji Pacific/Fiji" " Fiji Standard Time Pacific/Fiji" " FLE Europe/Helsinki" " FLE Standard Time Europe/Helsinki" " Georgian Standard Time Asia/Tbilisi" " GFT Europe/Athens" " GFT Standard Time Europe/Athens" " GMT Europe/London" " GMT Standard Time Europe/London" " Greenland Standard Time America/Godthab" " Greenwich GMT" " Greenwich Standard Time GMT" " GTB Europe/Athens" " GTB Standard Time Europe/Athens" " Hawaiian Pacific/Honolulu" " Hawaiian Standard Time Pacific/Honolulu" " India Asia/Calcutta" " India Standard Time Asia/Calcutta" " Iran Asia/Tehran" " Iran Standard Time Asia/Tehran" " Israel Asia/Jerusalem" " Israel Standard Time Asia/Jerusalem" " Jordan Standard Time Asia/Amman" " Korea Asia/Seoul" " Korea Standard Time Asia/Seoul" " Mexico America/Mexico_City" " Mexico Standard Time America/Mexico_City" " Mexico Standard Time 2 America/Chihuahua" " Mid-Atlantic Atlantic/South_Georgia" " Mid-Atlantic Standard Time Atlantic/South_Georgia" " Middle East Standard Time Asia/Beirut" " Mountain America/Denver" " Mountain Standard Time America/Denver" " Mountain Standard Time (Mexico) America/Chihuahua" " Myanmar Standard Time Asia/Rangoon" " N. Central Asia Standard Time Asia/Novosibirsk" " Namibia Standard Time Africa/Windhoek" " Nepal Standard Time Asia/Katmandu" " New Zealand Pacific/Auckland" " New Zealand Standard Time Pacific/Auckland" " Newfoundland America/St_Johns" " Newfoundland Standard Time America/St_Johns" " North Asia East Standard Time Asia/Ulaanbaatar" " North Asia Standard Time Asia/Krasnoyarsk" " Pacific America/Los_Angeles" " Pacific SA America/Santiago" " Pacific SA Standard Time America/Santiago" " Pacific Standard Time America/Los_Angeles" " Pacific Standard Time (Mexico) America/Tijuana" " Prague Bratislava Europe/Prague" " Romance Europe/Paris" " Romance Standard Time Europe/Paris" " Russian Europe/Moscow" " Russian Standard Time Europe/Moscow" " SA Eastern America/Buenos_Aires" " SA Eastern Standard Time America/Buenos_Aires" " SA Pacific America/Bogota" " SA Pacific Standard Time America/Bogota" " SA Western America/Caracas" " SA Western Standard Time America/Caracas" " Samoa Pacific/Apia" " Samoa Standard Time Pacific/Apia" " Saudi Arabia Asia/Riyadh" " Saudi Arabia Standard Time Asia/Riyadh" " SE Asia Standard Time Asia/Bangkok" " Singapore Asia/Singapore" " Singapore Standard Time Asia/Singapore" " South Africa Africa/Harare" " South Africa Standard Time Africa/Harare" " Sri Lanka Asia/Colombo" " Sri Lanka Standard Time Asia/Colombo" " Sydney Standard Time Australia/Sydney" " Taipei Asia/Taipei" " Taipei Standard Time Asia/Taipei" " Tasmania Australia/Hobart" " Tasmania Standard Time Australia/Hobart" " Tasmania Standard Time Australia/Hobart" " Tokyo Asia/Tokyo" " Tokyo Standard Time Asia/Tokyo" " Tonga Standard Time Pacific/Tongatapu" " US Eastern America/Indianapolis" " US Eastern Standard Time America/Indianapolis" " US Mountain America/Phoenix" " US Mountain Standard Time America/Phoenix" " Vladivostok Asia/Vladivostok" " Vladivostok Standard Time Asia/Vladivostok" " W. Australia Australia/Perth" " W. Australia Standard Time Australia/Perth" " W. Central Africa Standard Time Africa/Luanda" " W. Europe Europe/Berlin" " W. Europe Standard Time Europe/Berlin" " Warsaw Europe/Warsaw" " West Asia Asia/Karachi" " West Asia Standard Time Asia/Karachi" " West Pacific Pacific/Guam" " West Pacific Standard Time Pacific/Guam" " Western Brazilian Standard Time America/Rio_Branco" " Yakutsk Asia/Yakutsk" " " " "; CF_INLINE void __CFTimeZoneLockWinToOlson(void) { __CFSpinLock(&__CFTimeZoneWinToOlsonLock); } CF_INLINE void __CFTimeZoneUnlockWinToOlson(void) { __CFSpinUnlock(&__CFTimeZoneWinToOlsonLock); } CFDictionaryRef CFTimeZoneCopyWinToOlsonDictionary(void) { CFDictionaryRef dict; __CFTimeZoneLockWinToOlson(); if (NULL == __CFTimeZoneWinToOlsonDict) { CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneWinToOlsonDefaults, strlen(__CFTimeZoneWinToOlsonDefaults)); __CFTimeZoneWinToOlsonDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); CFRelease(data); } if (NULL == __CFTimeZoneWinToOlsonDict) { __CFTimeZoneWinToOlsonDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL); } dict = __CFTimeZoneWinToOlsonDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneWinToOlsonDict) : NULL; __CFTimeZoneUnlockWinToOlson(); return dict; } void CFTimeZoneSetWinToOlsonDictionary(CFDictionaryRef dict) { __CFGenericValidateType(dict, CFDictionaryGetTypeID()); __CFTimeZoneLockWinToOlson(); if (dict != __CFTimeZoneWinToOlsonDict) { if (dict) CFRetain(dict); if (__CFTimeZoneWinToOlsonDict) CFRelease(__CFTimeZoneWinToOlsonDict); __CFTimeZoneWinToOlsonDict = dict; } __CFTimeZoneUnlockWinToOlson(); } CFTimeZoneRef CFTimeZoneCreateWithWindowsName(CFAllocatorRef allocator, CFStringRef winName) { if (!winName) return NULL; CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary(); if (!winToOlson) return NULL; CFStringRef olsonName = CFDictionaryGetValue(winToOlson, winName); CFTimeZoneRef retval = NULL; if (olsonName) { retval = CFTimeZoneCreateWithName(allocator, olsonName, false); } CFRelease(winToOlson); return retval; } extern CFStringRef _CFGetWindowsAppleSystemLibraryDirectory(void); void __InitTZStrings(void) { static CFSpinLock_t __CFTZDirLock = CFSpinLockInit; __CFSpinLock(&__CFTZDirLock); if (!__tzZoneInfo) { CFStringRef winDir = _CFGetWindowsAppleSystemLibraryDirectory(); __tzZoneInfo = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\\etc\\zoneinfo"), winDir); } if (!__tzDir && __tzZoneInfo) { int length = CFStringGetLength(__tzZoneInfo) + sizeof("\\zone.tab") + 1; __tzDir = malloc(length); // If we don't use ascii, we'll need to malloc more space if (!__tzDir || !CFStringGetCString(__tzZoneInfo, __tzDir, length, kCFStringEncodingASCII)) { free(__tzDir); } else { strcat(__tzDir, "\\zone.tab"); } } __CFSpinUnlock(&__CFTZDirLock); } #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { CFTimeZoneRef result = NULL; #if DEPLOYMENT_TARGET_WINDOWS_SYNC CFStringRef name = NULL; TIME_ZONE_INFORMATION tzi = { 0 }; DWORD rval = GetTimeZoneInformation(&tzi); if (rval != TIME_ZONE_ID_INVALID) { LPWSTR standardName = (LPWSTR)&tzi.StandardName; CFStringRef cfStandardName = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (UInt8 *)standardName, wcslen(standardName)*sizeof(WCHAR), kCFStringEncodingUTF16LE, false); if (cfStandardName) { CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary(); if (winToOlson) { name = CFDictionaryGetValue(winToOlson, cfStandardName); if (name) CFRetain(name); CFRelease(winToOlson); } CFRelease(cfStandardName); } } else { CFLog(kCFLogLevelError, CFSTR("Couldn't get time zone information error %d"), GetLastError()); } if (name) { #else const char *tzenv; int ret; char linkbuf[CFMaxPathSize]; tzenv = __CFgetenv("TZFILE"); if (NULL != tzenv) { CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); CFRelease(name); if (result) return result; } tzenv = __CFgetenv("TZ"); if (NULL != tzenv) { CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true); CFRelease(name); if (result) return result; } ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf)); if (0 < ret) { CFStringRef name; linkbuf[ret] = '\0'; if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) { name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false); } else { name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false); } #endif result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); CFRelease(name); if (result) return result; } return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); } #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { CFTimeZoneRef result = NULL; /* The GetTimeZoneInformation function retrieves the current * time-zone parameters for Win32 * (Aleksey Dukhnyakov) */ CFDataRef data; TIME_ZONE_INFORMATION tz; DWORD dw_result; dw_result=GetTimeZoneInformation(&tz); if ( dw_result == TIME_ZONE_ID_STANDARD || dw_result == TIME_ZONE_ID_DAYLIGHT ) { CFStringRef name = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)tz.StandardName, wcslen(tz.StandardName)); data = CFDataCreate(kCFAllocatorSystemDefault, (UInt8 *)&tz, sizeof(tz)); result = CFTimeZoneCreate(kCFAllocatorSystemDefault, name, data); CFRelease(name); CFRelease(data); if (result) return result; } return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); } #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif CFTimeZoneRef CFTimeZoneCopySystem(void) { CFTimeZoneRef tz; __CFTimeZoneLockGlobal(); if (NULL == __CFTimeZoneSystem) { __CFTimeZoneUnlockGlobal(); tz = __CFTimeZoneCreateSystem(); __CFTimeZoneLockGlobal(); if (NULL == __CFTimeZoneSystem) { __CFTimeZoneSystem = tz; } else { if (tz) CFRelease(tz); } } tz = __CFTimeZoneSystem ? (CFTimeZoneRef)CFRetain(__CFTimeZoneSystem) : NULL; __CFTimeZoneUnlockGlobal(); return tz; } static CFIndex __noteCount = 0; void CFTimeZoneResetSystem(void) { __CFTimeZoneLockGlobal(); if (__CFTimeZoneDefault == __CFTimeZoneSystem) { if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); __CFTimeZoneDefault = NULL; } CFTimeZoneRef tz = __CFTimeZoneSystem; __CFTimeZoneSystem = NULL; __CFTimeZoneUnlockGlobal(); if (tz) CFRelease(tz); } CFIndex _CFTimeZoneGetNoteCount(void) { return __noteCount; } CFTimeZoneRef CFTimeZoneCopyDefault(void) { CFTimeZoneRef tz; __CFTimeZoneLockGlobal(); if (NULL == __CFTimeZoneDefault) { __CFTimeZoneUnlockGlobal(); tz = CFTimeZoneCopySystem(); __CFTimeZoneLockGlobal(); if (NULL == __CFTimeZoneDefault) { __CFTimeZoneDefault = tz; } else { if (tz) CFRelease(tz); } } tz = __CFTimeZoneDefault ? (CFTimeZoneRef)CFRetain(__CFTimeZoneDefault) : NULL; __CFTimeZoneUnlockGlobal(); return tz; } void CFTimeZoneSetDefault(CFTimeZoneRef tz) { if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); __CFTimeZoneLockGlobal(); if (tz != __CFTimeZoneDefault) { if (tz) CFRetain(tz); if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); __CFTimeZoneDefault = tz; } __CFTimeZoneUnlockGlobal(); } static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void); CFArrayRef CFTimeZoneCopyKnownNames(void) { CFArrayRef tzs; __CFTimeZoneLockGlobal(); if (NULL == __CFKnownTimeZoneList) { CFMutableArrayRef list; /* TimeZone information locate in the registry for Win32 * (Aleksey Dukhnyakov) */ #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC list = __CFCopyRecursiveDirectoryList(); #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI list = __CFCopyWindowsTimeZoneList(); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif // Remove undesirable ancient cruft CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); CFIndex idx; for (idx = CFArrayGetCount(list); idx--; ) { CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(list, idx); if (CFDictionaryContainsKey(dict, item)) { CFArrayRemoveValueAtIndex(list, idx); } } __CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list); CFRelease(list); } tzs = __CFKnownTimeZoneList ? (CFArrayRef)CFRetain(__CFKnownTimeZoneList) : NULL; __CFTimeZoneUnlockGlobal(); return tzs; } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC /* The criteria here are sort of: coverage for the U.S. and Europe, * large cities, abbreviation uniqueness, and perhaps a few others. * But do not make the list too large with obscure information. */ static const char *__CFTimeZoneAbbreviationDefaults = "" " " " " " " " ADT America/Halifax" " AKDT America/Juneau" " AKST America/Juneau" " ART America/Argentina/Buenos_Aires" " AST America/Halifax" " BDT Asia/Dhaka" " BRST America/Sao_Paulo" " BRT America/Sao_Paulo" " BST Europe/London" " CAT Africa/Harare" " CDT America/Chicago" " CEST Europe/Paris" " CET Europe/Paris" " CLST America/Santiago" " CLT America/Santiago" " COT America/Bogota" " CST America/Chicago" " EAT Africa/Addis_Ababa" " EDT America/New_York" " EEST Europe/Istanbul" " EET Europe/Istanbul" " EST America/New_York" " GMT GMT" " GST Asia/Dubai" " HKT Asia/Hong_Kong" " HST Pacific/Honolulu" " ICT Asia/Bangkok" " IRST Asia/Tehran" " IST Asia/Calcutta" " JST Asia/Tokyo" " KST Asia/Seoul" " MDT America/Denver" " MSD Europe/Moscow" " MSK Europe/Moscow" " MST America/Denver" " NZDT Pacific/Auckland" " NZST Pacific/Auckland" " PDT America/Los_Angeles" " PET America/Lima" " PHT Asia/Manila" " PKT Asia/Karachi" " PST America/Los_Angeles" " SGT Asia/Singapore" " UTC UTC" " WAT Africa/Lagos" " WEST Europe/Lisbon" " WET Europe/Lisbon" " WIT Asia/Jakarta" " " " "; #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI static const char *__CFTimeZoneAbbreviationDefaults = /* Mappings to time zones in Windows Registry are best-guess */ "" " " " " " " " ADT Atlantic Standard Time" " AKDT Alaskan Standard Time" " AKST Alaskan Standard Time" " ART SA Eastern Standard Time" " AST Atlantic Standard Time" " BDT Central Asia Standard Time" " BRST SA Eastern Standard Time" " BRT SA Eastern Standard Time" " BST GMT Standard Time" " CAT South Africa Standard Time" " CDT Central Standard Time" " CEST Central Europe Standard Time" " CET Central Europe Standard Time" " CLST SA Western Standard Time" " CLT SA Western Standard Time" " COT Central Standard Time" " CST Central Standard Time" " EAT E. Africa Standard Time" " EDT Eastern Standard Time" " EEST E. Europe Standard Time" " EET E. Europe Standard Time" " EST Eastern Standard Time" " GMT Greenwich Standard Time" " GST Arabian Standard Time" " HKT China Standard Time" " HST Hawaiian Standard Time" " ICT SE Asia Standard Time" " IRST Iran Standard Time" " IST India Standard Time" " JST Tokyo Standard Time" " KST Korea Standard Time" " MDT Mountain Standard Time" " MSD E. Europe Standard Time" " MSK E. Europe Standard Time" " MST Mountain Standard Time" " NZDT New Zealand Standard Time" " NZST New Zealand Standard Time" " PDT Pacific Standard Time" " PET SA Pacific Standard Time" " PHT Taipei Standard Time" " PKT West Asia Standard Time" " PST Pacific Standard Time" " SGT Singapore Standard Time" " UTC Greenwich Standard Time" " WAT W. Central Africa Standard Time" " WEST W. Europe Standard Time" " WET W. Europe Standard Time" " WIT SE Asia Standard Time" " " " "; #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) { CFDictionaryRef dict; __CFTimeZoneLockAbbreviations(); if (NULL == __CFTimeZoneAbbreviationDict) { CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults)); __CFTimeZoneAbbreviationDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); CFRelease(data); } if (NULL == __CFTimeZoneAbbreviationDict) { __CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL); } dict = __CFTimeZoneAbbreviationDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneAbbreviationDict) : NULL; __CFTimeZoneUnlockAbbreviations(); return dict; } void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) { __CFGenericValidateType(dict, CFDictionaryGetTypeID()); __CFTimeZoneLockGlobal(); if (dict != __CFTimeZoneAbbreviationDict) { if (dict) CFRetain(dict); if (__CFTimeZoneAbbreviationDict) { for (id key in (id)__CFTimeZoneAbbreviationDict) { CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)key); } CFRelease(__CFTimeZoneAbbreviationDict); } __CFTimeZoneAbbreviationDict = dict; } __CFTimeZoneUnlockGlobal(); } CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) { // assert: (NULL != name && NULL != data); CFTimeZoneRef memory; uint32_t size; CFTZPeriod *tzp = NULL; CFIndex idx, cnt = 0; if (allocator == NULL) allocator = __CFGetDefaultAllocator(); __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); __CFGenericValidateType(name, CFStringGetTypeID()); __CFGenericValidateType(data, CFDataGetTypeID()); __CFTimeZoneLockGlobal(); if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) { __CFTimeZoneUnlockGlobal(); return (CFTimeZoneRef)CFRetain(memory); } if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) { __CFTimeZoneUnlockGlobal(); return NULL; } size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase); memory = (CFTimeZoneRef)_CFRuntimeCreateInstance(allocator, CFTimeZoneGetTypeID(), size, NULL); if (NULL == memory) { __CFTimeZoneUnlockGlobal(); for (idx = 0; idx < cnt; idx++) { if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev); } if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp); return NULL; } ((struct __CFTimeZone *)memory)->_name = (CFStringRef)CFStringCreateCopy(allocator, name); ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data); ((struct __CFTimeZone *)memory)->_periods = tzp; ((struct __CFTimeZone *)memory)->_periodCnt = cnt; if (NULL == __CFTimeZoneCache) { __CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory); __CFTimeZoneUnlockGlobal(); return memory; } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { CFTimeZoneRef result; CFDataRef data; int32_t nameLen = CFStringGetLength(name); unsigned char dataBytes[52 + nameLen + 1]; memset(dataBytes, 0, sizeof(dataBytes)); // Put in correct magic bytes for timezone structures dataBytes[0] = 'T'; dataBytes[1] = 'Z'; dataBytes[2] = 'i'; dataBytes[3] = 'f'; __CFEntzcode(1, dataBytes + 20); __CFEntzcode(1, dataBytes + 24); __CFEntzcode(1, dataBytes + 36); __CFEntzcode(nameLen + 1, dataBytes + 40); __CFEntzcode(seconds, dataBytes + 44); dataBytes[48] = isDST ? 1 : 0; CFStringGetCString(name, (char *)dataBytes + 50, nameLen + 1, kCFStringEncodingASCII); data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1); result = CFTimeZoneCreate(allocator, name, data); CFRelease(data); return result; } #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure * to find current timezone * (Aleksey Dukhnyakov) */ CFTimeZoneRef result; TIME_ZONE_INFORMATION tzi; CFDataRef data; CFIndex length = CFStringGetLength(name); memset(&tzi,0,sizeof(tzi)); tzi.Bias=(long)(-seconds/60); CFStringGetCharacters(name, CFRangeMake(0, length < 31 ? length : 31 ), (UniChar *)tzi.StandardName); data = CFDataCreate(allocator,(UInt8 *)&tzi, sizeof(tzi)); result = CFTimeZoneCreate(allocator, name, data); CFRelease(data); return result; } #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif // rounds offset to nearest minute CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) { CFTimeZoneRef result; CFStringRef name; int32_t seconds, minute, hour; if (allocator == NULL) allocator = __CFGetDefaultAllocator(); __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL; ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0; seconds = (int32_t)ti; hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600); seconds -= ((ti < 0) ? -hour : hour) * 3600; minute = (ti < 0) ? (-seconds / 60) : (seconds / 60); if (fabs(ti) < 1.0) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC name = (CFStringRef)CFRetain(CFSTR("GMT")); #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI name = (CFStringRef)CFRetain(CFSTR("Greenwich Standard Time")); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif } else { name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute); } result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0); CFRelease(name); return result; } CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) { CFTimeZoneRef result = NULL; CFStringRef tzName = NULL; CFDataRef data = NULL; if (allocator == NULL) allocator = __CFGetDefaultAllocator(); __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); __CFGenericValidateType(name, CFStringGetTypeID()); if (CFEqual(CFSTR(""), name)) { // empty string is not a time zone name, just abort now, // following stuff will fail anyway return NULL; } __CFTimeZoneLockGlobal(); if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) { __CFTimeZoneUnlockGlobal(); return (CFTimeZoneRef)CFRetain(result); } __CFTimeZoneUnlockGlobal(); CFIndex len = CFStringGetLength(name); if (6 == len || 8 == len) { UniChar buffer[8]; CFStringGetCharacters(name, CFRangeMake(0, len), buffer); if ('G' == buffer[0] && 'M' == buffer[1] && 'T' == buffer[2] && ('+' == buffer[3] || '-' == buffer[3])) { if (('0' <= buffer[4] && buffer[4] <= '9') && ('0' <= buffer[5] && buffer[5] <= '9')) { int32_t hours = (buffer[4] - '0') * 10 + (buffer[5] - '0'); if (-14 <= hours && hours <= 14) { CFTimeInterval ti = hours * 3600.0; if (6 == len) { return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti); } else { if (('0' <= buffer[6] && buffer[6] <= '9') && ('0' <= buffer[7] && buffer[7] <= '9')) { int32_t minutes = (buffer[6] - '0') * 10 + (buffer[7] - '0'); if ((-14 == hours && 0 == minutes) || (14 == hours && 0 == minutes) || (0 <= minutes && minutes <= 59)) { ti = ti + minutes * 60.0; return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti); } } } } } } } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC CFURLRef baseURL, tempURL; void *bytes; CFIndex length; #if DEPLOYMENT_TARGET_WINDOWS_SYNC if (!__tzZoneInfo) __InitTZStrings(); if (!__tzZoneInfo) return NULL; baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLWindowsPathStyle, true); #else baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true); #endif if (tryAbbrev) { CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); tzName = CFDictionaryGetValue(abbrevs, name); if (NULL != tzName) { tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false); if (NULL != tempURL) { if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0)) { data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault); } CFRelease(tempURL); } } CFRelease(abbrevs); } if (NULL == data) { CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); CFStringRef mapping = CFDictionaryGetValue(dict, name); if (mapping) { name = mapping; #if DEPLOYMENT_TARGET_WINDOWS_SYNC } else if (CFStringHasPrefix(name, __tzZoneInfo)) { CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name); CFStringDelete(unprefixed, CFRangeMake(0, CFStringGetLength(__tzZoneInfo))); #else } else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) { CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name); CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO))); #endif mapping = CFDictionaryGetValue(dict, unprefixed); if (mapping) { name = mapping; } CFRelease(unprefixed); } CFRelease(dict); if (CFEqual(CFSTR(""), name)) { return NULL; } } if (NULL == data) { tzName = name; tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false); if (NULL != tempURL) { if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0)) { data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault); } CFRelease(tempURL); } } CFRelease(baseURL); if (NULL != data) { result = CFTimeZoneCreate(allocator, tzName, data); if (name != tzName) { CFStringRef nameCopy = (CFStringRef)CFStringCreateCopy(allocator, name); __CFTimeZoneLockGlobal(); CFDictionaryAddValue(__CFTimeZoneCache, nameCopy, result); __CFTimeZoneUnlockGlobal(); CFRelease(nameCopy); } CFRelease(data); } return result; } #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI /* Reading GMT offset and daylight flag from the registry * for TimeZone name * (Aleksey Dukhnyakov) */ { CFStringRef safeName = name; struct { LONG Bias; LONG StandardBias; LONG DaylightBias; SYSTEMTIME StandardDate; SYSTEMTIME DaylightDate; } tzi; TIME_ZONE_INFORMATION tzi_system; HKEY hkResult; DWORD dwType, dwSize=sizeof(tzi), dwSize_name1=sizeof(tzi_system.StandardName), dwSize_name2=sizeof(tzi_system.DaylightName); if (tryAbbrev) { CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); tzName = (CFStringRef)CFDictionaryGetValue(abbrevs, name); if (NULL == tzName) { CFRelease(abbrevs); return NULL; } name = tzName; CFRelease(abbrevs); } /* Open regestry and move down to the TimeZone information */ if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) != ERROR_SUCCESS ) { return NULL; } /* Move down to specific TimeZone name */ #if defined(UNICODE) UniChar *uniTimeZone = (UniChar*)CFStringGetCharactersPtr(name); if (uniTimeZone == NULL) { // We need to extract the bytes out of the CFStringRef and create our own // UNICODE string to pass to the Win32 API - RegOpenKey. UInt8 uniBuff[MAX_PATH+2]; // adding +2 to handle Unicode-null termination /0/0. CFIndex usedBuff = 0; CFIndex numChars = CFStringGetBytes(name, CFRangeMake(0, CFStringGetLength(name)), kCFStringEncodingUnicode, 0, FALSE, uniBuff, MAX_PATH, &usedBuff); if (numChars == 0) { return NULL; } else { // NULL-terminate the newly created Unicode string. uniBuff[usedBuff] = '\0'; uniBuff[usedBuff+1] = '\0'; } if (RegOpenKey(hkResult, (LPCWSTR)uniBuff ,&hkResult) != ERROR_SUCCESS ) { return NULL; } } else { if (RegOpenKey(hkResult, (LPCWSTR)uniTimeZone ,&hkResult) != ERROR_SUCCESS ) { return NULL; } } #else if (RegOpenKey(hkResult,CFStringGetCStringPtr(name, CFStringGetSystemEncoding()),&hkResult) != ERROR_SUCCESS ) { return NULL; } #endif /* TimeZone information(offsets, daylight flag, ...) assign to tzi structure */ if ( RegQueryValueEx(hkResult,_T("TZI"),NULL,&dwType,(LPBYTE)&tzi,&dwSize) != ERROR_SUCCESS && RegQueryValueEx(hkResult,_T("Std"),NULL,&dwType,(LPBYTE)&tzi_system.StandardName,&dwSize_name1) != ERROR_SUCCESS && RegQueryValueEx(hkResult,_T("Dlt"),NULL,&dwType,(LPBYTE)&tzi_system.DaylightName,&dwSize_name2) != ERROR_SUCCESS ) { return NULL; } tzi_system.Bias=tzi.Bias; tzi_system.StandardBias=tzi.StandardBias; tzi_system.DaylightBias=tzi.DaylightBias; tzi_system.StandardDate=tzi.StandardDate; tzi_system.DaylightDate=tzi.DaylightDate; /* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure * to find current timezone * (Aleksey Dukhnyakov) */ data = CFDataCreate(allocator,(UInt8 *)&tzi_system, sizeof(tzi_system)); RegCloseKey(hkResult); result = CFTimeZoneCreate(allocator, name, data); if (result) { if (tryAbbrev) result->_periods->abbrev = (CFStringRef)CFStringCreateCopy(allocator,safeName); else { } } CFRelease(data); } return result; } #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) { CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFStringRef, tz, "name"); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); return tz->_name; } CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) { CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFDataRef, tz, "data"); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); return tz->_data; } /* This function converts CFAbsoluteTime to (Win32) SYSTEMTIME * (Aleksey Dukhnyakov) */ #if DEPLOYMENT_TARGET_WINDOWS BOOL __CFTimeZoneGetWin32SystemTime(SYSTEMTIME * sys_time, CFAbsoluteTime time) { LONGLONG l; FILETIME * ftime=(FILETIME*)&l; /* seconds between 1601 and 1970 : 11644473600, * seconds between 1970 and 2001 : 978307200, * FILETIME - number of 100-nanosecond intervals since January 1, 1601 */ l=(LONGLONG)(time+11644473600LL+978307200)*10000000; if (FileTimeToSystemTime(ftime,sys_time)) return TRUE; else return FALSE; } #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC CFIndex idx; CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); idx = __CFBSearchTZPeriods(tz, at); return __CFTZPeriodGMTOffset(&(tz->_periods[idx])); #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI /* To calculate seconds from GMT, calculate current timezone time and * subtract GMT timnezone time * (Aleksey Dukhnyakov) */ TIME_ZONE_INFORMATION tzi; FILETIME ftime1,ftime2; SYSTEMTIME stime0,stime1,stime2; LONGLONG * l1= (LONGLONG*)&ftime1; LONGLONG * l2= (LONGLONG*)&ftime2; CFRange range={0,sizeof(TIME_ZONE_INFORMATION)}; double result; CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at); CFDataGetBytes(tz->_data,range,(UInt8 *)&tzi); if (!__CFTimeZoneGetWin32SystemTime(&stime0,at) || !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime1) || !SystemTimeToFileTime(&stime1,&ftime1) ) { CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); return 0; } tzi.DaylightDate.wMonth=0; tzi.StandardDate.wMonth=0; tzi.StandardBias=0; tzi.DaylightBias=0; tzi.Bias=0; if ( !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime2) || !SystemTimeToFileTime(&stime2,&ftime2)) { CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); return 0; } result=(double)((*l1-*l2)/10000000); return result; #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif } #if DEPLOYMENT_TARGET_WINDOWS_SAFARI /* * Get abbreviation for name for WIN32 platform * (Aleksey Dukhnyakov) */ typedef struct { CFStringRef tzName; CFStringRef tzAbbr; } _CFAbbrFind; static void _CFFindKeyForValue(const void *key, const void *value, void *context) { if ( ((_CFAbbrFind *)context)->tzAbbr != NULL ) { if ( ((_CFAbbrFind *)context)->tzName == (CFStringRef) value ) { ((_CFAbbrFind *)context)->tzAbbr = (CFStringRef)key ; } } } CFIndex __CFTimeZoneInitAbbrev(CFTimeZoneRef tz) { if ( tz->_periods->abbrev == NULL ) { _CFAbbrFind abbr = { NULL, NULL }; CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); CFDictionaryApplyFunction(abbrevs, _CFFindKeyForValue, &abbr); if ( abbr.tzAbbr != NULL) tz->_periods->abbrev = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, abbr.tzAbbr); else tz->_periods->abbrev = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, tz->_name); /* We should return name of TimeZone if couldn't find abbrevation. * (Ala on MACOSX) * * (Aleksey Dukhnyakov) */ CFRelease( abbrevs ); } return 0; } #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) { CFStringRef result; CFIndex idx; CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFStringRef, tz, "_abbreviationForAbsoluteTime:", at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC idx = __CFBSearchTZPeriods(tz, at); #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI /* * Initialize abbreviation for this TimeZone * (Aleksey Dukhnyakov) */ idx = __CFTimeZoneInitAbbrev(tz); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif result = __CFTZPeriodAbbreviation(&(tz->_periods[idx])); return result ? (CFStringRef)CFRetain(result) : NULL; } Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC CFIndex idx; CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); idx = __CFBSearchTZPeriods(tz, at); return __CFTZPeriodIsDST(&(tz->_periods[idx])); #elif DEPLOYMENT_TARGET_WINDOWS_SAFARI /* Compare current timezone time and current timezone time without * transition to day light saving time * (Aleskey Dukhnyakov) */ TIME_ZONE_INFORMATION tzi; SYSTEMTIME stime0,stime1,stime2; CFRange range={0,sizeof(TIME_ZONE_INFORMATION)}; CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at); CFDataGetBytes(tz->_data,range,(UInt8 *)&tzi); if ( !__CFTimeZoneGetWin32SystemTime(&stime0,at) || !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime1)) { CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); return FALSE; } tzi.DaylightDate.wMonth=0; tzi.StandardDate.wMonth=0; if ( !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime2)) { CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); return FALSE; } if ( !memcmp(&stime1,&stime2,sizeof(stime1)) ) return FALSE; return TRUE; #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif } CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) { CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_daylightSavingTimeOffsetForAbsoluteTime:", at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); CFIndex idx = __CFBSearchTZPeriods(tz, at); if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) { CFTimeInterval offset = __CFTZPeriodGMTOffset(&(tz->_periods[idx])); if (idx + 1 < tz->_periodCnt) { return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1])); } else if (0 < idx) { return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1])); } } return 0.0; } CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) { CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_nextDaylightSavingTimeTransitionAfterAbsoluteTime:", at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); CFIndex idx = __CFBSearchTZPeriods(tz, at); if (tz->_periodCnt <= idx + 1) { return 0.0; } return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1])); } extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); #define BUFFER_SIZE 768 CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) { CF_OBJC_FUNCDISPATCH2(CFTimeZoneGetTypeID(), CFStringRef, tz, "localizedName:locale:", style, locale); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); __CFGenericValidateType(locale, CFLocaleGetTypeID()); if (style == kCFTimeZoneNameStyleGeneric || style == kCFTimeZoneNameStyleShortGeneric) { CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorSystemDefault, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle); CFDateFormatterSetProperty(df, kCFDateFormatterTimeZone, tz); CFDateFormatterSetFormat(df, (style == kCFTimeZoneNameStyleGeneric) ? CFSTR("vvvv") : CFSTR("v")); CFStringRef str = CFDateFormatterCreateStringWithAbsoluteTime(CFGetAllocator(tz), df, 0.0); CFRelease(df); return str; } CFStringRef localeID = CFLocaleGetIdentifier(locale); UCalendar *cal = __CFCalendarCreateUCalendar(NULL, localeID, tz); if (NULL == cal) { return NULL; } char buffer[BUFFER_SIZE]; const char *cstr = CFStringGetCStringPtr(localeID, kCFStringEncodingASCII); if (NULL == cstr) { if (CFStringGetCString(localeID, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; } if (NULL == cstr) { ucal_close(cal); return NULL; } UChar ubuffer[BUFFER_SIZE]; UErrorCode status = U_ZERO_ERROR; int32_t cnt = ucal_getTimeZoneDisplayName(cal, (UCalendarDisplayNameType)style, cstr, ubuffer, BUFFER_SIZE, &status); ucal_close(cal); if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { return CFStringCreateWithCharacters(CFGetAllocator(tz), (const UniChar *)ubuffer, cnt); } return NULL; } static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) { CFDictionaryRef dict; __CFTimeZoneLockCompatibilityMapping(); if (NULL == __CFTimeZoneCompatibilityMappingDict) { __CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); // Empty string means delete/ignore these } dict = __CFTimeZoneCompatibilityMappingDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL; __CFTimeZoneUnlockCompatibilityMapping(); return dict; } #undef TZZONEINFO #undef TZZONELINK