]> err.no Git - sope/blobdiff - sope-core/NGExtensions/NGBundleManager.m
Drop apache 1 build-dependency
[sope] / sope-core / NGExtensions / NGBundleManager.m
index c2ab346f9a3452411f620af9b4526734f6cba085..61113ff3eb53d6d691c8766d7e279aa61bd91514 100644 (file)
@@ -1,27 +1,29 @@
 /*
-  Copyright (C) 2000-2004 SKYRIX Software AG
+  Copyright (C) 2000-2006 SKYRIX Software AG
+  Copyright (C) 2006      Helge Hess
 
-  This file is part of OpenGroupware.org.
+  This file is part of SOPE.
 
-  OGo is free software; you can redistribute it and/or modify it under
+  SOPE is free software; you can redistribute it and/or modify it under
   the terms of the GNU Lesser General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.
 
-  OGo is distributed in the hope that it will be useful, but WITHOUT ANY
+  SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
   WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
   License for more details.
 
   You should have received a copy of the GNU Lesser General Public
-  License along with OGo; see the file COPYING.  If not, write to the
+  License along with SOPE; see the file COPYING.  If not, write to the
   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 <NGExtensions/NSObject+Logs.h>
+#include <NGExtensions/NSNull+misc.h>
 #import <Foundation/NSFileManager.h>
 #import <EOControl/EOQualifier.h>
 #include <ctype.h>
 #  include <NGExtensions/NGPropertyListParser.h>
 #endif
 
+#if LIB_FOUNDATION_LIBRARY
+@interface NSBundle(UsedPrivates)
++ (BOOL)isFlattenedDirLayout;
+@end
+#endif
+
 #if NeXT_RUNTIME || APPLE_RUNTIME
 
 #include <objc/objc-runtime.h>
 //OBJC_EXPORT void objc_setClassHandler(int (*)(const char *));
 
 static BOOL debugClassHook = NO;
+static BOOL hookDoLookup   = YES;
 
 static int _getClassHook(const char *className) {
+  // Cocoa variant
   if (className == NULL) return 0;
   
   if (debugClassHook)
@@ -52,18 +62,21 @@ static int _getClassHook(const char *className) {
   if (objc_lookUpClass(className))
     return 1;
   
-  {
+  if (hookDoLookup) {
     static NGBundleManager *manager = nil;
     NSBundle *bundle;
+    NSString *cns;
     
     if (debugClassHook)
-      NSLog(@"%s: look for class %s", __PRETTY_FUNCTION__, className);
+      printf("%s: look for class %s\n", __PRETTY_FUNCTION__, className);
     if (manager == nil)
       manager = [NGBundleManager defaultBundleManager];
     
-    bundle  = [manager bundleForClassNamed:
-                        [NSString stringWithCString:className]];
-    if (bundle) {
+    cns = [[NSString alloc] initWithCString:className];
+    bundle = [manager bundleForClassNamed:cns];
+    [cns release]; cns = nil;
+    
+    if (bundle != nil) {
       if (debugClassHook) {
        NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, 
              [bundle bundlePath]);
@@ -119,8 +132,10 @@ static Class _classLoadHook(const char *_name) {
       manager = [NGBundleManager defaultBundleManager];
     
     bundle  = [manager bundleForClassNamed:[NSString stringWithCString:_name]];
-    if (bundle) {
-      //NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, [bundle bundlePath]);
+    if (bundle != nil) {
+#if 0
+      NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, [bundle bundlePath]);
+#endif
       
       if ([manager loadBundle:bundle]) {
         Class clazz;
@@ -205,6 +220,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];
   
@@ -233,9 +254,7 @@ static BOOL debugOn = NO;
        objc_setClassHandler(_getClassHook);
       }
     }
-#endif
-
-#if GNU_RUNTIME
+#elif GNU_RUNTIME
     if (_objc_lookup_class != _classLoadHook) {
       oldClassLoadHook = _objc_lookup_class;
       _objc_lookup_class = _classLoadHook;
@@ -245,37 +264,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 +309,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__, 
@@ -351,9 +381,9 @@ static BOOL debugOn = NO;
 - (void)_registerLoadedBundles {
   NSEnumerator *currentBundles;
   NSBundle     *loadedBundle;
-  
+
   currentBundles = [[NSBundle allBundles] objectEnumerator];
-  while ((loadedBundle = [currentBundles nextObject]))
+  while ((loadedBundle = [currentBundles nextObject]) != nil)
     [self registerBundle:loadedBundle classes:nil categories:nil];
 }
 
@@ -424,6 +454,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
@@ -433,16 +472,35 @@ static BOOL debugOn = NO;
   NSEnumerator *e;
   id v;
 
-  //NSLog(@"NGBundleManager: register loaded bundle %@", [_bundle bundlePath]);
-
+#if NeXT_RUNTIME || APPLE_RUNTIME
+  v = [_bundle bundlePath];
+  if ([v hasSuffix:@"Libraries"] || [v hasSuffix:@"Tools"]) {
+    if (debugOn)
+      fprintf(stderr, "INVALID BUNDLE: %s\n", [[_bundle bundlePath] cString]);
+    return;
+  }
+#endif
+  
+#if 0
+  NSLog(@"NGBundleManager: register loaded bundle %@", [_bundle bundlePath]);
+#endif
+  
   e = [_classes objectEnumerator];
-  while ((v = [e nextObject])) {
+  while ((v = [e nextObject]) != nil) {
+#if NeXT_RUNTIME || APPLE_RUNTIME
+    hookDoLookup = NO;
+#endif
+
     NSMapInsert(self->classToBundle, NSClassFromString(v), _bundle);
     NSMapInsert(self->classNameToBundle, v, _bundle);
+    
+#if NeXT_RUNTIME || APPLE_RUNTIME
+    hookDoLookup = YES;
+#endif
   }
-
+  
   e = [_categories objectEnumerator];
-  while ((v = [e nextObject]))
+  while ((v = [e nextObject]) != nil)
     NSMapInsert(self->categoryNameToBundle, v, _bundle);
 }
 
@@ -494,14 +552,38 @@ static BOOL debugOn = NO;
 - (NSBundle *)bundleForClass:(Class)aClass {
   /* this method never loads a dynamic bundle (since the class is set up) */
   NSBundle *bundle;
-
+  
+  if (aClass == Nil)
+    return nil;
+  
   bundle = NSMapGet(self->classToBundle, aClass);
 
 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
-  if (bundle == nil){
+  if (bundle == nil) {
+    NSString *p;
+    
     bundle = [NSBundle bundleForClass:aClass];
     if (bundle == [NSBundle mainBundle])
       bundle = nil;
+    else {
+      p = [bundle bundlePath];
+      if ([p hasSuffix:@"Libraries"]) {
+       if (debugOn) {
+         fprintf(stderr, "%s: Dylib bundle: 0x%p: %s\n",
+                 __PRETTY_FUNCTION__,
+                 bundle, [[bundle bundlePath] cString]);
+       }
+       bundle = nil;
+      }
+      else if ([p hasSuffix:@"Tools"]) {
+       if (debugOn) {
+         fprintf(stderr, "%s: Tool bundle: 0x%p: %s\n",
+                 __PRETTY_FUNCTION__,
+                 bundle, [[bundle bundlePath] cString]);
+       }
+       bundle = nil;
+      }
+    }
   }
 #endif
   if (bundle == nil) {
@@ -511,9 +593,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 +643,18 @@ 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 isNotNull]) {
+    bundle = [self bundleWithPath:
+                    [self pathForBundleWithName:_name type:_type]];
+  }
+  
+  if (![bundle isNotNull]) /* NSNull is used to signal missing bundles */
+    return nil;
+  
   if (![[bundle bundleType] isEqualToString:_type])
-    bundle = nil;
-
+    return nil;
+  
+  /* bundle matches */
   return bundle;
 }
 - (NSBundle *)bundleWithName:(NSString *)_name {
@@ -573,13 +664,13 @@ static BOOL debugOn = NO;
 - (NSBundle *)bundleForClassNamed:(NSString *)_className {
   NSString *path   = nil;
   NSBundle *bundle = nil;
-  
+
   if (_className == nil)
     return nil;
 
   /* first check in table */
   
-  if ((bundle = NSMapGet(self->classNameToBundle, _className)))
+  if ((bundle = NSMapGet(self->classNameToBundle, _className)) != nil)
     return bundle;
   
 #if GNU_RUNTIME
@@ -589,26 +680,47 @@ static BOOL debugOn = NO;
     void  *loadCallback;
     Class clazz;
     
-    
     loadCallback = _objc_lookup_class;
     _objc_lookup_class = NULL;
     clazz = NSClassFromString(_className);
     _objc_lookup_class = loadCallback;
 
-    if (clazz) {
+    if (clazz != Nil) {
       /* the class is already loaded */
       bundle = [self bundleForClass:clazz];
       NSMapInsert(self->classNameToBundle, _className, bundle);
       return bundle;
     }
   }
+#elif NeXT_RUNTIME || APPLE_RUNTIME
+  {
+    Class clazz;
+    
+    hookDoLookup = NO; // THREAD
+    clazz = NSClassFromString(_className);
+    hookDoLookup = YES;
+    
+    if (clazz != Nil) {
+      /* the class is already loaded */
+#if 0
+      printf("found class in runtime: %s\n", [_className cString]);
+#endif
+      bundle = [self bundleForClass:clazz];
+      NSMapInsert(self->classNameToBundle, _className, bundle);
+      return bundle;
+    }
+#if 0
+    else
+      printf("did NOT find class in runtime: %s\n", [_className cString]);
+#endif
+  }
 #endif
   
   path = [self pathForBundleProvidingResource:_className
                ofType:@"classes"
                resourceSelector:_selectClassByVersion
                context:NULL /* version */];
-  if (path) {
+  if (path != nil) {
     path = [path stringByResolvingSymlinksInPath];
     NSAssert(path, @"couldn't resolve symlinks in path ..");
   }
@@ -616,7 +728,7 @@ static BOOL debugOn = NO;
   if (path == nil)
     return nil;
   
-  if ((bundle = [self bundleWithPath:path]))
+  if ((bundle = [self bundleWithPath:path]) != nil)
     NSMapInsert(self->classNameToBundle, _className, bundle);
 
   return bundle;
@@ -634,15 +746,14 @@ static BOOL debugOn = NO;
 }
 
 - (NSArray *)classesProvidedByBundle:(NSBundle *)_bundle {
-  [self doesNotRecognizeSelector:_cmd];
-  return nil;
+  return [[_bundle providedResourcesOfType:@"classes"] valueForKey:@"name"];
 }
 - (NSArray *)classesRequiredByBundle:(NSBundle *)_bundle {
   [self doesNotRecognizeSelector:_cmd];
   return nil;
 }
 
-// initialization
+/* initialization */
 
 - (NSString *)makeBundleInfoPath:(NSString *)_path {
 #if (NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY) && !defined(GSWARN)
@@ -657,17 +768,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,9 +797,18 @@ static BOOL debugOn = NO;
     }
   }
   else {
-    if ((handler = [_bundle principalClass]) == nil)
+    [self debugWithFormat:
+           @"no bundle handler, lookup principal class of bundle: %@",
+           _bundle];
+    if ((handler = [_bundle principalClass]) == nil) {
       /* use NGBundle class as default bundle handler */
+#if !(NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY)
+      [self warnWithFormat:@"bundle has no principal class: %@", _bundle];
+#endif
       handler = [NGBundle class];
+    }
+    else
+      [self debugWithFormat:@"  => %@", handler];
   }
   
   return handler;
@@ -703,7 +826,7 @@ static BOOL debugOn = NO;
   bundleInfo = [NSDictionary dictionaryWithContentsOfFile:_path];
 #endif
   if (bundleInfo == nil) {
-    NSLog(@"couldn't load bundle-info at path '%@' !", _path);
+    NSLog(@"could not load bundle-info at path '%@' !", _path);
     return nil;
   }
   
@@ -730,6 +853,16 @@ static BOOL debugOn = NO;
     return nil;
   }
   
+  // TODO: do we need to check the runtime for already loaded classes?
+  //       Yes, I think so. But avoid recursions
+#if 0
+#if APPLE_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
+  // TODO: HACK, see above. w/o this, we get issues.
+  if ([className hasPrefix:@"NS"])
+    return nil;
+#endif
+#endif
+  
   if ((bundle = [self bundleForClassNamed:className]) == nil) {
 #if 0 // class might be already loaded
     NSLog(@"ERROR: did not find class %@ required by bundle %@.",
@@ -737,6 +870,9 @@ static BOOL debugOn = NO;
 #endif
   }
   
+  if (debugOn)
+    NSLog(@"CLASS %@ => BUNDLE %@", className, bundle);
+  
   return bundle;
 }
 - (NSArray *)_locateBundlesForClassInfos:(NSEnumerator *)_classInfos {
@@ -744,7 +880,7 @@ static BOOL debugOn = NO;
   NSDictionary   *i;
   
   requiredBundles = [NSMutableArray arrayWithCapacity:16];
-  while ((i = [_classInfos nextObject])) {
+  while ((i = [_classInfos nextObject]) != nil) {
     NSBundle *bundle;
     
     if ((bundle = [self _locateBundleForClassInfo:i]) == nil)
@@ -757,9 +893,11 @@ static BOOL debugOn = NO;
 
 - (BOOL)_preLoadBundle:(NSBundle *)_bundle info:(NSDictionary *)_bundleInfo {
   /* TODO: split up this huge method */
-  NSDictionary   *requires      = nil;
+  NSDictionary   *requires;
   NSMutableArray *requiredBundles = nil;
   NSBundle       *requiredBundle  = nil;
+  
+  if (debugOn) NSLog(@"NGBundleManager: preload bundle: %@", _bundle);
 
   requires = [_bundleInfo objectForKey:@"requires"];
   
@@ -775,7 +913,7 @@ static BOOL debugOn = NO;
     /* locate required bundles */
     
     e = [[requires objectForKey:@"bundles"] objectEnumerator];
-    while ((i = [e nextObject])) {
+    while ((i = [e nextObject]) != nil) {
       NSString *bundleName;
       
       if (![i respondsToSelector:@selector(objectForKey:)]) {
@@ -808,18 +946,24 @@ static BOOL debugOn = NO;
         NSLog(@"ERROR: error in bundle-info.plist of bundle %@", _bundle);
     }
   }
-
+  
   /* load located bundles */
   {
     NSEnumerator *e;
     
+    if (debugOn) {
+      NSLog(@"NGBundleManager:   preload required bundles: %@",
+           requiredBundles);
+    }
+    
     e = [requiredBundles objectEnumerator];
-    while ((requiredBundle = [e nextObject])) {
+    while ((requiredBundle = [e nextObject]) != nil) {
       Class bundleMaster;
       
       if ((bundleMaster = [self loadBundle:requiredBundle]) == Nil) {
         NSLog(@"ERROR: could not load bundle %@ (%@) required by bundle %@.",
-              [requiredBundle bundlePath], requiredBundle, [_bundle bundlePath]);
+              [requiredBundle bundlePath], requiredBundle,
+             [_bundle bundlePath]);
        continue;
       }
     }
@@ -831,23 +975,25 @@ static BOOL debugOn = NO;
     NSArray *reqClasses;
     
     reqClasses = [requires objectForKey:@"classes"];
+    
     bundles = [self _locateBundlesForClassInfos:[reqClasses objectEnumerator]];
     if (requiredBundles == nil)
       requiredBundles = [NSMutableArray arrayWithCapacity:16];
     [requiredBundles addObjectsFromArray:bundles];
   }
-  
+
   /* load located bundles */
   {
     NSEnumerator *e;
     
     e = [requiredBundles objectEnumerator];
-    while ((requiredBundle = [e nextObject])) {
+    while ((requiredBundle = [e nextObject]) != nil) {
       Class bundleMaster;
       
       if ((bundleMaster = [self loadBundle:requiredBundle]) == Nil) {
         NSLog(@"ERROR: could not load bundle %@ (%@) required by bundle %@.",
-              [requiredBundle bundlePath], requiredBundle, [_bundle bundlePath]);
+              [requiredBundle bundlePath], requiredBundle,
+             [_bundle bundlePath]);
        continue;
       }
     }
@@ -859,7 +1005,7 @@ static BOOL debugOn = NO;
     NSDictionary *i;
 
     e = [[requires objectForKey:@"classes"] objectEnumerator];
-    while ((i = [e nextObject])) {
+    while ((i = [e nextObject]) != nil) {
       NSString *className;
       Class clazz;
 
@@ -943,9 +1089,11 @@ static BOOL debugOn = NO;
   
   if (![self _preLoadBundle:_bundle info:bundleInfo])
     goto done;
-  
+
+  if (debugOn) NSLog(@"NGBundleManager: will load bundle: %@", _bundle);
   if (![_bundle _loadForBundleManager:self])
     goto done;
+  if (debugOn) NSLog(@"NGBundleManager: did load bundle: %@", _bundle);
   
   if (![self _postLoadBundle:_bundle info:bundleInfo])
     goto done;
@@ -1116,84 +1264,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]
+    : (NSArray *)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 +1434,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]) != nil) {
+      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;
-
-            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;
+      if ((bundleInfo = NSMapGet(self->pathToBundleInfo, infoPath)) == nil) {
+        if (![fm fileExistsAtPath:infoPath])
+          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 +1545,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 +1613,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 +1644,74 @@ 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;
-
-    if ([fm fileExistsAtPath:path isDirectory:&isDir]) {
-      NSString *tmp;
-      id info = nil;
-      if (!isDir) continue;
+  while ((path = [e nextObject]) != nil) {
+    NSEnumerator *dir;
+    BOOL     isDir = NO;
+    NSString *tmp;
+    id       info = nil;
 
-      /* check whether an appropriate bundle is contained in 'path' */
-      {
-        NSEnumerator *dir;
+    if (![fm fileExistsAtPath:path isDirectory:&isDir])
+      continue;
+    if (!isDir) continue;
 
-        dir = [[fm directoryContentsAtPath:path] objectEnumerator];
-        while ((tmp = [dir nextObject])) {
-          NSDictionary *bundleInfo      = nil;
-          NSArray      *providedResources = nil;
-          NSString     *infoPath;
+    /* check whether an appropriate bundle is contained in 'path' */
+    
+    // TODO: move to own method
+    dir = [[fm directoryContentsAtPath:path] objectEnumerator];
+    while ((tmp = [dir nextObject]) != nil) {
+      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 +1882,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 +1898,12 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info
         categories:[ui objectForKey:@"NSLoadedCategories"]];
 }
 
+/* debugging */
+
+- (BOOL)isDebuggingEnabled {
+  return debugOn;
+}
+
 @end /* NGBundleManager */
 
 @implementation NSBundle(BundleManagerSupport)
@@ -1710,7 +1968,7 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info
                            providedByBundle:self];
 }
 
-// loading
+/* loading */
 
 - (BOOL)_loadForBundleManager:(NGBundleManager *)_manager {
   return [self load];
@@ -1720,25 +1978,43 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info
 
 @implementation NSBundle(NGLanguageResourceExtensions)
 
+static BOOL debugLanguageLookup = NO;
+
 // locating resources
 
 - (NSString *)pathForResource:(NSString *)_name ofType:(NSString *)_ext
   inDirectory:(NSString *)_directory
   languages:(NSArray *)_languages
 {
-  NSFileManager *fm   = [NSFileManager defaultManager];
+  NSFileManager *fm;
   NSString      *path = nil;
   int i, langCount;
   id (*objAtIdx)(id,SEL,int);
-
-  path = _directory
-    ? [[self bundlePath] stringByAppendingPathComponent:_directory]
-    : [self bundlePath];
-
+  
+  if (debugLanguageLookup) {
+    NSLog(@"LOOKUP(%s): %@ | %@ | %@ | %@", __PRETTY_FUNCTION__,
+         _name, _ext, _directory, [_languages componentsJoinedByString:@","]);
+  }
+  
+  path = [self bundlePath];
+  if ([_directory isNotNull]) {
+    // TODO: should we change that?
+    path = [path stringByAppendingPathComponent:_directory];
+  }
+  else {
+#if (NeXT_Foundation_LIBRARY || APPLE_Foundation_LIBRARY)
+    path = [path stringByAppendingPathComponent:@"Contents"];
+#endif
+    path = [path stringByAppendingPathComponent:@"Resources"];
+  }
+  
+  if (debugLanguageLookup) NSLog(@"  BASE: %@", path);
+  
+  fm   = [NSFileManager defaultManager];
   if (![fm fileExistsAtPath:path])
     return nil;
   
-  if (_ext) _name = [_name stringByAppendingPathExtension:_ext];
+  if (_ext != nil) _name = [_name stringByAppendingPathExtension:_ext];
   
   langCount = [_languages count];
   objAtIdx = (langCount > 0)
@@ -1760,6 +2036,9 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info
     if ([fm fileExistsAtPath:lpath])
       return lpath;
   }
+  
+  if (debugLanguageLookup) 
+    NSLog(@"  no language matched, check base: %@", path);
 
   /* now look into x.bundle/Resources/name.type */
   if ([fm fileExistsAtPath:[path stringByAppendingPathComponent:_name]])
@@ -1826,17 +2105,17 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info
   Class c;
   NSString *cname;
   
-  if ((c = [super principalClass]))
+  if ((c = [super principalClass]) != Nil)
     return c;
   
   if ((cname = [[self infoDictionary] objectForKey:@"NSPrincipalClass"]) ==nil)
     return Nil;
   
-  if ((c = NSClassFromString(cname)))
+  if ((c = NSClassFromString(cname)) != Nil)
     return c;
   
-  NSLog(@"%s: did not find principal class named '%@' of bundle %@",
-       __PRETTY_FUNCTION__, cname, self);
+  NSLog(@"%s: did not find principal class named '%@' of bundle %@, dict: %@",
+       __PRETTY_FUNCTION__, cname, self, [self infoDictionary]);
   return Nil;
 }
 
@@ -1844,7 +2123,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),