2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "NGBundleManager.h"
24 #import <Foundation/NSFileManager.h>
25 #import <EOControl/EOQualifier.h>
28 #if 0 && GNUSTEP_BASE_LIBRARY /* supported in repository since 19990916-2254-MET */
29 /* hack until GNUstep provides the necessary callbacks */
30 # define NSNonRetainedObjectMapValueCallBacks NSObjectMapValueCallBacks
33 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
34 # include <NGExtensions/NGPropertyListParser.h>
37 #if LIB_FOUNDATION_LIBRARY
38 @interface NSBundle(UsedPrivates)
39 + (BOOL)isFlattenedDirLayout;
43 #if NeXT_RUNTIME || APPLE_RUNTIME
45 #include <objc/objc-runtime.h>
47 //OBJC_EXPORT void objc_setClassHandler(int (*)(const char *));
49 static BOOL debugClassHook = NO;
51 static int _getClassHook(const char *className) {
52 if (className == NULL) return 0;
55 printf("lookup class '%s'.\n", className);
57 if (objc_lookUpClass(className))
61 static NGBundleManager *manager = nil;
65 NSLog(@"%s: look for class %s", __PRETTY_FUNCTION__, className);
67 manager = [NGBundleManager defaultBundleManager];
69 bundle = [manager bundleForClassNamed:
70 [NSString stringWithCString:className]];
73 NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__,
77 if (![manager loadBundle:bundle]) {
79 "bundleManager couldn't load bundle for class '%s'.\n",
84 Class c = objc_lookUpClass(className);
85 NSLog(@"%s: loaded bundle %@ for className %s class %@",
87 bundle, className, c);
99 #include <objc/objc-api.h>
101 static Class (*oldClassLoadHook)(const char *_name) = NULL;
103 static inline BOOL _isValidClassName(const char *_name) {
106 if (_name == NULL) return NO;
108 for (len = 0; (len < 256) && (*_name != '\0'); len++, _name++) {
110 if (!isalnum((int)*_name))
114 return (len == 256) ? NO : YES;
117 static Class _classLoadHook(const char *_name) {
118 if (_isValidClassName(_name)) {
119 static NGBundleManager *manager = nil;
122 //NSLog(@"%s: look for class %s", __PRETTY_FUNCTION__, _name);
124 manager = [NGBundleManager defaultBundleManager];
126 bundle = [manager bundleForClassNamed:[NSString stringWithCString:_name]];
129 NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, [bundle bundlePath]);
132 if ([manager loadBundle:bundle]) {
136 hook = _objc_lookup_class;
137 _objc_lookup_class = NULL;
138 clazz = objc_lookup_class(_name);
139 _objc_lookup_class = hook;
141 if (clazz) return clazz;
145 return (oldClassLoadHook != NULL) ? oldClassLoadHook(_name) : Nil;
147 #endif // GNU_RUNTIME
149 NSString *NGBundleWasLoadedNotificationName = @"NGBundleWasLoadedNotification";
151 @interface NSBundle(NGBundleManagerPrivate)
152 - (BOOL)_loadForBundleManager:(NGBundleManager *)_manager;
155 @interface NGBundleManager(PrivateMethods)
157 - (void)registerBundle:(NSBundle *)_bundle
158 classes:(NSArray *)_classes
159 categories:(NSArray *)_categories;
161 - (NSString *)pathForBundleProvidingResource:(NSString *)_resourceName
162 ofType:(NSString *)_type
163 resourceSelector:(NGBundleResourceSelector)_selector
164 context:(void *)_ctx;
166 - (NSString *)makeBundleInfoPath:(NSString *)_path;
170 static BOOL _selectClassByVersion(NSString *_resourceName,
171 NSString *_resourceType,
173 NSDictionary *_resourceConfig,
174 NGBundleManager *_bundleManager,
180 if (![_resourceType isEqualToString:@"classes"])
183 if (_version == NULL)
185 if ([(id)_version intValue] == -1)
188 if ((tmp = [_resourceConfig objectForKey:@"version"])) {
189 classVersion = [tmp intValue];
191 if (classVersion < [(id)_version intValue]) {
192 NSLog(@"WARNING: class version mismatch for class %@: "
193 @"requested at least version %i, got version %i",
194 _resourceName, [(id)_version intValue], classVersion);
197 if ((tmp = [_resourceConfig objectForKey:@"exact-version"])) {
198 classVersion = [tmp intValue];
200 if (classVersion != [(id)_version intValue]) {
201 NSLog(@"WARNING: class version mismatch for class %@: "
202 @"requested exact version %i, got version %i",
203 _resourceName, [(id)_version intValue], classVersion);
209 @implementation NGBundleManager
212 static NGBundleManager *defaultManager = nil;
213 static BOOL debugOn = NO;
215 #if defined(__MINGW32__)
216 static NSString *NGEnvVarPathSeparator = @";";
218 static NSString *NGEnvVarPathSeparator = @":";
222 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
224 debugOn = [ud boolForKey:@"NGBundleManagerDebugEnabled"];
229 if (_objc_lookup_class != _classLoadHook) {
230 oldClassLoadHook = _objc_lookup_class;
231 _objc_lookup_class = _classLoadHook;
236 + (id)defaultBundleManager {
237 if (defaultManager == nil) {
238 defaultManager = [[NGBundleManager alloc] init];
240 #if NeXT_RUNTIME || APPLE_RUNTIME
242 static BOOL didRegisterCallback = NO;
244 if (!didRegisterCallback) {
245 didRegisterCallback = YES;
246 objc_setClassHandler(_getClassHook);
252 if (_objc_lookup_class != _classLoadHook) {
253 oldClassLoadHook = _objc_lookup_class;
254 _objc_lookup_class = _classLoadHook;
258 return defaultManager;
261 /* setup bundle search path */
263 - (void)_addMainBundlePathToPathArray:(NSMutableArray *)_paths {
267 pi = [NSProcessInfo processInfo];
268 path = [[pi arguments] objectAtIndex:0];
269 path = [path stringByDeletingLastPathComponent];
271 if ([path isEqual:@""])
275 // TODO: to be correct this would need to read the bundle-info
278 The path is the complete path to the executable, including the
279 processor, the OS and the library combo. Strip these directories
280 from the main bundle's path.
282 #if LIB_FOUNDATION_LIBRARY
283 if (![NSBundle isFlattenedDirLayout])
285 path = [[[path stringByDeletingLastPathComponent]
286 stringByDeletingLastPathComponent]
287 stringByDeletingLastPathComponent];
290 [_paths addObject:path];
293 - (void)_addBundlePathDefaultToPathArray:(NSMutableArray *)_paths {
297 if ((ud = [NSUserDefaults standardUserDefaults]) == nil) {
298 // got this with gstep-base during the port, apparently it happens
299 // if the bundle manager is created inside the setup process of
300 // gstep-base (for whatever reason)
301 NSLog(@"ERROR(NGBundleManager): got no system userdefaults object!");
307 if ((paths = [ud arrayForKey:@"NGBundlePath"]) == nil) {
308 if ((paths = [ud stringForKey:@"NGBundlePath"]) != nil)
309 paths = [paths componentsSeparatedByString:NGEnvVarPathSeparator];
312 [_paths addObjectsFromArray:paths];
314 NSLog(@"Note: NGBundlePath default is not configured.");
317 - (void)_addEnvironmentPathToPathArray:(NSMutableArray *)_paths {
321 pi = [NSProcessInfo processInfo];
322 paths = [[pi environment] objectForKey:@"NGBundlePath"];
324 paths = [paths componentsSeparatedByString:NGEnvVarPathSeparator];
325 if (paths) [_paths addObjectsFromArray:paths];
328 - (void)_addGNUstepPathsToPathArray:(NSMutableArray *)_paths {
331 // TODO: whats that supposed to do?
332 // TODO: replace with proper path locator function!
338 env = [[NSProcessInfo processInfo] environment];
340 if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
341 tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
342 tmp = [tmp componentsSeparatedByString:@":"];
344 for (i = 0, count = [tmp count]; i < count; i++) {
345 p = [tmp objectAtIndex:i];
346 p = [p stringByAppendingPathComponent:@"Library"];
347 p = [p stringByAppendingPathComponent:@"Bundles"];
348 if ([self->bundleSearchPaths containsObject:p]) continue;
350 if (p) [self->bundleSearchPaths addObject:p];
355 - (void)_setupBundleSearchPathes {
358 pi = [NSProcessInfo processInfo];
360 /* setup bundle search path */
362 self->bundleSearchPaths = [[NSMutableArray alloc] initWithCapacity:16];
364 [self _addMainBundlePathToPathArray:self->bundleSearchPaths];
365 [self _addBundlePathDefaultToPathArray:self->bundleSearchPaths];
366 [self _addEnvironmentPathToPathArray:self->bundleSearchPaths];
367 [self _addGNUstepPathsToPathArray:self->bundleSearchPaths];
369 #if DEBUG && NeXT_Foundation_LIBRARY && 0
370 NSLog(@"%s: bundle search pathes:\n%@", __PRETTY_FUNCTION__,
371 self->bundleSearchPaths);
375 - (void)_registerLoadedBundles {
376 NSEnumerator *currentBundles;
377 NSBundle *loadedBundle;
379 currentBundles = [[NSBundle allBundles] objectEnumerator];
380 while ((loadedBundle = [currentBundles nextObject]))
381 [self registerBundle:loadedBundle classes:nil categories:nil];
384 - (void)_registerForBundleLoadNotification {
385 [[NSNotificationCenter defaultCenter]
387 selector:@selector(_bundleDidLoadNotifcation:)
388 name:@"NSBundleDidLoadNotification"
393 #if GNUSTEP_BASE_LIBRARY
394 if ([NSUserDefaults standardUserDefaults] == nil) {
395 /* called inside setup process, deny creation (HACK) */
401 if ((self = [super init])) {
402 self->classToBundle =
403 NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
404 NSNonRetainedObjectMapValueCallBacks,
406 self->classNameToBundle =
407 NSCreateMapTable(NSObjectMapKeyCallBacks,
408 NSNonRetainedObjectMapValueCallBacks,
410 self->categoryNameToBundle =
411 NSCreateMapTable(NSObjectMapKeyCallBacks,
412 NSNonRetainedObjectMapValueCallBacks,
415 NSCreateMapTable(NSObjectMapKeyCallBacks,
416 NSNonRetainedObjectMapValueCallBacks,
418 self->pathToBundleInfo =
419 NSCreateMapTable(NSObjectMapKeyCallBacks,
420 NSObjectMapValueCallBacks,
423 NSCreateMapTable(NSObjectMapKeyCallBacks,
424 NSNonRetainedObjectMapValueCallBacks,
426 self->loadedBundles =
427 NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks,
428 NSObjectMapValueCallBacks,
431 [self _setupBundleSearchPathes];
432 [self _registerLoadedBundles];
433 [self _registerForBundleLoadNotification];
439 [self->loadingBundles release];
440 if (self->loadedBundles) NSFreeMapTable(self->loadedBundles);
441 if (self->classToBundle) NSFreeMapTable(self->classToBundle);
442 if (self->classNameToBundle) NSFreeMapTable(self->classNameToBundle);
443 if (self->categoryNameToBundle) NSFreeMapTable(self->categoryNameToBundle);
444 if (self->pathToBundle) NSFreeMapTable(self->pathToBundle);
445 if (self->pathToBundleInfo) NSFreeMapTable(self->pathToBundleInfo);
446 if (self->nameToBundle) NSFreeMapTable(self->nameToBundle);
447 [self->bundleSearchPaths release];
453 - (void)setBundleSearchPaths:(NSArray *)_paths {
454 ASSIGNCOPY(self->bundleSearchPaths, _paths);
456 - (NSArray *)bundleSearchPaths {
457 return self->bundleSearchPaths;
460 /* registering bundles */
462 - (void)registerBundle:(NSBundle *)_bundle
463 classes:(NSArray *)_classes
464 categories:(NSArray *)_categories
469 //NSLog(@"NGBundleManager: register loaded bundle %@", [_bundle bundlePath]);
471 e = [_classes objectEnumerator];
472 while ((v = [e nextObject])) {
473 NSMapInsert(self->classToBundle, NSClassFromString(v), _bundle);
474 NSMapInsert(self->classNameToBundle, v, _bundle);
477 e = [_categories objectEnumerator];
478 while ((v = [e nextObject]))
479 NSMapInsert(self->categoryNameToBundle, v, _bundle);
484 - (NSString *)pathForBundleWithName:(NSString *)_name type:(NSString *)_type {
485 NSFileManager *fm = [NSFileManager defaultManager];
488 NSString *bundlePath;
491 /* first check in table */
494 bundlePath = [_name stringByAppendingPathExtension:_type];
496 if ((bundle = NSMapGet(self->nameToBundle, bundlePath)))
497 return [bundle bundlePath];
499 e = [self->bundleSearchPaths objectEnumerator];
500 while ((path = [e nextObject])) {
503 if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
504 if (!isDir) continue;
506 if ([[path lastPathComponent] isEqualToString:bundlePath]) {
507 // direct match (a bundle was specified in the path)
513 tmp = [path stringByAppendingPathComponent:bundlePath];
514 if ([fm fileExistsAtPath:tmp isDirectory:&isDir]) {
525 /* getting bundles */
527 - (NSBundle *)bundleForClass:(Class)aClass {
528 /* this method never loads a dynamic bundle (since the class is set up) */
531 bundle = NSMapGet(self->classToBundle, aClass);
533 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
535 bundle = [NSBundle bundleForClass:aClass];
536 if (bundle == [NSBundle mainBundle])
542 if the class wasn't loaded from a bundle, it's *either* the main bundle
543 or a bundle loaded before NGExtension was loaded !!!
546 #if !LIB_FOUNDATION_LIBRARY && !GNUSTEP_BASE_LIBRARY
547 # warning incorrect behaviour if NGExtensions is dynamically loaded !
548 // TODO: can we do anything about this? Can we detect the situation and
549 // print a log instead of the compile warning?
551 bundle = [NSBundle mainBundle];
552 NSMapInsert(self->classToBundle, aClass, bundle);
553 NSMapInsert(self->classNameToBundle, NSStringFromClass(aClass), bundle);
557 - (NSBundle *)bundleWithPath:(NSString *)path {
558 NSBundle *bundle = nil;
561 path = [path stringByResolvingSymlinksInPath];
565 if (debugOn) NSLog(@"find bundle for path: '%@'", path);
566 bundle = NSMapGet(self->pathToBundle, path);
569 if (debugOn) NSLog(@" found: %@", bundle);
573 if ((bundle = [(NGBundle *)[NGBundle alloc] initWithPath:path]) == nil) {
574 NSLog(@"ERROR(%s): could not create bundle for path: '%@'",
575 __PRETTY_FUNCTION__, path);
579 bn = [[bundle bundleName]
580 stringByAppendingPathExtension:[bundle bundleType]],
582 NSMapInsert(self->pathToBundle, path, bundle);
583 NSMapInsert(self->nameToBundle, bn, bundle);
587 - (NSBundle *)bundleWithName:(NSString *)_name type:(NSString *)_type {
591 bn = [_name stringByAppendingPathExtension:_type];
592 bundle = NSMapGet(self->nameToBundle, bn);
595 bundle = [self bundleWithPath:[self pathForBundleWithName:_name type:_type]];
597 if (![[bundle bundleType] isEqualToString:_type])
602 - (NSBundle *)bundleWithName:(NSString *)_name {
603 return [self bundleWithName:_name type:@"bundle"];
606 - (NSBundle *)bundleForClassNamed:(NSString *)_className {
607 NSString *path = nil;
608 NSBundle *bundle = nil;
610 if (_className == nil)
613 /* first check in table */
615 if ((bundle = NSMapGet(self->classNameToBundle, _className)))
619 /* then look in runtime, reset load callback to avoid recursion */
626 loadCallback = _objc_lookup_class;
627 _objc_lookup_class = NULL;
628 clazz = NSClassFromString(_className);
629 _objc_lookup_class = loadCallback;
632 /* the class is already loaded */
633 bundle = [self bundleForClass:clazz];
634 NSMapInsert(self->classNameToBundle, _className, bundle);
640 path = [self pathForBundleProvidingResource:_className
642 resourceSelector:_selectClassByVersion
643 context:NULL /* version */];
645 path = [path stringByResolvingSymlinksInPath];
646 NSAssert(path, @"couldn't resolve symlinks in path ..");
652 if ((bundle = [self bundleWithPath:path]))
653 NSMapInsert(self->classNameToBundle, _className, bundle);
664 - (NSArray *)bundlesRequiredByBundle:(NSBundle *)_bundle {
665 [self doesNotRecognizeSelector:_cmd];
669 - (NSArray *)classesProvidedByBundle:(NSBundle *)_bundle {
670 [self doesNotRecognizeSelector:_cmd];
673 - (NSArray *)classesRequiredByBundle:(NSBundle *)_bundle {
674 [self doesNotRecognizeSelector:_cmd];
680 - (NSString *)makeBundleInfoPath:(NSString *)_path {
681 #if (NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) && !defined(GSWARN)
682 return [[[_path stringByAppendingPathComponent:@"Contents"]
683 stringByAppendingPathComponent:@"Resources"]
684 stringByAppendingPathComponent:@"bundle-info.plist"];
686 return [_path stringByAppendingPathComponent:@"bundle-info.plist"];
690 - (id)_initializeLoadedBundle:(NSBundle *)_bundle
691 info:(NSDictionary *)_bundleInfo
695 /* check whether a handler was specified */
697 if ((handler = [_bundleInfo objectForKey:@"bundleHandler"])) {
698 if ((handler = NSClassFromString(handler)) == nil) {
699 NSLog(@"ERROR: did not find handler class %@ of bundle %@.",
700 [_bundleInfo objectForKey:@"bundleHandler"], [_bundle bundlePath]);
701 handler = [_bundle principalClass];
704 handler = [handler alloc];
706 if ([handler respondsToSelector:@selector(initForBundle:bundleManager:)])
707 handler = [handler initForBundle:_bundle bundleManager:self];
709 handler = [handler init];
710 handler = [handler autorelease];
712 if (handler == nil) {
713 NSLog(@"ERROR: could not instantiate handler class %@ of bundle %@.",
714 [_bundleInfo objectForKey:@"bundleHandler"], [_bundle bundlePath]);
715 handler = [_bundle principalClass];
719 if ((handler = [_bundle principalClass]) == nil)
720 /* use NGBundle class as default bundle handler */
721 handler = [NGBundle class];
729 - (NSDictionary *)_loadBundleInfoAtExistingPath:(NSString *)_path {
730 NSDictionary *bundleInfo;
733 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
734 bundleInfo = NGParsePropertyListFromFile(_path);
736 bundleInfo = [NSDictionary dictionaryWithContentsOfFile:_path];
738 if (bundleInfo == nil) {
739 NSLog(@"couldn't load bundle-info at path '%@' !", _path);
743 /* check required bundle manager version */
744 info = [bundleInfo objectForKey:@"requires"];
745 if ((info = [(NSDictionary *)info objectForKey:@"bundleManagerVersion"])) {
746 if ([info intValue] > [[self class] version]) {
747 /* bundle manager version does not match ... */
751 NSMapInsert(self->pathToBundleInfo, _path, bundleInfo);
755 - (NSBundle *)_locateBundleForClassInfo:(NSDictionary *)_classInfo {
759 if (_classInfo == nil)
761 if ((className = [_classInfo objectForKey:@"name"]) == nil) {
762 NSLog(@"ERROR: missing classname in bundle-info.plist class section !");
766 if ((bundle = [self bundleForClassNamed:className]) == nil) {
767 #if 0 // class might be already loaded
768 NSLog(@"ERROR: did not find class %@ required by bundle %@.",
769 className, [_bundle bundlePath]);
775 - (NSArray *)_locateBundlesForClassInfos:(NSEnumerator *)_classInfos {
776 NSMutableArray *requiredBundles;
779 requiredBundles = [NSMutableArray arrayWithCapacity:16];
780 while ((i = [_classInfos nextObject])) {
783 if ((bundle = [self _locateBundleForClassInfo:i]) == nil)
786 [requiredBundles addObject:bundle];
788 return requiredBundles;
791 - (BOOL)_preLoadBundle:(NSBundle *)_bundle info:(NSDictionary *)_bundleInfo {
792 /* TODO: split up this huge method */
793 NSDictionary *requires = nil;
794 NSMutableArray *requiredBundles = nil;
795 NSBundle *requiredBundle = nil;
797 requires = [_bundleInfo objectForKey:@"requires"];
800 /* invalid bundle info specified */
803 /* load required bundles */
808 /* locate required bundles */
810 e = [[requires objectForKey:@"bundles"] objectEnumerator];
811 while ((i = [e nextObject])) {
812 NSString *bundleName;
814 if (![i respondsToSelector:@selector(objectForKey:)]) {
815 NSLog(@"ERROR(%s): invalid bundle-info of bundle %@ !!!\n"
816 @" requires-entry is not a dictionary: %@",
817 __PRETTY_FUNCTION__, _bundle, i);
821 if ((bundleName = [i objectForKey:@"name"])) {
824 type = [i objectForKey:@"type"];
825 if (type == nil) type = @"bundle";
827 if ((requiredBundle = [self bundleWithName:bundleName type:type])) {
828 if (requiredBundles == nil)
829 requiredBundles = [NSMutableArray arrayWithCapacity:16];
831 [requiredBundles addObject:requiredBundle];
834 NSLog(@"ERROR(NGBundleManager): did not find bundle '%@' (type=%@) "
835 @"required by bundle %@.",
836 bundleName, type, [_bundle bundlePath]);
841 NSLog(@"ERROR: error in bundle-info.plist of bundle %@", _bundle);
845 /* load located bundles */
849 e = [requiredBundles objectEnumerator];
850 while ((requiredBundle = [e nextObject])) {
853 if ((bundleMaster = [self loadBundle:requiredBundle]) == Nil) {
854 NSLog(@"ERROR: could not load bundle %@ (%@) required by bundle %@.",
855 [requiredBundle bundlePath], requiredBundle, [_bundle bundlePath]);
861 /* load required classes */
866 reqClasses = [requires objectForKey:@"classes"];
867 bundles = [self _locateBundlesForClassInfos:[reqClasses objectEnumerator]];
868 if (requiredBundles == nil)
869 requiredBundles = [NSMutableArray arrayWithCapacity:16];
870 [requiredBundles addObjectsFromArray:bundles];
873 /* load located bundles */
877 e = [requiredBundles objectEnumerator];
878 while ((requiredBundle = [e nextObject])) {
881 if ((bundleMaster = [self loadBundle:requiredBundle]) == Nil) {
882 NSLog(@"ERROR: could not load bundle %@ (%@) required by bundle %@.",
883 [requiredBundle bundlePath], requiredBundle, [_bundle bundlePath]);
889 /* check whether versions of classes match */
894 e = [[requires objectForKey:@"classes"] objectEnumerator];
895 while ((i = [e nextObject])) {
899 if ((className = [i objectForKey:@"name"]) == nil)
902 if ((clazz = NSClassFromString(className)) == Nil)
905 if ([i objectForKey:@"exact-version"]) {
908 v = [[i objectForKey:@"exact-version"] intValue];
910 if (v != [clazz version]) {
911 NSLog(@"ERROR: required exact class match failed:\n"
913 @" required version: %i\n"
914 @" loaded version: %i\n"
918 [_bundle bundlePath]);
921 else if ([i objectForKey:@"version"]) {
924 v = [[i objectForKey:@"version"] intValue];
926 if (v > [clazz version]) {
927 NSLog(@"ERROR: provided class does not match required version:\n"
929 @" least required version: %i\n"
930 @" loaded version: %i\n"
934 [_bundle bundlePath]);
942 - (BOOL)_postLoadBundle:(NSBundle *)_bundle info:(NSDictionary *)_bundleInfo {
946 - (id)loadBundle:(NSBundle *)_bundle {
947 NSString *path = nil;
948 NSDictionary *bundleInfo = nil;
949 id bundleManager = nil;
952 NSAssert(self->loadedBundles, @"missing loadedBundles hashmap ..");
955 if ((bundleManager = NSMapGet(self->loadedBundles, _bundle)))
956 return bundleManager;
958 if (_bundle == [NSBundle mainBundle])
959 return [NSBundle mainBundle];
961 if ([self->loadingBundles containsObject:_bundle])
965 if (self->loadingBundles == nil)
966 self->loadingBundles = [[NSMutableSet allocWithZone:[self zone]] init];
967 [self->loadingBundles addObject:_bundle];
969 path = [_bundle bundlePath];
970 path = [self makeBundleInfoPath:path];
972 if ((bundleInfo = NSMapGet(self->pathToBundleInfo, path)) == nil) {
973 if ([[NSFileManager defaultManager] fileExistsAtPath:path])
974 bundleInfo = [self _loadBundleInfoAtExistingPath:path];
977 if (![self _preLoadBundle:_bundle info:bundleInfo])
980 if (![_bundle _loadForBundleManager:self])
983 if (![self _postLoadBundle:_bundle info:bundleInfo])
987 [self _initializeLoadedBundle:_bundle info:bundleInfo])) {
988 NSMapInsert(self->loadedBundles, _bundle, bundleManager);
990 if ([bundleManager respondsToSelector:
991 @selector(bundleManager:didLoadBundle:)])
992 [bundleManager bundleManager:self didLoadBundle:_bundle];
996 NSLog(@"ERROR(%s): couldn't initialize loaded bundle '%@'",
997 __PRETTY_FUNCTION__, [_bundle bundlePath]);
1001 [self->loadingBundles removeObject:_bundle];
1003 if (bundleManager) {
1004 if (bundleInfo == nil)
1005 bundleInfo = [NSDictionary dictionary];
1007 [[NSNotificationCenter defaultCenter]
1008 postNotificationName:
1009 NGBundleWasLoadedNotificationName
1011 userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
1012 self, @"NGBundleManager",
1013 bundleManager, @"NGBundleHandler",
1014 bundleInfo, @"NGBundleInfo",
1017 return bundleManager;
1022 - (id)principalObjectOfBundle:(NSBundle *)_bundle {
1023 return (id)NSMapGet(self->loadedBundles, _bundle);
1028 static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info)
1032 for (i = 0, count = [keys count]; i < count; i++) {
1036 key = [keys objectAtIndex:i];
1037 vv = [info objectForKey:key];
1040 /* info has no matching key */
1044 kv = [dict objectForKey:key];
1045 if (![kv isEqual:vv])
1051 - (NSDictionary *)configForResource:(id)_resource ofType:(NSString *)_type
1052 providedByBundle:(NSBundle *)_bundle
1054 NSDictionary *bundleInfo = nil;
1056 NSEnumerator *providedResources;
1057 NSArray *rnKeys = nil;
1061 if ([_resource respondsToSelector:@selector(objectForKey:)]) {
1062 rnKeys = [_resource allKeys];
1063 rnKeyCount = [rnKeys count];
1066 infoPath = [self makeBundleInfoPath:[_bundle bundlePath]];
1068 /* check whether info is in cache */
1069 if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
1070 if (![[NSFileManager defaultManager] fileExistsAtPath:infoPath])
1071 /* no bundle-info.plist available .. */
1075 bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
1078 /* get provided resources config */
1081 [[(NSDictionary *)[bundleInfo objectForKey:@"provides"] objectForKey:_type]
1083 if (providedResources == nil) return nil;
1085 /* scan provided resources */
1087 while ((info = [providedResources nextObject])) {
1089 if (!_doesInfoMatch(rnKeys, _resource, info))
1095 name = [[(NSDictionary *)info objectForKey:@"name"] stringValue];
1096 if (name == nil) continue;
1097 if (![name isEqualToString:_resource]) continue;
1104 - (void)_processInfoForProvidedResources:(NSDictionary *)info
1105 ofType:(NSString *)_type path:(NSString *)path
1106 resourceName:(NSString *)_resourceName
1107 resourceSelector:(NGBundleResourceSelector)_selector
1108 context:(void *)_context
1109 andAddToResultArray:(NSMutableArray *)result
1111 NSEnumerator *providedResources = nil;
1112 if (info == nil) return;
1114 /* direct match (a bundle was specified in the path) */
1116 providedResources = [[(NSDictionary *)[info objectForKey:@"provides"]
1120 if (providedResources == nil) return;
1122 /* scan provide array */
1123 while ((info = [providedResources nextObject])) {
1126 if ((name = [[info objectForKey:@"name"] stringValue]) == nil)
1129 if (_resourceName) {
1130 if (![name isEqualToString:_resourceName])
1134 if (!_selector(_resourceName, _type, path, info, self, _context))
1138 [result addObject:path];
1142 - (NSArray *)pathsForBundlesProvidingResource:(NSString *)_resourceName
1143 ofType:(NSString *)_type
1144 resourceSelector:(NGBundleResourceSelector)_selector
1145 context:(void *)_context
1147 /* TODO: split up method */
1148 NSMutableArray *result = nil;
1153 fm = [NSFileManager defaultManager];
1154 result = [NSMutableArray arrayWithCapacity:64];
1156 e = [self->bundleSearchPaths objectEnumerator];
1157 while ((path = [e nextObject])) {
1160 if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
1163 if (!isDir) continue;
1165 /* check whether an appropriate bundle is contained in 'path' */
1169 dir = [[fm directoryContentsAtPath:path] objectEnumerator];
1170 while ((tmp = [dir nextObject])) {
1171 NSDictionary *bundleInfo = nil;
1172 NSEnumerator *providedResources = nil;
1176 tmp = [path stringByAppendingPathComponent:tmp];
1177 infoPath = [self makeBundleInfoPath:tmp];
1179 if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
1180 if (![fm fileExistsAtPath:infoPath])
1183 bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
1187 [[(NSDictionary *)[bundleInfo objectForKey:@"provides"]
1190 if (providedResources == nil) continue;
1192 // scan provide array
1193 while ((info = [providedResources nextObject])) {
1196 name = [[(NSDictionary *)info objectForKey:@"name"] stringValue];
1197 if (name == nil) continue;
1199 if (_resourceName) {
1200 if (![name isEqualToString:_resourceName])
1204 if (!_selector(name, _type, tmp, info, self, _context))
1208 [result addObject:tmp];
1214 /* check for direct match */
1216 tmp = [self makeBundleInfoPath:path];
1218 if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
1219 if ([fm fileExistsAtPath:tmp])
1220 info = [self _loadBundleInfoAtExistingPath:tmp];
1223 [self _processInfoForProvidedResources:info ofType:_type path:path
1224 resourceName:_resourceName resourceSelector:_selector
1226 andAddToResultArray:result];
1229 return [[result copy] autorelease];
1232 - (NSString *)pathForBundleProvidingResource:(id)_resourceName
1233 ofType:(NSString *)_type
1234 resourceSelector:(NGBundleResourceSelector)_selector
1235 context:(void *)_context
1237 NSFileManager *fm = [NSFileManager defaultManager];
1240 NSArray *rnKeys = nil;
1243 if ([_resourceName respondsToSelector:@selector(objectForKey:)]) {
1244 rnKeys = [_resourceName allKeys];
1245 rnKeyCount = [rnKeys count];
1248 e = [self->bundleSearchPaths objectEnumerator];
1249 while ((path = [e nextObject])) {
1252 if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
1256 if (!isDir) continue;
1258 /* check whether an appropriate bundle is contained in 'path' */
1262 dir = [[fm directoryContentsAtPath:path] objectEnumerator];
1263 while ((tmp = [dir nextObject])) {
1264 NSDictionary *bundleInfo = nil;
1265 NSEnumerator *providedResources = nil;
1269 tmp = [path stringByAppendingPathComponent:tmp];
1270 infoPath = [self makeBundleInfoPath:tmp];
1273 NSLog(@"check path path=%@ info=%@", tmp, infoPath);
1275 if ((bundleInfo=NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
1276 if (![fm fileExistsAtPath:infoPath])
1279 bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
1282 NSLog(@"found info for path=%@ info=%@: %@",
1283 tmp, infoPath, bundleInfo);
1287 [[(NSDictionary *)[bundleInfo objectForKey:@"provides"]
1290 if (providedResources == nil) continue;
1292 // scan provide array
1293 while ((info = [providedResources nextObject])) {
1295 if (!_doesInfoMatch(rnKeys, _resourceName, info))
1301 name = [[(NSDictionary *)info objectForKey:@"name"] stringValue];
1302 if (name == nil) continue;
1303 if (![name isEqualToString:_resourceName]) continue;
1307 if (!_selector(_resourceName, _type, tmp, info, self, _context))
1310 /* all conditions applied */
1316 /* check for direct match */
1318 tmp = [self makeBundleInfoPath:path];
1320 if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
1321 if ([fm fileExistsAtPath:tmp])
1322 info = [self _loadBundleInfoAtExistingPath:tmp];
1324 NSLog(@"WARNING(%s): did not find direct path '%@'",
1325 __PRETTY_FUNCTION__, tmp);
1330 // direct match (a bundle was specified in the path)
1331 NSEnumerator *providedResources;
1332 NSDictionary *provides;
1334 provides = [(NSDictionary *)info objectForKey:@"provides"];
1335 providedResources = [[provides objectForKey:_type] objectEnumerator];
1337 if (providedResources == nil) continue;
1339 // scan provide array
1340 while ((info = [providedResources nextObject])) {
1342 if (!_doesInfoMatch(rnKeys, _resourceName, info))
1348 name = [[(NSDictionary *)info objectForKey:@"name"] stringValue];
1349 if (name == nil) continue;
1350 if (![name isEqualToString:_resourceName]) continue;
1354 if (!_selector(_resourceName, _type, tmp, info, self, _context))
1357 /* all conditions applied */
1366 - (NSBundle *)bundleProvidingResource:(id)_resourceName
1367 ofType:(NSString *)_resourceType
1371 bp = [self pathForBundleProvidingResource:_resourceName
1372 ofType:_resourceType
1373 resourceSelector:NULL context:nil];
1374 if ([bp length] == 0) {
1375 #if (NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) && HEAVY_DEBUG
1376 NSLog(@"%s: found no resource '%@' of type '%@' ...",
1377 __PRETTY_FUNCTION__, _resourceName, _resourceType);
1382 return [self bundleWithPath:bp];
1385 - (NSArray *)bundlesProvidingResource:(id)_resourceName
1386 ofType:(NSString *)_type
1389 NSMutableArray *bundles;
1392 paths = [self pathsForBundlesProvidingResource:_resourceName
1394 resourceSelector:NULL context:nil];
1396 count = [paths count];
1397 if (paths == nil) return nil;
1398 if (count == 0) return paths;
1400 bundles = [NSMutableArray arrayWithCapacity:count];
1401 for (i = 0; i < count; i++) {
1404 if ((bundle = [self bundleWithPath:[paths objectAtIndex:i]]))
1405 [bundles addObject:bundle];
1407 return [[bundles copy] autorelease];
1410 - (NSArray *)providedResourcesOfType:(NSString *)_resourceType
1411 inBundle:(NSBundle *)_bundle
1414 NSDictionary *bundleInfo;
1416 path = [self makeBundleInfoPath:[_bundle bundlePath]];
1417 if (path == nil) return nil;
1419 /* retrieve bundle info dictionary */
1420 if ((bundleInfo = NSMapGet(self->pathToBundleInfo, path)) == nil)
1421 bundleInfo = [self _loadBundleInfoAtExistingPath:path];
1423 return [(NSDictionary *)[bundleInfo objectForKey:@"provides"]
1424 objectForKey:_resourceType];
1427 - (NSArray *)providedResourcesOfType:(NSString *)_resourceType {
1428 NSMutableSet *result = nil;
1429 NSFileManager *fm = [NSFileManager defaultManager];
1433 result = [NSMutableSet setWithCapacity:128];
1435 e = [self->bundleSearchPaths objectEnumerator];
1436 while ((path = [e nextObject])) {
1439 if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
1442 if (!isDir) continue;
1444 /* check whether an appropriate bundle is contained in 'path' */
1448 dir = [[fm directoryContentsAtPath:path] objectEnumerator];
1449 while ((tmp = [dir nextObject])) {
1450 NSDictionary *bundleInfo = nil;
1451 NSArray *providedResources = nil;
1454 tmp = [path stringByAppendingPathComponent:tmp];
1455 infoPath = [self makeBundleInfoPath:tmp];
1457 //NSLog(@" info path: %@", tmp);
1459 if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
1460 if (![fm fileExistsAtPath:infoPath])
1463 bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
1467 [(NSDictionary *)[bundleInfo objectForKey:@"provides"]
1468 objectForKey:_resourceType];
1469 if (providedResources == nil) continue;
1471 [result addObjectsFromArray:providedResources];
1475 /* check for direct match */
1477 tmp = [self makeBundleInfoPath:path];
1479 if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
1480 if ([fm fileExistsAtPath:tmp])
1481 info = [self _loadBundleInfoAtExistingPath:tmp];
1485 // direct match (a bundle was specified in the path)
1486 NSArray *providedResources;
1487 NSDictionary *provides;
1489 provides = [(NSDictionary *)info objectForKey:@"provides"];
1490 providedResources = [provides objectForKey:_resourceType];
1492 if (providedResources == nil) continue;
1494 [result addObjectsFromArray:providedResources];
1498 return [result allObjects];
1501 - (NSBundle *)bundleProvidingResourceOfType:(NSString *)_resourceType
1502 matchingQualifier:(EOQualifier *)_qual
1504 NSFileManager *fm = [NSFileManager defaultManager];
1508 /* foreach search path entry */
1510 e = [self->bundleSearchPaths objectEnumerator];
1511 while ((path = [e nextObject])) {
1514 if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
1517 if (!isDir) continue;
1519 /* check whether an appropriate bundle is contained in 'path' */
1523 dir = [[fm directoryContentsAtPath:path] objectEnumerator];
1524 while ((tmp = [dir nextObject])) {
1525 NSDictionary *bundleInfo;
1526 NSArray *providedResources;
1529 tmp = [path stringByAppendingPathComponent:tmp];
1530 infoPath = [self makeBundleInfoPath:tmp];
1532 if ((bundleInfo=NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
1533 if (![fm fileExistsAtPath:infoPath])
1536 bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
1539 bundleInfo = [bundleInfo objectForKey:@"provides"];
1540 providedResources = [bundleInfo objectForKey:_resourceType];
1542 if (providedResources == nil) continue;
1545 [providedResources filteredArrayUsingQualifier:_qual];
1547 if ([providedResources count] > 0)
1548 return [self bundleWithPath:tmp];
1552 /* check for direct match */
1554 tmp = [self makeBundleInfoPath:path];
1556 if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
1557 if ([fm fileExistsAtPath:tmp])
1558 info = [self _loadBundleInfoAtExistingPath:tmp];
1562 // direct match (a bundle was specified in the path)
1563 NSArray *providedResources;
1564 NSDictionary *provides;
1566 provides = [(NSDictionary *)info objectForKey:@"provides"];
1567 providedResources = [provides objectForKey:_resourceType];
1569 if (providedResources == nil) continue;
1572 [providedResources filteredArrayUsingQualifier:_qual];
1574 if ([providedResources count] > 0)
1575 return [self bundleWithPath:path];
1582 - (NSBundle *)bundlesProvidingResourcesOfType:(NSString *)_resourceType
1583 matchingQualifier:(EOQualifier *)_qual
1585 NSMutableArray *bundles = nil;
1586 NSFileManager *fm = [NSFileManager defaultManager];
1590 bundles = [NSMutableArray arrayWithCapacity:128];
1592 /* foreach search path entry */
1594 e = [self->bundleSearchPaths objectEnumerator];
1595 while ((path = [e nextObject])) {
1598 if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
1601 if (!isDir) continue;
1603 /* check whether an appropriate bundle is contained in 'path' */
1607 dir = [[fm directoryContentsAtPath:path] objectEnumerator];
1608 while ((tmp = [dir nextObject])) {
1609 NSDictionary *bundleInfo = nil;
1610 NSArray *providedResources = nil;
1613 tmp = [path stringByAppendingPathComponent:tmp];
1614 infoPath = [self makeBundleInfoPath:tmp];
1616 if ((bundleInfo=NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
1617 if (![fm fileExistsAtPath:infoPath])
1620 bundleInfo = [self _loadBundleInfoAtExistingPath:infoPath];
1623 bundleInfo = [bundleInfo objectForKey:@"provides"];
1624 providedResources = [bundleInfo objectForKey:_resourceType];
1626 if (providedResources == nil) continue;
1629 [providedResources filteredArrayUsingQualifier:_qual];
1631 if ([providedResources count] > 0)
1632 [bundles addObject:[self bundleWithPath:tmp]];
1636 /* check for direct match */
1638 tmp = [self makeBundleInfoPath:path];
1640 if ((info = NSMapGet(self->pathToBundleInfo, tmp)) == nil) {
1641 if ([fm fileExistsAtPath:tmp])
1642 info = [self _loadBundleInfoAtExistingPath:tmp];
1646 // direct match (a bundle was specified in the path)
1647 NSArray *providedResources;
1648 NSDictionary *provides;
1650 provides = [(NSDictionary *)info objectForKey:@"provides"];
1651 providedResources = [provides objectForKey:_resourceType];
1653 if (providedResources == nil) continue;
1656 [providedResources filteredArrayUsingQualifier:_qual];
1658 if ([providedResources count] > 0)
1659 [bundles addObject:[self bundleWithPath:path]];
1663 return [[bundles copy] autorelease];
1668 - (void)_bundleDidLoadNotifcation:(NSNotification *)_notification {
1669 NSDictionary *ui = [_notification userInfo];
1672 NSLog(@"bundle %@ did load with classes %@",
1673 [[_notification object] bundlePath],
1674 [ui objectForKey:@"NSLoadedClasses"]);
1677 [self registerBundle:[_notification object]
1678 classes:[ui objectForKey:@"NSLoadedClasses"]
1679 categories:[ui objectForKey:@"NSLoadedCategories"]];
1682 @end /* NGBundleManager */
1684 @implementation NSBundle(BundleManagerSupport)
1687 return [NGBundle alloc];
1689 + (id)allocWithZone:(NSZone *)zone {
1690 return [NGBundle allocWithZone:zone];
1693 #if !(NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY)
1694 //#warning remember, bundleForClass is not overridden !
1696 + (NSBundle *)bundleForClass:(Class)aClass {
1697 return [[NGBundleManager defaultBundleManager] bundleForClass:aClass];
1700 + (NSBundle *)bundleWithPath:(NSString*)path {
1701 return [[NGBundleManager defaultBundleManager] bundleWithPath:path];
1705 @end /* NSBundle(BundleManagerSupport) */
1707 @implementation NSBundle(NGBundleManagerExtensions)
1709 - (id)principalObject {
1710 return [[NGBundleManager defaultBundleManager]
1711 principalObjectOfBundle:self];
1714 - (NSArray *)providedResourcesOfType:(NSString *)_resourceType {
1715 return [[NGBundleManager defaultBundleManager]
1716 providedResourcesOfType:_resourceType
1720 - (NSString *)bundleName {
1721 return [[[self bundlePath] lastPathComponent] stringByDeletingPathExtension];
1724 - (NSString *)bundleType {
1725 return [[self bundlePath] pathExtension];
1728 - (NSArray *)providedClasses {
1729 return [[NGBundleManager defaultBundleManager] classesProvidedByBundle:self];
1732 - (NSArray *)requiredClasses {
1733 return [[NGBundleManager defaultBundleManager] classesRequiredByBundle:self];
1736 - (NSArray *)requiredBundles {
1737 return [[NGBundleManager defaultBundleManager] bundlesRequiredByBundle:self];
1740 - (NSDictionary *)configForResource:(id)_resource ofType:(NSString *)_type {
1741 return [[NGBundleManager defaultBundleManager]
1742 configForResource:_resource ofType:_type
1743 providedByBundle:self];
1748 - (BOOL)_loadForBundleManager:(NGBundleManager *)_manager {
1752 @end /* NSBundle(NGBundleManagerExtensions) */
1754 @implementation NSBundle(NGLanguageResourceExtensions)
1756 // locating resources
1758 - (NSString *)pathForResource:(NSString *)_name ofType:(NSString *)_ext
1759 inDirectory:(NSString *)_directory
1760 languages:(NSArray *)_languages
1762 NSFileManager *fm = [NSFileManager defaultManager];
1763 NSString *path = nil;
1765 id (*objAtIdx)(id,SEL,int);
1768 ? [[self bundlePath] stringByAppendingPathComponent:_directory]
1769 : [self bundlePath];
1771 if (![fm fileExistsAtPath:path])
1774 if (_ext) _name = [_name stringByAppendingPathExtension:_ext];
1776 langCount = [_languages count];
1777 objAtIdx = (langCount > 0)
1778 ? (void*)[_languages methodForSelector:@selector(objectAtIndex:)]
1781 for (i = 0; i < langCount; i++) {
1786 ? objAtIdx(_languages, @selector(objectAtIndex:), i)
1787 : [_languages objectAtIndex:i];
1789 language = [language stringByAppendingPathExtension:@"lproj"];
1790 lpath = [path stringByAppendingPathComponent:language];
1791 lpath = [lpath stringByAppendingPathComponent:_name];
1793 if ([fm fileExistsAtPath:lpath])
1797 /* now look into x.bundle/Resources/name.type */
1798 if ([fm fileExistsAtPath:[path stringByAppendingPathComponent:_name]])
1799 return [path stringByAppendingPathComponent:_name];
1804 - (NSString *)pathForResource:(NSString *)_name ofType:(NSString *)_ext
1805 languages:(NSArray *)_languages
1809 path = [self pathForResource:_name ofType:_ext
1810 inDirectory:@"Resources"
1811 languages:_languages];
1812 if (path) return path;
1814 path = [self pathForResource:_name ofType:_ext
1816 languages:_languages];
1820 @end /* NSBundle(NGLanguageResourceExtensions) */
1822 @implementation NGBundle
1825 return [self allocWithZone:NULL];
1827 + (id)allocWithZone:(NSZone*)zone {
1828 return NSAllocateObject(self, 0, zone);
1831 - (id)initWithPath:(NSString *)__path {
1832 return [super initWithPath:__path];
1837 - (BOOL)_loadForBundleManager:(NGBundleManager *)_manager {
1838 return [super load];
1842 NGBundleManager *bm;
1844 bm = [NGBundleManager defaultBundleManager];
1846 return [bm loadBundle:self] ? YES : NO;
1849 + (NSBundle *)bundleForClass:(Class)aClass {
1850 return [[NGBundleManager defaultBundleManager] bundleForClass:aClass];
1852 + (NSBundle *)bundleWithPath:(NSString*)path {
1853 return [[NGBundleManager defaultBundleManager] bundleWithPath:path];
1856 #if GNUSTEP_BASE_LIBRARY
1858 - (Class)principalClass {
1862 if ((c = [super principalClass]))
1865 if ((cname = [[self infoDictionary] objectForKey:@"NSPrincipalClass"]) ==nil)
1868 if ((c = NSClassFromString(cname)))
1871 NSLog(@"%s: did not find principal class named '%@' of bundle %@",
1872 __PRETTY_FUNCTION__, cname, self);
1878 - (NSString *)description {
1882 "<%s %p fullPath: %s infoDictionary: %p loaded=%s>",
1883 (char*)object_get_class_name(self),
1885 [[self bundlePath] cString],
1886 [self infoDictionary],
1887 self->_codeLoaded ? "yes" : "no");
1889 return [NSString stringWithCString:buffer];