/ CFTimeZone.c
CFTimeZone.c
   1  /*
   2   * Copyright (c) 2015 Apple Inc. All rights reserved.
   3   *
   4   * @APPLE_LICENSE_HEADER_START@
   5   *
   6   * This file contains Original Code and/or Modifications of Original Code
   7   * as defined in and that are subject to the Apple Public Source License
   8   * Version 2.0 (the 'License'). You may not use this file except in
   9   * compliance with the License. Please obtain a copy of the License at
  10   * http://www.opensource.apple.com/apsl/ and read it before using this
  11   * file.
  12   *
  13   * The Original Code and all software distributed under the License are
  14   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15   * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16   * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17   * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18   * Please see the License for the specific language governing rights and
  19   * limitations under the License.
  20   *
  21   * @APPLE_LICENSE_HEADER_END@
  22   */
  23  
  24  /*	CFTimeZone.c
  25  	Copyright (c) 1998-2014, Apple Inc. All rights reserved.
  26  	Responsibility: Christopher Kane
  27  */
  28  
  29  
  30  #include <CoreFoundation/CFTimeZone.h>
  31  #include <CoreFoundation/CFPropertyList.h>
  32  #include <CoreFoundation/CFDateFormatter.h>
  33  #include <CoreFoundation/CFPriv.h>
  34  #include "CFInternal.h"
  35  #include <math.h>
  36  #include <limits.h>
  37  #include <sys/stat.h>
  38  #include <fcntl.h>
  39  #include <stdlib.h>
  40  #include <string.h>
  41  #include <unicode/ucal.h>
  42  #include <CoreFoundation/CFDateFormatter.h>
  43  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX
  44  #include <dirent.h>
  45  #include <unistd.h>
  46  #include <sys/fcntl.h>
  47  #endif
  48  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
  49  #include <tzfile.h>
  50  #elif DEPLOYMENT_TARGET_LINUX
  51  #ifndef TZDIR
  52  #define TZDIR	"/usr/share/zoneinfo" /* Time zone object file directory */
  53  #endif /* !defined TZDIR */
  54  
  55  #ifndef TZDEFAULT
  56  #define TZDEFAULT	"/etc/localtime"
  57  #endif /* !defined TZDEFAULT */
  58  
  59  struct tzhead {
  60      char	tzh_magic[4];		/* TZ_MAGIC */
  61      char	tzh_reserved[16];	/* reserved for future use */
  62      char	tzh_ttisgmtcnt[4];	/* coded number of trans. time flags */
  63      char	tzh_ttisstdcnt[4];	/* coded number of trans. time flags */
  64      char	tzh_leapcnt[4];		/* coded number of leap seconds */
  65      char	tzh_timecnt[4];		/* coded number of transition times */
  66      char	tzh_typecnt[4];		/* coded number of local time types */
  67      char	tzh_charcnt[4];		/* coded number of abbr. chars */
  68  };
  69  #endif
  70  
  71  #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX
  72  #define TZZONELINK	TZDEFAULT
  73  #define TZZONEINFO	TZDIR "/"
  74  #elif DEPLOYMENT_TARGET_WINDOWS
  75  static CFStringRef __tzZoneInfo = NULL;
  76  static char *__tzDir = NULL;
  77  static void __InitTZStrings(void);
  78  #else
  79  #error Unknown or unspecified DEPLOYMENT_TARGET
  80  #endif
  81  
  82  #if DEPLOYMENT_TARGET_LINUX
  83  // Symbol aliases
  84  CF_EXPORT CFStringRef const kCFDateFormatterTimeZone __attribute__((weak, alias ("kCFDateFormatterTimeZoneKey")));
  85  #endif
  86  
  87  CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification")
  88  
  89  static CFTimeZoneRef __CFTimeZoneSystem = NULL;
  90  static CFTimeZoneRef __CFTimeZoneDefault = NULL;
  91  static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL;
  92  static CFLock_t __CFTimeZoneAbbreviationLock = CFLockInit;
  93  static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL;
  94  static CFLock_t __CFTimeZoneCompatibilityMappingLock = CFLockInit;
  95  static CFArrayRef __CFKnownTimeZoneList = NULL;
  96  static CFMutableDictionaryRef __CFTimeZoneCache = NULL;
  97  static CFLock_t __CFTimeZoneGlobalLock = CFLockInit;
  98  
  99  #if DEPLOYMENT_TARGET_WINDOWS
 100  static CFDictionaryRef __CFTimeZoneWinToOlsonDict = NULL;
 101  static CFLock_t __CFTimeZoneWinToOlsonLock = CFLockInit;
 102  #endif
 103  
 104  CF_INLINE void __CFTimeZoneLockGlobal(void) {
 105      __CFLock(&__CFTimeZoneGlobalLock);
 106  }
 107  
 108  CF_INLINE void __CFTimeZoneUnlockGlobal(void) {
 109      __CFUnlock(&__CFTimeZoneGlobalLock);
 110  }
 111  
 112  CF_INLINE void __CFTimeZoneLockAbbreviations(void) {
 113      __CFLock(&__CFTimeZoneAbbreviationLock);
 114  }
 115  
 116  CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) {
 117      __CFUnlock(&__CFTimeZoneAbbreviationLock);
 118  }
 119  
 120  CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) {
 121      __CFLock(&__CFTimeZoneCompatibilityMappingLock);
 122  }
 123  
 124  CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) {
 125      __CFUnlock(&__CFTimeZoneCompatibilityMappingLock);
 126  }
 127  
 128  #if DEPLOYMENT_TARGET_WINDOWS
 129  /* This function should be used for WIN32 instead of
 130   * __CFCopyRecursiveDirectoryList function.
 131   * It takes TimeZone names from the registry
 132   * (Aleksey Dukhnyakov)
 133   */
 134  static CFMutableArrayRef __CFCopyWindowsTimeZoneList() {
 135      CFMutableArrayRef result = NULL;
 136      HKEY hkResult;
 137      TCHAR lpName[MAX_PATH+1];
 138      DWORD dwIndex, retCode;
 139  
 140      if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) !=
 141          ERROR_SUCCESS )
 142          return NULL;
 143  
 144      result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
 145      for (dwIndex=0; (retCode = RegEnumKey(hkResult,dwIndex,lpName,MAX_PATH)) != ERROR_NO_MORE_ITEMS ; dwIndex++) {
 146          if (retCode != ERROR_SUCCESS) {
 147              RegCloseKey(hkResult);
 148              CFRelease(result);
 149              return NULL;
 150          } else {
 151  #if defined(UNICODE)
 152  	    CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const UInt8 *)lpName, (_tcslen(lpName) * sizeof(UniChar)), kCFStringEncodingUnicode, false);
 153  #else
 154  	    CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, lpName, _tcslen(lpName), CFStringGetSystemEncoding(), false);
 155  #endif
 156  	    CFArrayAppendValue(result, string);
 157  	    CFRelease(string);
 158          }
 159      }
 160  
 161      RegCloseKey(hkResult);
 162      return result;
 163  }
 164  #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX
 165  static CFMutableArrayRef __CFCopyRecursiveDirectoryList() {
 166      CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
 167  #if DEPLOYMENT_TARGET_WINDOWS
 168      if (!__tzDir) __InitTZStrings();
 169      if (!__tzDir) return result;
 170      int fd = open(__tzDir, O_RDONLY);
 171  #else
 172      int fd = open(TZDIR "/zone.tab", O_RDONLY);
 173  #endif
 174  
 175      for (; 0 <= fd;) {
 176          uint8_t buffer[4096];
 177          ssize_t len = read(fd, buffer, sizeof(buffer));
 178          if (len <= 0) break;
 179  	if (len < sizeof(buffer)) {
 180  	    // assumes that partial read only occurs at the end of the file
 181  	    buffer[len] = '\n';
 182  	    len++;
 183  	}
 184          const uint8_t *bytes = buffer;
 185          for (;;) {
 186  	    const uint8_t *nextl = memchr(bytes, '\n', len);
 187  	    if (!nextl) break;
 188  	    nextl++;
 189  	    if ('#' == *bytes) {
 190  		len -= (nextl - bytes);
 191  		bytes = nextl;
 192  		continue;
 193  	    }
 194  	    const uint8_t *tab1 = memchr(bytes, '\t', (nextl - bytes));
 195  	    if (!tab1) {
 196  		len -= (nextl - bytes);
 197  		bytes = nextl;
 198  		continue;
 199  	    }
 200  	    tab1++;
 201  	    len -= (tab1 - bytes);
 202  	    bytes = tab1; 
 203  	    const uint8_t *tab2 = memchr(bytes, '\t', (nextl - bytes));
 204  	    if (!tab2) {
 205  		len -= (nextl - bytes);
 206  		bytes = nextl;
 207  		continue;
 208  	    }
 209  	    tab2++;
 210  	    len -= (tab2 - bytes);
 211  	    bytes = tab2; 
 212  	    const uint8_t *tab3 = memchr(bytes, '\t', (nextl - bytes));
 213  	    int nmlen = tab3 ? (tab3 - bytes) : (nextl - 1 - bytes);
 214  	    CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, bytes, nmlen, kCFStringEncodingUTF8, false);
 215  	    CFArrayAppendValue(result, string);
 216  	    CFRelease(string);
 217  	    len -= (nextl - bytes);
 218  	    bytes = nextl;
 219          }
 220          lseek(fd, -len, SEEK_CUR);
 221      }
 222      close(fd);
 223      return result;
 224  }
 225  #else
 226  #error Unknown or unspecified DEPLOYMENT_TARGET
 227  #endif
 228  
 229  typedef struct _CFTZPeriod {
 230      int32_t startSec;
 231      CFStringRef abbrev;
 232      uint32_t info;
 233  } CFTZPeriod;
 234  
 235  struct __CFTimeZone {
 236      CFRuntimeBase _base;
 237      CFStringRef _name;		/* immutable */
 238      CFDataRef _data;		/* immutable */
 239      CFTZPeriod *_periods;	/* immutable */
 240      int32_t _periodCnt;		/* immutable */
 241  };
 242  
 243  /* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates
 244   * between 1933 and 2069; info outside these years is discarded on read-in */
 245  /* Bits 31-18 of the info are unused */
 246  /* Bit 17 of the info is used for the is-DST state */
 247  /* Bit 16 of the info is used for the sign of the offset (1 == negative) */
 248  /* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */
 249  
 250  CF_INLINE void __CFTZPeriodInit(CFTZPeriod *period, int32_t startTime, CFStringRef abbrev, int32_t offset, Boolean isDST) {
 251      period->startSec = startTime;
 252      period->abbrev = abbrev ? (CFStringRef)CFRetain(abbrev) : NULL;
 253      __CFBitfieldSetValue(period->info, 15, 0, abs(offset));
 254      __CFBitfieldSetValue(period->info, 16, 16, (offset < 0 ? 1 : 0));
 255      __CFBitfieldSetValue(period->info, 17, 17, (isDST ? 1 : 0));
 256  }
 257  
 258  CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) {
 259      return period->startSec;
 260  }
 261  
 262  CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) {
 263      return period->abbrev;
 264  }
 265  
 266  CF_INLINE int32_t __CFTZPeriodGMTOffset(const CFTZPeriod *period) {
 267      int32_t v = __CFBitfieldGetValue(period->info, 15, 0);
 268      if (__CFBitfieldGetValue(period->info, 16, 16)) v = -v;
 269      return v;
 270  }
 271  
 272  CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) {
 273      return (Boolean)__CFBitfieldGetValue(period->info, 17, 17);
 274  }
 275  
 276  static CFComparisonResult __CFCompareTZPeriods(const void *val1, const void *val2, void *context) {
 277      CFTZPeriod *tzp1 = (CFTZPeriod *)val1;
 278      CFTZPeriod *tzp2 = (CFTZPeriod *)val2;
 279      // we treat equal as less than, as the code which uses the
 280      // result of the bsearch doesn't expect exact matches
 281      // (they're pretty rare, so no point in over-coding for them)
 282      if (__CFTZPeriodStartSeconds(tzp1) <= __CFTZPeriodStartSeconds(tzp2)) return kCFCompareLessThan;
 283      return kCFCompareGreaterThan;
 284  }
 285  
 286  static CFIndex __CFBSearchTZPeriods(CFTimeZoneRef tz, CFAbsoluteTime at) {
 287      CFTZPeriod elem;
 288      __CFTZPeriodInit(&elem, (int32_t)floor(at + 1.0), NULL, 0, false);
 289      CFIndex idx = CFBSearch(&elem, sizeof(CFTZPeriod), tz->_periods, tz->_periodCnt, __CFCompareTZPeriods, NULL);
 290      if (tz->_periodCnt <= idx) {
 291  	idx = tz->_periodCnt;
 292      } else if (0 == idx) {
 293  	idx = 1;
 294      }
 295      return idx - 1;
 296  }
 297  
 298  
 299  CF_INLINE int32_t __CFDetzcode(const unsigned char *bufp) {
 300      int32_t result = (bufp[0] & 0x80) ? ~0L : 0L;
 301      result = (result << 8) | (bufp[0] & 0xff);
 302      result = (result << 8) | (bufp[1] & 0xff);
 303      result = (result << 8) | (bufp[2] & 0xff);
 304      result = (result << 8) | (bufp[3] & 0xff);
 305      return result;
 306  }
 307  
 308  CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) {
 309      bufp[0] = (value >> 24) & 0xff;
 310      bufp[1] = (value >> 16) & 0xff;
 311      bufp[2] = (value >> 8) & 0xff;
 312      bufp[3] = (value >> 0) & 0xff;
 313  }
 314  
 315  static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) {
 316      int32_t len, timecnt, typecnt, charcnt, idx, cnt;
 317      const uint8_t *p, *timep, *typep, *ttisp, *charp;
 318      CFStringRef *abbrs;
 319      Boolean result = true;
 320  
 321      p = CFDataGetBytePtr(data);
 322      len = CFDataGetLength(data);
 323      if (len < (int32_t)sizeof(struct tzhead)) {
 324  	return false;
 325      }
 326      
 327      if (!(p[0] == 'T' && p[1] == 'Z' && p[2] == 'i' && p[3] == 'f')) return false;  /* Don't parse without TZif at head of file */
 328     
 329      p += 20 + 4 + 4 + 4;	/* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */
 330      timecnt = __CFDetzcode(p);
 331      p += 4;
 332      typecnt = __CFDetzcode(p);
 333      p += 4;
 334      charcnt = __CFDetzcode(p);
 335      p += 4;
 336      if (typecnt <= 0 || timecnt < 0 || charcnt < 0) {
 337  	return false;
 338      }
 339      if (1024 < timecnt || 32 < typecnt || 128 < charcnt) {
 340  	// reject excessive timezones to avoid arithmetic overflows for
 341  	// security reasons and to reject potentially corrupt files
 342  	return false;
 343      }
 344      if (len - (int32_t)sizeof(struct tzhead) < (4 + 1) * timecnt + (4 + 1 + 1) * typecnt + charcnt) {
 345  	return false;
 346      }
 347      timep = p;
 348      typep = timep + 4 * timecnt;
 349      ttisp = typep + timecnt;
 350      charp = ttisp + (4 + 1 + 1) * typecnt;
 351      cnt = (0 < timecnt) ? timecnt : 1;
 352      *tzpp = CFAllocatorAllocate(allocator, cnt * sizeof(CFTZPeriod), 0);
 353      if (__CFOASafe) __CFSetLastAllocationEventName(*tzpp, "CFTimeZone (store)");
 354      memset(*tzpp, 0, cnt * sizeof(CFTZPeriod));
 355      abbrs = CFAllocatorAllocate(allocator, (charcnt + 1) * sizeof(CFStringRef), 0);
 356      if (__CFOASafe) __CFSetLastAllocationEventName(abbrs, "CFTimeZone (temp)");
 357      for (idx = 0; idx < charcnt + 1; idx++) {
 358  	abbrs[idx] = NULL;
 359      }
 360      for (idx = 0; idx < cnt; idx++) {
 361  	CFAbsoluteTime at;
 362  	int32_t itime, offset;
 363  	uint8_t type, dst, abbridx;
 364  
 365  	at = (CFAbsoluteTime)(__CFDetzcode(timep) + 0.0) - kCFAbsoluteTimeIntervalSince1970;
 366  	if (0 == timecnt) itime = INT_MIN;
 367  	else if (at < (CFAbsoluteTime)INT_MIN) itime = INT_MIN;
 368  	else if ((CFAbsoluteTime)INT_MAX < at) itime = INT_MAX;
 369  	else itime = (int32_t)at;
 370  	timep += 4;	/* harmless if 0 == timecnt */
 371  	type = (0 < timecnt) ? (uint8_t)*typep++ : 0;
 372  	if (typecnt <= type) {
 373  	    result = false;
 374  	    break;
 375  	}
 376  	offset = __CFDetzcode(ttisp + 6 * type);
 377  	dst = (uint8_t)*(ttisp + 6 * type + 4);
 378  	if (0 != dst && 1 != dst) {
 379  	    result = false;
 380  	    break;
 381  	}
 382  	abbridx = (uint8_t)*(ttisp + 6 * type + 5);
 383  	if (charcnt < abbridx) {
 384  	    result = false;
 385  	    break;
 386  	}
 387  	if (NULL == abbrs[abbridx]) {
 388  	    abbrs[abbridx] = CFStringCreateWithCString(allocator, (char *)&charp[abbridx], kCFStringEncodingASCII);
 389  	}
 390  	__CFTZPeriodInit(*tzpp + idx, itime, abbrs[abbridx], offset, (dst ? true : false));
 391      }
 392      for (idx = 0; idx < charcnt + 1; idx++) {
 393  	if (NULL != abbrs[idx]) {
 394  	    CFRelease(abbrs[idx]);
 395  	}
 396      }
 397      CFAllocatorDeallocate(allocator, abbrs);
 398      if (result) {
 399  	// dump all but the last INT_MIN and the first INT_MAX
 400  	for (idx = 0; idx < cnt; idx++) {
 401  	    if (((*tzpp + idx)->startSec == INT_MIN) && (idx + 1 < cnt) && (((*tzpp + idx + 1)->startSec == INT_MIN))) {
 402  		if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev);
 403  		cnt--;
 404  		memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx));
 405  		idx--;
 406  	    }
 407  	}
 408  	// Don't combine these loops!  Watch the idx decrementing...
 409  	for (idx = 0; idx < cnt; idx++) {
 410  	    if (((*tzpp + idx)->startSec == INT_MAX) && (0 < idx) && (((*tzpp + idx - 1)->startSec == INT_MAX))) {
 411  		if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev);
 412  		cnt--;
 413  		memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx));
 414  		idx--;
 415  	    }
 416  	}
 417  	CFQSortArray(*tzpp, cnt, sizeof(CFTZPeriod), __CFCompareTZPeriods, NULL);
 418  	// if the first period is in DST and there is more than one period, drop it
 419  	if (1 < cnt && __CFTZPeriodIsDST(*tzpp + 0)) {
 420  	    if (NULL != (*tzpp + 0)->abbrev) CFRelease((*tzpp + 0)->abbrev);
 421  	    cnt--;
 422  	    memmove((*tzpp + 0), (*tzpp + 0 + 1), sizeof(CFTZPeriod) * (cnt - 0));
 423  	}
 424  	*cntp = cnt;
 425      } else {
 426  	CFAllocatorDeallocate(allocator, *tzpp);
 427  	*tzpp = NULL;
 428      }
 429      return result;
 430  }
 431  
 432  static Boolean __CFTimeZoneEqual(CFTypeRef cf1, CFTypeRef cf2) {
 433      CFTimeZoneRef tz1 = (CFTimeZoneRef)cf1;
 434      CFTimeZoneRef tz2 = (CFTimeZoneRef)cf2;
 435      if (!CFEqual(CFTimeZoneGetName(tz1), CFTimeZoneGetName(tz2))) return false;
 436      if (!CFEqual(CFTimeZoneGetData(tz1), CFTimeZoneGetData(tz2))) return false;
 437      return true;
 438  }
 439  
 440  static CFHashCode __CFTimeZoneHash(CFTypeRef cf) {
 441      CFTimeZoneRef tz = (CFTimeZoneRef)cf;
 442      return CFHash(CFTimeZoneGetName(tz));
 443  }
 444  
 445  static CFStringRef __CFTimeZoneCopyDescription(CFTypeRef cf) {
 446      CFTimeZoneRef tz = (CFTimeZoneRef)cf;
 447      CFStringRef result, abbrev;
 448      CFAbsoluteTime at;
 449      at = CFAbsoluteTimeGetCurrent();
 450      abbrev = CFTimeZoneCopyAbbreviation(tz, at);
 451      result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFTimeZone %p [%p]>{name = %@; abbreviation = %@; GMT offset = %g; is DST = %s}"), cf, CFGetAllocator(tz), tz->_name, abbrev, CFTimeZoneGetSecondsFromGMT(tz, at), CFTimeZoneIsDaylightSavingTime(tz, at) ? "true" : "false");
 452      CFRelease(abbrev);
 453      return result;
 454  }
 455  
 456  static void __CFTimeZoneDeallocate(CFTypeRef cf) {
 457      CFTimeZoneRef tz = (CFTimeZoneRef)cf;
 458      CFAllocatorRef allocator = CFGetAllocator(tz);
 459      CFIndex idx;
 460      if (tz->_name) CFRelease(tz->_name);
 461      if (tz->_data) CFRelease(tz->_data);
 462      for (idx = 0; idx < tz->_periodCnt; idx++) {
 463  	if (NULL != tz->_periods[idx].abbrev) CFRelease(tz->_periods[idx].abbrev);
 464      }
 465      if (NULL != tz->_periods) CFAllocatorDeallocate(allocator, tz->_periods);
 466  }
 467  
 468  static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID;
 469  
 470  static const CFRuntimeClass __CFTimeZoneClass = {
 471      0,
 472      "CFTimeZone",
 473      NULL,	// init
 474      NULL,	// copy
 475      __CFTimeZoneDeallocate,
 476      __CFTimeZoneEqual,
 477      __CFTimeZoneHash,
 478      NULL,	//
 479      __CFTimeZoneCopyDescription
 480  };
 481  
 482  CFTypeID CFTimeZoneGetTypeID(void) {
 483      static dispatch_once_t initOnce;
 484      dispatch_once(&initOnce, ^{ __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass); });
 485      return __kCFTimeZoneTypeID;
 486  }
 487  
 488  #if DEPLOYMENT_TARGET_WINDOWS
 489  static const char *__CFTimeZoneWinToOlsonDefaults =
 490  /* Mappings to time zones in Windows Registry are best-guess */
 491  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
 492  " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
 493  " <plist version=\"1.0\">"
 494  " <dict>"
 495  "    <key>Afghanistan</key>                 <string>Asia/Kabul</string>"
 496  "    <key>Afghanistan Standard Time</key>   <string>Asia/Kabul</string>"
 497  "    <key>Alaskan</key>                     <string>America/Anchorage</string>"
 498  "    <key>Alaskan Standard Time</key>       <string>America/Anchorage</string>"
 499  "    <key>Arab</key>                        <string>Asia/Riyadh</string>"
 500  "    <key>Arab Standard Time</key>          <string>Asia/Riyadh</string>"
 501  "    <key>Arabian</key>                     <string>Asia/Muscat</string>"
 502  "    <key>Arabian Standard Time</key>       <string>Asia/Muscat</string>"
 503  "    <key>Arabic Standard Time</key>        <string>Asia/Baghdad</string>"
 504  "    <key>Atlantic</key>                    <string>America/Halifax</string>"
 505  "    <key>Atlantic Standard Time</key>      <string>America/Halifax</string>"
 506  "    <key>AUS Central</key>                 <string>Australia/Darwin</string>"
 507  "    <key>AUS Central Standard Time</key>	<string>Australia/Darwin</string>"
 508  "    <key>AUS Eastern</key>                 <string>Australia/Sydney</string>"
 509  "    <key>AUS Eastern Standard Time</key>	<string>Australia/Sydney</string>"
 510  "    <key>Azerbaijan Standard Time</key>	<string>Asia/Baku</string>"
 511  "    <key>Azores</key>                      <string>Atlantic/Azores</string>"
 512  "    <key>Azores Standard Time</key>        <string>Atlantic/Azores</string>"
 513  "    <key>Bangkok</key>                     <string>Asia/Bangkok</string>"
 514  "    <key>Bangkok Standard Time</key>       <string>Asia/Bangkok</string>"
 515  "    <key>Beijing</key>                     <string>Asia/Shanghai</string>"
 516  "    <key>Canada Central</key>              <string>America/Regina</string>"
 517  "    <key>Canada Central Standard Time</key> <string>America/Regina</string>"
 518  "    <key>Cape Verde Standard Time</key>    <string>Atlantic/Cape_Verde</string>"
 519  "    <key>Caucasus</key>                    <string>Asia/Yerevan</string>"
 520  "    <key>Caucasus Standard Time</key>      <string>Asia/Yerevan</string>"
 521  "    <key>Cen. Australia</key>              <string>Australia/Adelaide</string>"
 522  "    <key>Cen. Australia Standard Time</key> <string>Australia/Adelaide</string>"
 523  "    <key>Central</key>                     <string>America/Chicago</string>"
 524  "    <key>Central America Standard Time</key> <string>America/Regina</string>"
 525  "    <key>Central Asia</key>                <string>Asia/Dhaka</string>"
 526  "    <key>Central Asia Standard Time</key>	<string>Asia/Dhaka</string>"
 527  "    <key>Central Brazilian Standard Time</key>	<string>America/Manaus</string>"
 528  "    <key>Central Europe</key>              <string>Europe/Prague</string>"
 529  "    <key>Central Europe Standard Time</key> <string>Europe/Prague</string>"
 530  "    <key>Central European</key>            <string>Europe/Belgrade</string>"
 531  "    <key>Central European Standard Time</key>	<string>Europe/Belgrade</string>"
 532  "    <key>Central Pacific</key>             <string>Pacific/Guadalcanal</string>"
 533  "    <key>Central Pacific Standard Time</key>	<string>Pacific/Guadalcanal</string>"
 534  "    <key>Central Standard Time</key>       <string>America/Chicago</string>"
 535  "    <key>Central Standard Time (Mexico)</key> <string>America/Mexico_City</string>"
 536  "    <key>China</key>                       <string>Asia/Shanghai</string>"
 537  "    <key>China Standard Time</key>         <string>Asia/Shanghai</string>"
 538  "    <key>Dateline</key>                    <string>GMT-1200</string>"
 539  "    <key>Dateline Standard Time</key>      <string>GMT-1200</string>"
 540  "    <key>E. Africa</key>                   <string>Africa/Nairobi</string>"
 541  "    <key>E. Africa Standard Time</key>     <string>Africa/Nairobi</string>"
 542  "    <key>E. Australia</key>                <string>Australia/Brisbane</string>"
 543  "    <key>E. Australia Standard Time</key>	<string>Australia/Brisbane</string>"
 544  "    <key>E. Europe</key>                   <string>Europe/Minsk</string>"
 545  "    <key>E. Europe Standard Time</key>     <string>Europe/Minsk</string>"
 546  "    <key>E. South America</key>            <string>America/Sao_Paulo</string>"
 547  "    <key>E. South America Standard Time</key>	<string>America/Sao_Paulo</string>"
 548  "    <key>Eastern</key>                     <string>America/New_York</string>"
 549  "    <key>Eastern Standard Time</key>       <string>America/New_York</string>"
 550  "    <key>Egypt</key>       <string>Africa/Cairo</string>"
 551  "    <key>Egypt Standard Time</key> <string>Africa/Cairo</string>"
 552  "    <key>Ekaterinburg</key>                <string>Asia/Yekaterinburg</string>"
 553  "    <key>Ekaterinburg Standard Time</key>	<string>Asia/Yekaterinburg</string>"
 554  "    <key>Fiji</key>	<string>Pacific/Fiji</string>"
 555  "    <key>Fiji Standard Time</key>	<string>Pacific/Fiji</string>"
 556  "    <key>FLE</key>	<string>Europe/Helsinki</string>"
 557  "    <key>FLE Standard Time</key>	<string>Europe/Helsinki</string>"
 558  "    <key>Georgian Standard Time</key>	<string>Asia/Tbilisi</string>"
 559  "    <key>GFT</key>	<string>Europe/Athens</string>"
 560  "    <key>GFT Standard Time</key>	<string>Europe/Athens</string>"
 561  "    <key>GMT</key>	<string>Europe/London</string>"
 562  "    <key>GMT Standard Time</key>	<string>Europe/London</string>"
 563  "    <key>Greenland Standard Time</key>	<string>America/Godthab</string>"
 564  "    <key>Greenwich</key>	<string>GMT</string>"
 565  "    <key>Greenwich Standard Time</key>	<string>GMT</string>"
 566  "    <key>GTB</key>	<string>Europe/Athens</string>"
 567  "    <key>GTB Standard Time</key>	<string>Europe/Athens</string>"
 568  "    <key>Hawaiian</key>	<string>Pacific/Honolulu</string>"
 569  "    <key>Hawaiian Standard Time</key>	<string>Pacific/Honolulu</string>"
 570  "    <key>India</key>	<string>Asia/Calcutta</string>"
 571  "    <key>India Standard Time</key>	<string>Asia/Calcutta</string>"
 572  "    <key>Iran</key>	<string>Asia/Tehran</string>"
 573  "    <key>Iran Standard Time</key>	<string>Asia/Tehran</string>"
 574  "    <key>Israel</key>	<string>Asia/Jerusalem</string>"
 575  "    <key>Israel Standard Time</key>	<string>Asia/Jerusalem</string>"
 576  "    <key>Jordan Standard Time</key>	<string>Asia/Amman</string>"
 577  "    <key>Korea</key>	<string>Asia/Seoul</string>"
 578  "    <key>Korea Standard Time</key>	<string>Asia/Seoul</string>"
 579  "    <key>Mexico</key>	<string>America/Mexico_City</string>"
 580  "    <key>Mexico Standard Time</key>	<string>America/Mexico_City</string>"
 581  "    <key>Mexico Standard Time 2</key>	<string>America/Chihuahua</string>"
 582  "    <key>Mid-Atlantic</key>	<string>Atlantic/South_Georgia</string>"
 583  "    <key>Mid-Atlantic Standard Time</key>	<string>Atlantic/South_Georgia</string>"
 584  "    <key>Middle East Standard Time</key>	<string>Asia/Beirut</string>"
 585  "    <key>Mountain</key>	<string>America/Denver</string>"
 586  "    <key>Mountain Standard Time</key>	<string>America/Denver</string>"
 587  "    <key>Mountain Standard Time (Mexico)</key>	<string>America/Chihuahua</string>"
 588  "    <key>Myanmar Standard Time</key>	<string>Asia/Rangoon</string>"
 589  "    <key>N. Central Asia Standard Time</key>   <string>Asia/Novosibirsk</string>"
 590  "    <key>Namibia Standard Time</key>   <string>Africa/Windhoek</string>"
 591  "    <key>Nepal Standard Time</key>	<string>Asia/Katmandu</string>"
 592  "    <key>New Zealand</key>	<string>Pacific/Auckland</string>"
 593  "    <key>New Zealand Standard Time</key>	<string>Pacific/Auckland</string>"
 594  "    <key>Newfoundland</key>	<string>America/St_Johns</string>"
 595  "    <key>Newfoundland Standard Time</key>	<string>America/St_Johns</string>"
 596  "    <key>North Asia East Standard Time</key>	<string>Asia/Ulaanbaatar</string>"
 597  "    <key>North Asia Standard Time</key>	<string>Asia/Krasnoyarsk</string>"
 598  "    <key>Pacific</key>	<string>America/Los_Angeles</string>"
 599  "    <key>Pacific SA</key>	<string>America/Santiago</string>"
 600  "    <key>Pacific SA Standard Time</key>	<string>America/Santiago</string>"
 601  "    <key>Pacific Standard Time</key>	<string>America/Los_Angeles</string>"
 602  "    <key>Pacific Standard Time (Mexico)</key>	<string>America/Tijuana</string>"
 603  "    <key>Prague Bratislava</key>	<string>Europe/Prague</string>"
 604  "    <key>Romance</key>	<string>Europe/Paris</string>"
 605  "    <key>Romance Standard Time</key>	<string>Europe/Paris</string>"
 606  "    <key>Russian</key>	<string>Europe/Moscow</string>"
 607  "    <key>Russian Standard Time</key>	<string>Europe/Moscow</string>"
 608  "    <key>SA Eastern</key>	<string>America/Buenos_Aires</string>"
 609  "    <key>SA Eastern Standard Time</key>	<string>America/Buenos_Aires</string>"
 610  "    <key>SA Pacific</key>	<string>America/Bogota</string>"
 611  "    <key>SA Pacific Standard Time</key>	<string>America/Bogota</string>"
 612  "    <key>SA Western</key>	<string>America/Caracas</string>"
 613  "    <key>SA Western Standard Time</key>	<string>America/Caracas</string>"
 614  "    <key>Samoa</key>	<string>Pacific/Apia</string>"
 615  "    <key>Samoa Standard Time</key>	<string>Pacific/Apia</string>"
 616  "    <key>Saudi Arabia</key>	<string>Asia/Riyadh</string>"
 617  "    <key>Saudi Arabia Standard Time</key>	<string>Asia/Riyadh</string>"
 618  "    <key>SE Asia Standard Time</key>	<string>Asia/Bangkok</string>"
 619  "    <key>Singapore</key>	<string>Asia/Singapore</string>"
 620  "    <key>Singapore Standard Time</key>	<string>Asia/Singapore</string>"
 621  "    <key>South Africa</key>	<string>Africa/Harare</string>"
 622  "    <key>South Africa Standard Time</key>	<string>Africa/Harare</string>"
 623  "    <key>Sri Lanka</key>	<string>Asia/Colombo</string>"
 624  "    <key>Sri Lanka Standard Time</key>	<string>Asia/Colombo</string>"
 625  "    <key>Sydney Standard Time</key>	<string>Australia/Sydney</string>"
 626  "    <key>Taipei</key>	<string>Asia/Taipei</string>"
 627  "    <key>Taipei Standard Time</key>	<string>Asia/Taipei</string>"
 628  "    <key>Tasmania</key>	<string>Australia/Hobart</string>"
 629  "    <key>Tasmania Standard Time</key>	<string>Australia/Hobart</string>"
 630  "    <key>Tasmania Standard Time</key>	<string>Australia/Hobart</string>"
 631  "    <key>Tokyo</key>	<string>Asia/Tokyo</string>"
 632  "    <key>Tokyo Standard Time</key>	<string>Asia/Tokyo</string>"
 633  "    <key>Tonga Standard Time</key>	<string>Pacific/Tongatapu</string>"
 634  "    <key>US Eastern</key>	<string>America/Indianapolis</string>"
 635  "    <key>US Eastern Standard Time</key>	<string>America/Indianapolis</string>"
 636  "    <key>US Mountain</key>	<string>America/Phoenix</string>"
 637  "    <key>US Mountain Standard Time</key>	<string>America/Phoenix</string>"
 638  "    <key>Vladivostok</key>	<string>Asia/Vladivostok</string>"
 639  "    <key>Vladivostok Standard Time</key>	<string>Asia/Vladivostok</string>"
 640  "    <key>W. Australia</key>	<string>Australia/Perth</string>"
 641  "    <key>W. Australia Standard Time</key>	<string>Australia/Perth</string>"
 642  "    <key>W. Central Africa Standard Time</key>	<string>Africa/Luanda</string>"
 643  "    <key>W. Europe</key>	<string>Europe/Berlin</string>"
 644  "    <key>W. Europe Standard Time</key>	<string>Europe/Berlin</string>"
 645  "    <key>Warsaw</key>	<string>Europe/Warsaw</string>"
 646  "    <key>West Asia</key>	<string>Asia/Karachi</string>"
 647  "    <key>West Asia Standard Time</key>	<string>Asia/Karachi</string>"
 648  "    <key>West Pacific</key>	<string>Pacific/Guam</string>"
 649  "    <key>West Pacific Standard Time</key>	<string>Pacific/Guam</string>"
 650  "    <key>Western Brazilian Standard Time</key>	<string>America/Rio_Branco</string>"
 651  "    <key>Yakutsk</key>	<string>Asia/Yakutsk</string>"
 652  " </dict>"
 653  " </plist>";
 654  
 655  CF_INLINE void __CFTimeZoneLockWinToOlson(void) {
 656      __CFLock(&__CFTimeZoneWinToOlsonLock);
 657  }
 658  
 659  CF_INLINE void __CFTimeZoneUnlockWinToOlson(void) {
 660      __CFUnlock(&__CFTimeZoneWinToOlsonLock);
 661  }
 662  
 663  CFDictionaryRef CFTimeZoneCopyWinToOlsonDictionary(void) {
 664      CFDictionaryRef dict;
 665      __CFTimeZoneLockWinToOlson();
 666      if (NULL == __CFTimeZoneWinToOlsonDict) {
 667          CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneWinToOlsonDefaults, strlen(__CFTimeZoneWinToOlsonDefaults));
 668          __CFTimeZoneWinToOlsonDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL);
 669          CFRelease(data);
 670      }
 671      if (NULL == __CFTimeZoneWinToOlsonDict) {
 672          __CFTimeZoneWinToOlsonDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL);
 673      }
 674      dict = __CFTimeZoneWinToOlsonDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneWinToOlsonDict) : NULL;
 675      __CFTimeZoneUnlockWinToOlson();
 676      return dict;
 677  }
 678  
 679  void CFTimeZoneSetWinToOlsonDictionary(CFDictionaryRef dict) {
 680      __CFGenericValidateType(dict, CFDictionaryGetTypeID());
 681      __CFTimeZoneLockWinToOlson();
 682      if (dict != __CFTimeZoneWinToOlsonDict) {
 683          if (dict) CFRetain(dict);
 684          if (__CFTimeZoneWinToOlsonDict) CFRelease(__CFTimeZoneWinToOlsonDict);
 685          __CFTimeZoneWinToOlsonDict = dict;
 686      }
 687      __CFTimeZoneUnlockWinToOlson();
 688  }
 689  
 690  CFTimeZoneRef CFTimeZoneCreateWithWindowsName(CFAllocatorRef allocator, CFStringRef winName) {
 691      if (!winName) return NULL;
 692      
 693      CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary();
 694      if (!winToOlson) return NULL;
 695      
 696      CFStringRef olsonName = CFDictionaryGetValue(winToOlson, winName);
 697      CFTimeZoneRef retval = NULL;
 698      if (olsonName) {
 699           retval = CFTimeZoneCreateWithName(allocator, olsonName, false);
 700      }
 701      CFRelease(winToOlson);
 702      return retval;
 703  }
 704  
 705  extern CFStringRef _CFGetWindowsAppleSystemLibraryDirectory(void);
 706  void __InitTZStrings(void) {
 707      static CFLock_t __CFTZDirLock = CFLockInit;
 708      __CFLock(&__CFTZDirLock);
 709      if (!__tzZoneInfo) {
 710          CFStringRef winDir = _CFGetWindowsAppleSystemLibraryDirectory();
 711          __tzZoneInfo = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@\\etc\\zoneinfo"), winDir);
 712      }   
 713      if (!__tzDir && __tzZoneInfo) {
 714          int length = CFStringGetLength(__tzZoneInfo) + sizeof("\\zone.tab") + 1;
 715          __tzDir = malloc(length); // If we don't use ascii, we'll need to malloc more space
 716          if (!__tzDir || !CFStringGetCString(__tzZoneInfo, __tzDir, length, kCFStringEncodingASCII)) {
 717              free(__tzDir);
 718          } else {
 719              strcat(__tzDir, "\\zone.tab");
 720          }
 721      }
 722      __CFUnlock(&__CFTZDirLock);
 723  }
 724  #endif
 725  
 726  static CFTimeZoneRef __CFTimeZoneCreateSystem(void) {
 727      CFTimeZoneRef result = NULL;
 728      
 729  #if DEPLOYMENT_TARGET_WINDOWS
 730      CFStringRef name = NULL;
 731      TIME_ZONE_INFORMATION tzi = { 0 };
 732      DWORD rval = GetTimeZoneInformation(&tzi);
 733      if (rval != TIME_ZONE_ID_INVALID) {
 734          LPWSTR standardName = (LPWSTR)&tzi.StandardName;
 735          CFStringRef cfStandardName = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (UInt8 *)standardName, wcslen(standardName)*sizeof(WCHAR), kCFStringEncodingUTF16LE, false);
 736          if (cfStandardName) {
 737              CFDictionaryRef winToOlson = CFTimeZoneCopyWinToOlsonDictionary();
 738              if (winToOlson) {
 739                  name = CFDictionaryGetValue(winToOlson, cfStandardName);
 740                  if (name) CFRetain(name);
 741                  CFRelease(winToOlson);
 742              }
 743              CFRelease(cfStandardName);
 744          }
 745      } else {
 746          CFLog(kCFLogLevelError, CFSTR("Couldn't get time zone information error %d"), GetLastError());
 747      }
 748      if (name) {
 749  #else
 750      const char *tzenv;
 751      int ret;
 752      char linkbuf[CFMaxPathSize];
 753  
 754      tzenv = __CFgetenv("TZFILE");
 755      if (NULL != tzenv) {
 756  	CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false);
 757  	result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false);
 758  	CFRelease(name);
 759  	if (result) return result;
 760      }
 761      tzenv = __CFgetenv("TZ");
 762      if (NULL != tzenv) {
 763  	CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false);
 764  	result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true);
 765  	CFRelease(name);
 766  	if (result) return result;
 767      }
 768      ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf));
 769      if (0 < ret) {
 770  	CFStringRef name;
 771  	linkbuf[ret] = '\0';
 772  	if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) {
 773  	    name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false);
 774  	} else {
 775  	    name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false);
 776  	}
 777  #endif
 778  
 779  	result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false);
 780  	CFRelease(name);
 781  	if (result) return result;
 782      }
 783      return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0);
 784  }
 785  
 786  CFTimeZoneRef CFTimeZoneCopySystem(void) {
 787      CFTimeZoneRef tz;
 788      __CFTimeZoneLockGlobal();
 789      if (NULL == __CFTimeZoneSystem) {
 790  	__CFTimeZoneUnlockGlobal();
 791  	tz = __CFTimeZoneCreateSystem();
 792  	__CFTimeZoneLockGlobal();
 793  	if (NULL == __CFTimeZoneSystem) {
 794  	    __CFTimeZoneSystem = tz;
 795  	} else {
 796  	    if (tz) CFRelease(tz);
 797  	}
 798      }
 799      tz = __CFTimeZoneSystem ? (CFTimeZoneRef)CFRetain(__CFTimeZoneSystem) : NULL;
 800      __CFTimeZoneUnlockGlobal();
 801      return tz;
 802  }
 803  
 804  static CFIndex __noteCount = 0;
 805  
 806  void CFTimeZoneResetSystem(void) {
 807      __CFTimeZoneLockGlobal();
 808      if (__CFTimeZoneDefault == __CFTimeZoneSystem) {
 809  	if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault);
 810  	__CFTimeZoneDefault = NULL;
 811      }
 812      CFTimeZoneRef tz = __CFTimeZoneSystem;
 813      __CFTimeZoneSystem = NULL;
 814      __CFTimeZoneUnlockGlobal();
 815      if (tz) CFRelease(tz);
 816  }
 817  
 818  CFIndex _CFTimeZoneGetNoteCount(void) {
 819      return __noteCount;
 820  }
 821  
 822  CFTimeZoneRef CFTimeZoneCopyDefault(void) {
 823      CFTimeZoneRef tz;
 824      __CFTimeZoneLockGlobal();
 825      if (NULL == __CFTimeZoneDefault) {
 826  	__CFTimeZoneUnlockGlobal();
 827  	tz = CFTimeZoneCopySystem();
 828  	__CFTimeZoneLockGlobal();
 829  	if (NULL == __CFTimeZoneDefault) {
 830  	    __CFTimeZoneDefault = tz;
 831  	} else {
 832  	    if (tz) CFRelease(tz);
 833  	}
 834      }
 835      tz = __CFTimeZoneDefault ? (CFTimeZoneRef)CFRetain(__CFTimeZoneDefault) : NULL;
 836      __CFTimeZoneUnlockGlobal();
 837      return tz;
 838  }
 839  
 840  void CFTimeZoneSetDefault(CFTimeZoneRef tz) {
 841      if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
 842      __CFTimeZoneLockGlobal();
 843      if (tz != __CFTimeZoneDefault) {
 844  	if (tz) CFRetain(tz);
 845  	if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault);
 846  	__CFTimeZoneDefault = tz;
 847      }
 848      __CFTimeZoneUnlockGlobal();
 849  }
 850  
 851  static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void);
 852  
 853  CFArrayRef CFTimeZoneCopyKnownNames(void) {
 854      CFArrayRef tzs;
 855      __CFTimeZoneLockGlobal();
 856      if (NULL == __CFKnownTimeZoneList) {
 857  	CFMutableArrayRef list;
 858  /* TimeZone information locate in the registry for Win32
 859   * (Aleksey Dukhnyakov)
 860   */
 861          list = __CFCopyRecursiveDirectoryList();
 862  	// Remove undesirable ancient cruft
 863  	CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary();
 864  	CFIndex idx;
 865  	for (idx = CFArrayGetCount(list); idx--; ) {
 866  	    CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(list, idx);
 867  	    if (CFDictionaryContainsKey(dict, item)) {
 868  		CFArrayRemoveValueAtIndex(list, idx);
 869  	    }
 870  	}
 871  	__CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list);
 872  	CFRelease(list);
 873      }
 874      tzs = __CFKnownTimeZoneList ? (CFArrayRef)CFRetain(__CFKnownTimeZoneList) : NULL;
 875      __CFTimeZoneUnlockGlobal();
 876      return tzs;
 877  }
 878  
 879  /* The criteria here are sort of: coverage for the U.S. and Europe,
 880   * large cities, abbreviation uniqueness, and perhaps a few others.
 881   * But do not make the list too large with obscure information.
 882   */
 883  static const char *__CFTimeZoneAbbreviationDefaults =
 884  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
 885  " <!DOCTYPE plist SYSTEM \"file://localhost/System/Library/DTDs/PropertyList.dtd\">"
 886  " <plist version=\"1.0\">"
 887  " <dict>"
 888  "    <key>ADT</key>  <string>America/Halifax</string>"
 889  "    <key>AKDT</key> <string>America/Juneau</string>"
 890  "    <key>AKST</key> <string>America/Juneau</string>"
 891  "    <key>ART</key>  <string>America/Argentina/Buenos_Aires</string>"
 892  "    <key>AST</key>  <string>America/Halifax</string>"
 893  "    <key>BDT</key>  <string>Asia/Dhaka</string>"
 894  "    <key>BRST</key> <string>America/Sao_Paulo</string>"
 895  "    <key>BRT</key>  <string>America/Sao_Paulo</string>"
 896  "    <key>BST</key>  <string>Europe/London</string>"
 897  "    <key>CAT</key>  <string>Africa/Harare</string>"
 898  "    <key>CDT</key>  <string>America/Chicago</string>"
 899  "    <key>CEST</key> <string>Europe/Paris</string>"
 900  "    <key>CET</key>  <string>Europe/Paris</string>"
 901  "    <key>CLST</key> <string>America/Santiago</string>"
 902  "    <key>CLT</key>  <string>America/Santiago</string>"
 903  "    <key>COT</key>  <string>America/Bogota</string>"
 904  "    <key>CST</key>  <string>America/Chicago</string>"
 905  "    <key>EAT</key>  <string>Africa/Addis_Ababa</string>"
 906  "    <key>EDT</key>  <string>America/New_York</string>"
 907  "    <key>EEST</key> <string>Europe/Istanbul</string>"
 908  "    <key>EET</key>  <string>Europe/Istanbul</string>"
 909  "    <key>EST</key>  <string>America/New_York</string>"
 910  "    <key>GMT</key>  <string>GMT</string>"
 911  "    <key>GST</key>  <string>Asia/Dubai</string>"
 912  "    <key>HKT</key>  <string>Asia/Hong_Kong</string>"
 913  "    <key>HST</key>  <string>Pacific/Honolulu</string>"
 914  "    <key>ICT</key>  <string>Asia/Bangkok</string>"
 915  "    <key>IRST</key> <string>Asia/Tehran</string>"
 916  "    <key>IST</key>  <string>Asia/Calcutta</string>"
 917  "    <key>JST</key>  <string>Asia/Tokyo</string>"
 918  "    <key>KST</key>  <string>Asia/Seoul</string>"
 919  "    <key>MDT</key>  <string>America/Denver</string>"
 920  "    <key>MSD</key>  <string>Europe/Moscow</string>"
 921  "    <key>MSK</key>  <string>Europe/Moscow</string>"
 922  "    <key>MST</key>  <string>America/Denver</string>"
 923  "    <key>NZDT</key> <string>Pacific/Auckland</string>"
 924  "    <key>NZST</key> <string>Pacific/Auckland</string>"
 925  "    <key>PDT</key>  <string>America/Los_Angeles</string>"
 926  "    <key>PET</key>  <string>America/Lima</string>"
 927  "    <key>PHT</key>  <string>Asia/Manila</string>"
 928  "    <key>PKT</key>  <string>Asia/Karachi</string>"
 929  "    <key>PST</key>  <string>America/Los_Angeles</string>"
 930  "    <key>SGT</key>  <string>Asia/Singapore</string>"
 931  "    <key>UTC</key>  <string>UTC</string>"
 932  "    <key>WAT</key>  <string>Africa/Lagos</string>"
 933  "    <key>WEST</key> <string>Europe/Lisbon</string>"
 934  "    <key>WET</key>  <string>Europe/Lisbon</string>"
 935  "    <key>WIT</key>  <string>Asia/Jakarta</string>"
 936  " </dict>"
 937  " </plist>";
 938  
 939  CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) {
 940      CFDictionaryRef dict;
 941      __CFTimeZoneLockAbbreviations();
 942      if (NULL == __CFTimeZoneAbbreviationDict) {
 943  	CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults));
 944  	__CFTimeZoneAbbreviationDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL);
 945  	CFRelease(data);
 946      }
 947      if (NULL == __CFTimeZoneAbbreviationDict) {
 948  	__CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL);
 949      }
 950      dict = __CFTimeZoneAbbreviationDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneAbbreviationDict) : NULL;
 951      __CFTimeZoneUnlockAbbreviations();
 952      return dict;
 953  }
 954  
 955  void _removeFromCache(const void *key, const void *value, void *context) {
 956      CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)key);
 957  }
 958  
 959  void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) {
 960      __CFGenericValidateType(dict, CFDictionaryGetTypeID());
 961      __CFTimeZoneLockGlobal();
 962      if (dict != __CFTimeZoneAbbreviationDict) {
 963  	if (dict) CFRetain(dict);
 964  	if (__CFTimeZoneAbbreviationDict) {
 965  	    CFDictionaryApplyFunction(__CFTimeZoneAbbreviationDict, _removeFromCache, NULL);
 966  	    CFRelease(__CFTimeZoneAbbreviationDict);
 967  	}
 968  	__CFTimeZoneAbbreviationDict = dict;
 969      }
 970      __CFTimeZoneUnlockGlobal();
 971  }
 972  
 973  CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) {
 974  // assert:    (NULL != name && NULL != data);
 975      CFTimeZoneRef memory;
 976      uint32_t size;
 977      CFTZPeriod *tzp = NULL;
 978      CFIndex idx, cnt = 0;
 979  
 980      if (allocator == NULL) allocator = __CFGetDefaultAllocator();
 981      __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
 982      __CFGenericValidateType(name, CFStringGetTypeID());
 983      __CFGenericValidateType(data, CFDataGetTypeID());
 984      __CFTimeZoneLockGlobal();
 985      if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) {
 986  	__CFTimeZoneUnlockGlobal();
 987  	return (CFTimeZoneRef)CFRetain(memory);
 988      }
 989      if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) {
 990  	__CFTimeZoneUnlockGlobal();
 991  	return NULL;
 992      }
 993      size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase);
 994      memory = (CFTimeZoneRef)_CFRuntimeCreateInstance(allocator, CFTimeZoneGetTypeID(), size, NULL);
 995      if (NULL == memory) {
 996  	__CFTimeZoneUnlockGlobal();
 997  	for (idx = 0; idx < cnt; idx++) {
 998  	    if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev);
 999  	}
1000  	if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp);
1001          return NULL;
1002      }
1003      ((struct __CFTimeZone *)memory)->_name = (CFStringRef)CFStringCreateCopy(allocator, name);
1004      ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data);
1005      ((struct __CFTimeZone *)memory)->_periods = tzp;
1006      ((struct __CFTimeZone *)memory)->_periodCnt = cnt;
1007      if (NULL == __CFTimeZoneCache) {
1008  	__CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1009      }
1010      CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory);
1011      __CFTimeZoneUnlockGlobal();
1012      return memory;
1013  }
1014  
1015  static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) {
1016      CFTimeZoneRef result;
1017      CFDataRef data;
1018      int32_t nameLen = CFStringGetLength(name);
1019      unsigned char dataBytes[52 + nameLen + 1];
1020      memset(dataBytes, 0, sizeof(dataBytes));
1021      
1022      // Put in correct magic bytes for timezone structures
1023      dataBytes[0] = 'T';
1024      dataBytes[1] = 'Z';
1025      dataBytes[2] = 'i';
1026      dataBytes[3] = 'f';
1027      
1028      __CFEntzcode(1, dataBytes + 20);
1029      __CFEntzcode(1, dataBytes + 24);
1030      __CFEntzcode(1, dataBytes + 36);
1031      __CFEntzcode(nameLen + 1, dataBytes + 40);
1032      __CFEntzcode(seconds, dataBytes + 44);
1033      dataBytes[48] = isDST ? 1 : 0;
1034      CFStringGetCString(name, (char *)dataBytes + 50, nameLen + 1, kCFStringEncodingASCII);
1035      data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1);
1036      result = CFTimeZoneCreate(allocator, name, data);
1037      CFRelease(data);
1038      return result;
1039  }
1040  
1041  
1042  // rounds offset to nearest minute
1043  CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) {
1044      CFTimeZoneRef result;
1045      CFStringRef name;
1046      int32_t seconds, minute, hour;
1047      if (allocator == NULL) allocator = __CFGetDefaultAllocator();
1048      __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
1049      if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL;
1050      ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0;
1051      seconds = (int32_t)ti;
1052      hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600);
1053      seconds -= ((ti < 0) ? -hour : hour) * 3600;
1054      minute = (ti < 0) ? (-seconds / 60) : (seconds / 60);
1055      if (fabs(ti) < 1.0) {
1056  	name = (CFStringRef)CFRetain(CFSTR("GMT"));
1057      } else {
1058  	name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute);
1059      }
1060      result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0);
1061      CFRelease(name);
1062      return result;
1063  }
1064  
1065  CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) {
1066      CFTimeZoneRef result = NULL;
1067      CFStringRef tzName = NULL;
1068      CFDataRef data = NULL;
1069  
1070      if (allocator == NULL) allocator = __CFGetDefaultAllocator();
1071      __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
1072      __CFGenericValidateType(name, CFStringGetTypeID());
1073      if (CFEqual(CFSTR(""), name)) {
1074  	// empty string is not a time zone name, just abort now,
1075  	// following stuff will fail anyway
1076  	return NULL;
1077      }
1078      __CFTimeZoneLockGlobal();
1079      if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) {
1080  	__CFTimeZoneUnlockGlobal();
1081  	return (CFTimeZoneRef)CFRetain(result);
1082      }
1083      __CFTimeZoneUnlockGlobal();
1084      CFIndex len = CFStringGetLength(name);
1085      if (6 == len || 8 == len) {
1086  	UniChar buffer[8];
1087  	CFStringGetCharacters(name, CFRangeMake(0, len), buffer);
1088  	if ('G' == buffer[0] && 'M' == buffer[1] && 'T' == buffer[2] && ('+' == buffer[3] || '-' == buffer[3])) {
1089  	    if (('0' <= buffer[4] && buffer[4] <= '9') && ('0' <= buffer[5] && buffer[5] <= '9')) {
1090  		int32_t hours = (buffer[4] - '0') * 10 + (buffer[5] - '0');
1091  		if (-14 <= hours && hours <= 14) {
1092  		    CFTimeInterval ti = hours * 3600.0;
1093  		    if (6 == len) {
1094  			return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti);
1095  		    } else {
1096  			if (('0' <= buffer[6] && buffer[6] <= '9') && ('0' <= buffer[7] && buffer[7] <= '9')) {
1097  			    int32_t minutes = (buffer[6] - '0') * 10 + (buffer[7] - '0');
1098  			    if ((-14 == hours && 0 == minutes) || (14 == hours && 0 == minutes) || (0 <= minutes && minutes <= 59)) {
1099  				ti = ti + minutes * 60.0;
1100  				return CFTimeZoneCreateWithTimeIntervalFromGMT(allocator, ('-' == buffer[3] ? -1.0 : 1.0) * ti);
1101  			    }
1102  			}
1103  		    }
1104  		}
1105  	    }
1106  	}
1107      }
1108      CFURLRef baseURL, tempURL;
1109      void *bytes;
1110      CFIndex length;
1111  
1112  #if DEPLOYMENT_TARGET_WINDOWS
1113      if (!__tzZoneInfo) __InitTZStrings();
1114      if (!__tzZoneInfo) return NULL;
1115      baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLWindowsPathStyle, true);
1116  #else
1117      baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true);
1118  #endif
1119      if (tryAbbrev) {
1120  	CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
1121  	tzName = CFDictionaryGetValue(abbrevs, name);
1122  	if (NULL != tzName) {
1123  	    tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false);
1124  	    if (NULL != tempURL) {
1125  		if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0, 0)) {
1126  		    data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault);
1127  		}
1128  		CFRelease(tempURL);
1129  	    }
1130  	}
1131  	CFRelease(abbrevs);
1132      }
1133      if (NULL == data) {
1134  	CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary();
1135  	CFStringRef mapping = CFDictionaryGetValue(dict, name);
1136  	if (mapping) {
1137  	    name = mapping;
1138  #if DEPLOYMENT_TARGET_WINDOWS
1139  	} else if (CFStringHasPrefix(name, __tzZoneInfo)) {
1140  	    CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name);
1141  	    CFStringDelete(unprefixed, CFRangeMake(0, CFStringGetLength(__tzZoneInfo)));
1142  #else
1143  	} else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) {
1144  	    CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name);
1145  	    CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO)));
1146  #endif
1147  	    mapping = CFDictionaryGetValue(dict, unprefixed);
1148  	    if (mapping) {
1149  		name = mapping;
1150  	    }
1151  	    CFRelease(unprefixed);
1152  	}
1153  	CFRelease(dict);
1154  	if (CFEqual(CFSTR(""), name)) {
1155  	    return NULL;
1156  	}
1157      }
1158      if (NULL == data) {
1159         tzName = name;
1160         tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false);
1161         if (NULL != tempURL) {
1162             if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0, 0)) {
1163                 data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault);
1164             }
1165             CFRelease(tempURL);
1166         }
1167      }
1168      CFRelease(baseURL);
1169      if (NULL != data) {
1170  	result = CFTimeZoneCreate(allocator, tzName, data);
1171  	if (name != tzName) {
1172  	    CFStringRef nameCopy = (CFStringRef)CFStringCreateCopy(allocator, name);
1173  	    __CFTimeZoneLockGlobal();
1174  	    CFDictionaryAddValue(__CFTimeZoneCache, nameCopy, result);
1175  	    __CFTimeZoneUnlockGlobal();
1176  	    CFRelease(nameCopy);
1177  	}
1178  	CFRelease(data);
1179      }
1180      return result;
1181  }
1182  
1183  CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) {
1184      CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFStringRef, (NSTimeZone *)tz, name);
1185      __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1186      return tz->_name;
1187  }
1188  
1189  CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) {
1190      CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFDataRef, (NSTimeZone *)tz, data);
1191      __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1192      return tz->_data;
1193  }
1194  
1195  /* This function converts CFAbsoluteTime to (Win32) SYSTEMTIME
1196   * (Aleksey Dukhnyakov)
1197   */
1198  #if DEPLOYMENT_TARGET_WINDOWS
1199  BOOL __CFTimeZoneGetWin32SystemTime(SYSTEMTIME * sys_time, CFAbsoluteTime time)
1200  {
1201      LONGLONG l;
1202      FILETIME * ftime=(FILETIME*)&l;
1203  
1204      /*  seconds between 1601 and 1970 : 11644473600,
1205       *  seconds between 1970 and 2001 : 978307200,
1206       *  FILETIME - number of 100-nanosecond intervals since January 1, 1601
1207       */
1208      l=(LONGLONG)(time+11644473600LL+978307200)*10000000;
1209      if (FileTimeToSystemTime(ftime,sys_time))
1210          return TRUE;
1211      else
1212          return FALSE;
1213  }
1214  #endif
1215  
1216  CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) {
1217      CFIndex idx;
1218      __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1219      idx = __CFBSearchTZPeriods(tz, at);
1220      return __CFTZPeriodGMTOffset(&(tz->_periods[idx]));
1221  }
1222  
1223  CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) {
1224      CFStringRef result;
1225      CFIndex idx;
1226      __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1227      idx = __CFBSearchTZPeriods(tz, at);
1228      result = __CFTZPeriodAbbreviation(&(tz->_periods[idx]));
1229      return result ? (CFStringRef)CFRetain(result) : NULL;
1230  }
1231  
1232  Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) {
1233      CFIndex idx;
1234      __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1235      idx = __CFBSearchTZPeriods(tz, at);
1236      return __CFTZPeriodIsDST(&(tz->_periods[idx]));
1237  }
1238  
1239  CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) {
1240      CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval, (NSTimeZone *)tz, _daylightSavingTimeOffsetForAbsoluteTime:at);
1241      __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1242      CFIndex idx = __CFBSearchTZPeriods(tz, at);
1243      if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) {
1244  	CFTimeInterval offset = __CFTZPeriodGMTOffset(&(tz->_periods[idx]));
1245  	if (idx + 1 < tz->_periodCnt) {
1246  	    return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1]));
1247  	} else if (0 < idx) {
1248              return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1]));
1249  	}
1250      }
1251      return 0.0;
1252  }
1253  
1254  CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) {
1255      CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFTimeInterval, (NSTimeZone *)tz, _nextDaylightSavingTimeTransitionAfterAbsoluteTime:at);
1256      __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1257      CFIndex idx = __CFBSearchTZPeriods(tz, at);
1258      if (tz->_periodCnt <= idx + 1) {
1259          return 0.0;
1260      }
1261      return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1]));
1262  }
1263  
1264  extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz);
1265  
1266  #define BUFFER_SIZE 768
1267  
1268  CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) {
1269      CF_OBJC_FUNCDISPATCHV(CFTimeZoneGetTypeID(), CFStringRef, (NSTimeZone *)tz, localizedName:(NSTimeZoneNameStyle)style locale:(NSLocale *)locale);
1270      __CFGenericValidateType(tz, CFTimeZoneGetTypeID());
1271      __CFGenericValidateType(locale, CFLocaleGetTypeID());
1272  
1273      if (style == kCFTimeZoneNameStyleGeneric || style == kCFTimeZoneNameStyleShortGeneric) {
1274  	CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorSystemDefault, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle);
1275  	CFDateFormatterSetProperty(df, kCFDateFormatterTimeZone, tz);
1276  	CFDateFormatterSetFormat(df, (style == kCFTimeZoneNameStyleGeneric) ? CFSTR("vvvv") : CFSTR("v"));
1277  	CFStringRef str = CFDateFormatterCreateStringWithAbsoluteTime(CFGetAllocator(tz), df, 0.0);
1278  	CFRelease(df);
1279  	return str;
1280      }
1281  
1282      CFStringRef localeID = CFLocaleGetIdentifier(locale);
1283      UCalendar *cal = __CFCalendarCreateUCalendar(NULL, localeID, tz);
1284      if (NULL == cal) {
1285          return NULL;
1286      }
1287  
1288      char buffer[BUFFER_SIZE];
1289      const char *cstr = CFStringGetCStringPtr(localeID, kCFStringEncodingASCII);
1290      if (NULL == cstr) {
1291          if (CFStringGetCString(localeID, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer;
1292      }
1293      if (NULL == cstr) {
1294  	ucal_close(cal);
1295          return NULL;
1296      }
1297  
1298      UChar ubuffer[BUFFER_SIZE];
1299      UErrorCode status = U_ZERO_ERROR;
1300      int32_t cnt = ucal_getTimeZoneDisplayName(cal, (UCalendarDisplayNameType)style, cstr, ubuffer, BUFFER_SIZE, &status);
1301      ucal_close(cal);
1302      if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) {
1303          return CFStringCreateWithCharacters(CFGetAllocator(tz), (const UniChar *)ubuffer, cnt);
1304      }
1305      return NULL;
1306  }
1307  
1308  static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) {
1309      CFDictionaryRef dict;
1310      __CFTimeZoneLockCompatibilityMapping();
1311      if (NULL == __CFTimeZoneCompatibilityMappingDict) {
1312  	__CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1313  
1314  	// Empty string means delete/ignore these 
1315      }
1316      dict = __CFTimeZoneCompatibilityMappingDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL;
1317      __CFTimeZoneUnlockCompatibilityMapping();
1318      return dict;
1319  }
1320  
1321  #undef TZZONEINFO
1322  #undef TZZONELINK
1323