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);