X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=sope-core%2FNGExtensions%2FNGBundleManager.m;h=001fc60dbcf4ac586272307cc0fce4b8b8054a8b;hb=61879b49f7cbc5be91e5c46018ed0fb2b37067f3;hp=c2ab346f9a3452411f620af9b4526734f6cba085;hpb=7f8b255ea0038570bd4c81050ad2e2225754820c;p=sope diff --git a/sope-core/NGExtensions/NGBundleManager.m b/sope-core/NGExtensions/NGBundleManager.m index c2ab346f..001fc60d 100644 --- a/sope-core/NGExtensions/NGBundleManager.m +++ b/sope-core/NGExtensions/NGBundleManager.m @@ -18,10 +18,10 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id: NGBundleManager.m 4 2004-08-20 17:04:31Z helge $ #include "NGBundleManager.h" #include "common.h" +#include #import #import #include @@ -35,6 +35,12 @@ # include #endif +#if LIB_FOUNDATION_LIBRARY +@interface NSBundle(UsedPrivates) ++ (BOOL)isFlattenedDirLayout; +@end +#endif + #if NeXT_RUNTIME || APPLE_RUNTIME #include @@ -120,7 +126,9 @@ static Class _classLoadHook(const char *_name) { bundle = [manager bundleForClassNamed:[NSString stringWithCString:_name]]; if (bundle) { - //NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, [bundle bundlePath]); +#if 0 + NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, [bundle bundlePath]); +#endif if ([manager loadBundle:bundle]) { Class clazz; @@ -205,6 +213,12 @@ static BOOL _selectClassByVersion(NSString *_resourceName, static NGBundleManager *defaultManager = nil; static BOOL debugOn = NO; +#if defined(__MINGW32__) +static NSString *NGEnvVarPathSeparator = @";"; +#else +static NSString *NGEnvVarPathSeparator = @":"; +#endif + + (void)initialize { NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; @@ -245,37 +259,42 @@ static BOOL debugOn = NO; return defaultManager; } -- (void)_setupBundleSearchPathes { - NSProcessInfo *pi; - NSUserDefaults *ud; - id paths; - NSString *path; +/* setup bundle search path */ - pi = [NSProcessInfo processInfo]; +- (void)_addMainBundlePathToPathArray:(NSMutableArray *)_paths { + NSProcessInfo *pi; + NSString *path; - /* setup bundle search path */ - - self->bundleSearchPaths = [[NSMutableArray alloc] init]; - - // first add main-bundle path + pi = [NSProcessInfo processInfo]; + path = [[pi arguments] objectAtIndex:0]; + path = [path stringByDeletingLastPathComponent]; - path = [[[pi arguments] objectAtIndex:0] stringByDeletingLastPathComponent]; if ([path isEqual:@""]) - path = @"."; + path = @"."; #if WITH_GNUSTEP else { - /* The path is the complete path to the executable, including the - processor, the OS and the library combo. Strip these directories - from the main bundle's path. */ - path = [[[path stringByDeletingLastPathComponent] - stringByDeletingLastPathComponent] - stringByDeletingLastPathComponent]; + // TODO: to be correct this would need to read the bundle-info + // NSExecutable?! + /* + The path is the complete path to the executable, including the + processor, the OS and the library combo. Strip these directories + from the main bundle's path. + */ +#if LIB_FOUNDATION_LIBRARY + if (![NSBundle isFlattenedDirLayout]) +#endif + path = [[[path stringByDeletingLastPathComponent] + stringByDeletingLastPathComponent] + stringByDeletingLastPathComponent]; } #endif - [self->bundleSearchPaths addObject:path]; - - // look into NGBundlePath default - + [_paths addObject:path]; +} + +- (void)_addBundlePathDefaultToPathArray:(NSMutableArray *)_paths { + NSUserDefaults *ud; + id paths; + if ((ud = [NSUserDefaults standardUserDefaults]) == nil) { // got this with gstep-base during the port, apparently it happens // if the bundle manager is created inside the setup process of @@ -285,62 +304,68 @@ static BOOL debugOn = NO; abort(); #endif } - - paths = [ud arrayForKey:@"NGBundlePath"]; - if (paths == nil) { - paths = [ud stringForKey:@"NGBundlePath"]; - if (paths) { -#if defined(__MINGW32__) - paths = [paths componentsSeparatedByString:@";"]; -#else - paths = [paths componentsSeparatedByString:@":"]; -#endif - } + + if ((paths = [ud arrayForKey:@"NGBundlePath"]) == nil) { + if ((paths = [ud stringForKey:@"NGBundlePath"]) != nil) + paths = [paths componentsSeparatedByString:NGEnvVarPathSeparator]; } - if (paths) - [self->bundleSearchPaths addObjectsFromArray:paths]; - else + if (paths != nil) + [_paths addObjectsFromArray:paths]; + else if (debugOn) NSLog(@"Note: NGBundlePath default is not configured."); +} - // look into environment - +- (void)_addEnvironmentPathToPathArray:(NSMutableArray *)_paths { + NSProcessInfo *pi; + id paths; + + pi = [NSProcessInfo processInfo]; paths = [[pi environment] objectForKey:@"NGBundlePath"]; - if (paths) { -#if defined(__MINGW32__) - paths = [paths componentsSeparatedByString:@";"]; -#else - paths = [paths componentsSeparatedByString:@":"]; -#endif - } - if (paths) [self->bundleSearchPaths addObjectsFromArray:paths]; + if (paths) + paths = [paths componentsSeparatedByString:NGEnvVarPathSeparator]; + if (paths) [_paths addObjectsFromArray:paths]; +} - /* add standard bundle paths */ - { +- (void)_addGNUstepPathsToPathArray:(NSMutableArray *)_paths { #if !GNUSTEP #else - // TODO: whats that supposed to do? - // TODO: replace with proper path locator function! - NSDictionary *env; - NSString *p; - unsigned i, count; - id tmp; + // TODO: whats that supposed to do? + // TODO: replace with proper path locator function! + NSDictionary *env; + NSString *p; + unsigned i, count; + id tmp; - env = [[NSProcessInfo processInfo] environment]; + env = [[NSProcessInfo processInfo] environment]; - if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil) - tmp = [env objectForKey:@"GNUSTEP_PATHLIST"]; - tmp = [tmp componentsSeparatedByString:@":"]; + if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil) + tmp = [env objectForKey:@"GNUSTEP_PATHLIST"]; + tmp = [tmp componentsSeparatedByString:@":"]; + + for (i = 0, count = [tmp count]; i < count; i++) { + p = [tmp objectAtIndex:i]; + p = [p stringByAppendingPathComponent:@"Library"]; + p = [p stringByAppendingPathComponent:@"Bundles"]; + if ([self->bundleSearchPaths containsObject:p]) continue; + + if (p) [self->bundleSearchPaths addObject:p]; + } +#endif +} - for (i = 0; i < count; i++) { - p = [tmp objectAtIndex:i]; - p = [p stringByAppendingPathComponent:@"Library"]; - p = [p stringByAppendingPathComponent:@"Bundles"]; - if ([self->bundleSearchPaths containsObject:p]) continue; +- (void)_setupBundleSearchPathes { + NSProcessInfo *pi; + + pi = [NSProcessInfo processInfo]; + + /* setup bundle search path */ - [self->bundleSearchPaths addObject:p]; - } -#endif - } + self->bundleSearchPaths = [[NSMutableArray alloc] initWithCapacity:16]; + + [self _addMainBundlePathToPathArray:self->bundleSearchPaths]; + [self _addBundlePathDefaultToPathArray:self->bundleSearchPaths]; + [self _addEnvironmentPathToPathArray:self->bundleSearchPaths]; + [self _addGNUstepPathsToPathArray:self->bundleSearchPaths]; #if DEBUG && NeXT_Foundation_LIBRARY && 0 NSLog(@"%s: bundle search pathes:\n%@", __PRETTY_FUNCTION__, @@ -424,6 +449,15 @@ static BOOL debugOn = NO; [super dealloc]; } +/* accessors */ + +- (void)setBundleSearchPaths:(NSArray *)_paths { + ASSIGNCOPY(self->bundleSearchPaths, _paths); +} +- (NSArray *)bundleSearchPaths { + return self->bundleSearchPaths; +} + /* registering bundles */ - (void)registerBundle:(NSBundle *)_bundle @@ -511,9 +545,12 @@ static BOOL debugOn = NO; */ #if !LIB_FOUNDATION_LIBRARY && !GNUSTEP_BASE_LIBRARY -# warning incorrect behaviour if NGExtensions is dynamically loaded ! + // Note: incorrect behaviour if NGExtensions is dynamically loaded ! // TODO: can we do anything about this? Can we detect the situation and // print a log instead of the compile warning? + // Note: the above refers to the situation when a framework is implicitly + // loaded by loading a bundle (the framework is not linked against + // the main tool) #endif bundle = [NSBundle mainBundle]; NSMapInsert(self->classToBundle, aClass, bundle); @@ -558,12 +595,14 @@ static BOOL debugOn = NO; bn = [_name stringByAppendingPathExtension:_type]; bundle = NSMapGet(self->nameToBundle, bn); - if (bundle == nil) - bundle = [self bundleWithPath:[self pathForBundleWithName:_name type:_type]]; - - if (![[bundle bundleType] isEqualToString:_type]) + if (bundle == nil) { + bundle = [self bundleWithPath: + [self pathForBundleWithName:_name type:_type]]; + } + + if (bundle != nil && ![[bundle bundleType] isEqualToString:_type]) bundle = nil; - + return bundle; } - (NSBundle *)bundleWithName:(NSString *)_name { @@ -642,7 +681,7 @@ static BOOL debugOn = NO; return nil; } -// initialization +/* initialization */ - (NSString *)makeBundleInfoPath:(NSString *)_path { #if (NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) && !defined(GSWARN) @@ -657,17 +696,20 @@ static BOOL debugOn = NO; - (id)_initializeLoadedBundle:(NSBundle *)_bundle info:(NSDictionary *)_bundleInfo { - id handler = nil; + id handler; /* check whether a handler was specified */ - - if ((handler = [_bundleInfo objectForKey:@"bundleHandler"])) { + + if ((handler = [_bundleInfo objectForKey:@"bundleHandler"]) != nil) { + [self debugWithFormat:@"lookup bundle handler %@ of bundle: %@", + handler, _bundle]; + if ((handler = NSClassFromString(handler)) == nil) { NSLog(@"ERROR: did not find handler class %@ of bundle %@.", [_bundleInfo objectForKey:@"bundleHandler"], [_bundle bundlePath]); handler = [_bundle principalClass]; } - + handler = [handler alloc]; if ([handler respondsToSelector:@selector(initForBundle:bundleManager:)]) @@ -683,6 +725,9 @@ static BOOL debugOn = NO; } } else { + [self debugWithFormat: + @"no bundle handler, lookup principal class of bundle: %@", + _bundle]; if ((handler = [_bundle principalClass]) == nil) /* use NGBundle class as default bundle handler */ handler = [NGBundle class]; @@ -1116,84 +1161,169 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info NSFileManager *fm; NSEnumerator *e; NSString *path; + + if (debugOn) { + NSLog(@"BM LOOKUP pathes (%d bundles loaded): %@ / %@", + NSCountMapTable(self->loadedBundles), _resourceName, _type); + } fm = [NSFileManager defaultManager]; result = [NSMutableArray arrayWithCapacity:64]; + // TODO: look in loaded bundles + + /* check physical pathes */ + e = [self->bundleSearchPaths objectEnumerator]; - while ((path = [e nextObject])) { - BOOL isDir = NO; + while ((path = [e nextObject]) != nil) { + NSEnumerator *dir; + BOOL isDir = NO; + NSString *tmp, *bundleDirPath; + id info = nil; - if ([fm fileExistsAtPath:path isDirectory:&isDir]) { - NSString *tmp; - id info = nil; - if (!isDir) continue; - - /* check whether an appropriate bundle is contained in 'path' */ - { - NSEnumerator *dir; - - dir = [[fm directoryContentsAtPath:path] objectEnumerator]; - while ((tmp = [dir nextObject])) { - NSDictionary *bundleInfo = nil; - NSEnumerator *providedResources = nil; - NSString *infoPath; - id info; + if (![fm fileExistsAtPath:path isDirectory:&isDir]) + continue; + + if (!isDir) continue; + + /* check whether an appropriate bundle is contained in 'path' */ + + dir = [[fm directoryContentsAtPath:path] objectEnumerator]; + while ((bundleDirPath = [dir nextObject]) != nil) { + NSDictionary *bundleInfo = nil; + NSEnumerator *providedResources = nil; + NSString *infoPath; + id info; - tmp = [path stringByAppendingPathComponent:tmp]; - infoPath = [self makeBundleInfoPath:tmp]; - - if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) { - if (![fm fileExistsAtPath:infoPath]) - continue; - - bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath]; - } - - providedResources = - [[(NSDictionary *)[bundleInfo objectForKey:@"provides"] - objectForKey:_type] - objectEnumerator]; - if (providedResources == nil) continue; + bundleDirPath = [path stringByAppendingPathComponent:bundleDirPath]; + infoPath = [self makeBundleInfoPath:bundleDirPath]; + + // TODO: can we use _doesBundleInfo:path:providedResource:... ? + if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath))==nil) { + if (![fm fileExistsAtPath:infoPath]) + continue; - // scan provide array - while ((info = [providedResources nextObject])) { - NSString *name; + bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath]; + } + + providedResources = + [[(NSDictionary *)[bundleInfo objectForKey:@"provides"] + objectForKey:_type] + objectEnumerator]; + if (providedResources == nil) continue; + + /* scan 'provides' array */ + while ((info = [providedResources nextObject])) { + NSString *name; - name = [[(NSDictionary *)info objectForKey:@"name"] stringValue]; - if (name == nil) continue; - - if (_resourceName) { - if (![name isEqualToString:_resourceName]) - continue; - } - if (_selector) { - if (!_selector(name, _type, tmp, info, self, _context)) - continue; - } - - [result addObject:tmp]; - break; - } - } + name = [[(NSDictionary *)info objectForKey:@"name"] stringValue]; + if (name == nil) continue; + + if (_resourceName != nil) { + if (![name isEqualToString:_resourceName]) + continue; + } + if (_selector != NULL) { + if (!_selector(name, _type, bundleDirPath, info, self, _context)) + continue; + } + + [result addObject:bundleDirPath]; + break; } + } + + /* check for direct match (NGBundlePath element is a bundle) */ + + tmp = [self makeBundleInfoPath:path]; - /* check for direct match */ + if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) { + if ([fm fileExistsAtPath:tmp]) + info = [self _loadBundleInfoAtExistingPath:tmp]; + } + + [self _processInfoForProvidedResources:info ofType:_type path:path + resourceName:_resourceName resourceSelector:_selector + context:_context + andAddToResultArray:result]; + } + + if ([result count] == 0) { + [self logWithFormat: + @"Note(%s): method does not search in loaded bundles for " + @"resources of type '%@'", + __PRETTY_FUNCTION__, _type]; + } + + return [[result copy] autorelease]; +} - tmp = [self makeBundleInfoPath:path]; +- (BOOL)_doesBundleInfo:(NSDictionary *)_bundleInfo path:(NSString *)_path + provideResource:(id)_resourceName ofType:(NSString *)_type + rnKeys:(NSArray *)_rnKeys + resourceSelector:(NGBundleResourceSelector)_selector context:(void *)_context +{ + NSEnumerator *providedResources; + NSDictionary *info; + + providedResources = + [[(NSDictionary *)[_bundleInfo objectForKey:@"provides"] + objectForKey:_type] objectEnumerator]; + if (providedResources == nil) return NO; + + /* scan provide array */ + while ((info = [providedResources nextObject])) { + if (_rnKeys != nil) { + if (!_doesInfoMatch(_rnKeys, _resourceName, info)) + continue; + } + else { + NSString *name; - if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) { - if ([fm fileExistsAtPath:tmp]) - info = [self _loadBundleInfoAtExistingPath:tmp]; - } - - [self _processInfoForProvidedResources:info ofType:_type path:path - resourceName:_resourceName resourceSelector:_selector - context:_context - andAddToResultArray:result]; + name = [[(NSDictionary *)info objectForKey:@"name"] stringValue]; + if (name == nil) continue; + if (![name isEqualToString:_resourceName]) continue; } + + if (_selector != NULL) { + if (!_selector(_resourceName, _type, _path, info, self, _context)) + continue; + } + + /* all conditions applied (found) */ + return YES; } - return [[result copy] autorelease]; + return NO; +} + +- (NSString *)pathOfLoadedBundleProvidingResource:(id)_resourceName + ofType:(NSString *)_type + resourceSelector:(NGBundleResourceSelector)_selector context:(void *)_context +{ + NSMapEnumerator menum; + NSString *path; + NSDictionary *bundleInfo; + NSArray *rnKeys; + + rnKeys = ([_resourceName respondsToSelector:@selector(objectForKey:)]) + ? [_resourceName allKeys] + : nil; + + menum = NSEnumerateMapTable(self->pathToBundleInfo); + while (NSNextMapEnumeratorPair(&menum, (void *)&path, (void *)&bundleInfo)) { + if (debugOn) { + NSLog(@"check loaded bundle for resource %@: %@", _resourceName, + path); + } + + if ([self _doesBundleInfo:bundleInfo path:path + provideResource:_resourceName ofType:_type rnKeys:rnKeys + resourceSelector:_selector context:_context]) + /* strip bundle-info.plist name */ + return [path stringByDeletingLastPathComponent]; + } + + return nil; } - (NSString *)pathForBundleProvidingResource:(id)_resourceName @@ -1201,99 +1331,87 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info resourceSelector:(NGBundleResourceSelector)_selector context:(void *)_context { - NSFileManager *fm = [NSFileManager defaultManager]; + /* main path lookup method */ + // TODO: this method seriously needs some refactoring + NSFileManager *fm; NSEnumerator *e; NSString *path; NSArray *rnKeys = nil; int rnKeyCount = 0; - + + if (debugOn) { + NSLog(@"BM LOOKUP path (%d bundles loaded): %@ / %@", + NSCountMapTable(self->loadedBundles), _resourceName, _type); + } + + /* look in loaded bundles */ + + path = [self pathOfLoadedBundleProvidingResource:_resourceName ofType:_type + resourceSelector:_selector context:_context]; + if (path != nil) return path; + + /* look in filesystem */ + if ([_resourceName respondsToSelector:@selector(objectForKey:)]) { rnKeys = [_resourceName allKeys]; rnKeyCount = [rnKeys count]; } + fm = [NSFileManager defaultManager]; e = [self->bundleSearchPaths objectEnumerator]; - while ((path = [e nextObject])) { - BOOL isDir = NO; + while ((path = [e nextObject]) != nil) { + NSEnumerator *dir; + BOOL isDir = NO; + NSString *tmp; + id info = nil; - if ([fm fileExistsAtPath:path isDirectory:&isDir]) { - NSString *tmp; - id info = nil; + if (![fm fileExistsAtPath:path isDirectory:&isDir]) + continue; + + if (!isDir) continue; + + /* check whether an appropriate bundle is contained in 'path' */ + + dir = [[fm directoryContentsAtPath:path] objectEnumerator]; + while ((tmp = [dir nextObject])) { + NSDictionary *bundleInfo = nil; + NSString *infoPath; - if (!isDir) continue; + tmp = [path stringByAppendingPathComponent:tmp]; + infoPath = [self makeBundleInfoPath:tmp]; - /* check whether an appropriate bundle is contained in 'path' */ - { - NSEnumerator *dir; - - dir = [[fm directoryContentsAtPath:path] objectEnumerator]; - while ((tmp = [dir nextObject])) { - NSDictionary *bundleInfo = nil; - NSEnumerator *providedResources = nil; - NSString *infoPath; - id info; - - tmp = [path stringByAppendingPathComponent:tmp]; - infoPath = [self makeBundleInfoPath:tmp]; - - if (debugOn) - NSLog(@"check path path=%@ info=%@", tmp, infoPath); + if (debugOn) + NSLog(@"check path path=%@ info=%@", tmp, infoPath); - if ((bundleInfo=NSMapGet(self->pathToBundleInfo, infoPath)) == nil) { - if (![fm fileExistsAtPath:infoPath]) - continue; + if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) { + if (![fm fileExistsAtPath:infoPath]) + continue; - bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath]; - } - if (debugOn) { - NSLog(@"found info for path=%@ info=%@: %@", - tmp, infoPath, bundleInfo); - } - - providedResources = - [[(NSDictionary *)[bundleInfo objectForKey:@"provides"] - objectForKey:_type] - objectEnumerator]; - if (providedResources == nil) continue; - - // scan provide array - while ((info = [providedResources nextObject])) { - if (rnKeys) { - if (!_doesInfoMatch(rnKeys, _resourceName, info)) - continue; - } - else { - NSString *name; - - name = [[(NSDictionary *)info objectForKey:@"name"] stringValue]; - if (name == nil) continue; - if (![name isEqualToString:_resourceName]) continue; - } - - if (_selector) { - if (!_selector(_resourceName, _type, tmp, info, self, _context)) - continue; - } - /* all conditions applied */ - return tmp; - } - } + bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath]; } - - /* check for direct match */ + if (debugOn) + NSLog(@"found info for path=%@ info=%@: %@", tmp,infoPath,bundleInfo); - tmp = [self makeBundleInfoPath:path]; + if ([self _doesBundleInfo:bundleInfo path:tmp + provideResource:_resourceName ofType:_type rnKeys:rnKeys + resourceSelector:_selector context:_context]) + return tmp; + } + + /* check for direct match */ + + tmp = [self makeBundleInfoPath:path]; - if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) { + if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) { if ([fm fileExistsAtPath:tmp]) info = [self _loadBundleInfoAtExistingPath:tmp]; else if (debugOn) { NSLog(@"WARNING(%s): did not find direct path '%@'", __PRETTY_FUNCTION__, tmp); } - } + } - if (info) { + if (info != nil) { // direct match (a bundle was specified in the path) NSEnumerator *providedResources; NSDictionary *provides; @@ -1324,28 +1442,29 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info /* all conditions applied */ return tmp; } - } } } return nil; } -- (NSBundle *)bundleProvidingResource:(id)_resourceName - ofType:(NSString *)_resourceType -{ +- (NSBundle *)bundleProvidingResource:(id)_name ofType:(NSString *)_type { NSString *bp; - bp = [self pathForBundleProvidingResource:_resourceName - ofType:_resourceType + if (debugOn) NSLog(@"BM LOOKUP: %@ / %@", _name, _type); + + bp = [self pathForBundleProvidingResource:_name + ofType:_type resourceSelector:NULL context:nil]; if ([bp length] == 0) { #if (NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) && HEAVY_DEBUG NSLog(@"%s: found no resource '%@' of type '%@' ...", __PRETTY_FUNCTION__, _resourceName, _resourceType); #endif + if (debugOn) NSLog(@" did not find: %@ / %@", _name, _type); return nil; } + if (debugOn) NSLog(@" FOUND: %@", bp); return [self bundleWithPath:bp]; } @@ -1391,6 +1510,29 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info objectForKey:_resourceType]; } +- (void)_addRegisteredProvidedResourcesOfType:(NSString *)_type + toSet:(NSMutableSet *)_result +{ + NSMapEnumerator menum; + NSString *path; + NSDictionary *bundleInfo; + + menum = NSEnumerateMapTable(self->pathToBundleInfo); + while (NSNextMapEnumeratorPair(&menum, (void *)&path, (void *)&bundleInfo)) { + NSArray *providedResources; + + if (debugOn) + NSLog(@"check loaded bundle for resource types %@: %@", _type, path); + + providedResources = + [(NSDictionary *)[bundleInfo objectForKey:@"provides"] + objectForKey:_type]; + if (providedResources == nil) continue; + + [_result addObjectsFromArray:providedResources]; + } +} + - (NSArray *)providedResourcesOfType:(NSString *)_resourceType { NSMutableSet *result = nil; NSFileManager *fm = [NSFileManager defaultManager]; @@ -1399,67 +1541,73 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info result = [NSMutableSet setWithCapacity:128]; + /* scan loaded bundles */ + + [self _addRegisteredProvidedResourcesOfType:_resourceType toSet:result]; + + /* scan all bundle search paths */ + e = [self->bundleSearchPaths objectEnumerator]; while ((path = [e nextObject])) { - BOOL isDir = NO; + NSEnumerator *dir; + BOOL isDir = NO; + NSString *tmp; + id info = nil; - if ([fm fileExistsAtPath:path isDirectory:&isDir]) { - NSString *tmp; - id info = nil; - if (!isDir) continue; + if (![fm fileExistsAtPath:path isDirectory:&isDir]) + continue; + if (!isDir) continue; - /* check whether an appropriate bundle is contained in 'path' */ - { - NSEnumerator *dir; + /* check whether an appropriate bundle is contained in 'path' */ - dir = [[fm directoryContentsAtPath:path] objectEnumerator]; - while ((tmp = [dir nextObject])) { - NSDictionary *bundleInfo = nil; - NSArray *providedResources = nil; - NSString *infoPath; + dir = [[fm directoryContentsAtPath:path] objectEnumerator]; + while ((tmp = [dir nextObject])) { + NSDictionary *bundleInfo = nil; + NSArray *providedResources = nil; + NSString *infoPath; - tmp = [path stringByAppendingPathComponent:tmp]; - infoPath = [self makeBundleInfoPath:tmp]; - - //NSLog(@" info path: %@", tmp); - - if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) { - if (![fm fileExistsAtPath:infoPath]) - continue; - - bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath]; - } + tmp = [path stringByAppendingPathComponent:tmp]; + infoPath = [self makeBundleInfoPath:tmp]; + +#if 0 + NSLog(@" info path: %@", tmp); +#endif - providedResources = - [(NSDictionary *)[bundleInfo objectForKey:@"provides"] - objectForKey:_resourceType]; - if (providedResources == nil) continue; + if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) { + if (![fm fileExistsAtPath:infoPath]) + continue; - [result addObjectsFromArray:providedResources]; - } + bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath]; } - /* check for direct match */ + providedResources = + [(NSDictionary *)[bundleInfo objectForKey:@"provides"] + objectForKey:_resourceType]; + if (providedResources == nil) continue; + + [result addObjectsFromArray:providedResources]; + } + + /* check for direct match */ - tmp = [self makeBundleInfoPath:path]; + tmp = [self makeBundleInfoPath:path]; - if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) { - if ([fm fileExistsAtPath:tmp]) - info = [self _loadBundleInfoAtExistingPath:tmp]; - } + if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) { + if ([fm fileExistsAtPath:tmp]) + info = [self _loadBundleInfoAtExistingPath:tmp]; + } - if (info) { - // direct match (a bundle was specified in the path) - NSArray *providedResources; - NSDictionary *provides; + if (info != nil) { + // direct match (a bundle was specified in the path) + NSArray *providedResources; + NSDictionary *provides; - provides = [(NSDictionary *)info objectForKey:@"provides"]; - providedResources = [provides objectForKey:_resourceType]; - info = nil; - if (providedResources == nil) continue; + provides = [(NSDictionary *)info objectForKey:@"provides"]; + providedResources = [provides objectForKey:_resourceType]; + info = nil; + if (providedResources == nil) continue; - [result addObjectsFromArray:providedResources]; - } + [result addObjectsFromArray:providedResources]; } } return [result allObjects]; @@ -1630,7 +1778,7 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info return [[bundles copy] autorelease]; } -// notifications +/* notifications */ - (void)_bundleDidLoadNotifcation:(NSNotification *)_notification { NSDictionary *ui = [_notification userInfo]; @@ -1646,6 +1794,12 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info categories:[ui objectForKey:@"NSLoadedCategories"]]; } +/* debugging */ + +- (BOOL)isDebuggingEnabled { + return debugOn; +} + @end /* NGBundleManager */ @implementation NSBundle(BundleManagerSupport) @@ -1844,7 +1998,7 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info - (NSString *)description { char buffer[1024]; - + sprintf (buffer, "<%s %p fullPath: %s infoDictionary: %p loaded=%s>", (char*)object_get_class_name(self),