This is NSBundle.m in view mode; [Download] [Up]
/* NSBundle.m Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea. All rights reserved. Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro> This file is part of libFoundation. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. We disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness, in no event shall we be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ #include <sys/types.h> #include <sys/stat.h> #include <Foundation/common.h> #include <Foundation/NSBundle.h> #include <Foundation/NSArray.h> #include <Foundation/NSDictionary.h> #include <Foundation/NSString.h> #include <Foundation/NSAutoreleasePool.h> #include <Foundation/NSProcessInfo.h> #include <Foundation/NSNotification.h> #include <Foundation/NSUserDefaults.h> #include <extensions/objc-runtime.h> /* * Static class variables */ typedef struct { Class class; Category* category; } LoadingClassCategory; static NSMapTable* bundleClasses; // class -> bundle mapping static NSMapTable* bundleNames; // path -> bundle mapping static NSBundle* mainBundle; // application bundle static LoadingClassCategory*load_Classes; // used while loading static int load_classes_size; // used while loading static int load_classes_used; // used while loading /* * NSBundle methods */ @implementation NSBundle // Library resource directory static NSString* resourcesPath = nil; + (NSString*)libraryResourceDirectory { if (!resourcesPath) { char* res_path = getenv("LIB_FOUNDATION_RESOURCES_PATH"); resourcesPath = (res_path == NULL) ? @RESOURCES_PATH : [[NSString stringWithCString:res_path] retain]; } return resourcesPath; } // Bundle initialization + (void)initialize { mainBundle = nil; bundleClasses = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, NSNonRetainedObjectMapValueCallBacks, 23); bundleNames = NSCreateMapTable(NSObjectMapKeyCallBacks, NSNonRetainedObjectMapValueCallBacks, 23); } // Load info for bundle - (void)loadInfo { NSString* file; if (infoDictionary) return; file = [self pathForResource:@"Info" ofType:@"plist"]; if (file) infoDictionary = [[[NSString stringWithContentsOfFile:file] propertyList] retain]; if (!infoDictionary) infoDictionary = [[NSDictionary alloc] init]; } // Internal code loading static void load_callback(Class class, Category* category) { if (load_classes_used >= load_classes_size) { load_classes_size += 128; load_Classes = Realloc(load_Classes, load_classes_size*sizeof(LoadingClassCategory)); } load_Classes[load_classes_used].class = class; load_Classes[load_classes_used].category = category; load_classes_used++; } - (BOOL)loadCode { int i; NSString* file; NSString* rfile; BOOL status; int objc_load_module(const char*, void (*)(Class, Category*)); if (codeLoaded) return YES; else codeLoaded = YES; // Find file to load if ((file = [[self infoDictionary] objectForKey:@"NSExecutable"])) file = [fullPath stringByAppendingPathComponent:file]; else file = [fullPath stringByAppendingPathComponent: [fullPath lastPathComponent]]; rfile = [file stringByResolvingSymlinksInPath]; if (!rfile) { NSLog(@"%@:NSBundle: cannot find executable file %@", [[NSProcessInfo processInfo] processName], file); return NO; } // Prepare to keep classes/categories loaded load_classes_size = 128; load_classes_used = 0; load_Classes = Malloc(load_classes_size*sizeof(LoadingClassCategory)); status = objc_load_module([file fileSystemRepresentation], load_callback); if (status) { NSDictionary* info; firstLoadedClass = Nil; for (i = 0; i < load_classes_used; i++) { // get first class from bundle if (!firstLoadedClass && !load_Classes[i].category) firstLoadedClass = load_Classes[i].class; // TODO - call class/category load method // insert in bundle hash if (!load_Classes[i].category) NSMapInsert(bundleClasses, load_Classes[i].class, self); // post notification if (!load_Classes[i].category) info = [NSDictionary dictionaryWithObjectsAndKeys: [NSString stringWithCStringNoCopy: (char*)(load_Classes[i].class->name) freeWhenDone:NO], @"NSClass", nil]; else info = [NSDictionary dictionaryWithObjectsAndKeys: [NSString stringWithCStringNoCopy: (char*)(load_Classes[i].class->name) freeWhenDone:NO], @"NSClass", [NSString stringWithCStringNoCopy: (char*)(load_Classes[i].category->category_name) freeWhenDone:NO], @"NSCategory", nil]; [[NSNotificationCenter defaultCenter] postNotificationName:@"NSBundleDidLoadNotification" object:nil userInfo:info]; } [[NSNotificationCenter defaultCenter] postNotificationName:@"NSBundleDidLoadNotification" object:nil userInfo:nil]; } Free(load_Classes); return status; } // Initializing an NSBundle static BOOL canReadDirectory(NSString* path) { const char* cpath = [path fileSystemRepresentation]; struct stat statbuf; if (stat(cpath, &statbuf) < 0) return NO; if (S_IFDIR != (S_IFMT & statbuf.st_mode)) return NO; if (access(cpath, R_OK | X_OK) < 0) return NO; return YES; } static BOOL canReadFile(NSString* path) { const char* cpath = [path fileSystemRepresentation]; if (access(cpath, R_OK) < 0) return NO; return YES; } - (id)initWithPath:(NSString*)path { NSBundle* old; path = [path stringByResolvingSymlinksInPath]; if (!path || !canReadDirectory(path)) { [self release]; return nil; } old = (NSBundle*)NSMapGet(bundleNames, path); if (old) { [self release]; return [old retain]; } NSMapInsert(bundleNames, path, self); fullPath = [path retain]; return self; } // TODO - now bundle is not capable of dealloc & code unloading - retain {return self;} - autorelease {return self;} - (void)release{} - (unsigned int)retainCount {return 1;} - (void)dealloc { NSMapRemove(bundleNames, fullPath); [fullPath release]; [infoDictionary release]; [stringTables release]; [super dealloc]; } // Getting an NSBundle + (NSBundle*)bundleForClass:(Class)aClass { NSBundle* bundle = (NSBundle*)NSMapGet(bundleClasses, aClass); return bundle ? bundle : [self mainBundle]; } + (NSBundle*)bundleWithPath:(NSString*)path { return [[[self alloc] initWithPath:path] autorelease]; } + (NSBundle*)mainBundle { if (!mainBundle) { NSString* path = [[[NSProcessInfo processInfo] processName] stringByDeletingLastPathComponent]; if ([path isEqual:@""]) path = @"."; mainBundle = [[NSBundle alloc] initWithPath:path]; } return mainBundle; } // Getting a Bundled Class - (Class)classNamed:(NSString*)className { Class class; [self loadCode]; class = NSClassFromString(className); if (class && (NSBundle*)NSMapGet(bundleClasses, class) == self) return class; return nil; } - (Class)principalClass { NSString* className; Class class; [self loadCode]; className = [[self infoDictionary] objectForKey:@"NSPrincipalClass"]; class = NSClassFromString(className); return class ? class : firstLoadedClass; } // Finding a Resource + (NSString*)pathForResource:(NSString*)name ofType:(NSString*)ext inDirectories:(NSArray*)directories { int i, n; NSAutoreleasePool* pool; NSString* file; pool = [NSAutoreleasePool new]; if (ext) name = [name stringByAppendingPathExtension:ext]; n = [directories count]; for (i = 0; i < n; i++) { file = [[directories objectAtIndex:i] stringByAppendingPathComponent:name]; if (canReadFile(file)) goto found; } file = nil; found: [file retain]; [pool release]; return [file autorelease]; } - (NSString*)pathForResource:(NSString*)name ofType:(NSString*)ext inDirectory:(NSString*)directory { int i, n; NSString* path; NSString* file; NSAutoreleasePool* pool; NSMutableArray* languages; pool = [NSAutoreleasePool new]; // Get languages and translate list by adding "lproj" extension // {English, German, ...} to {English.lproj, German.lproj, ...} languages = [[[NSUserDefaults standardUserDefaults] stringArrayForKey:@"Languages"] mutableCopy]; n = [languages count]; for (i = 0; i < n; i++) { file = [[languages objectAtIndex:i] stringByAppendingPathExtension:@"lproj"]; [languages replaceObjectAtIndex:i withObject:file]; } // make file name name.ext if extension is present if (ext) name = [name stringByAppendingPathExtension:ext]; // look for fullPath/Resources/directory/... path = [fullPath stringByAppendingPathComponent:@"Resources"]; if (directory && ![directory isEqualToString:@""]) path = [path stringByAppendingPathComponent:directory]; if (canReadDirectory(path)) { // check languages for (i = 0; i < n; i++) { file = [[path stringByAppendingPathComponent: [languages objectAtIndex:i]] stringByAppendingPathComponent:name]; if (canReadFile(file)) goto found; } // check base file = [path stringByAppendingPathComponent:name]; if (canReadFile(file)) goto found; } // look for fullPath/directory/... if (directory && ![directory isEqualToString:@""]) path = [fullPath stringByAppendingPathComponent:directory]; else path = fullPath; if (canReadDirectory(path)) { // check languages for (i = 0; i < n; i++) { file = [[path stringByAppendingPathComponent: [languages objectAtIndex:i]] stringByAppendingPathComponent:name]; if (canReadFile(file)) goto found; } // check base file = [path stringByAppendingPathComponent:name]; if (canReadFile(file)) goto found; } file = nil; found: [file retain]; [pool release]; return [file autorelease]; } - (NSArray*)pathsForResourcesOfType:(NSString*)extension inDirectory:(NSString*)bundlePath { // TODO - needs NSFileManager [self notImplemented:_cmd]; return nil; } - (NSString*)pathForResource:(NSString*)name ofType:(NSString*)ext { return [self pathForResource:name ofType:ext inDirectory:nil]; } - (NSString*)resourcePath { return fullPath; } // Getting bundle information - (NSDictionary*)infoDictionary { [self loadInfo]; return infoDictionary; } // Getting the Bundle Directory - (NSString*)bundlePath { return fullPath; } // Managing Localized Resources - (NSString*)localizedStringForKey:(NSString*)key value:(NSString*)value table:(NSString*)tableName { NSDictionary* table; NSString* string; if (!stringTables) stringTables = [NSMutableDictionary new]; table = [stringTables objectForKey:tableName]; if (!table) { string = [NSString stringWithContentsOfFile: [self pathForResource:tableName ofType:@"strings"]]; if (!string) return value; table = [string propertyListFromStringsFileFormat]; if (table) [stringTables setObject:table forKey:tableName]; } string = [table objectForKey:key]; if (!string) string = value; return string; } - (void)releaseStringtableCache { [stringTables release]; stringTables = nil; } @end /* NSBundle */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.