From e06f28da0d4f18473e14c0c1590647d9b868c56a Mon Sep 17 00:00:00 2001
From: CaS
Date: Tue, 1 Oct 2002 10:25:40 +0000
Subject: [PATCH] Various fixes.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@14613 72102866-910b-0410-8b05-ffd578937521
---
Headers/gnustep/base/NSTimeZone.h | 1 +
Source/NSCalendarDate.m | 54 ++--
Source/NSTimeZone.m | 458 +++++++++++++++++++++++-------
3 files changed, 385 insertions(+), 128 deletions(-)
diff --git a/Headers/gnustep/base/NSTimeZone.h b/Headers/gnustep/base/NSTimeZone.h
index c0085c5e0..a8cc4759c 100644
--- a/Headers/gnustep/base/NSTimeZone.h
+++ b/Headers/gnustep/base/NSTimeZone.h
@@ -57,6 +57,7 @@
+ (NSTimeZone*) timeZoneWithName: (NSString*)name data: (NSData*)data;
- (NSString*) abbreviation;
- (NSString*) abbreviationForDate: (NSDate*)when;
+- (NSData*) data;
- (id) initWithName: (NSString*)name;
- (id) initWithName: (NSString*)name data: (NSData*)data;
- (BOOL) isDaylightSavingTime;
diff --git a/Source/NSCalendarDate.m b/Source/NSCalendarDate.m
index cdb77be9f..6152c0a0a 100644
--- a/Source/NSCalendarDate.m
+++ b/Source/NSCalendarDate.m
@@ -59,7 +59,9 @@
#define GREGORIAN_REFERENCE 730486
@class GSTimeZone;
-@class NSConcreteAbsoluteTimeZone;
+@class GSAbsTimeZone;
+
+static NSString *cformat = @"%Y-%m-%d %H:%M:%S %z";
static NSTimeZone *localTZ = nil;
@@ -85,7 +87,11 @@ static NSString* (*dstAbrIMP)(id, SEL, id);
static inline int
offset(NSTimeZone *tz, NSDate *d)
{
- if (tz == localTZ)
+ if (tz == nil)
+ {
+ return 0;
+ }
+ if (tz == localTZ && offIMP != 0)
{
return (*offIMP)(tz, offSEL, d);
}
@@ -93,11 +99,11 @@ offset(NSTimeZone *tz, NSDate *d)
{
Class c = GSObjCClass(tz);
- if (c == dstClass)
+ if (c == dstClass && dstOffIMP != 0)
{
return (*dstOffIMP)(tz, offSEL, d);
}
- if (c == absClass)
+ if (c == absClass && absOffIMP != 0)
{
return (*absOffIMP)(tz, offSEL, d);
}
@@ -113,7 +119,11 @@ offset(NSTimeZone *tz, NSDate *d)
static inline NSString*
abbrev(NSTimeZone *tz, NSDate *d)
{
- if (tz == localTZ)
+ if (tz == nil)
+ {
+ return @"GMT";
+ }
+ if (tz == localTZ && abrIMP != 0)
{
return (*abrIMP)(tz, abrSEL, d);
}
@@ -121,11 +131,11 @@ abbrev(NSTimeZone *tz, NSDate *d)
{
Class c = GSObjCClass(tz);
- if (c == dstClass)
+ if (c == dstClass && dstAbrIMP != 0)
{
return (*dstAbrIMP)(tz, abrSEL, d);
}
- if (c == absClass)
+ if (c == absClass && absAbrIMP != 0)
{
return (*absAbrIMP)(tz, abrSEL, d);
}
@@ -274,7 +284,7 @@ GSBreakTime(NSTimeInterval when, int *year, int *month, int *day,
localTZ = RETAIN([NSTimeZone localTimeZone]);
dstClass = [GSTimeZone class];
- absClass = [NSConcreteAbsoluteTimeZone class];
+ absClass = [GSAbsTimeZone class];
offSEL = @selector(secondsFromGMTForDate:);
offIMP = (int (*)(id,SEL,id))
@@ -393,7 +403,7 @@ GSBreakTime(NSTimeInterval when, int *year, int *month, int *day,
{
// +++ What is the locale?
return [self initWithString: description
- calendarFormat: @"%Y-%m-%d %H:%M:%S %z"
+ calendarFormat: cformat
locale: nil];
}
@@ -1162,13 +1172,13 @@ static inline int getDigits(const char *from, char *to, int limit)
// Assign time zone detail
if (aTimeZone == nil)
{
- _time_zone = RETAIN(localTZ);
+ _time_zone = localTZ; // retain is a no-op for the local timezone.
}
else
{
_time_zone = RETAIN(aTimeZone);
}
- _calendar_format = @"%Y-%m-%d %H:%M:%S %z";
+ _calendar_format = cformat;
_seconds_since_ref = s;
/*
@@ -1210,11 +1220,11 @@ static inline int getDigits(const char *from, char *to, int limit)
_seconds_since_ref = seconds;
if (_calendar_format == nil)
{
- _calendar_format = @"%Y-%m-%d %H:%M:%S %z";
+ _calendar_format = cformat;
}
if (_time_zone == nil)
{
- _time_zone = RETAIN(localTZ);
+ _time_zone = localTZ; // retain is a no-op for the local timezone.
}
return self;
}
@@ -1387,8 +1397,8 @@ static inline int getDigits(const char *from, char *to, int limit)
}
#define UNIX_REFERENCE_INTERVAL -978307200.0
-- (NSString *)descriptionWithCalendarFormat: (NSString *)format
- locale: (NSDictionary *)locale
+- (NSString*) descriptionWithCalendarFormat: (NSString*)format
+ locale: (NSDictionary*)locale
{
char buf[1024];
const char *f;
@@ -1666,10 +1676,16 @@ static inline int getDigits(const char *from, char *to, int limit)
{
newDate = (NSCalendarDate*)NSCopyObject(self, 0, zone);
- if (newDate)
+ if (newDate != nil)
{
- newDate->_calendar_format = [_calendar_format copyWithZone: zone];
- newDate->_time_zone = RETAIN(_time_zone);
+ if (_calendar_format != cformat)
+ {
+ newDate->_calendar_format = [_calendar_format copyWithZone: zone];
+ }
+ if (_time_zone != localTZ)
+ {
+ newDate->_time_zone = RETAIN(_time_zone);
+ }
}
}
return newDate;
@@ -1866,7 +1882,7 @@ static inline int getDigits(const char *from, char *to, int limit)
*/
s = GSTime(day, month, year, hour, minute, second, mil);
c = [NSCalendarDate alloc];
- c->_calendar_format = @"%Y-%m-%d %H:%M:%S %z";
+ c->_calendar_format = cformat;
c->_time_zone = RETAIN([self timeZone]);
c->_seconds_since_ref = s;
diff --git a/Source/NSTimeZone.m b/Source/NSTimeZone.m
index ee2ffeac7..0e47c0c78 100644
--- a/Source/NSTimeZone.m
+++ b/Source/NSTimeZone.m
@@ -106,8 +106,9 @@
#define ZONES_DIR @"zones/"
-@class NSConcreteAbsoluteTimeZone;
-@class NSConcreteTimeZoneDetail;
+@class GSAbsTimeZone;
+@class GSTimeZoneDetail;
+@class GSAbsTimeZoneDetail;
@class GSPlaceholderTimeZone;
@@ -117,25 +118,38 @@
static GSPlaceholderTimeZone *defaultPlaceholderTimeZone;
static NSMapTable *placeholderMap;
-/* Temporary structure for holding time zone details. */
+/*
+ * Temporary structure for holding time zone details.
+ * This is the format in the data object.
+ */
struct ttinfo
{
char offset[4]; // Seconds east of UTC
- BOOL isdst; // Daylight savings time?
- char abbr_idx; // Index into time zone abbreviations string
+ unsigned char isdst; // Daylight savings time?
+ unsigned char abbr_idx; // Index into time zone abbreviations string
};
+/*
+ * And this is the structure used in the time zone instances.
+ */
+typedef struct {
+ gss32 offset;
+ BOOL isdst;
+ unsigned char abbr_idx;
+ char pad[2];
+ NSString *abbreviation;
+} TypeInfo;
+
@interface GSTimeZone : NSTimeZone
{
@public
NSString *timeZoneName;
- NSMutableData *md;
+ NSData *timeZoneData;
unsigned int n_trans;
unsigned int n_types;
gss32 *trans;
+ TypeInfo *types;
unsigned char *idxs;
- NSString **abbrevs;
- struct ttinfo *types;
}
@end
@@ -201,11 +215,12 @@ decode (const void *ptr)
@interface GSPlaceholderTimeZone : NSTimeZone
@end
-@interface NSConcreteAbsoluteTimeZone : NSTimeZone
+@interface GSAbsTimeZone : NSTimeZone
{
- NSString *name;
- id detail;
- int offset; // Offset from UTC in seconds.
+@public
+ NSString *name;
+ id detail;
+ int offset; // Offset from UTC in seconds.
}
- (id) initWithOffset: (int)anOffset;
@@ -214,8 +229,7 @@ decode (const void *ptr)
@interface NSLocalTimeZone : NSTimeZone
@end
-
-@interface NSConcreteTimeZoneDetail : NSTimeZoneDetail
+@interface GSTimeZoneDetail : NSTimeZoneDetail
{
NSTimeZone *timeZone; // Time zone which created this object.
NSString *abbrev; // Abbreviation for time zone detail.
@@ -229,6 +243,14 @@ decode (const void *ptr)
withDST: (BOOL)isDST;
@end
+@interface GSAbsTimeZoneDetail : NSTimeZoneDetail
+{
+ GSAbsTimeZone *zone; // Time zone which created this object.
+}
+
+- (id) initWithTimeZone: (GSAbsTimeZone*)aZone;
+@end
+
/* Private methods for obtaining resource file names. */
@interface NSTimeZone (Private)
+ (void) _becomeThreaded: (NSNotification*)notification;
@@ -317,8 +339,14 @@ decode (const void *ptr)
- (id) initWithName: (NSString*)name data: (NSData*)data
{
NSTimeZone *zone;
+ unsigned length = [name length];
- if ([name isEqual: @"NSLocalTimeZone"])
+ if (length == 0)
+ {
+ NSLog(@"Disallowed null time zone name");
+ return nil;
+ }
+ if (length == 15 && [name isEqual: @"NSLocalTimeZone"])
{
zone = RETAIN(localTimeZone);
DESTROY(self);
@@ -327,50 +355,76 @@ decode (const void *ptr)
/*
* Return a cached time zone if possible.
+ * NB. if data of cached zone does not match new data ... don't use cache
*/
if (zone_mutex != nil)
{
[zone_mutex lock];
}
zone = [zoneDictionary objectForKey: name];
+ if (data != [zone data] && [data isEqual: [zone data]] == NO)
+ {
+ zone = nil;
+ }
IF_NO_GC(RETAIN(zone));
if (zone_mutex != nil)
{
[zone_mutex unlock];
}
+
if (zone == nil)
{
- if ([name hasPrefix: @"NSAbsoluteTimeZone:"] == YES)
- {
- int i = [[name substringFromIndex: 19] intValue];
+ unichar c;
+ unsigned i;
- zone = [[NSConcreteAbsoluteTimeZone alloc] initWithOffset: i];
+ if (length == 8 && [name hasPrefix: @"GMT"] == YES
+ && ((c = [name characterAtIndex: 3]) == '+' || c == '-'))
+ {
+ c = [name characterAtIndex: 4];
+ if (c >= '0' && c <= '9')
+ {
+ i = c - '0';
+ c = [name characterAtIndex: 5];
+ if (c >= '0' && c <= '9')
+ {
+ i = i * 10 + (c - '0');
+ c = [name characterAtIndex: 6];
+ if (c >= '0' && c <= '9')
+ {
+ i = i * 6 + (c - '0');
+ c = [name characterAtIndex: 7];
+ if (c >= '0' && c <= '9')
+ {
+ i = i * 10 + (c - '0');
+ zone = [[GSAbsTimeZone alloc] initWithOffset: i*60];
+ }
+ }
+ }
+ }
}
- else
+
+ if (zone == nil && length > 19
+ && [name hasPrefix: @"NSAbsoluteTimeZone:"] == YES)
+ {
+ i = [[name substringFromIndex: 19] intValue];
+
+ zone = [[GSAbsTimeZone alloc] initWithOffset: i];
+ }
+
+ if (zone == nil)
{
if (data == nil)
{
- NSString *fileName;
- unsigned length;
+ NSString *fileName;
+ const char *str = [name UTF8String];
- length = [name length];
- if (length == 0)
+ /* Make sure that only time zone files are accessed.
+ FIXME: Make this more robust. */
+ if ((str)[0] == '/' || strchr(str, '.') != NULL)
{
- NSLog(@"Disallowed null time zone name");
+ NSLog(@"Disallowed time zone name `%@'.", name);
return nil;
}
- else
- {
- const char *str = [name lossyCString];
-
- /* Make sure that only time zone files are accessed.
- FIXME: Make this more robust. */
- if ((str)[0] == '/' || strchr(str, '.') != NULL)
- {
- NSLog(@"Disallowed time zone name `%@'.", name);
- return nil;
- }
- }
fileName = [NSTimeZoneClass getTimeZoneFile: name];
if (fileName == nil)
@@ -417,6 +471,11 @@ decode (const void *ptr)
return self;
}
+- (NSData*) data
+{
+ return [[NSTimeZoneClass defaultTimeZone] data];
+}
+
- (void) encodeWithCoder: (NSCoder*)aCoder
{
[aCoder encodeObject: @"NSLocalTimeZone"];
@@ -478,13 +537,13 @@ decode (const void *ptr)
@end
-@implementation NSConcreteAbsoluteTimeZone
+@implementation GSAbsTimeZone
static NSMapTable *absolutes = 0;
+ (void) initialize
{
- if (self == [NSConcreteAbsoluteTimeZone class])
+ if (self == [GSAbsTimeZone class])
{
absolutes = NSCreateMapTable(NSIntMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
@@ -515,13 +574,36 @@ static NSMapTable *absolutes = 0;
- (id) initWithOffset: (int)anOffset
{
- NSConcreteAbsoluteTimeZone *z;
+ GSAbsTimeZone *z;
+ int extra;
+ int sign = anOffset >= 0 ? 1 : -1;
+
+ /*
+ * Round the offset to the nearest minute, (for MacOS-X compatibility)
+ * and ensure it is no more than 18 hours.
+ */
+ anOffset *= sign;
+ extra = anOffset % 60;
+ if (extra < 30)
+ {
+ anOffset -= extra;
+ }
+ else
+ {
+ anOffset += 60 - extra;
+ }
+ if (anOffset > 64800)
+ {
+ RELEASE(self);
+ return nil;
+ }
+ anOffset *= sign;
if (zone_mutex != nil)
{
[zone_mutex lock];
}
- z = (NSConcreteAbsoluteTimeZone*)NSMapGet(absolutes, (void*)(gsaddr)anOffset);
+ z = (GSAbsTimeZone*)NSMapGet(absolutes, (void*)(gsaddr)anOffset);
if (z != nil)
{
IF_NO_GC(RETAIN(z));
@@ -529,11 +611,25 @@ static NSMapTable *absolutes = 0;
}
else
{
- name = [[NSString alloc] initWithFormat: @"NSAbsoluteTimeZone:%d",
- anOffset];
- detail = [[NSConcreteTimeZoneDetail alloc]
- initWithTimeZone: self withAbbrev: name
- withOffset: anOffset withDST: NO];
+ if (anOffset % 60 == 0)
+ {
+ char s = (anOffset >= 0) ? '+' : '-';
+ int i = (anOffset >= 0) ? anOffset / 60 : -anOffset / 60;
+ int h = i / 60;
+ int m = i % 60;
+
+ name = [[NSString alloc] initWithFormat: @"GMT%c%02d%02d", s, h, m];
+ }
+ else
+ {
+ /*
+ * Should never happen now we round to the minute
+ * for MacOS-X compatibnility.
+ */
+ name = [[NSString alloc] initWithFormat: @"NSAbsoluteTimeZone:%d",
+ anOffset];
+ }
+ detail = [[GSAbsTimeZoneDetail alloc] initWithTimeZone: self];
offset = anOffset;
z = self;
NSMapInsert(absolutes, (void*)(gsaddr)anOffset, (void*)z);
@@ -571,10 +667,14 @@ static NSMapTable *absolutes = 0;
return detail;
}
+- (NSString*) timeZoneName
+{
+ return name;
+}
@end
-@implementation NSConcreteTimeZoneDetail
+@implementation GSTimeZoneDetail
- (void) dealloc
{
@@ -639,6 +739,76 @@ static NSMapTable *absolutes = 0;
@end
+
+
+@implementation GSAbsTimeZoneDetail
+
+- (NSString*) abbreviation
+{
+ return zone->name;
+}
+
+- (NSString*) abbreviationForDate: (NSDate*)aDate
+{
+ return zone->name;
+}
+
+- (void) dealloc
+{
+ RELEASE(zone);
+ [super dealloc];
+}
+
+- (id) initWithTimeZone: (GSAbsTimeZone*)aZone
+{
+ zone = RETAIN(aZone);
+ return self;
+}
+
+- (BOOL) isDaylightSavingTimeZone
+{
+ return NO;
+}
+
+- (BOOL) isDaylightSavingTimeZoneForDate: (NSDate*)aDate
+{
+ return NO;
+}
+
+- (NSString*) name
+{
+ return zone->name;
+}
+
+- (NSString*) timeZoneAbbreviation
+{
+ return zone->name;
+}
+
+- (NSArray*) timeZoneDetailArray
+{
+ return [zone timeZoneDetailArray];
+}
+
+- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
+{
+ return self;
+}
+
+- (int) timeZoneSecondsFromGMT
+{
+ return zone->offset;
+}
+
+- (int) timeZoneSecondsFromGMTForDate: (NSDate*)aDate
+{
+ return zone->offset;
+}
+
+@end
+
+
+
/**
*
* If the GNUstep time zone datafiles become too out of date, one
@@ -646,17 +816,17 @@ static NSMapTable *absolutes = 0;
* url="ftp://elsie.nci.nih.gov/pub/">ftp://elsie.nci.nih.gov/pub/
* and compile it as specified in the README file in the
* NSTimeZones directory.
- *
- * Time zone names in NSDates should be GMT, MET etc. not
+ *
+ * Time zone names in NSDates should be GMT, MET etc. not
* Europe/Berlin, America/Washington etc.
- *
+ *
* The problem with this is that various time zones may use the
* same abbreviation (e.g. Australia/Brisbane and
* America/New_York both use EST), and some time zones
* may have different rules for daylight saving time even if the
* abbreviation and offsets from UTC are the same.
- *
- * The problems with depending on the OS for providing time zone
+ *
+ * The problems with depending on the OS for providing time zone
* info are that some methods for the NSTimeZone classes might be
* difficult to implement, and also that time zone names may vary
* wildly between OSes (this could be a big problem when
@@ -1010,14 +1180,19 @@ static NSMapTable *absolutes = 0;
return regionsArray;
}
+/**
+ * Return a timezone for the specified offset from GMT.
+ * The timezone returned does not use daylight savings time.
+ * The actual timezone returned has an offset rounded to the nearest
+ * minute.
+ * Time zones with an offset of more than +/- 18 hours are disallowed,
+ * and nil is returned.
+ */
+ (NSTimeZone*) timeZoneForSecondsFromGMT: (int)seconds
{
NSTimeZone *zone;
- /* We simply return the following because an existing time zone with
- the given offset might not always have the same offset (daylight
- savings time, change in standard time, etc.). */
- zone = [[NSConcreteAbsoluteTimeZone alloc] initWithOffset: seconds];
+ zone = [[GSAbsTimeZone alloc] initWithOffset: seconds];
return AUTORELEASE(zone);
}
@@ -1089,6 +1264,14 @@ static NSMapTable *absolutes = 0;
return RETAIN(self);
}
+/**
+ * Returns the data with which the receiver was initialised.
+ */
+- (NSData*) data
+{
+ return nil;
+}
+
- (NSString*) description
{
return [self name];
@@ -1113,11 +1296,21 @@ static NSMapTable *absolutes = 0;
return self;
}
+/**
+ * Initialise a timezone with the supplied name. May return a cached
+ * timezone object rather than the newly created one.
+ */
- (id) initWithName: (NSString*)name
{
return [self initWithName: name data: nil];
}
+/**
+ * Initialises a time zone object using the supplied data object.
+ * This method is intended for internal use by the NSTimeZone
+ * class cluster.
+ * Don't use it ... use -initWithName: instead.
+ */
- (id) initWithName: (NSString*)name data: (NSData*)data
{
[self notImplemented: _cmd];
@@ -1161,7 +1354,10 @@ static NSMapTable *absolutes = 0;
{
if (aTimeZone == self)
return YES;
- if ([[self name] isEqual: [aTimeZone name]] == YES)
+ if ([[self name] isEqual: [aTimeZone name]] == NO)
+ return NO;
+ if (([self data] == nil && [aTimeZone data] == nil)
+ || [[self name] isEqual: [aTimeZone name]] == YES)
return YES;
return NO;
}
@@ -1174,7 +1370,9 @@ static NSMapTable *absolutes = 0;
- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
{
if ([aCoder isByref] == NO)
- return self;
+ {
+ return self;
+ }
return [super replacementObjectForPortCoder: aCoder];
}
@@ -1222,7 +1420,11 @@ static NSMapTable *absolutes = 0;
@end
-
+/**
+ * This class serves no useful purpose in GNUstep, and is provided
+ * solely for backward compatibility with the OpenStep spec. It is
+ * missing entirely from MacOS-X.
+ */
@implementation NSTimeZoneDetail
- (NSString*) description
@@ -1306,7 +1508,7 @@ static NSMapTable *absolutes = 0;
* We locate the index of the highest transition before the date, or zero
* if there is no transition before it.
*/
-static struct ttinfo*
+static TypeInfo*
chop(NSTimeInterval since, GSTimeZone *zone)
{
gss32 when = (gss32)since;
@@ -1320,7 +1522,7 @@ chop(NSTimeInterval since, GSTimeZone *zone)
unsigned n_types = zone->n_types;
/*
- * If and the first transition is greater than our date,
+ * If the first transition is greater than our date,
* we locate the first non-DST transition and use that offset,
* or just use the first transition.
*/
@@ -1364,39 +1566,44 @@ chop(NSTimeInterval since, GSTimeZone *zone)
}
static NSTimeZoneDetail*
-newDetailInZoneForType(GSTimeZone *zone, struct ttinfo *type)
+newDetailInZoneForType(GSTimeZone *zone, TypeInfo *type)
{
- NSConcreteTimeZoneDetail *detail;
+ GSTimeZoneDetail *detail;
- detail = [NSConcreteTimeZoneDetail alloc];
+ detail = [GSTimeZoneDetail alloc];
detail = [detail initWithTimeZone: zone
- withAbbrev: zone->abbrevs[(int)type->abbr_idx]
- withOffset: decode(type->offset)
- withDST: type->isdst > 0 ? YES : NO];
+ withAbbrev: type->abbreviation
+ withOffset: type->offset
+ withDST: type->isdst];
return detail;
}
- (NSString*) abbreviationForDate: (NSDate*)aDate
{
- struct ttinfo *type = chop([aDate timeIntervalSince1970], self);
+ TypeInfo *type = chop([aDate timeIntervalSince1970], self);
- return abbrevs[(int)type->abbr_idx];
+ return type->abbreviation;
+}
+
+- (NSData*) data
+{
+ return timeZoneData;
}
- (void) dealloc
{
RELEASE(timeZoneName);
- if (abbrevs != 0)
+ RELEASE(timeZoneData);
+ if (types != 0)
{
unsigned i;
for (i = 0; i < n_types; i++)
{
- TEST_RELEASE(abbrevs[i]);
+ RELEASE(types[i].abbreviation);
}
- NSZoneFree(NSDefaultMallocZone(), abbrevs);
+ NSZoneFree(NSDefaultMallocZone(), types);
}
- RELEASE(md);
[super dealloc];
}
@@ -1405,11 +1612,12 @@ newDetailInZoneForType(GSTimeZone *zone, struct ttinfo *type)
static NSString *fileException = @"GSTimeZoneFileException";
timeZoneName = [name copy];
- md = [data mutableCopy];
+ timeZoneData = [data copy];
NS_DURING
{
- void *bytes = [md mutableBytes];
- unsigned length = [md length];
+ const void *bytes = [timeZoneData bytes];
+ unsigned length = [timeZoneData length];
+ void *buf;
unsigned pos = 0;
unsigned i, charcnt;
unsigned char *abbr;
@@ -1428,55 +1636,87 @@ newDetailInZoneForType(GSTimeZone *zone, struct ttinfo *type)
format: @"TZ_MAGIC is incorrect"];
}
n_trans = GSSwapBigI32ToHost(*(gss32*)header->tzh_timecnt);
- if (pos + 5*n_trans > length)
+ n_types = GSSwapBigI32ToHost(*(gss32*)header->tzh_typecnt);
+ charcnt = GSSwapBigI32ToHost(*(gss32*)header->tzh_charcnt);
+
+ i = pos;
+ i += sizeof(gss32)*n_trans;
+ if (i > length)
{
[NSException raise: fileException
format: @"Transitions list is truncated"];
}
-
- /* Read in transitions. */
- trans = (gss32*)(bytes + pos);
- for (i = 0; i < n_trans; i++)
+ i += n_trans;
+ if (i > length)
{
- trans[i] = GSSwapBigI32ToHost(*(gss32*)(bytes + pos));
- pos += 4;
+ [NSException raise: fileException
+ format: @"Transition indexes are truncated"];
}
- idxs = (unsigned char*)(bytes + pos);
- pos += n_trans;
-
- n_types = GSSwapBigI32ToHost(*(gss32*)header->tzh_typecnt);
- if (pos + n_types*sizeof(struct ttinfo) > length)
+ i += sizeof(struct ttinfo)*n_types;
+ if (i > length)
{
[NSException raise: fileException
format: @"Types list is truncated"];
}
- types = (struct ttinfo*)(bytes + pos);
- pos += n_types*sizeof(struct ttinfo);
-
- charcnt = decode(header->tzh_charcnt);
- charcnt = GSSwapBigI32ToHost(*(gss32*)header->tzh_charcnt);
- if (pos + charcnt > length)
+ if (i + charcnt > length)
{
[NSException raise: fileException
format: @"Abbreviations list is truncated"];
}
- abbr = (char*)(bytes + pos);
/*
- * Create an NSString object to hold each abbreviation.
+ * Now calculate size we need to store the information
+ * for efficient access ... not the same saze as the data
+ * we received.
*/
- abbrevs = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*charcnt);
- memset(abbrevs, '\0', sizeof(id)*charcnt);
+ i = n_trans * (sizeof(gss32)+1) + n_types * sizeof(TypeInfo);
+ buf = NSZoneMalloc(NSDefaultMallocZone(), i);
+ types = (TypeInfo*)buf;
+ buf += (n_types * sizeof(TypeInfo));
+ trans = (gss32*)buf;
+ buf += (n_trans * sizeof(gss32));
+ idxs = (unsigned char*)buf;
+
+ /* Read in transitions. */
+ for (i = 0; i < n_trans; i++)
+ {
+ trans[i] = GSSwapBigI32ToHost(*(gss32*)(bytes + pos));
+ pos += sizeof(gss32);
+ }
+ for (i = 0; i < n_trans; i++)
+ {
+ idxs[i] = *(unsigned char*)(bytes + pos);
+ pos++;
+ }
for (i = 0; i < n_types; i++)
{
- struct ttinfo *inf = types + i;
- int loc = inf->abbr_idx;
+ struct ttinfo *ptr = (struct ttinfo*)(bytes + pos);
- if (abbrevs[loc] == nil)
- {
- abbrevs[loc] = [[NSString alloc] initWithCString: abbr + loc];
- }
+ types[i].isdst = (ptr->isdst != 0 ? YES : NO);
+ types[i].abbr_idx = ptr->abbr_idx;
+ types[i].offset = decode(ptr->offset);
+ pos += sizeof(struct ttinfo);
}
+ abbr = (char*)(bytes + pos);
+ {
+ id abbrevs[charcnt];
+
+ memset(abbrevs, '\0', sizeof(id)*charcnt);
+ for (i = 0; i < n_types; i++)
+ {
+ int loc = types[i].abbr_idx;
+
+ if (abbrevs[loc] == nil)
+ {
+ abbrevs[loc] = [[NSString alloc] initWithCString: abbr + loc];
+ }
+ else
+ {
+ RETAIN(abbrevs[loc]);
+ }
+ types[i].abbreviation = abbrevs[loc];
+ }
+ }
if (zone_mutex != nil)
{
@@ -1503,9 +1743,9 @@ newDetailInZoneForType(GSTimeZone *zone, struct ttinfo *type)
- (BOOL) isDaylightSavingTimeForDate: (NSDate*)aDate
{
- struct ttinfo *type = chop([aDate timeIntervalSince1970], self);
+ TypeInfo *type = chop([aDate timeIntervalSince1970], self);
- return type->isdst > 0 ? YES : NO;
+ return type->isdst;
}
- (NSString*) name
@@ -1515,9 +1755,9 @@ newDetailInZoneForType(GSTimeZone *zone, struct ttinfo *type)
- (int) secondsFromGMTForDate: (NSDate*)aDate
{
- struct ttinfo *type = chop([aDate timeIntervalSince1970], self);
+ TypeInfo *type = chop([aDate timeIntervalSince1970], self);
- return decode(type->offset);
+ return type->offset;
}
- (NSArray*) timeZoneDetailArray
@@ -1540,7 +1780,7 @@ newDetailInZoneForType(GSTimeZone *zone, struct ttinfo *type)
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)aDate
{
- struct ttinfo *type;
+ TypeInfo *type;
NSTimeZoneDetail *detail;
type = chop([aDate timeIntervalSince1970], self);