X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=sope-core%2FNGExtensions%2FNGBundleManager.m;h=5d006c7f0f24d83b3cb62a015eb6ef54ddf556e0;hb=44a8a29f4a941d3eacfb4c115717da7ba36f520d;hp=8edd9d4da3f90e45c3185988fc10e7298837f41b;hpb=1201d1c9194b8d906b5b5abd1ed00e0b179d991d;p=sope diff --git a/sope-core/NGExtensions/NGBundleManager.m b/sope-core/NGExtensions/NGBundleManager.m index 8edd9d4d..5d006c7f 100644 --- a/sope-core/NGExtensions/NGBundleManager.m +++ b/sope-core/NGExtensions/NGBundleManager.m @@ -1,20 +1,20 @@ /* - Copyright (C) 2000-2004 SKYRIX Software AG + Copyright (C) 2000-2005 SKYRIX Software AG - 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. */ @@ -22,7 +22,7 @@ #include "NGBundleManager.h" #include "common.h" #include -#include +#include #import #import #include @@ -49,8 +49,10 @@ //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) @@ -59,18 +61,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]); @@ -126,7 +131,7 @@ static Class _classLoadHook(const char *_name) { manager = [NGBundleManager defaultBundleManager]; bundle = [manager bundleForClassNamed:[NSString stringWithCString:_name]]; - if (bundle) { + if (bundle != nil) { #if 0 NSLog(@"%s: found bundle %@", __PRETTY_FUNCTION__, [bundle bundlePath]); #endif @@ -248,9 +253,7 @@ static NSString *NGEnvVarPathSeparator = @":"; objc_setClassHandler(_getClassHook); } } -#endif - -#if GNU_RUNTIME +#elif GNU_RUNTIME if (_objc_lookup_class != _classLoadHook) { oldClassLoadHook = _objc_lookup_class; _objc_lookup_class = _classLoadHook; @@ -377,9 +380,9 @@ static NSString *NGEnvVarPathSeparator = @":"; - (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]; } @@ -468,16 +471,35 @@ static NSString *NGEnvVarPathSeparator = @":"; 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); } @@ -529,14 +551,38 @@ static NSString *NGEnvVarPathSeparator = @":"; - (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%08X: %s\n", + __PRETTY_FUNCTION__, + (unsigned int )bundle, [[bundle bundlePath] cString]); + } + bundle = nil; + } + else if ([p hasSuffix:@"Tools"]) { + if (debugOn) { + fprintf(stderr, "%s: Tool bundle: 0x%08X: %s\n", + __PRETTY_FUNCTION__, + (unsigned int )bundle, [[bundle bundlePath] cString]); + } + bundle = nil; + } + } } #endif if (bundle == nil) { @@ -617,13 +663,13 @@ static NSString *NGEnvVarPathSeparator = @":"; - (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 @@ -633,26 +679,47 @@ static NSString *NGEnvVarPathSeparator = @":"; 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 .."); } @@ -660,7 +727,7 @@ static NSString *NGEnvVarPathSeparator = @":"; if (path == nil) return nil; - if ((bundle = [self bundleWithPath:path])) + if ((bundle = [self bundleWithPath:path]) != nil) NSMapInsert(self->classNameToBundle, _className, bundle); return bundle; @@ -678,8 +745,7 @@ static NSString *NGEnvVarPathSeparator = @":"; } - (NSArray *)classesProvidedByBundle:(NSBundle *)_bundle { - [self doesNotRecognizeSelector:_cmd]; - return nil; + return [[_bundle providedResourcesOfType:@"classes"] valueForKey:@"name"]; } - (NSArray *)classesRequiredByBundle:(NSBundle *)_bundle { [self doesNotRecognizeSelector:_cmd]; @@ -733,9 +799,15 @@ static NSString *NGEnvVarPathSeparator = @":"; [self debugWithFormat: @"no bundle handler, lookup principal class of bundle: %@", _bundle]; - if ((handler = [_bundle principalClass]) == nil) + 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; @@ -780,6 +852,16 @@ static NSString *NGEnvVarPathSeparator = @":"; 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 %@.", @@ -787,6 +869,9 @@ static NSString *NGEnvVarPathSeparator = @":"; #endif } + if (debugOn) + NSLog(@"CLASS %@ => BUNDLE %@", className, bundle); + return bundle; } - (NSArray *)_locateBundlesForClassInfos:(NSEnumerator *)_classInfos { @@ -794,7 +879,7 @@ static NSString *NGEnvVarPathSeparator = @":"; NSDictionary *i; requiredBundles = [NSMutableArray arrayWithCapacity:16]; - while ((i = [_classInfos nextObject])) { + while ((i = [_classInfos nextObject]) != nil) { NSBundle *bundle; if ((bundle = [self _locateBundleForClassInfo:i]) == nil) @@ -807,7 +892,7 @@ static NSString *NGEnvVarPathSeparator = @":"; - (BOOL)_preLoadBundle:(NSBundle *)_bundle info:(NSDictionary *)_bundleInfo { /* TODO: split up this huge method */ - NSDictionary *requires = nil; + NSDictionary *requires; NSMutableArray *requiredBundles = nil; NSBundle *requiredBundle = nil; @@ -825,7 +910,7 @@ static NSString *NGEnvVarPathSeparator = @":"; /* locate required bundles */ e = [[requires objectForKey:@"bundles"] objectEnumerator]; - while ((i = [e nextObject])) { + while ((i = [e nextObject]) != nil) { NSString *bundleName; if (![i respondsToSelector:@selector(objectForKey:)]) { @@ -858,18 +943,19 @@ static NSString *NGEnvVarPathSeparator = @":"; NSLog(@"ERROR: error in bundle-info.plist of bundle %@", _bundle); } } - + /* 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; } } @@ -881,23 +967,25 @@ static NSString *NGEnvVarPathSeparator = @":"; 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; } } @@ -909,7 +997,7 @@ static NSString *NGEnvVarPathSeparator = @":"; NSDictionary *i; e = [[requires objectForKey:@"classes"] objectEnumerator]; - while ((i = [e nextObject])) { + while ((i = [e nextObject]) != nil) { NSString *className; Class clazz; @@ -1378,7 +1466,7 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info /* check whether an appropriate bundle is contained in 'path' */ dir = [[fm directoryContentsAtPath:path] objectEnumerator]; - while ((tmp = [dir nextObject])) { + while ((tmp = [dir nextObject]) != nil) { NSDictionary *bundleInfo = nil; NSString *infoPath; @@ -1553,7 +1641,7 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info /* scan all bundle search paths */ e = [self->bundleSearchPaths objectEnumerator]; - while ((path = [e nextObject])) { + while ((path = [e nextObject]) != nil) { NSEnumerator *dir; BOOL isDir = NO; NSString *tmp; @@ -1564,9 +1652,10 @@ static BOOL _doesInfoMatch(NSArray *keys, NSDictionary *dict, NSDictionary *info if (!isDir) continue; /* check whether an appropriate bundle is contained in 'path' */ - + + // TODO: move to own method dir = [[fm directoryContentsAtPath:path] objectEnumerator]; - while ((tmp = [dir nextObject])) { + while ((tmp = [dir nextObject]) != nil) { NSDictionary *bundleInfo = nil; NSArray *providedResources = nil; NSString *infoPath; @@ -1879,25 +1968,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) @@ -1919,6 +2026,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]])