[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
NSTimeZone.m Bug on Windows
From: |
Roland Schwingel |
Subject: |
NSTimeZone.m Bug on Windows |
Date: |
Wed, 12 May 2004 19:32:12 +0200 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.5) Gecko/20031007 |
Hi...
After being busy with other things over a longer a period I pulled
current gnustep sources today from CVS. There is the new function to
init NSTimeZone from Windows data directly. Fine thing from the idea.
But current implementation contained some bugs making it not working at
all on non-english systems.
Attached you will find a patch to fix this problem.
What are the problems. Windows stores timezoneinformation in the
registry. The current time zone (spelled in windows words) is stored in
localized in the
registry at
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
The whole table in the registry containing all timezoneentries is stored in
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
But here the keys are in english. The current code in NSTimeZone tryies
to lookup the localized name among the unlocalized keys. This must fail
on non english windows.
The localized name can be found underneath each entry in the last
mentioned table. My patch now dives directly in the list and compares
the correct entries. Additionally it fixes an impossible lookup for a
timezone file named according to the windows names, which results in an
annoying NSLog() error. Even if somedays GNUstep would have
timezonefiles for windows it would find them anyway.
Hope this patch can be applied
Roland
PS: Anyway the work for the new NSTimeZone was a good idea (forgot who
made it)
--- NSTimeZone.m 2004-05-12 10:01:16.000000000 +0200
+++ NSTimeZone.m.new 2004-05-12 19:02:09.000000000 +0200
@@ -96,6 +96,7 @@
#include "Foundation/NSDate.h"
#include "Foundation/NSDictionary.h"
#include "Foundation/NSException.h"
+#include "Foundation/NSFileManager.h"
#include "Foundation/NSLock.h"
#include "Foundation/NSObject.h"
#include "Foundation/NSProcessInfo.h"
@@ -490,7 +491,7 @@
}
fileName = [NSTimeZoneClass getTimeZoneFile: name];
- if (fileName == nil)
+ if (fileName == nil || ![[NSFileManager defaultManager]
fileExistsAtPath:fileName])
#ifdef WIN32
{
zone = [[GSWindowsTimeZone alloc] initWithName:name data:0];
@@ -1234,8 +1235,8 @@
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, \
"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation", 0,
KEY_READ, ®key))
{
- char buf[100];
- DWORD bufsize=100;
+ char buf[255];
+ DWORD bufsize=255;
DWORD type;
if (ERROR_SUCCESS==RegQueryValueEx(regkey, "StandardName", 0,
&type, buf, &bufsize))
{
@@ -1720,73 +1721,164 @@
- (id) initWithName: (NSString*)name data: (NSData*)data
{
- NSString *shortName;
- HKEY regkey;
+ HKEY regDirKey;
+ BOOL isNT = NO,regFound=NO;
- if ([name hasSuffix:@" Standard Time"])
- {
- shortName = [name substringWithRange:NSMakeRange(0,[name length]-14)];
- }
+ /* Open the key in the local machine hive where the time zone data is
stored. */
+ if (ERROR_SUCCESS ==
RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows
NT\\CurrentVersion\\Time Zones", 0, KEY_READ, ®DirKey))
+ {
+ isNT=YES;
+ regFound=YES;
+ }
else
+ {
+ if (ERROR_SUCCESS ==
RegOpenKeyEx(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Windows
NT\\CurrentVersion\\Time Zones", 0, KEY_READ, ®DirKey))
{
- shortName = name;
+ regFound=YES;
}
+ }
- /* Open the key in the local machine hive where the time zone data is
stored. */
- if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, \
- [[NSString
- stringWithFormat:@"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time
Zones\\%@", name] cString], 0, KEY_READ, ®key) \
- || ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, \
- [[NSString
- stringWithFormat:@"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time
Zones\\%@", shortName] cString], 0, KEY_READ, ®key))
- {
- char buf[200];
- DWORD bufsize=sizeof(buf);
- DWORD type;
-
- /* Read in the time zone data */
- if (ERROR_SUCCESS==RegQueryValueEx(regkey, "TZI", 0, &type, buf,
&bufsize))
- {
- TZI *tzi = (void*)buf;
- Bias = tzi->Bias;
- StandardBias = tzi->StandardBias;
- DaylightBias = tzi->DaylightBias;
- StandardDate = tzi->StandardDate;
- DaylightDate = tzi->DaylightDate;
- }
- bufsize=sizeof(buf);
- /* Read the standard name for the time zone. */
- if (ERROR_SUCCESS==RegQueryValueEx(regkey, "Std", 0, &type, buf,
&bufsize))
- {
- int a, b;
- [timeZoneName release];
- timeZoneName = [[NSString stringWithCString:buf] retain];
- for(a=0,b=0;buf[a];a++)
- {
- if (isupper(buf[a]))
- buf[b++]=buf[a];
- }
- buf[b]=0;
- [timeZoneNameAbbr release];
- timeZoneNameAbbr = [[NSString stringWithCString:buf] retain];
- }
- /* Read the daylight savings name for the time zone. */
- if (ERROR_SUCCESS==RegQueryValueEx(regkey, "Dlt", 0, &type, buf,
&bufsize))
- {
- int a,b;
- [daylightZoneName release];
- daylightZoneName = [[NSString stringWithCString:buf] retain];
- for(a=0,b=0;buf[a];a++)
- {
- if (isupper(buf[a]))
- buf[b++]=buf[a];
- }
- buf[b]=0;
- [daylightZoneNameAbbr release];
- daylightZoneNameAbbr = [[NSString stringWithCString:buf] retain];
- }
- RegCloseKey(regkey);
- }
+ if (regFound)
+ {
+ /* Iterate over all subKeys in the registry to find the right one.
+ Unfortunately name is a localized value. The keys in the registry are
+ unlocalized names. */
+ CHAR achKey[255]; // buffer for subkey name
+ DWORD cbName; // size of name string
+ CHAR achClass[MAX_PATH] = ""; // buffer for class name
+ DWORD cchClassName = MAX_PATH; // size of class string
+ DWORD cSubKeys=0; // number of subkeys
+ DWORD cbMaxSubKey; // longest subkey size
+ DWORD cchMaxClass; // longest class string
+ DWORD cValues; // number of values for key
+ DWORD cchMaxValue; // longest value name
+ DWORD cbMaxValueData; // longest value data
+ DWORD cbSecurityDescriptor; // size of security descriptor
+ FILETIME ftLastWriteTime; // last write time
+
+ DWORD i, retCode;
+ BOOL tzFound = NO;
+
+ /* Get the class name and the value count. */
+ retCode = RegQueryInfoKey(
+ regDirKey, // key handle
+ achClass, // buffer for class name
+ &cchClassName, // size of class string
+ NULL, // reserved
+ &cSubKeys, // number of subkeys
+ &cbMaxSubKey, // longest subkey size
+ &cchMaxClass, // longest class string
+ &cValues, // number of values for this key
+ &cchMaxValue, // longest value name
+ &cbMaxValueData, // longest value data
+ &cbSecurityDescriptor, // security descriptor
+ &ftLastWriteTime); // last write time
+
+ if (cSubKeys && (retCode == ERROR_SUCCESS))
+ {
+ const char *cName = [name cString];
+
+ for (i=0; i<cSubKeys && !tzFound; i++)
+ {
+ cbName = 255;
+
+ retCode = RegEnumKeyEx(regDirKey, i, achKey,
&cbName, NULL, NULL, NULL, &ftLastWriteTime);
+ if (retCode == ERROR_SUCCESS)
+ {
+ char keyBuffer[16384];
+ HKEY regKey;
+
+ if (isNT)
+ sprintf(keyBuffer,"SOFTWARE\\Microsoft\\Windows
NT\\CurrentVersion\\Time Zones\\%s",achKey);
+ else
+
sprintf(keyBuffer,"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time
Zones\\%s",achKey);
+
+ if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
keyBuffer, 0, KEY_READ, ®Key))
+ {
+ char buf[256];
+ char standardName[256];
+ char daylightName[256];
+ DWORD bufsize;
+ DWORD type;
+
+ /* check standardname */
+ standardName[0]='\0';
+ bufsize=sizeof(buf);
+ if
(ERROR_SUCCESS==RegQueryValueEx(regKey, "Std", 0, &type, buf, &bufsize))
+ {
+ strcpy(standardName,buf);
+ if (strcmp(standardName,cName) == 0)
+ tzFound = YES;
+ }
+
+ /* check daylightname */
+ daylightName[0]='\0';
+ bufsize=sizeof(buf);
+ if
(ERROR_SUCCESS==RegQueryValueEx(regKey, "Dlt", 0, &type, buf, &bufsize))
+ {
+ strcpy(daylightName,buf);
+ if (strcmp(daylightName,cName) == 0)
+ tzFound = YES;
+ }
+
+ if (tzFound)
+ {
+ /* Read in the time zone data */
+ bufsize=sizeof(buf);
+ if
(ERROR_SUCCESS==RegQueryValueEx(regKey, "TZI", 0, &type, buf, &bufsize))
+ {
+ TZI *tzi = (void*)buf;
+ Bias = tzi->Bias;
+ StandardBias =
tzi->StandardBias;
+ DaylightBias =
tzi->DaylightBias;
+ StandardDate =
tzi->StandardDate;
+ DaylightDate =
tzi->DaylightDate;
+ }
+
+ /* Set the standard name for the
time zone. */
+ if (strlen(standardName))
+ {
+ int a, b;
+ [timeZoneName release];
+ timeZoneName = [[NSString
stringWithCString:standardName] retain];
+
+ /* Abbr generated here is
IMHO a bit suspicous but I kept it */
+
for(a=0,b=0;standardName[a];a++)
+ {
+ if
(isupper(standardName[a]))
+
standardName[b++]=standardName[a];
+ }
+ standardName[b]=0;
+ [timeZoneNameAbbr release];
+ timeZoneNameAbbr = [[NSString
stringWithCString:standardName] retain];
+ }
+
+ /* Set the daylight savings name
for the time zone. */
+ if (strlen(daylightName))
+ {
+ int a,b;
+ [daylightZoneName release];
+ daylightZoneName = [[NSString
stringWithCString:daylightName] retain];
+
+ /* Abbr generated here is
IMHO a bit suspicous but I kept it */
+
for(a=0,b=0;daylightName[a];a++)
+ {
+ if
(isupper(daylightName[a]))
+
daylightName[b++]=daylightName[a];
+ }
+ daylightName[b]=0;
+ [daylightZoneNameAbbr
release];
+ daylightZoneNameAbbr =
[[NSString stringWithCString:daylightName] retain];
+ }
+ }
+ RegCloseKey(regKey);
+ }
+ }
+ }
+ }
+ RegCloseKey(regDirKey);
+ }
+
return self;
}
- NSTimeZone.m Bug on Windows,
Roland Schwingel <=