mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 16:30:41 +00:00
Use placeholder class for efficiency
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@8957 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
2cf148585f
commit
e163d5932d
2 changed files with 320 additions and 200 deletions
|
@ -3,6 +3,8 @@
|
||||||
* Source/NSDate.m: pass dates over DO bycopy unless explicitly byref.
|
* Source/NSDate.m: pass dates over DO bycopy unless explicitly byref.
|
||||||
* Source/NSTimeZone.m: pass time zones over DO bycopy unless
|
* Source/NSTimeZone.m: pass time zones over DO bycopy unless
|
||||||
explicitly byref.
|
explicitly byref.
|
||||||
|
Use placeholder class for newly created objects - to improve
|
||||||
|
eficiency of selection of classes in cluster.
|
||||||
|
|
||||||
2001-01-30 Michael Hanni <mhanni@sprintmail.com>
|
2001-01-30 Michael Hanni <mhanni@sprintmail.com>
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
#include <Foundation/NSThread.h>
|
#include <Foundation/NSThread.h>
|
||||||
#include <Foundation/NSNotification.h>
|
#include <Foundation/NSNotification.h>
|
||||||
#include <Foundation/NSPortCoder.h>
|
#include <Foundation/NSPortCoder.h>
|
||||||
|
#include <Foundation/NSDebug.h>
|
||||||
|
|
||||||
#define NOID
|
#define NOID
|
||||||
#include "tzfile.h"
|
#include "tzfile.h"
|
||||||
|
@ -99,6 +100,13 @@
|
||||||
@class NSConcreteAbsoluteTimeZone;
|
@class NSConcreteAbsoluteTimeZone;
|
||||||
@class NSConcreteTimeZoneDetail;
|
@class NSConcreteTimeZoneDetail;
|
||||||
|
|
||||||
|
@class GSPlaceholderTimeZone;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Information for abstract placeholder class.
|
||||||
|
*/
|
||||||
|
static GSPlaceholderTimeZone *defaultPlaceholderTimeZone;
|
||||||
|
static NSMapTable *placeholderMap;
|
||||||
|
|
||||||
/* Temporary structure for holding time zone details. */
|
/* Temporary structure for holding time zone details. */
|
||||||
struct ttinfo
|
struct ttinfo
|
||||||
|
@ -124,6 +132,7 @@ static NSDictionary *fake_abbrev_dict;
|
||||||
static NSRecursiveLock *zone_mutex = nil;
|
static NSRecursiveLock *zone_mutex = nil;
|
||||||
|
|
||||||
static Class NSTimeZoneClass;
|
static Class NSTimeZoneClass;
|
||||||
|
static Class GSPlaceholderTimeZoneClass;
|
||||||
|
|
||||||
/* Decode the four bytes at PTR as a signed integer in network byte order.
|
/* Decode the four bytes at PTR as a signed integer in network byte order.
|
||||||
Based on code included in the GNU C Library 2.0.3. */
|
Based on code included in the GNU C Library 2.0.3. */
|
||||||
|
@ -171,14 +180,16 @@ decode (const void *ptr)
|
||||||
- (char) detailIndex;
|
- (char) detailIndex;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface GSPlaceholderTimeZone : NSTimeZone
|
||||||
|
@end
|
||||||
|
|
||||||
@interface NSConcreteTimeZone : NSTimeZone
|
@interface NSConcreteTimeZone : NSTimeZone
|
||||||
{
|
{
|
||||||
NSString *name;
|
NSString *name;
|
||||||
NSArray *transitions; // Transition times and rules
|
NSArray *transitions; // Transition times and rules
|
||||||
NSArray *details; // Time zone details
|
NSArray *details; // Time zone details
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithName: (NSString*)aName
|
- (id) initWithName: (NSString*)aName
|
||||||
withTransitions: (NSArray*)trans
|
withTransitions: (NSArray*)trans
|
||||||
withDetails: (NSArray*)zoneDetails;
|
withDetails: (NSArray*)zoneDetails;
|
||||||
|
@ -313,6 +324,226 @@ decode (const void *ptr)
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
@implementation GSPlaceholderTimeZone
|
||||||
|
|
||||||
|
- (id) autorelease
|
||||||
|
{
|
||||||
|
NSWarnLog(@"-autorelease sent to uninitialised time zone");
|
||||||
|
return self; // placeholders never get released.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) objectAtIndex: (unsigned)index
|
||||||
|
{
|
||||||
|
[NSException raise: NSInternalInconsistencyException
|
||||||
|
format: @"attempt to use uninitialised time zone"];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) dealloc
|
||||||
|
{
|
||||||
|
return; // placeholders never get deallocated.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) initWithName: (NSString*)name
|
||||||
|
{
|
||||||
|
NSTimeZone *zone;
|
||||||
|
|
||||||
|
if ([name isEqual: @"NSLocalTimeZone"])
|
||||||
|
{
|
||||||
|
zone = RETAIN(localTimeZone);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static NSString *fileException = @"fileException";
|
||||||
|
static NSString *errMess = @"File read error in NSTimeZone.";
|
||||||
|
id transArray, detailsArray;
|
||||||
|
int i, n_trans, n_types, names_size;
|
||||||
|
id *abbrevsArray;
|
||||||
|
char *trans, *type_idxs, *zone_abbrevs;
|
||||||
|
struct tzhead header;
|
||||||
|
struct ttinfo *types; // Temporary array for details
|
||||||
|
FILE *file = NULL;
|
||||||
|
NSString *fileName;
|
||||||
|
|
||||||
|
if (zone_mutex != nil)
|
||||||
|
{
|
||||||
|
[zone_mutex lock];
|
||||||
|
}
|
||||||
|
zone = [zoneDictionary objectForKey: name];
|
||||||
|
if (zone != nil)
|
||||||
|
{
|
||||||
|
IF_NO_GC(RETAIN(zone));
|
||||||
|
if (zone_mutex != nil)
|
||||||
|
{
|
||||||
|
[zone_mutex unlock];
|
||||||
|
}
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = [name length];
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
NSLog(@"Disallowed null time zone name");
|
||||||
|
if (zone_mutex != nil)
|
||||||
|
{
|
||||||
|
[zone_mutex unlock];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char *str = [name lossyCString];
|
||||||
|
|
||||||
|
if ([name hasPrefix: @"NSAbsoluteTimeZone:"] == YES)
|
||||||
|
{
|
||||||
|
i = atoi(&str[19]);
|
||||||
|
if (zone_mutex != nil)
|
||||||
|
{
|
||||||
|
[zone_mutex unlock];
|
||||||
|
}
|
||||||
|
zone = [[NSConcreteAbsoluteTimeZone alloc] initWithOffset: i];
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
if (zone_mutex != nil)
|
||||||
|
{
|
||||||
|
[zone_mutex unlock];
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
zone = [NSConcreteTimeZone alloc];
|
||||||
|
|
||||||
|
/* Open file. */
|
||||||
|
fileName = [NSTimeZoneClass getTimeZoneFile: name];
|
||||||
|
#if defined(__WIN32__)
|
||||||
|
file = fopen([fileName fileSystemRepresentation], "rb");
|
||||||
|
#else
|
||||||
|
file = fopen([fileName fileSystemRepresentation], "r");
|
||||||
|
#endif
|
||||||
|
if (file == NULL)
|
||||||
|
[NSException raise: fileException format: errMess];
|
||||||
|
|
||||||
|
/* Read header. */
|
||||||
|
if (fread(&header, sizeof(struct tzhead), 1, file) != 1)
|
||||||
|
[NSException raise: fileException format: errMess];
|
||||||
|
|
||||||
|
n_trans = decode(header.tzh_timecnt);
|
||||||
|
n_types = decode(header.tzh_typecnt);
|
||||||
|
names_size = decode(header.tzh_charcnt);
|
||||||
|
|
||||||
|
/* Read in transitions. */
|
||||||
|
trans = NSZoneMalloc(NSDefaultMallocZone(), 4*n_trans);
|
||||||
|
type_idxs = NSZoneMalloc(NSDefaultMallocZone(), n_trans);
|
||||||
|
if (fread(trans, 4, n_trans, file) != n_trans
|
||||||
|
|| fread(type_idxs, 1, n_trans, file) != n_trans)
|
||||||
|
[NSException raise: fileException format: errMess];
|
||||||
|
transArray = [NSMutableArray arrayWithCapacity: n_trans];
|
||||||
|
for (i = 0; i < n_trans; i++)
|
||||||
|
[transArray
|
||||||
|
addObject: [[NSInternalTimeTransition alloc]
|
||||||
|
initWithTime: decode(trans+(i*4))
|
||||||
|
withIndex: type_idxs[i]]];
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), trans);
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), type_idxs);
|
||||||
|
|
||||||
|
/* Read in time zone details. */
|
||||||
|
types =
|
||||||
|
NSZoneMalloc(NSDefaultMallocZone(), sizeof(struct ttinfo)*n_types);
|
||||||
|
for (i = 0; i < n_types; i++)
|
||||||
|
{
|
||||||
|
unsigned char x[4];
|
||||||
|
|
||||||
|
if (fread(x, 1, 4, file) != 4
|
||||||
|
|| fread(&types[i].isdst, 1, 1, file) != 1
|
||||||
|
|| fread(&types[i].abbr_idx, 1, 1, file) != 1)
|
||||||
|
[NSException raise: fileException format: errMess];
|
||||||
|
types[i].offset = decode(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read in time zone abbreviation strings. */
|
||||||
|
zone_abbrevs = NSZoneMalloc(NSDefaultMallocZone(), names_size);
|
||||||
|
if (fread(zone_abbrevs, 1, names_size, file) != names_size)
|
||||||
|
[NSException raise: fileException format: errMess];
|
||||||
|
abbrevsArray = NSZoneMalloc(NSDefaultMallocZone(),
|
||||||
|
sizeof(id)*names_size);
|
||||||
|
memset(abbrevsArray, '\0', sizeof(id)*names_size);
|
||||||
|
for (i = 0; i < n_types; i++)
|
||||||
|
{
|
||||||
|
int pos = types[i].abbr_idx;
|
||||||
|
|
||||||
|
if (abbrevsArray[pos] == nil)
|
||||||
|
{
|
||||||
|
abbrevsArray[pos]
|
||||||
|
= [NSString stringWithCString: zone_abbrevs+pos];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), zone_abbrevs);
|
||||||
|
|
||||||
|
/* Create time zone details. */
|
||||||
|
detailsArray = [NSMutableArray arrayWithCapacity: n_types];
|
||||||
|
for (i = 0; i < n_types; i++)
|
||||||
|
{
|
||||||
|
NSConcreteTimeZoneDetail *detail;
|
||||||
|
|
||||||
|
detail = [[NSConcreteTimeZoneDetail alloc]
|
||||||
|
initWithTimeZone: zone
|
||||||
|
withAbbrev: abbrevsArray[(int)types[i].abbr_idx]
|
||||||
|
withOffset: types[i].offset
|
||||||
|
withDST: (types[i].isdst > 0)];
|
||||||
|
[detailsArray addObject: detail];
|
||||||
|
RELEASE(detail);
|
||||||
|
}
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), abbrevsArray);
|
||||||
|
NSZoneFree(NSDefaultMallocZone(), types);
|
||||||
|
|
||||||
|
zone = [(id)zone initWithName: name
|
||||||
|
withTransitions: transArray
|
||||||
|
withDetails: detailsArray];
|
||||||
|
[zoneDictionary setObject: zone forKey: (NSString*)[zone name]];
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
DESTROY(zone);
|
||||||
|
if ([localException name] != fileException)
|
||||||
|
[localException raise];
|
||||||
|
NSLog(@"Unable to obtain time zone `%@'.", name);
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
|
||||||
|
if (file != NULL)
|
||||||
|
{
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
if (zone_mutex != nil)
|
||||||
|
{
|
||||||
|
[zone_mutex unlock];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return zone;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) release
|
||||||
|
{
|
||||||
|
return; // placeholders never get released.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id) retain
|
||||||
|
{
|
||||||
|
return self; // placeholders never get retained.
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@implementation NSConcreteTimeZone
|
@implementation NSConcreteTimeZone
|
||||||
|
|
||||||
|
@ -326,10 +557,7 @@ decode (const void *ptr)
|
||||||
|
|
||||||
- (void) encodeWithCoder: (NSCoder*)aCoder
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
||||||
{
|
{
|
||||||
if (self == (id)localTimeZone)
|
[aCoder encodeObject: name];
|
||||||
[aCoder encodeObject: @"NSLocalTimeZone"];
|
|
||||||
else
|
|
||||||
[aCoder encodeObject: name];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithName: (NSString*)aName
|
- (id) initWithName: (NSString*)aName
|
||||||
|
@ -400,6 +628,16 @@ decode (const void *ptr)
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
||||||
|
{
|
||||||
|
[aCoder encodeObject: @"NSLocalTimeZone"];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSString*) name
|
||||||
|
{
|
||||||
|
return [[NSTimeZoneClass defaultTimeZone] name];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) release
|
- (void) release
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -409,11 +647,6 @@ decode (const void *ptr)
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString*) name
|
|
||||||
{
|
|
||||||
return [[NSTimeZoneClass defaultTimeZone] name];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSArray*) timeZoneDetailArray
|
- (NSArray*) timeZoneDetailArray
|
||||||
{
|
{
|
||||||
return [[NSTimeZoneClass defaultTimeZone] timeZoneDetailArray];
|
return [[NSTimeZoneClass defaultTimeZone] timeZoneDetailArray];
|
||||||
|
@ -490,9 +723,9 @@ static NSMapTable *absolutes = 0;
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray*) timeZoneDetailArray
|
- (NSTimeZone*) timeZoneDetailTimeZone
|
||||||
{
|
{
|
||||||
return [NSArray arrayWithObject: detail];
|
return [NSTimeZone arrayWithObject: detail];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
||||||
|
@ -512,13 +745,6 @@ static NSMapTable *absolutes = 0;
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
||||||
{
|
|
||||||
[aCoder encodeObject: abbrev];
|
|
||||||
[aCoder encodeValueOfObjCType: @encode(int) at: &offset];
|
|
||||||
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &is_dst];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) initWithCoder: (NSCoder*)aDecoder
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
||||||
{
|
{
|
||||||
[aDecoder decodeValueOfObjCType: @encode(id) at: &abbrev];
|
[aDecoder decodeValueOfObjCType: @encode(id) at: &abbrev];
|
||||||
|
@ -631,6 +857,59 @@ static NSMapTable *absolutes = 0;
|
||||||
return abbreviationDictionary;
|
return abbreviationDictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (id) allocWithZone: (NSZone*)z
|
||||||
|
{
|
||||||
|
if (self == NSTimeZoneClass)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We return a placeholder object that can
|
||||||
|
* be converted to a real object when its initialisation method
|
||||||
|
* is called.
|
||||||
|
*/
|
||||||
|
if (z == NSDefaultMallocZone() || z == 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* As a special case, we can return a placeholder for a time zone
|
||||||
|
* in the default malloc zone extremely efficiently.
|
||||||
|
*/
|
||||||
|
return defaultPlaceholderTimeZone;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id obj;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For anything other than the default zone, we need to
|
||||||
|
* locate the correct placeholder in the (lock protected)
|
||||||
|
* table of placeholders.
|
||||||
|
*/
|
||||||
|
if (zone_mutex != nil)
|
||||||
|
{
|
||||||
|
[zone_mutex lock];
|
||||||
|
}
|
||||||
|
obj = (id)NSMapGet(placeholderMap, (void*)z);
|
||||||
|
if (obj == nil)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* There is no placeholder object for this zone, so we
|
||||||
|
* create a new one and use that.
|
||||||
|
*/
|
||||||
|
obj = (id)NSAllocateObject(GSPlaceholderTimeZoneClass, 0, z);
|
||||||
|
NSMapInsert(placeholderMap, (void*)z, (void*)obj);
|
||||||
|
}
|
||||||
|
if (zone_mutex != nil)
|
||||||
|
{
|
||||||
|
[zone_mutex unlock];
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return NSAllocateObject(self, 0, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+ (NSTimeZone*) defaultTimeZone
|
+ (NSTimeZone*) defaultTimeZone
|
||||||
{
|
{
|
||||||
NSTimeZone *zone;
|
NSTimeZone *zone;
|
||||||
|
@ -658,8 +937,17 @@ static NSMapTable *absolutes = 0;
|
||||||
if (self == [NSTimeZone class])
|
if (self == [NSTimeZone class])
|
||||||
{
|
{
|
||||||
NSTimeZoneClass = self;
|
NSTimeZoneClass = self;
|
||||||
|
GSPlaceholderTimeZoneClass = [GSPlaceholderTimeZone class];
|
||||||
zoneDictionary = [[NSMutableDictionary alloc] init];
|
zoneDictionary = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up infrastructure for placeholder timezones.
|
||||||
|
*/
|
||||||
|
defaultPlaceholderTimeZone = (GSPlaceholderTimeZone*)
|
||||||
|
NSAllocateObject(GSPlaceholderTimeZoneClass, 0, NSDefaultMallocZone());
|
||||||
|
placeholderMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
||||||
|
NSNonRetainedObjectMapValueCallBacks, 0);
|
||||||
|
|
||||||
localTimeZone = [[NSLocalTimeZone alloc] init];
|
localTimeZone = [[NSLocalTimeZone alloc] init];
|
||||||
[self setDefaultTimeZone: [self systemTimeZone]];
|
[self setDefaultTimeZone: [self systemTimeZone]];
|
||||||
|
|
||||||
|
@ -753,7 +1041,7 @@ static NSMapTable *absolutes = 0;
|
||||||
}
|
}
|
||||||
if (localZoneString != nil)
|
if (localZoneString != nil)
|
||||||
{
|
{
|
||||||
zone = RETAIN([NSTimeZoneClass timeZoneWithName: localZoneString]);
|
zone = [defaultPlaceholderTimeZone initWithName: localZoneString];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -837,169 +1125,14 @@ static NSMapTable *absolutes = 0;
|
||||||
|
|
||||||
+ (NSTimeZone*) timeZoneWithName: (NSString*)aTimeZoneName
|
+ (NSTimeZone*) timeZoneWithName: (NSString*)aTimeZoneName
|
||||||
{
|
{
|
||||||
static NSString *fileException = @"fileException";
|
NSTimeZone *zone;
|
||||||
static NSString *errMess = @"File read error in NSTimeZone.";
|
|
||||||
id zone, transArray, detailsArray;
|
|
||||||
int i, n_trans, n_types, names_size;
|
|
||||||
id *abbrevsArray;
|
|
||||||
char *trans, *type_idxs, *zone_abbrevs;
|
|
||||||
struct tzhead header;
|
|
||||||
struct ttinfo *types; // Temporary array for details
|
|
||||||
FILE *file = NULL;
|
|
||||||
NSString *fileName;
|
|
||||||
|
|
||||||
if (zone_mutex != nil)
|
zone = [defaultPlaceholderTimeZone initWithName: aTimeZoneName];
|
||||||
[zone_mutex lock];
|
return AUTORELEASE(zone);
|
||||||
zone = [zoneDictionary objectForKey: aTimeZoneName];
|
|
||||||
if (zone != nil)
|
|
||||||
{
|
|
||||||
if (zone_mutex != nil)
|
|
||||||
[zone_mutex unlock];
|
|
||||||
return zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = [aTimeZoneName length];
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
NSLog(@"Disallowed null time zone name");
|
|
||||||
if (zone_mutex != nil)
|
|
||||||
[zone_mutex unlock];
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const char *str = [aTimeZoneName lossyCString];
|
|
||||||
|
|
||||||
if ([aTimeZoneName hasPrefix: @"NSAbsoluteTimeZone:"] == YES)
|
|
||||||
{
|
|
||||||
i = atoi(&str[19]);
|
|
||||||
if (zone_mutex != nil)
|
|
||||||
[zone_mutex unlock];
|
|
||||||
zone = [[NSConcreteAbsoluteTimeZone alloc] initWithOffset: i];
|
|
||||||
AUTORELEASE(zone);
|
|
||||||
return zone;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 `%@'.", aTimeZoneName);
|
|
||||||
if (zone_mutex != nil)
|
|
||||||
[zone_mutex unlock];
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_DURING
|
|
||||||
{
|
|
||||||
zone = [NSConcreteTimeZone alloc];
|
|
||||||
|
|
||||||
/* Open file. */
|
|
||||||
fileName = [NSTimeZoneClass getTimeZoneFile: aTimeZoneName];
|
|
||||||
#if defined(__WIN32__)
|
|
||||||
file = fopen([fileName fileSystemRepresentation], "rb");
|
|
||||||
#else
|
|
||||||
file = fopen([fileName fileSystemRepresentation], "r");
|
|
||||||
#endif
|
|
||||||
if (file == NULL)
|
|
||||||
[NSException raise: fileException format: errMess];
|
|
||||||
|
|
||||||
/* Read header. */
|
|
||||||
if (fread(&header, sizeof(struct tzhead), 1, file) != 1)
|
|
||||||
[NSException raise: fileException format: errMess];
|
|
||||||
|
|
||||||
n_trans = decode(header.tzh_timecnt);
|
|
||||||
n_types = decode(header.tzh_typecnt);
|
|
||||||
names_size = decode(header.tzh_charcnt);
|
|
||||||
|
|
||||||
/* Read in transitions. */
|
|
||||||
trans = NSZoneMalloc(NSDefaultMallocZone(), 4*n_trans);
|
|
||||||
type_idxs = NSZoneMalloc(NSDefaultMallocZone(), n_trans);
|
|
||||||
if (fread(trans, 4, n_trans, file) != n_trans
|
|
||||||
|| fread(type_idxs, 1, n_trans, file) != n_trans)
|
|
||||||
[NSException raise: fileException format: errMess];
|
|
||||||
transArray = [NSMutableArray arrayWithCapacity: n_trans];
|
|
||||||
for (i = 0; i < n_trans; i++)
|
|
||||||
[transArray
|
|
||||||
addObject: [[NSInternalTimeTransition alloc]
|
|
||||||
initWithTime: decode(trans+(i*4))
|
|
||||||
withIndex: type_idxs[i]]];
|
|
||||||
NSZoneFree(NSDefaultMallocZone(), trans);
|
|
||||||
NSZoneFree(NSDefaultMallocZone(), type_idxs);
|
|
||||||
|
|
||||||
/* Read in time zone details. */
|
|
||||||
types =
|
|
||||||
NSZoneMalloc(NSDefaultMallocZone(), sizeof(struct ttinfo)*n_types);
|
|
||||||
for (i = 0; i < n_types; i++)
|
|
||||||
{
|
|
||||||
unsigned char x[4];
|
|
||||||
|
|
||||||
if (fread(x, 1, 4, file) != 4
|
|
||||||
|| fread(&types[i].isdst, 1, 1, file) != 1
|
|
||||||
|| fread(&types[i].abbr_idx, 1, 1, file) != 1)
|
|
||||||
[NSException raise: fileException format: errMess];
|
|
||||||
types[i].offset = decode(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read in time zone abbreviation strings. */
|
|
||||||
zone_abbrevs = NSZoneMalloc(NSDefaultMallocZone(), names_size);
|
|
||||||
if (fread(zone_abbrevs, 1, names_size, file) != names_size)
|
|
||||||
[NSException raise: fileException format: errMess];
|
|
||||||
abbrevsArray = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*names_size);
|
|
||||||
memset(abbrevsArray, '\0', sizeof(id)*names_size);
|
|
||||||
for (i = 0; i < n_types; i++)
|
|
||||||
{
|
|
||||||
int pos = types[i].abbr_idx;
|
|
||||||
|
|
||||||
if (abbrevsArray[pos] == nil)
|
|
||||||
abbrevsArray[pos] = [NSString stringWithCString: zone_abbrevs+pos];
|
|
||||||
}
|
|
||||||
NSZoneFree(NSDefaultMallocZone(), zone_abbrevs);
|
|
||||||
|
|
||||||
/* Create time zone details. */
|
|
||||||
detailsArray = [NSMutableArray arrayWithCapacity: n_types];
|
|
||||||
for (i = 0; i < n_types; i++)
|
|
||||||
{
|
|
||||||
NSConcreteTimeZoneDetail *detail;
|
|
||||||
|
|
||||||
detail = [[NSConcreteTimeZoneDetail alloc]
|
|
||||||
initWithTimeZone: zone
|
|
||||||
withAbbrev: abbrevsArray[(int)types[i].abbr_idx]
|
|
||||||
withOffset: types[i].offset
|
|
||||||
withDST: (types[i].isdst > 0)];
|
|
||||||
[detailsArray addObject: detail];
|
|
||||||
RELEASE(detail);
|
|
||||||
}
|
|
||||||
NSZoneFree(NSDefaultMallocZone(), abbrevsArray);
|
|
||||||
NSZoneFree(NSDefaultMallocZone(), types);
|
|
||||||
|
|
||||||
[zone initWithName: aTimeZoneName
|
|
||||||
withTransitions: transArray
|
|
||||||
withDetails: detailsArray];
|
|
||||||
[zoneDictionary setObject: zone forKey: (NSString*)[zone name]];
|
|
||||||
}
|
|
||||||
NS_HANDLER
|
|
||||||
{
|
|
||||||
if (zone != nil)
|
|
||||||
RELEASE(zone);
|
|
||||||
zone = nil;
|
|
||||||
if ([localException name] != fileException)
|
|
||||||
[localException raise];
|
|
||||||
NSLog(@"Unable to obtain time zone `%@'.", aTimeZoneName);
|
|
||||||
}
|
|
||||||
NS_ENDHANDLER
|
|
||||||
|
|
||||||
RELEASE(zone); /* retained in zoneDictionary. */
|
|
||||||
|
|
||||||
if (file != NULL)
|
|
||||||
fclose(file);
|
|
||||||
if (zone_mutex != nil)
|
|
||||||
[zone_mutex unlock];
|
|
||||||
return zone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSTimeZone*) timeZoneWithName: (NSString*)name data: (NSData*)data
|
+ (NSTimeZone*) timeZoneWithName: (NSString*)name data: (NSData*)data
|
||||||
|
|
||||||
{
|
{
|
||||||
[self notImplemented: _cmd];
|
[self notImplemented: _cmd];
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -1035,30 +1168,15 @@ static NSMapTable *absolutes = 0;
|
||||||
|
|
||||||
- (void) encodeWithCoder: (NSCoder*)aCoder
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
||||||
{
|
{
|
||||||
if (self == localTimeZone)
|
[aCoder encodeObject: [self name]];
|
||||||
{
|
|
||||||
[aCoder encodeObject: @"NSLocalTimeZone"];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
[aCoder encodeObject: [self name]];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id) initWithCoder: (NSCoder*)aDecoder
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
||||||
{
|
{
|
||||||
NSString *name;
|
NSString *name;
|
||||||
|
|
||||||
[aDecoder decodeValueOfObjCType: @encode(id) at: &name];
|
name = [aDecoder decodeObject];
|
||||||
RELEASE(self);
|
self = [self initWithName: name];
|
||||||
if ([name isEqual: @"NSLocalTimeZone"])
|
|
||||||
{
|
|
||||||
self = RETAIN(localTimeZone);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self = RETAIN([NSTimeZoneClass timeZoneWithName: name]);
|
|
||||||
}
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue