NSBundle improvements for bundles created using bundleForLibrary:

or bundleForClass:


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@22859 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2006-05-05 11:06:57 +00:00
parent 4ca24f23f8
commit f7d0a2e48b
3 changed files with 166 additions and 61 deletions

View file

@ -1,3 +1,14 @@
2006-05-05 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/NSBundle.h: fix type of _bundleClasses
* Source/NSBundle.m: Try to make bundles for libraries behave as
well as possible with respect to the code in the libraries.
Rather depends on the Info.plist in the resource directory
specifying an NSPrincipalClass so that we can look up that
class at runtime and determine the file it came from.
Added documentation to mmake it clear that this is not
reliable (eg impossible for static or non-existent libraries).
2006-04-30 David Ayers <d.ayers@inode.at>
* Source/NSString: Define _GNU_SOURCE to make protoype of fwprintf

View file

@ -33,6 +33,7 @@
@class NSString;
@class NSArray;
@class NSDictionary;
@class NSMutableArray;
@class NSMutableDictionary;
/**
@ -91,15 +92,15 @@ GS_EXPORT NSString* const NSLoadedClasses;
*/
@interface NSBundle : NSObject
{
NSString *_path;
NSArray *_bundleClasses;
Class _principalClass;
NSDictionary *_infoDict;
NSString *_path;
NSMutableArray *_bundleClasses;
Class _principalClass;
NSDictionary *_infoDict;
NSMutableDictionary *_localizations;
unsigned _bundleType;
BOOL _codeLoaded;
unsigned _version;
NSString *_frameworkVersion;
unsigned _bundleType;
BOOL _codeLoaded;
unsigned _version;
NSString *_frameworkVersion;
}
/** Return an array enumerating all the bundles in the application. This

View file

@ -64,7 +64,10 @@
@end
typedef enum {
NSBUNDLE_BUNDLE = 1, NSBUNDLE_APPLICATION, NSBUNDLE_FRAMEWORK
NSBUNDLE_BUNDLE = 1,
NSBUNDLE_APPLICATION,
NSBUNDLE_FRAMEWORK,
NSBUNDLE_LIBRARY
} bundle_t;
/* Class variables - We keep track of all the bundles */
@ -378,7 +381,6 @@ _find_framework(NSString *name)
@interface NSBundle (Private)
+ (NSString *) _absolutePathOfExecutable: (NSString *)path;
+ (void) _addFrameworkFromClass: (Class)frameworkClass;
- (NSArray *) _bundleClasses;
+ (NSString*) _gnustep_target_cpu;
+ (NSString*) _gnustep_target_dir;
+ (NSString*) _gnustep_target_os;
@ -604,7 +606,7 @@ _find_framework(NSString *name)
value = [NSValue valueWithNonretainedObject: class];
[(NSMutableArray *)[bundle _bundleClasses] addObject: value];
[bundle->_bundleClasses addObject: value];
fmClasses++;
}
@ -620,17 +622,12 @@ _find_framework(NSString *name)
*/
if (_loadingBundle != nil && _loadingBundle != bundle)
{
[(NSMutableArray *)[_loadingBundle _bundleClasses]
removeObjectsInArray: [bundle _bundleClasses]];
[_loadingBundle->_bundleClasses
removeObjectsInArray: bundle->_bundleClasses];
}
}
}
- (NSArray *) _bundleClasses
{
return _bundleClasses;
}
+ (NSString*) _gnustep_target_cpu
{
return gnustep_target_cpu;
@ -662,6 +659,10 @@ _find_framework(NSString *name)
*/
typedef struct {
@defs(NSBundle)
} *bptr;
void
_bundle_load_callback(Class theClass, struct objc_category *theCategory)
{
@ -695,14 +696,14 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
}
/* Store classes (but don't store categories) */
[(NSMutableArray *)[_loadingBundle _bundleClasses] addObject:
[NSValue valueWithNonretainedObject: (id)theClass]];
[((bptr)_loadingBundle)->_bundleClasses addObject:
[NSValue valueWithNonretainedObject: (id)theClass]];
}
@implementation NSBundle
+ (void)initialize
+ (void) initialize
{
if (self == [NSBundle class])
{
@ -1004,7 +1005,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
while (NSNextMapEnumeratorPair(&enumerate, &key, (void **)&bundle))
{
int i, j;
NSArray *bundleClasses = [bundle _bundleClasses];
NSArray *bundleClasses = bundle->_bundleClasses;
BOOL found = NO;
j = [bundleClasses count];
@ -1020,13 +1021,61 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
bundle = nil;
}
[load_lock unlock];
if (!bundle)
if (bundle == nil)
{
/* Is it in the main bundle? */
/* Is it in the main bundle or a library? */
if (class_is_class(aClass))
bundle = [self mainBundle];
{
NSString *lib;
/*
* Take the path to the binary containing the class and
* convert it to the format for a library name as used
* for obtaining a library resource bundle.
*/
lib = objc_get_symbol_path (aClass, NULL);
if ([lib isEqual: ExecutablePath()] == YES)
{
lib = nil; // In program, not library.
}
lib = [lib lastPathComponent];
do
{
lib = [lib stringByDeletingPathExtension];
}
while ([[lib pathExtension] length] > 0);
if ([lib hasPrefix: @"lib"] == YES)
{
lib = [lib substringFromIndex: 3];
}
/*
* Get the library bundle ... if there wasn't one
* then we will assume the class was in the program
* executable and return the mainBundle instead.
*/
bundle = [NSBundle bundleForLibrary: lib];
if (bundle == nil)
{
bundle = [self mainBundle];
}
/*
* Add the class to the list of classes known to be in
* the library or executable. We didn't find it there
* to start with, so we know it's safe to add now.
*/
if (bundle->_bundleClasses == nil)
{
bundle->_bundleClasses
= [[NSMutableArray alloc] initWithCapacity: 2];
}
[bundle->_bundleClasses addObject:
[NSValue valueWithNonretainedObject: aClass]];
}
}
[load_lock unlock];
return bundle;
}
@ -1132,7 +1181,13 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
[super dealloc];
}
- (NSString *) bundlePath
- (NSString*) description
{
return [[super description] stringByAppendingFormat:
@" <%@>%@", [self bundlePath], [self isLoaded] ? @" (loaded)" : @""];
}
- (NSString*) bundlePath
{
return _path;
}
@ -1162,6 +1217,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
BOOL found = NO;
theClass = NSClassFromString(className);
[load_lock lock];
j = [_bundleClasses count];
for (i = 0; i < j && found == NO; i++)
@ -1173,6 +1229,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
found = YES;
}
}
[load_lock unlock];
if (found == NO)
{
@ -1185,39 +1242,38 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
- (Class) principalClass
{
NSString* class_name;
NSString *class_name;
if (_principalClass)
{
return _principalClass;
}
class_name = [[self infoDictionary] objectForKey: @"NSPrincipalClass"];
if (self == _mainBundle || self == _gnustep_bundle)
{
_codeLoaded = YES;
if (class_name)
{
_principalClass = NSClassFromString(class_name);
}
return _principalClass;
}
if ([self load] == NO)
{
return Nil;
}
class_name = [[self infoDictionary] objectForKey: @"NSPrincipalClass"];
if (class_name)
{
_principalClass = NSClassFromString(class_name);
}
if (!_principalClass && [_bundleClasses count])
else if (self == _gnustep_bundle)
{
_principalClass = [[_bundleClasses objectAtIndex: 0]
nonretainedObjectValue];
_principalClass = [NSObject class];
}
if (_principalClass == nil)
{
[load_lock lock];
if (_principalClass == nil && [_bundleClasses count] > 0)
{
_principalClass = [[_bundleClasses objectAtIndex: 0]
nonretainedObjectValue];
}
[load_lock unlock];
}
return _principalClass;
}
@ -1232,11 +1288,12 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
- (BOOL) load
{
if (self == _mainBundle || self == _gnustep_bundle)
if (self == _mainBundle || self ->_bundleType == NSBUNDLE_LIBRARY)
{
_codeLoaded = YES;
return YES;
}
[load_lock lock];
if (!_codeLoaded)
@ -1253,7 +1310,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
return NO;
}
_loadingBundle = self;
_bundleClasses = RETAIN([NSMutableArray arrayWithCapacity: 2]);
_bundleClasses = [[NSMutableArray alloc] initWithCapacity: 2];
_loadingFrameworks = RETAIN([NSMutableArray arrayWithCapacity: 2]);
/* This code is executed twice if a class linked in the bundle call a
@ -1295,8 +1352,8 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
classEnumerator = [_bundleClasses objectEnumerator];
while ((class = [classEnumerator nextObject]) != nil)
{
[classNames addObject: NSStringFromClass([class
nonretainedObjectValue])];
[classNames addObject:
NSStringFromClass([class nonretainedObjectValue])];
}
[load_lock unlock];
@ -1615,7 +1672,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
return dict;
}
- (NSArray *)localizations
- (NSArray *) localizations
{
NSString *locale;
NSArray *localizations;
@ -1633,7 +1690,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
return [array makeImmutableCopyOnFail: NO];
}
- (NSArray *)preferredLocalizations
- (NSArray *) preferredLocalizations
{
return [NSBundle preferredLocalizationsFromArray: [self localizations]];
}
@ -1796,6 +1853,10 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
{
return ExecutablePath();
}
if (self->_bundleType == NSBUNDLE_LIBRARY)
{
return objc_get_symbol_path ([self principalClass], NULL);
}
object = [[self infoDictionary] objectForKey: @"NSExecutable"];
if (object == nil || [object length] == 0)
{
@ -1884,7 +1945,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
return _infoDict;
}
- (NSString *)builtInPlugInsPath
- (NSString *) builtInPlugInsPath
{
NSString *version = _frameworkVersion;
@ -1907,17 +1968,17 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
}
}
- (NSString *)bundleIdentifier
- (NSString*) bundleIdentifier
{
return [[self infoDictionary] objectForKey:@"CFBundleIdentifier"];
}
- (unsigned)bundleVersion
- (unsigned) bundleVersion
{
return _version;
}
- (void)setBundleVersion:(unsigned)version
- (void) setBundleVersion: (unsigned)version
{
_version = version;
}
@ -1926,11 +1987,30 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
@implementation NSBundle (GNUstep)
/** Return a bundle which accesses the first existing directory from the list
GNUSTEP_USER_ROOT/Libraries/Resources/libraryName/
GNUSTEP_NETWORK_ROOT/Libraries/Resources/libraryName/
GNUSTEP_LOCAL_ROOT/Libraries/Resources/libraryName/
GNUSTEP_SYSTEM_ROOT/Libraries/Resources/libraryName/
/**
* <p>Return a bundle which accesses the first existing directory from the list
* GNUSTEP_USER_ROOT/Libraries/Resources/libraryName/
* GNUSTEP_NETWORK_ROOT/Libraries/Resources/libraryName/
* GNUSTEP_LOCAL_ROOT/Libraries/Resources/libraryName/
* GNUSTEP_SYSTEM_ROOT/Libraries/Resources/libraryName/<br />
* Where libraryName is the name of a library without the <em>lib</em>
* prefix or any extensions.
* </p>
* <p>This method exists to provide resource bundles for libraries and hos no
* particular relationship to the library code itsself. The named library
* could be a dynamic library linked in to the running program, a static
* library (whose code may not even exist on the host machine except where
* it is linked in to the program), or even a library which is not linked
* into the program at all (eg. where you want to share resources provided
* for a library you do not actually use).
* </p>
* <p>The bundle for the library <em>gnustep-base</em> is a special case ...
* for this bundle the -principalClass method returns [NSObject] and the
* -executablePath method returns the path to the gnustep-base dynamic
* library (if it can be found). As a general rule, library bundles are
* not guaranteed to return values for these methods as the library may
* not exist on disk.
* </p>
*/
+ (NSBundle *) bundleForLibrary: (NSString *)libraryName
{
@ -1940,7 +2020,14 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
NSString *tail;
NSFileManager *fm = [NSFileManager defaultManager];
if (libraryName == nil)
libraryName = [libraryName lastPathComponent];
do
{
libraryName = [libraryName stringByDeletingPathExtension];
}
while ([[libraryName pathExtension] length] > 0);
if ([libraryName length] == 0)
{
return nil;
}
@ -1958,7 +2045,13 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
if ([fm fileExistsAtPath: path isDirectory: &isDir] && isDir)
{
return [self bundleWithPath: path];
NSBundle *b = [self bundleWithPath: path];
if (b != nil && b->_bundleType == NSBUNDLE_BUNDLE)
{
b->_bundleType = NSBUNDLE_LIBRARY;
}
return b;
}
}