Skip to content

Commit f3f675e

Browse files
committed
NumberDate: read the TimeZone information from the registry
This queries the timezone information from the registry on Windows to create and initialize the timezone. This should allow CFTimeZoneCreate to function. Doing this will finally allow Foundation to use timezones on Windows!
1 parent 322a30d commit f3f675e

File tree

1 file changed

+122
-42
lines changed

1 file changed

+122
-42
lines changed

CoreFoundation/NumberDate.subproj/CFTimeZone.c

Lines changed: 122 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,11 @@ struct tzhead {
7070

7171
#include <time.h>
7272

73+
#if !TARGET_OS_WIN32
7374
static CFStringRef __tzZoneInfo = NULL;
7475
static char *__tzDir = NULL;
7576
static void __InitTZStrings(void);
77+
#endif
7678

7779
CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification")
7880

@@ -116,6 +118,9 @@ CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) {
116118
}
117119

118120
#if TARGET_OS_WIN32
121+
#define CF_TIME_ZONES_KEY L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"
122+
#define COUNT_OF(array) (sizeof((array)) / sizeof((array)[0]))
123+
119124
/* This function should be used for WIN32 instead of
120125
* __CFCopyRecursiveDirectoryList function.
121126
* It takes TimeZone names from the registry
@@ -124,33 +129,60 @@ CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) {
124129
static CFMutableArrayRef __CFCopyWindowsTimeZoneList() {
125130
CFMutableArrayRef result = NULL;
126131
HKEY hkResult;
127-
TCHAR lpName[MAX_PATH+1];
132+
WCHAR szName[MAX_PATH + 1];
128133
DWORD dwIndex, retCode;
129134

130-
if (RegOpenKey(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones"), &hkResult) !=
131-
ERROR_SUCCESS )
135+
if (RegOpenKeyW(HKEY_LOCAL_MACHINE, CF_TIME_ZONES_KEY, &hkResult) != ERROR_SUCCESS)
132136
return NULL;
133137

134138
result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
135-
for (dwIndex=0; (retCode = RegEnumKey(hkResult,dwIndex,lpName,MAX_PATH)) != ERROR_NO_MORE_ITEMS ; dwIndex++) {
139+
for (dwIndex = 0; (retCode = RegEnumKeyW(hkResult, dwIndex, szName, COUNT_OF(szName) - 1)) != ERROR_NO_MORE_ITEMS; dwIndex++) {
136140
if (retCode != ERROR_SUCCESS) {
137141
RegCloseKey(hkResult);
138142
CFRelease(result);
139143
return NULL;
140144
} else {
141-
#if defined(UNICODE)
142-
CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const UInt8 *)lpName, (_tcslen(lpName) * sizeof(UniChar)), kCFStringEncodingUnicode, false);
143-
#else
144-
CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const unsigned char *)lpName, _tcslen(lpName), CFStringGetSystemEncoding(), false);
145-
#endif
146-
CFArrayAppendValue(result, string);
147-
CFRelease(string);
145+
CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const UInt8 *)szName, (wcslen(szName) * sizeof(WCHAR)), kCFStringEncodingUTF16, false);
146+
CFArrayAppendValue(result, string);
147+
CFRelease(string);
148148
}
149149
}
150150

151151
RegCloseKey(hkResult);
152152
return result;
153153
}
154+
155+
static void __CFTimeZoneGetOffset(CFStringRef timezone, int32_t *offset) {
156+
typedef struct _REG_TZI_FORMAT {
157+
LONG Bias;
158+
LONG StandardBias;
159+
LONG DaylightBias;
160+
SYSTEMTIME StandardDate;
161+
SYSTEMTIME DaylightDate;
162+
} REG_TZI_FORMAT;
163+
164+
WCHAR szRegKey[COUNT_OF(CF_TIME_ZONES_KEY) + 1 + COUNT_OF(((TIME_ZONE_INFORMATION *)0)->StandardName) + 1];
165+
REG_TZI_FORMAT tziInfo;
166+
Boolean bResult;
167+
DWORD cbData;
168+
HKEY hKey;
169+
170+
*offset = 0;
171+
172+
memset(szRegKey, 0, sizeof(szRegKey));
173+
wcscpy(szRegKey, CF_TIME_ZONES_KEY);
174+
szRegKey[COUNT_OF(CF_TIME_ZONES_KEY) - 1] = L'\\';
175+
CFStringGetBytes(timezone, CFRangeMake(0, CFStringGetLength(timezone)), kCFStringEncodingUnicode, FALSE, FALSE, (uint8_t *)&szRegKey[wcslen(CF_TIME_ZONES_KEY) + 1], sizeof(((TIME_ZONE_INFORMATION *)0)->StandardName) + sizeof(WCHAR), NULL);
176+
177+
if (RegOpenKeyW(HKEY_LOCAL_MACHINE, szRegKey, &hKey) != ERROR_SUCCESS)
178+
return;
179+
180+
cbData = sizeof(tziInfo);
181+
if (RegQueryValueExW(hKey, L"TZI", NULL, NULL, (LPBYTE)&tziInfo, &cbData) == ERROR_SUCCESS)
182+
*offset = tziInfo.Bias;
183+
184+
RegCloseKey(hKey);
185+
}
154186
#elif TARGET_OS_MAC || TARGET_OS_LINUX || TARGET_OS_BSD
155187
static CFMutableArrayRef __CFCopyRecursiveDirectoryList() {
156188
CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
@@ -476,21 +508,27 @@ CF_INLINE void __CFTimeZoneUnlockWinToOlson(void) {
476508
__CFUnlock(&__CFTimeZoneWinToOlsonLock);
477509
}
478510

479-
static Boolean CFTimeZoneLoadWindowsOlsonPlist(LPVOID *ppResource, LPDWORD pdwSize) {
511+
static Boolean CFTimeZoneLoadPlistResource(LPCSTR lpName, LPVOID *ppResource, LPDWORD pdwSize) {
480512
HRSRC hResource;
481513
HGLOBAL hMemory;
514+
HMODULE hModule;
515+
516+
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
517+
(LPCWSTR)&CFTimeZoneLoadPlistResource, &hModule)) {
518+
return FALSE;
519+
}
482520

483-
hResource = FindResourceA(NULL, MAKEINTRESOURCEA(IDR_WINDOWS_OLSON_MAPPING), "PLIST");
521+
hResource = FindResourceA(hModule, lpName, "PLIST");
484522
if (hResource == NULL) {
485523
return FALSE;
486524
}
487525

488-
hMemory = LoadResource(NULL, hResource);
526+
hMemory = LoadResource(hModule, hResource);
489527
if (hMemory == NULL) {
490528
return FALSE;
491529
}
492530

493-
*pdwSize = SizeofResource(NULL, hResource);
531+
*pdwSize = SizeofResource(hModule, hResource);
494532
*ppResource = LockResource(hMemory);
495533

496534
return *pdwSize && *ppResource;
@@ -504,7 +542,7 @@ CFDictionaryRef CFTimeZoneCopyWinToOlsonDictionary(void) {
504542
const uint8_t *plist;
505543
DWORD dwSize;
506544

507-
if (CFTimeZoneLoadWindowsOlsonPlist(&plist, &dwSize)) {
545+
if (CFTimeZoneLoadPlistResource(MAKEINTRESOURCEA(IDR_WINDOWS_OLSON_MAPPING), (LPVOID *)&plist, &dwSize)) {
508546
CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, plist, dwSize);
509547
__CFTimeZoneWinToOlsonDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL);
510548
CFRelease(data);
@@ -519,6 +557,26 @@ CFDictionaryRef CFTimeZoneCopyWinToOlsonDictionary(void) {
519557
return dict;
520558
}
521559

560+
static CFDictionaryRef CFTimeZoneCopyOlsonToWindowsDictionary(void) {
561+
static CFDictionaryRef dict;
562+
static CFLock_t lock;
563+
564+
__CFLock(&lock);
565+
if (dict == NULL) {
566+
const uint8_t *plist;
567+
DWORD dwSize;
568+
569+
if (CFTimeZoneLoadPlistResource(MAKEINTRESOURCEA(IDR_OLSON_WINDOWS_MAPPING), (LPVOID *)&plist, &dwSize)) {
570+
CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, plist, dwSize);
571+
dict = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL);
572+
CFRelease(data);
573+
}
574+
}
575+
__CFUnlock(&lock);
576+
577+
return dict ? CFRetain(dict) : NULL;
578+
}
579+
522580
void CFTimeZoneSetWinToOlsonDictionary(CFDictionaryRef dict) {
523581
__CFGenericValidateType(dict, CFDictionaryGetTypeID());
524582
__CFTimeZoneLockWinToOlson();
@@ -544,23 +602,6 @@ CFTimeZoneRef CFTimeZoneCreateWithWindowsName(CFAllocatorRef allocator, CFString
544602
CFRelease(winToOlson);
545603
return retval;
546604
}
547-
548-
static void __InitTZStrings(void) {
549-
static CFLock_t __CFTZDirLock = CFLockInit;
550-
__CFLock(&__CFTZDirLock);
551-
// TODO(compnerd) figure out how to initialize __tzZoneInfo
552-
if (!__tzDir && __tzZoneInfo) {
553-
int length = CFStringGetLength(__tzZoneInfo) + sizeof("\\zone.tab") + 1;
554-
__tzDir = malloc(length); // If we don't use ascii, we'll need to malloc more space
555-
if (!__tzDir || !CFStringGetCString(__tzZoneInfo, __tzDir, length, kCFStringEncodingASCII)) {
556-
free(__tzDir);
557-
} else {
558-
strcat(__tzDir, "\\zone.tab");
559-
}
560-
}
561-
__CFUnlock(&__CFTZDirLock);
562-
}
563-
564605
#elif TARGET_OS_MAC
565606
static void __InitTZStrings(void) {
566607
static dispatch_once_t initOnce = 0;
@@ -1056,14 +1097,33 @@ Boolean _CFTimeZoneInit(CFTimeZoneRef timeZone, CFStringRef name, CFDataRef data
10561097
void *bytes;
10571098
CFIndex length;
10581099
Boolean result = false;
1059-
1060-
if (!__tzZoneInfo) __InitTZStrings();
1061-
if (!__tzZoneInfo) return NULL;
1100+
10621101
#if TARGET_OS_WIN32
1063-
baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLWindowsPathStyle, true);
1102+
CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
1103+
1104+
tzName = CFDictionaryGetValue(abbrevs, name);
1105+
if (tzName == NULL) {
1106+
CFDictionaryRef olson = CFTimeZoneCopyOlsonToWindowsDictionary();
1107+
tzName = CFDictionaryGetValue(olson, name);
1108+
CFRelease(olson);
1109+
}
1110+
1111+
CFRelease(abbrevs);
1112+
1113+
if (tzName) {
1114+
int32_t offset;
1115+
__CFTimeZoneGetOffset(tzName, &offset);
1116+
CFRelease(tzName);
1117+
// TODO(compnerd) handle DST
1118+
__CFTimeZoneInitFixed(timeZone, offset, name, 0);
1119+
return TRUE;
1120+
}
1121+
1122+
return FALSE;
10641123
#else
1124+
if (!__tzZoneInfo) __InitTZStrings();
1125+
if (!__tzZoneInfo) return NULL;
10651126
baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLPOSIXPathStyle, true);
1066-
#endif
10671127

10681128
CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
10691129
tzName = CFDictionaryGetValue(abbrevs, name);
@@ -1113,6 +1173,7 @@ Boolean _CFTimeZoneInit(CFTimeZoneRef timeZone, CFStringRef name, CFDataRef data
11131173
CFRelease(data);
11141174
}
11151175
return result;
1176+
#endif
11161177
}
11171178

11181179
CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) {
@@ -1254,13 +1315,31 @@ CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef nam
12541315
void *bytes;
12551316
CFIndex length;
12561317

1257-
if (!__tzZoneInfo) __InitTZStrings();
1258-
if (!__tzZoneInfo) return NULL;
12591318
#if TARGET_OS_WIN32
1260-
baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLWindowsPathStyle, true);
1319+
CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
1320+
1321+
tzName = CFDictionaryGetValue(abbrevs, name);
1322+
if (tzName == NULL) {
1323+
CFDictionaryRef olson = CFTimeZoneCopyOlsonToWindowsDictionary();
1324+
tzName = CFDictionaryGetValue(olson, name);
1325+
CFRelease(olson);
1326+
}
1327+
1328+
CFRelease(abbrevs);
1329+
1330+
if (tzName) {
1331+
int32_t offset;
1332+
__CFTimeZoneGetOffset(tzName, &offset);
1333+
CFRelease(tzName);
1334+
// TODO(compnerd) handle DST
1335+
result = __CFTimeZoneCreateFixed(allocator, offset, name, 0);
1336+
}
1337+
1338+
return result;
12611339
#else
1340+
if (!__tzZoneInfo) __InitTZStrings();
1341+
if (!__tzZoneInfo) return NULL;
12621342
baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLPOSIXPathStyle, true);
1263-
#endif
12641343
if (tryAbbrev) {
12651344
CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary();
12661345
tzName = CFDictionaryGetValue(abbrevs, name);
@@ -1317,6 +1396,7 @@ CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef nam
13171396
CFRelease(data);
13181397
}
13191398
return result;
1399+
#endif
13201400
}
13211401

13221402
CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) {

0 commit comments

Comments
 (0)