2001-12-17 14:31:42 +00:00
|
|
|
/** Implementation of NSBundle class
|
2002-02-26 18:06:51 +00:00
|
|
|
Copyright (C) 1993-2002 Free Software Foundation, Inc.
|
1995-04-03 20:07:18 +00:00
|
|
|
|
|
|
|
Written by: Adam Fedor <fedor@boulder.colorado.edu>
|
|
|
|
Date: May 1993
|
|
|
|
|
2000-10-28 21:58:48 +00:00
|
|
|
Author: Mirko Viviani <mirko.viviani@rccr.cremona.it>
|
|
|
|
Date: October 2000 Added frameworks support
|
|
|
|
|
2002-02-09 01:06:05 +00:00
|
|
|
Author: Nicola Pero <nicola@brainstorm.co.uk>
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
This file is part of the GNUstep Base Library.
|
1995-04-03 20:07:18 +00:00
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; if not, write to the Free
|
2005-05-22 03:32:16 +00:00
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
|
1995-04-03 20:07:18 +00:00
|
|
|
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
<title>NSBundle class reference</title>
|
|
|
|
$Date$ $Revision$
|
1995-04-03 20:07:18 +00:00
|
|
|
*/
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
#include "config.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
#include "GNUstepBase/preface.h"
|
|
|
|
#include "objc-load.h"
|
2003-06-07 01:24:41 +00:00
|
|
|
#include "Foundation/NSBundle.h"
|
|
|
|
#include "Foundation/NSException.h"
|
|
|
|
#include "Foundation/NSString.h"
|
|
|
|
#include "Foundation/NSArray.h"
|
|
|
|
#include "Foundation/NSDebug.h"
|
|
|
|
#include "Foundation/NSDictionary.h"
|
|
|
|
#include "Foundation/NSProcessInfo.h"
|
|
|
|
#include "Foundation/NSObjCRuntime.h"
|
|
|
|
#include "Foundation/NSUserDefaults.h"
|
|
|
|
#include "Foundation/NSNotification.h"
|
|
|
|
#include "Foundation/NSLock.h"
|
|
|
|
#include "Foundation/NSMapTable.h"
|
|
|
|
#include "Foundation/NSAutoreleasePool.h"
|
|
|
|
#include "Foundation/NSFileManager.h"
|
|
|
|
#include "Foundation/NSPathUtilities.h"
|
2006-04-09 16:16:07 +00:00
|
|
|
#include "Foundation/NSData.h"
|
2003-06-07 01:24:41 +00:00
|
|
|
#include "Foundation/NSValue.h"
|
2005-03-31 23:22:44 +00:00
|
|
|
#include "GNUstepBase/GSFunctions.h"
|
2002-05-02 21:22:06 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
1997-01-09 17:01:14 +00:00
|
|
|
#include <unistd.h>
|
2002-02-20 06:42:05 +00:00
|
|
|
#endif
|
2000-10-28 21:58:48 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
@interface NSObject (PrivateFrameworks)
|
2000-11-01 12:31:21 +00:00
|
|
|
+ (NSString*) frameworkEnv;
|
|
|
|
+ (NSString*) frameworkPath;
|
|
|
|
+ (NSString*) frameworkVersion;
|
|
|
|
+ (NSString**) frameworkClasses;
|
2000-10-28 21:58:48 +00:00
|
|
|
@end
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
typedef enum {
|
2006-05-10 03:18:08 +00:00
|
|
|
NSBUNDLE_BUNDLE = 1,
|
|
|
|
NSBUNDLE_APPLICATION,
|
|
|
|
NSBUNDLE_FRAMEWORK,
|
|
|
|
NSBUNDLE_LIBRARY
|
1997-01-06 22:30:33 +00:00
|
|
|
} bundle_t;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Class variables - We keep track of all the bundles */
|
2000-11-01 12:31:21 +00:00
|
|
|
static NSBundle *_mainBundle = nil;
|
|
|
|
static NSMapTable *_bundles = NULL;
|
2006-05-15 00:49:06 +00:00
|
|
|
static NSMapTable *_byIdentifier = NULL;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
/* Store the working directory at startup */
|
|
|
|
static NSString *_launchDirectory = nil;
|
2000-04-18 21:34:59 +00:00
|
|
|
|
1999-04-23 13:56:22 +00:00
|
|
|
/*
|
|
|
|
* An empty strings file table for use when localization files can't be found.
|
|
|
|
*/
|
|
|
|
static NSDictionary *_emptyTable = nil;
|
|
|
|
|
1995-03-18 17:15:15 +00:00
|
|
|
/* When we are linking in an object file, objc_load_modules calls our
|
1995-04-03 20:07:18 +00:00
|
|
|
callback routine for every Class and Category loaded. The following
|
1995-03-18 17:15:15 +00:00
|
|
|
variable stores the bundle that is currently doing the loading so we know
|
2005-02-22 11:22:44 +00:00
|
|
|
where to store the class names.
|
1995-03-18 17:15:15 +00:00
|
|
|
*/
|
2000-11-01 12:31:21 +00:00
|
|
|
static NSBundle *_loadingBundle = nil;
|
|
|
|
static NSBundle *_gnustep_bundle = nil;
|
|
|
|
static NSRecursiveLock *load_lock = nil;
|
|
|
|
static BOOL _strip_after_loading = NO;
|
1997-01-06 22:30:33 +00:00
|
|
|
|
2002-10-13 10:29:54 +00:00
|
|
|
/* List of framework linked in the _loadingBundle */
|
|
|
|
static NSMutableArray *_loadingFrameworks = nil;
|
|
|
|
static NSString *_currentFrameworkName = nil;
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
static NSString *gnustep_target_dir =
|
1997-10-16 23:56:27 +00:00
|
|
|
#ifdef GNUSTEP_TARGET_DIR
|
|
|
|
@GNUSTEP_TARGET_DIR;
|
|
|
|
#else
|
|
|
|
nil;
|
|
|
|
#endif
|
2005-02-22 11:22:44 +00:00
|
|
|
static NSString *gnustep_target_cpu =
|
1997-10-30 22:23:50 +00:00
|
|
|
#ifdef GNUSTEP_TARGET_CPU
|
|
|
|
@GNUSTEP_TARGET_CPU;
|
|
|
|
#else
|
|
|
|
nil;
|
|
|
|
#endif
|
2005-02-22 11:22:44 +00:00
|
|
|
static NSString *gnustep_target_os =
|
1997-10-30 22:23:50 +00:00
|
|
|
#ifdef GNUSTEP_TARGET_OS
|
|
|
|
@GNUSTEP_TARGET_OS;
|
|
|
|
#else
|
|
|
|
nil;
|
|
|
|
#endif
|
2005-02-22 11:22:44 +00:00
|
|
|
static NSString *library_combo =
|
1997-10-16 23:56:27 +00:00
|
|
|
#ifdef LIBRARY_COMBO
|
|
|
|
@LIBRARY_COMBO;
|
|
|
|
#else
|
|
|
|
nil;
|
|
|
|
#endif
|
1995-03-18 17:15:15 +00:00
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to find the absolute path of an executable.
|
|
|
|
* Search all the directoried in the PATH.
|
|
|
|
* The atLaunch flag determines whether '.' is considered to be
|
|
|
|
* the current working directory or the working directory at the
|
|
|
|
* time when the program was launched (technically the directory
|
|
|
|
* at the point when NSBundle was first used ... so programs must
|
|
|
|
* use NSBundle *before* changing their working directories).
|
|
|
|
*/
|
|
|
|
static NSString*
|
|
|
|
AbsolutePathOfExecutable(NSString *path, BOOL atLaunch)
|
|
|
|
{
|
|
|
|
NSFileManager *mgr;
|
|
|
|
NSDictionary *env;
|
|
|
|
NSString *pathlist;
|
|
|
|
NSString *prefix;
|
|
|
|
id patharr;
|
|
|
|
|
|
|
|
path = [path stringByStandardizingPath];
|
|
|
|
if ([path isAbsolutePath])
|
|
|
|
{
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
mgr = [NSFileManager defaultManager];
|
|
|
|
env = [[NSProcessInfo processInfo] environment];
|
|
|
|
pathlist = [env objectForKey:@"PATH"];
|
|
|
|
|
|
|
|
/* Windows 2000 and perhaps others have "Path" not "PATH" */
|
|
|
|
if (pathlist == nil)
|
|
|
|
{
|
|
|
|
pathlist = [env objectForKey:@"Path"];
|
|
|
|
}
|
|
|
|
#if defined(__MINGW32__)
|
|
|
|
patharr = [pathlist componentsSeparatedByString:@";"];
|
|
|
|
#else
|
|
|
|
patharr = [pathlist componentsSeparatedByString:@":"];
|
|
|
|
#endif
|
|
|
|
/* Add . if not already in path */
|
|
|
|
if ([patharr indexOfObject: @"."] == NSNotFound)
|
|
|
|
{
|
|
|
|
patharr = AUTORELEASE([patharr mutableCopy]);
|
|
|
|
[patharr addObject: @"."];
|
|
|
|
}
|
|
|
|
patharr = [patharr objectEnumerator];
|
|
|
|
while ((prefix = [patharr nextObject]))
|
|
|
|
{
|
|
|
|
if ([prefix isEqual:@"."])
|
|
|
|
{
|
|
|
|
if (atLaunch == YES)
|
|
|
|
{
|
|
|
|
prefix = _launchDirectory;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
prefix = [mgr currentDirectoryPath];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
prefix = [prefix stringByAppendingPathComponent: path];
|
|
|
|
if ([mgr isExecutableFileAtPath: prefix])
|
|
|
|
{
|
|
|
|
return [prefix stringByStandardizingPath];
|
|
|
|
}
|
|
|
|
#if defined(__WIN32__)
|
|
|
|
{
|
|
|
|
NSString *ext = [path pathExtension];
|
|
|
|
|
|
|
|
/* Also add common executable extensions on windows */
|
|
|
|
if (ext == nil || [ext length] == 0)
|
|
|
|
{
|
|
|
|
NSString *wpath;
|
|
|
|
wpath = [prefix stringByAppendingPathExtension: @"exe"];
|
|
|
|
if ([mgr isExecutableFileAtPath: wpath])
|
|
|
|
return [wpath stringByStandardizingPath];
|
|
|
|
wpath = [prefix stringByAppendingPathExtension: @"com"];
|
|
|
|
if ([mgr isExecutableFileAtPath: wpath])
|
|
|
|
return [wpath stringByStandardizingPath];
|
|
|
|
wpath = [prefix stringByAppendingPathExtension: @"cmd"];
|
|
|
|
if ([mgr isExecutableFileAtPath: wpath])
|
|
|
|
return [wpath stringByStandardizingPath];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the path to this executable.
|
|
|
|
*/
|
|
|
|
static NSString *ExecutablePath()
|
|
|
|
{
|
|
|
|
static NSString *executablePath = nil;
|
|
|
|
static BOOL beenHere = NO;
|
|
|
|
|
|
|
|
if (beenHere == NO)
|
|
|
|
{
|
|
|
|
[load_lock lock];
|
|
|
|
if (beenHere == NO)
|
|
|
|
{
|
|
|
|
#ifdef PROCFS_EXE_LINK
|
|
|
|
executablePath = [[NSFileManager defaultManager]
|
|
|
|
pathContentOfSymbolicLinkAtPath:
|
|
|
|
[NSString stringWithCString: PROCFS_EXE_LINK]];
|
|
|
|
|
|
|
|
/*
|
|
|
|
On some systems, the link is of the form "[device]:inode", which
|
|
|
|
can be used to open the executable, but is useless if you want
|
|
|
|
the path to it. Thus we check that the path is an actual absolute
|
|
|
|
path. (Using '/' here is safe; it isn't the path separator
|
|
|
|
everywhere, but it is on all systems that have PROCFS_EXE_LINK.)
|
|
|
|
*/
|
|
|
|
if ([executablePath length] > 0
|
|
|
|
&& [executablePath characterAtIndex: 0] != '/')
|
|
|
|
{
|
|
|
|
executablePath = nil;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (executablePath == nil || [executablePath length] == 0)
|
|
|
|
{
|
|
|
|
executablePath
|
|
|
|
= [[[NSProcessInfo processInfo] arguments] objectAtIndex: 0];
|
|
|
|
executablePath = AbsolutePathOfExecutable(executablePath, YES);
|
|
|
|
}
|
|
|
|
|
|
|
|
RETAIN(executablePath);
|
|
|
|
beenHere = YES;
|
|
|
|
}
|
|
|
|
[load_lock unlock];
|
|
|
|
NSCAssert(executablePath != nil, NSInternalInconsistencyException);
|
|
|
|
}
|
|
|
|
return executablePath;
|
|
|
|
}
|
|
|
|
|
1996-01-21 01:36:47 +00:00
|
|
|
/* This function is provided for objc-load.c, although I'm not sure it
|
|
|
|
really needs it (So far only needed if using GNU dld library) */
|
2006-04-25 03:28:59 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
const unichar *
|
2006-05-20 13:24:53 +00:00
|
|
|
objc_executable_location (void)
|
|
|
|
{
|
|
|
|
return [[ExecutablePath() stringByDeletingLastPathComponent]
|
|
|
|
fileSystemRepresentation];
|
|
|
|
}
|
2006-04-25 03:28:59 +00:00
|
|
|
#else
|
1996-01-21 01:36:47 +00:00
|
|
|
const char *
|
2002-02-26 18:06:51 +00:00
|
|
|
objc_executable_location (void)
|
1996-01-21 01:36:47 +00:00
|
|
|
{
|
2006-04-25 03:28:59 +00:00
|
|
|
return [[ExecutablePath() stringByDeletingLastPathComponent]
|
2002-05-08 23:19:22 +00:00
|
|
|
fileSystemRepresentation];
|
1996-01-21 01:36:47 +00:00
|
|
|
}
|
2006-05-20 13:24:53 +00:00
|
|
|
#endif
|
1996-01-21 01:36:47 +00:00
|
|
|
|
2000-06-06 16:50:52 +00:00
|
|
|
static BOOL
|
|
|
|
bundle_directory_readable(NSString *path)
|
|
|
|
{
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
2000-11-01 12:31:21 +00:00
|
|
|
BOOL directory;
|
2000-06-06 16:50:52 +00:00
|
|
|
|
2000-11-01 12:31:21 +00:00
|
|
|
if ([mgr fileExistsAtPath: path isDirectory: &directory] == NO
|
|
|
|
|| !directory)
|
2000-06-06 16:50:52 +00:00
|
|
|
return NO;
|
|
|
|
|
|
|
|
return [mgr isReadableFileAtPath: path];
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
bundle_file_readable(NSString *path)
|
|
|
|
{
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
return [mgr isReadableFileAtPath: path];
|
|
|
|
}
|
|
|
|
|
1995-03-18 17:15:15 +00:00
|
|
|
/* Get the object file that should be located in the bundle of the same name */
|
|
|
|
static NSString *
|
1997-01-06 22:30:33 +00:00
|
|
|
bundle_object_name(NSString *path, NSString* executable)
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1999-04-13 21:56:03 +00:00
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
NSString *name, *path0, *path1, *path2;
|
|
|
|
|
|
|
|
if (executable)
|
|
|
|
{
|
|
|
|
NSString *exepath;
|
|
|
|
|
|
|
|
name = [executable lastPathComponent];
|
|
|
|
exepath = [executable stringByDeletingLastPathComponent];
|
|
|
|
if ([exepath isEqualToString: @""] == NO)
|
|
|
|
{
|
|
|
|
if ([exepath isAbsolutePath] == YES)
|
|
|
|
path = exepath;
|
|
|
|
else
|
|
|
|
path = [path stringByAppendingPathComponent: exepath];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = [[path lastPathComponent] stringByDeletingPathExtension];
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
|
|
|
}
|
|
|
|
path0 = [path stringByAppendingPathComponent: name];
|
|
|
|
path = [path stringByAppendingPathComponent: gnustep_target_dir];
|
|
|
|
path1 = [path stringByAppendingPathComponent: name];
|
|
|
|
path = [path stringByAppendingPathComponent: library_combo];
|
|
|
|
path2 = [path stringByAppendingPathComponent: executable];
|
|
|
|
|
|
|
|
if ([mgr isReadableFileAtPath: path2] == YES)
|
|
|
|
return path2;
|
|
|
|
else if ([mgr isReadableFileAtPath: path1] == YES)
|
|
|
|
return path1;
|
|
|
|
else if ([mgr isReadableFileAtPath: path0] == YES)
|
|
|
|
return path0;
|
|
|
|
return path2;
|
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Construct a path from components */
|
2005-02-22 11:22:44 +00:00
|
|
|
static NSString *
|
1997-01-06 22:30:33 +00:00
|
|
|
_bundle_resource_path(NSString *primary, NSString* bundlePath, NSString *lang)
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
if (bundlePath)
|
|
|
|
primary = [primary stringByAppendingPathComponent: bundlePath];
|
|
|
|
if (lang)
|
2005-02-22 11:22:44 +00:00
|
|
|
primary = [primary stringByAppendingPathComponent:
|
2000-11-01 12:31:21 +00:00
|
|
|
[NSString stringWithFormat: @"%@.lproj", lang]];
|
1997-01-06 22:30:33 +00:00
|
|
|
return primary;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find the first directory entry with a given name (with any extension) */
|
|
|
|
static NSString *
|
2000-06-06 16:50:52 +00:00
|
|
|
_bundle_name_first_match(NSString* directory, NSString* name)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-06-06 16:50:52 +00:00
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
2000-11-01 12:31:21 +00:00
|
|
|
NSEnumerator *filelist;
|
|
|
|
NSString *path;
|
|
|
|
NSString *match;
|
|
|
|
NSString *cleanname;
|
1997-01-06 22:30:33 +00:00
|
|
|
|
2000-06-21 15:25:30 +00:00
|
|
|
/* name might have a directory in it also, so account for this */
|
2005-02-22 11:22:44 +00:00
|
|
|
path = [[directory stringByAppendingPathComponent: name]
|
2000-11-01 12:31:21 +00:00
|
|
|
stringByDeletingLastPathComponent];
|
2004-10-14 04:08:24 +00:00
|
|
|
cleanname = [[name lastPathComponent] stringByDeletingPathExtension];
|
2000-06-21 15:25:30 +00:00
|
|
|
filelist = [[mgr directoryContentsAtPath: path] objectEnumerator];
|
2000-06-06 16:50:52 +00:00
|
|
|
while ((match = [filelist nextObject]))
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-06-21 15:25:30 +00:00
|
|
|
if ([cleanname isEqual: [match stringByDeletingPathExtension]])
|
|
|
|
return [path stringByAppendingPathComponent: match];
|
1995-08-02 16:58:51 +00:00
|
|
|
}
|
1995-04-03 20:07:18 +00:00
|
|
|
|
2000-06-06 16:50:52 +00:00
|
|
|
return nil;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2005-03-31 23:22:44 +00:00
|
|
|
/* Try to locate name framework in standard places
|
|
|
|
which are like /Library/Frameworks/(name).framework */
|
|
|
|
static inline NSString *
|
|
|
|
_find_framework(NSString *name)
|
|
|
|
{
|
|
|
|
NSArray *paths;
|
|
|
|
|
|
|
|
paths = NSSearchPathForDirectoriesInDomains(GSFrameworksDirectory,
|
|
|
|
NSAllDomainsMask,YES);
|
|
|
|
return GSFindNamedFile(paths, name, @"framework");
|
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
@interface NSBundle (Private)
|
2006-04-09 16:16:07 +00:00
|
|
|
+ (NSString *) _absolutePathOfExecutable: (NSString *)path;
|
2002-10-13 10:29:54 +00:00
|
|
|
+ (void) _addFrameworkFromClass: (Class)frameworkClass;
|
2006-04-09 16:16:07 +00:00
|
|
|
+ (NSString*) _gnustep_target_cpu;
|
|
|
|
+ (NSString*) _gnustep_target_dir;
|
|
|
|
+ (NSString*) _gnustep_target_os;
|
|
|
|
+ (NSString*) _library_combo;
|
1997-01-06 22:30:33 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSBundle (Private)
|
2000-10-28 21:58:48 +00:00
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
+ (NSString *) _absolutePathOfExecutable: (NSString *)path
|
|
|
|
{
|
|
|
|
return AbsolutePathOfExecutable(path, NO);
|
|
|
|
}
|
|
|
|
|
2002-10-30 23:04:06 +00:00
|
|
|
/* Nicola & Mirko:
|
2002-01-16 13:52:39 +00:00
|
|
|
|
|
|
|
Frameworks can be used in an application in two different ways:
|
|
|
|
|
|
|
|
() the framework is dynamically/manually loaded, as if it were a
|
|
|
|
bundle. This is the easier case, because we already have the
|
|
|
|
bundle setup with the correct path (it's the programmer's
|
|
|
|
responsibility to find the framework bundle on disk); we get all
|
|
|
|
information from the bundle dictionary, such as the version; we
|
|
|
|
also create the class list when loading the bundle, as for any
|
|
|
|
other bundle.
|
|
|
|
|
|
|
|
() the framework was linked into the application. This is much
|
|
|
|
more difficult, because without using tricks, we have no way of
|
|
|
|
knowing where the framework bundle (needed eg for resources) is on
|
|
|
|
disk, and we have no way of knowing what the class list is, or the
|
|
|
|
version. So the trick we use in this case to work around those
|
|
|
|
problems is that gnustep-make generates a 'NSFramework_xxx' class
|
2002-10-30 23:04:06 +00:00
|
|
|
and compiles it into each framework. By asking to the class, we
|
|
|
|
can get the version information and the list of classes which were
|
|
|
|
compiled into the framework. To get the location of the framework
|
|
|
|
on disk, we try using advanced dynamic linker features to get the
|
|
|
|
shared object file on disk from which the NSFramework_xxx class was
|
|
|
|
loaded. If that doesn't work, because the dynamic linker can't
|
|
|
|
provide this information on this platform (or maybe because the
|
|
|
|
framework was statically linked into the application), we have a
|
2005-03-31 23:22:44 +00:00
|
|
|
fallback trick :-) We look for the framework in the standard
|
|
|
|
locations and in the main bundle. This might fail if the framework
|
|
|
|
is not in a standard location or there is more than one installed
|
|
|
|
framework of the same name (and different versions?).
|
2002-01-16 13:52:39 +00:00
|
|
|
|
|
|
|
So at startup, we scan all classes which were compiled into the
|
|
|
|
application. For each NSFramework_ class, we call the following
|
|
|
|
function, which records the name of the framework, the version,
|
|
|
|
the classes belonging to it, and tries to determine the path
|
|
|
|
on disk to the framework bundle.
|
|
|
|
|
2002-10-30 23:04:06 +00:00
|
|
|
Bundles (and frameworks if dynamically loaded as bundles) could
|
|
|
|
depend on other frameworks (linked togheter on platform that
|
|
|
|
supports this behaviour) so whenever we dynamically load a bundle,
|
|
|
|
we need to spot out any additional NSFramework_* classes which are
|
|
|
|
loaded, and call this method (exactly as for frameworks linked into
|
|
|
|
the main application) to record them, and try finding the path on
|
|
|
|
disk to those framework bundles.
|
2002-10-13 10:29:54 +00:00
|
|
|
|
2002-01-16 13:52:39 +00:00
|
|
|
*/
|
2002-10-13 10:29:54 +00:00
|
|
|
+ (void) _addFrameworkFromClass: (Class)frameworkClass
|
2000-10-28 21:58:48 +00:00
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
NSBundle *bundle = nil;
|
2000-11-01 12:31:21 +00:00
|
|
|
NSString **fmClasses;
|
2003-01-03 20:14:47 +00:00
|
|
|
NSString *bundlePath = nil;
|
|
|
|
unsigned int len;
|
2000-11-10 10:57:36 +00:00
|
|
|
|
|
|
|
if (frameworkClass == Nil)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
2002-01-16 13:52:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen (frameworkClass->name);
|
2002-10-13 10:29:54 +00:00
|
|
|
|
2002-01-16 13:03:45 +00:00
|
|
|
if (len > 12 * sizeof(char)
|
2005-07-12 14:11:03 +00:00
|
|
|
&& !strncmp ("NSFramework_", frameworkClass->name, 12))
|
2000-10-28 21:58:48 +00:00
|
|
|
{
|
2002-01-16 13:52:39 +00:00
|
|
|
/* The name of the framework. */
|
2002-10-30 23:04:06 +00:00
|
|
|
NSString *name = [NSString stringWithCString: &frameworkClass->name[12]];
|
2002-01-16 13:52:39 +00:00
|
|
|
|
2005-07-12 14:11:03 +00:00
|
|
|
/* Important - gnustep-make mangles framework names to encode
|
|
|
|
* them as ObjC class names. Here we need to demangle them. We
|
|
|
|
* apply the reverse transformations in the reverse order.
|
|
|
|
*/
|
|
|
|
name = [name stringByReplacingString: @"_1" withString: @"+"];
|
|
|
|
name = [name stringByReplacingString: @"_0" withString: @"-"];
|
|
|
|
name = [name stringByReplacingString: @"__" withString: @"_"];
|
|
|
|
|
2002-10-30 23:04:06 +00:00
|
|
|
/* Try getting the path to the framework using the dynamic
|
|
|
|
* linker. When it works it's really cool :-) This is the only
|
|
|
|
* really universal way of getting the framework path ... we can
|
|
|
|
* locate the framework no matter where it is on disk!
|
|
|
|
*/
|
|
|
|
bundlePath = objc_get_symbol_path (frameworkClass, NULL);
|
2000-10-28 21:58:48 +00:00
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
if ([bundlePath isEqualToString: ExecutablePath()])
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
2002-10-30 23:04:06 +00:00
|
|
|
/* Ops ... the NSFramework_xxx class is linked in the main
|
|
|
|
* executable. Maybe the framework was statically linked
|
|
|
|
* into the application ... resort to searching the
|
|
|
|
* framework bundle on the filesystem manually.
|
|
|
|
*/
|
|
|
|
bundlePath = nil;
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2002-10-30 23:04:06 +00:00
|
|
|
if (bundlePath != nil)
|
2000-10-28 21:58:48 +00:00
|
|
|
{
|
2002-10-30 23:04:06 +00:00
|
|
|
NSString *pathComponent;
|
|
|
|
|
|
|
|
/* Dereference symlinks, and standardize path. This will
|
|
|
|
* only work properly if the original bundlePath is
|
|
|
|
* absolute. This should normally be the case if, as
|
|
|
|
* recommended, you use only absolute paths in
|
|
|
|
* LD_LIBRARY_PATH.
|
|
|
|
*/
|
|
|
|
bundlePath = [bundlePath stringByStandardizingPath];
|
|
|
|
|
|
|
|
/* We now have the location of the shared library object
|
|
|
|
* file inside the framework directory. We need to walk up
|
|
|
|
* the directory tree up to the top of the framework. To do
|
|
|
|
* so, we need to chop off the extra subdirectories, the
|
|
|
|
* library combo and the target cpu/os if they exist. The
|
|
|
|
* framework and this library should match so we can use the
|
|
|
|
* compiled-in settings.
|
|
|
|
*/
|
|
|
|
/* library name */
|
|
|
|
bundlePath = [bundlePath stringByDeletingLastPathComponent];
|
|
|
|
/* library combo */
|
|
|
|
pathComponent = [bundlePath lastPathComponent];
|
|
|
|
if ([pathComponent isEqual: library_combo])
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
2002-10-30 23:04:06 +00:00
|
|
|
bundlePath = [bundlePath stringByDeletingLastPathComponent];
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
2002-10-30 23:04:06 +00:00
|
|
|
/* target os */
|
|
|
|
pathComponent = [bundlePath lastPathComponent];
|
|
|
|
if ([pathComponent isEqual: gnustep_target_os])
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
2002-10-30 23:04:06 +00:00
|
|
|
bundlePath = [bundlePath stringByDeletingLastPathComponent];
|
|
|
|
}
|
|
|
|
/* target cpu */
|
|
|
|
pathComponent = [bundlePath lastPathComponent];
|
|
|
|
if ([pathComponent isEqual: gnustep_target_cpu])
|
|
|
|
{
|
|
|
|
bundlePath = [bundlePath stringByDeletingLastPathComponent];
|
|
|
|
}
|
2005-07-13 14:51:57 +00:00
|
|
|
/* There are no Versions on MinGW. Skip the Versions check here. */
|
2005-10-11 19:09:26 +00:00
|
|
|
#if !defined(__MINGW32__)
|
2002-10-30 23:04:06 +00:00
|
|
|
/* version name */
|
|
|
|
bundlePath = [bundlePath stringByDeletingLastPathComponent];
|
|
|
|
|
|
|
|
pathComponent = [bundlePath lastPathComponent];
|
|
|
|
if ([pathComponent isEqual: @"Versions"])
|
|
|
|
{
|
|
|
|
bundlePath = [bundlePath stringByDeletingLastPathComponent];
|
2005-07-13 14:51:57 +00:00
|
|
|
#endif
|
2002-10-30 23:04:06 +00:00
|
|
|
pathComponent = [bundlePath lastPathComponent];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
|
|
if ([pathComponent isEqualToString:
|
2002-10-30 23:04:06 +00:00
|
|
|
[NSString stringWithFormat: @"%@%@",
|
|
|
|
name, @".framework"]])
|
|
|
|
{
|
|
|
|
/* Try creating the bundle. */
|
2005-07-25 16:11:44 +00:00
|
|
|
if (bundlePath)
|
|
|
|
bundle = [[self alloc] initWithPath: bundlePath];
|
2002-10-30 23:04:06 +00:00
|
|
|
}
|
2005-10-11 19:09:26 +00:00
|
|
|
#if !defined(__MINGW32__)
|
2002-10-30 23:04:06 +00:00
|
|
|
}
|
2005-07-13 14:51:57 +00:00
|
|
|
#endif
|
2005-03-31 23:22:44 +00:00
|
|
|
|
2002-10-30 23:04:06 +00:00
|
|
|
/* Failed - buu - try the fallback trick. */
|
|
|
|
if (bundle == nil)
|
|
|
|
{
|
|
|
|
bundlePath = nil;
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
2000-10-28 21:58:48 +00:00
|
|
|
}
|
2002-10-30 23:04:06 +00:00
|
|
|
|
|
|
|
if (bundlePath == nil)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
2002-10-30 23:04:06 +00:00
|
|
|
/* NICOLA: In an ideal world, the following is just a hack
|
|
|
|
* for when objc_get_symbol_path() fails! But in real life
|
|
|
|
* objc_get_symbol_path() is risky (some platforms don't
|
|
|
|
* have it at all!), so this hack might be used a lot! It
|
|
|
|
* must be quite robust. We try to look for the framework
|
2005-03-31 23:22:44 +00:00
|
|
|
* in the standard GNUstep installation dirs and in the main
|
|
|
|
* bundle. This should be reasonably safe if the user is
|
|
|
|
* not being too clever ... :-)
|
2002-10-30 23:04:06 +00:00
|
|
|
*/
|
2005-03-31 23:22:44 +00:00
|
|
|
bundlePath = _find_framework(name);
|
|
|
|
if (bundlePath == nil)
|
2002-10-30 23:04:06 +00:00
|
|
|
{
|
2005-03-31 23:22:44 +00:00
|
|
|
bundlePath = [[NSBundle mainBundle] pathForResource: name
|
|
|
|
ofType: @"framework"
|
|
|
|
inDirectory: @"Frameworks"];
|
2002-10-30 23:04:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Try creating the bundle. */
|
2005-03-31 23:22:44 +00:00
|
|
|
if (bundlePath != nil)
|
|
|
|
{
|
|
|
|
bundle = [[self alloc] initWithPath: bundlePath];
|
|
|
|
}
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2002-01-16 13:52:39 +00:00
|
|
|
if (bundle == nil)
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
NSWarnMLog (@"Could not find framework %@ in any standard location",
|
|
|
|
name);
|
2002-01-16 13:52:39 +00:00
|
|
|
return;
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2000-10-28 21:58:48 +00:00
|
|
|
bundle->_bundleType = NSBUNDLE_FRAMEWORK;
|
|
|
|
bundle->_codeLoaded = YES;
|
2002-01-16 13:03:45 +00:00
|
|
|
/* frameworkVersion is something like 'A'. */
|
2000-10-28 21:58:48 +00:00
|
|
|
bundle->_frameworkVersion = RETAIN([frameworkClass frameworkVersion]);
|
|
|
|
bundle->_bundleClasses = RETAIN([NSMutableArray arrayWithCapacity: 2]);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2002-01-16 13:03:45 +00:00
|
|
|
/* A NULL terminated list of class names - the classes contained
|
2002-01-16 13:52:39 +00:00
|
|
|
in the framework. */
|
2000-10-28 21:58:48 +00:00
|
|
|
fmClasses = [frameworkClass frameworkClasses];
|
2002-10-13 10:29:54 +00:00
|
|
|
|
2002-01-16 13:03:45 +00:00
|
|
|
while (*fmClasses != NULL)
|
2000-10-28 21:58:48 +00:00
|
|
|
{
|
|
|
|
NSValue *value;
|
|
|
|
Class class = NSClassFromString(*fmClasses);
|
2002-10-13 10:29:54 +00:00
|
|
|
|
2000-10-28 21:58:48 +00:00
|
|
|
value = [NSValue valueWithNonretainedObject: class];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
[bundle->_bundleClasses addObject: value];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2000-10-28 21:58:48 +00:00
|
|
|
fmClasses++;
|
|
|
|
}
|
2002-10-13 10:29:54 +00:00
|
|
|
|
2002-10-30 23:04:06 +00:00
|
|
|
/* If _loadingBundle is not nil, it means we reached this point
|
|
|
|
* while loading a bundle. This can happen if the framework is
|
|
|
|
* linked into the bundle (then, the dynamic linker
|
|
|
|
* automatically drags in the framework when the bundle is
|
|
|
|
* loaded). But then, the classes in the framework should be
|
2003-09-08 02:47:50 +00:00
|
|
|
* removed from the list of classes in the bundle. Check that
|
|
|
|
* _loadingBundle != bundle which happens on Windows machines when
|
|
|
|
* loading in Frameworks.
|
2002-10-30 23:04:06 +00:00
|
|
|
*/
|
2003-09-08 02:47:50 +00:00
|
|
|
if (_loadingBundle != nil && _loadingBundle != bundle)
|
2002-10-30 23:04:06 +00:00
|
|
|
{
|
2006-05-10 03:18:08 +00:00
|
|
|
[_loadingBundle->_bundleClasses
|
|
|
|
removeObjectsInArray: bundle->_bundleClasses];
|
2002-10-30 23:04:06 +00:00
|
|
|
}
|
2000-10-28 21:58:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
+ (NSString*) _gnustep_target_cpu
|
|
|
|
{
|
|
|
|
return gnustep_target_cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString*) _gnustep_target_dir
|
|
|
|
{
|
|
|
|
return gnustep_target_dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString*) _gnustep_target_os
|
|
|
|
{
|
|
|
|
return gnustep_target_os;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString*) _library_combo
|
|
|
|
{
|
|
|
|
return library_combo;
|
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
@end
|
|
|
|
|
2002-10-25 15:12:35 +00:00
|
|
|
/*
|
|
|
|
Mirko:
|
|
|
|
|
|
|
|
The gnu-runtime calls the +load method of each class before the
|
|
|
|
_bundle_load_callback() is called and we can't provide the list of classes
|
|
|
|
ready for this method.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
typedef struct {
|
|
|
|
@defs(NSBundle)
|
|
|
|
} *bptr;
|
|
|
|
|
1995-03-18 17:15:15 +00:00
|
|
|
void
|
2001-05-29 02:38:22 +00:00
|
|
|
_bundle_load_callback(Class theClass, struct objc_category *theCategory)
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1998-11-19 21:26:27 +00:00
|
|
|
NSCAssert(_loadingBundle, NSInternalInconsistencyException);
|
2002-10-13 10:29:54 +00:00
|
|
|
NSCAssert(_loadingFrameworks, NSInternalInconsistencyException);
|
2000-10-28 21:58:48 +00:00
|
|
|
|
2002-02-26 17:36:13 +00:00
|
|
|
/* We never record categories - if this is a category, just do nothing. */
|
|
|
|
if (theCategory != 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-01-16 13:52:39 +00:00
|
|
|
/* Don't store the internal NSFramework_xxx class into the list of
|
2002-10-13 10:29:54 +00:00
|
|
|
bundle classes, but store the linked frameworks in _loadingFrameworks */
|
2005-02-22 11:22:44 +00:00
|
|
|
if (strlen (theClass->name) > 12 && !strncmp ("NSFramework_",
|
2002-02-26 17:36:13 +00:00
|
|
|
theClass->name, 12))
|
2000-11-15 11:40:00 +00:00
|
|
|
{
|
2002-10-13 10:29:54 +00:00
|
|
|
if (_currentFrameworkName)
|
|
|
|
{
|
|
|
|
const char *frameworkName;
|
|
|
|
|
|
|
|
frameworkName = [_currentFrameworkName cString];
|
|
|
|
|
|
|
|
if (!strcmp(theClass->name, frameworkName))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
[_loadingFrameworks
|
|
|
|
addObject: [NSValue valueWithNonretainedObject: (id)theClass]];
|
2005-02-22 11:22:44 +00:00
|
|
|
return;
|
2000-11-15 11:40:00 +00:00
|
|
|
}
|
2000-10-28 21:58:48 +00:00
|
|
|
|
2002-02-26 17:36:13 +00:00
|
|
|
/* Store classes (but don't store categories) */
|
2006-05-10 03:18:08 +00:00
|
|
|
[((bptr)_loadingBundle)->_bundleClasses addObject:
|
|
|
|
[NSValue valueWithNonretainedObject: (id)theClass]];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2000-10-28 21:58:48 +00:00
|
|
|
|
1995-03-18 17:15:15 +00:00
|
|
|
@implementation NSBundle
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
+ (void) initialize
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1998-05-13 19:25:38 +00:00
|
|
|
if (self == [NSBundle class])
|
|
|
|
{
|
2000-10-28 21:58:48 +00:00
|
|
|
NSDictionary *env;
|
|
|
|
void *state = NULL;
|
|
|
|
Class class;
|
1998-08-12 14:41:20 +00:00
|
|
|
|
1999-04-23 13:56:22 +00:00
|
|
|
_emptyTable = RETAIN([NSDictionary dictionary]);
|
|
|
|
|
1998-05-13 19:25:38 +00:00
|
|
|
/* Need to make this recursive since both mainBundle and initWithPath:
|
|
|
|
want to lock the thread */
|
1998-05-15 21:01:11 +00:00
|
|
|
load_lock = [NSRecursiveLock new];
|
1998-08-12 14:41:20 +00:00
|
|
|
env = [[NSProcessInfo processInfo] environment];
|
|
|
|
if (env)
|
|
|
|
{
|
1999-04-22 21:26:10 +00:00
|
|
|
NSString *str;
|
1998-08-12 14:41:20 +00:00
|
|
|
|
1998-08-12 15:07:03 +00:00
|
|
|
if ((str = [env objectForKey: @"GNUSTEP_TARGET_CPU"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_cpu = RETAIN(str);
|
1998-08-12 15:07:03 +00:00
|
|
|
else if ((str = [env objectForKey: @"GNUSTEP_HOST_CPU"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_cpu = RETAIN(str);
|
1998-08-12 14:41:20 +00:00
|
|
|
|
1998-08-12 15:07:03 +00:00
|
|
|
if ((str = [env objectForKey: @"GNUSTEP_TARGET_OS"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_os = RETAIN(str);
|
1998-08-12 15:07:03 +00:00
|
|
|
else if ((str = [env objectForKey: @"GNUSTEP_HOST_OS"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
gnustep_target_os = RETAIN(str);
|
1998-08-12 14:41:20 +00:00
|
|
|
|
2002-02-08 13:39:51 +00:00
|
|
|
if ((str = [env objectForKey: @"GNUSTEP_TARGET_DIR"]) != nil)
|
|
|
|
gnustep_target_dir = RETAIN(str);
|
|
|
|
else if ((str = [env objectForKey: @"GNUSTEP_HOST_DIR"]) != nil)
|
|
|
|
gnustep_target_dir = RETAIN(str);
|
|
|
|
|
1998-08-12 15:07:03 +00:00
|
|
|
if ((str = [env objectForKey: @"LIBRARY_COMBO"]) != nil)
|
1999-04-23 13:56:22 +00:00
|
|
|
library_combo = RETAIN(str);
|
1999-04-22 21:26:10 +00:00
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
_launchDirectory = RETAIN([[NSFileManager defaultManager]
|
|
|
|
currentDirectoryPath]);
|
1999-04-22 21:26:10 +00:00
|
|
|
|
2006-04-09 16:16:07 +00:00
|
|
|
_gnustep_bundle = RETAIN([self bundleForLibrary: @"gnustep-base"]);
|
2000-10-28 21:58:48 +00:00
|
|
|
|
|
|
|
#if 0
|
2002-02-26 18:06:51 +00:00
|
|
|
_loadingBundle = [self mainBundle];
|
2000-10-28 21:58:48 +00:00
|
|
|
handle = objc_open_main_module(stderr);
|
|
|
|
printf("%08x\n", handle);
|
|
|
|
#endif
|
2001-05-29 02:38:22 +00:00
|
|
|
#if NeXT_RUNTIME
|
|
|
|
{
|
|
|
|
int i, numClasses = 0, newNumClasses = objc_getClassList(NULL, 0);
|
|
|
|
Class *classes = NULL;
|
|
|
|
while (numClasses < newNumClasses) {
|
|
|
|
numClasses = newNumClasses;
|
|
|
|
classes = realloc(classes, sizeof(Class) * numClasses);
|
|
|
|
newNumClasses = objc_getClassList(classes, numClasses);
|
|
|
|
}
|
|
|
|
for (i = 0; i < numClasses; i++)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
2002-02-26 18:06:51 +00:00
|
|
|
[self _addFrameworkFromClass: classes[i]];
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
2001-05-29 02:38:22 +00:00
|
|
|
free(classes);
|
|
|
|
}
|
|
|
|
#else
|
2002-12-03 20:30:08 +00:00
|
|
|
{
|
|
|
|
int i, numBufClasses = 10, numClasses = 0;
|
|
|
|
Class *classes;
|
|
|
|
|
|
|
|
classes = malloc(sizeof(Class) * numBufClasses);
|
|
|
|
|
|
|
|
while ((class = objc_next_class(&state)))
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
unsigned int len = strlen (class->name);
|
2002-12-03 20:30:08 +00:00
|
|
|
|
|
|
|
if (len > 12 * sizeof(char)
|
2003-01-03 20:14:47 +00:00
|
|
|
&& !strncmp("NSFramework_", class->name, 12))
|
|
|
|
{
|
|
|
|
classes[numClasses++] = class;
|
|
|
|
}
|
2002-12-03 20:30:08 +00:00
|
|
|
if (numClasses == numBufClasses)
|
|
|
|
{
|
|
|
|
Class *ptr;
|
|
|
|
|
|
|
|
numClasses += 10;
|
|
|
|
ptr = realloc(classes, sizeof(Class) * numClasses);
|
|
|
|
|
|
|
|
if (!ptr)
|
|
|
|
break;
|
|
|
|
|
|
|
|
classes = ptr;
|
|
|
|
}
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
2002-12-03 20:30:08 +00:00
|
|
|
|
|
|
|
for (i = 0; i < numClasses; i++)
|
|
|
|
{
|
|
|
|
[self _addFrameworkFromClass: classes[i]];
|
|
|
|
}
|
|
|
|
free(classes);
|
|
|
|
}
|
2001-05-29 02:38:22 +00:00
|
|
|
#endif
|
2000-10-28 21:58:48 +00:00
|
|
|
#if 0
|
2002-01-16 13:03:45 +00:00
|
|
|
// _bundle_load_callback(class, NULL);
|
|
|
|
// bundle = (NSBundle *)NSMapGet(_bundles, bundlePath);
|
2000-10-28 21:58:48 +00:00
|
|
|
|
|
|
|
objc_close_main_module(handle);
|
|
|
|
_loadingBundle = nil;
|
|
|
|
#endif
|
1998-08-12 14:41:20 +00:00
|
|
|
}
|
1998-05-13 19:25:38 +00:00
|
|
|
}
|
|
|
|
}
|
1995-08-02 16:58:51 +00:00
|
|
|
|
2003-05-08 17:29:52 +00:00
|
|
|
/**
|
|
|
|
* Returns an array of all the bundles which do not belong to frameworks.<br />
|
|
|
|
* This always contains the main bundle.
|
|
|
|
*/
|
1998-11-16 19:36:51 +00:00
|
|
|
+ (NSArray *) allBundles
|
|
|
|
{
|
1999-04-14 08:48:32 +00:00
|
|
|
NSMutableArray *array = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
|
2000-05-27 05:05:10 +00:00
|
|
|
[load_lock lock];
|
2005-02-22 11:22:44 +00:00
|
|
|
if (!_mainBundle)
|
2003-05-08 17:29:52 +00:00
|
|
|
{
|
|
|
|
[self mainBundle];
|
|
|
|
}
|
2002-05-27 10:00:05 +00:00
|
|
|
if (_bundles != 0)
|
1999-04-14 08:48:32 +00:00
|
|
|
{
|
2002-05-27 10:00:05 +00:00
|
|
|
NSMapEnumerator enumerate;
|
|
|
|
void *key;
|
|
|
|
NSBundle *bundle;
|
2000-10-28 21:58:48 +00:00
|
|
|
|
2002-05-27 10:00:05 +00:00
|
|
|
enumerate = NSEnumerateMapTable(_bundles);
|
|
|
|
while (NSNextMapEnumeratorPair(&enumerate, &key, (void **)&bundle))
|
1999-04-14 08:48:32 +00:00
|
|
|
{
|
2002-05-27 10:00:05 +00:00
|
|
|
if (bundle->_bundleType == NSBUNDLE_FRAMEWORK)
|
2002-05-28 05:23:36 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2002-05-27 10:00:05 +00:00
|
|
|
if ([array indexOfObjectIdenticalTo: bundle] == NSNotFound)
|
|
|
|
{
|
|
|
|
[array addObject: bundle];
|
|
|
|
}
|
1999-04-14 08:48:32 +00:00
|
|
|
}
|
2002-05-28 05:23:36 +00:00
|
|
|
NSEndMapTableEnumeration(&enumerate);
|
1999-04-14 08:48:32 +00:00
|
|
|
}
|
2000-05-27 05:05:10 +00:00
|
|
|
[load_lock unlock];
|
1999-04-14 08:48:32 +00:00
|
|
|
return array;
|
1998-11-16 19:36:51 +00:00
|
|
|
}
|
|
|
|
|
2003-05-08 17:29:52 +00:00
|
|
|
/**
|
|
|
|
* Returns an array containing all the known bundles representing frameworks.
|
|
|
|
*/
|
1998-11-16 19:36:51 +00:00
|
|
|
+ (NSArray *) allFrameworks
|
|
|
|
{
|
2000-10-28 21:58:48 +00:00
|
|
|
NSMapEnumerator enumerate;
|
|
|
|
NSMutableArray *array = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
void *key;
|
|
|
|
NSBundle *bundle;
|
|
|
|
|
|
|
|
[load_lock lock];
|
|
|
|
enumerate = NSEnumerateMapTable(_bundles);
|
|
|
|
while (NSNextMapEnumeratorPair(&enumerate, &key, (void **)&bundle))
|
|
|
|
{
|
|
|
|
if (bundle->_bundleType == NSBUNDLE_FRAMEWORK
|
|
|
|
&& [array indexOfObjectIdenticalTo: bundle] == NSNotFound)
|
|
|
|
{
|
|
|
|
[array addObject: bundle];
|
|
|
|
}
|
|
|
|
}
|
2002-05-28 05:23:36 +00:00
|
|
|
NSEndMapTableEnumeration(&enumerate);
|
2000-10-28 21:58:48 +00:00
|
|
|
[load_lock unlock];
|
|
|
|
return array;
|
1998-11-16 19:36:51 +00:00
|
|
|
}
|
|
|
|
|
2003-05-08 17:29:52 +00:00
|
|
|
/**
|
|
|
|
* For an application, returns the main bundle of the application.<br />
|
|
|
|
* For a tool, returns the main bundle associated with the tool.<br />
|
|
|
|
* <br />
|
2005-02-22 11:22:44 +00:00
|
|
|
* For an application, the structure is as follows -
|
|
|
|
* <p>
|
2003-05-08 17:29:52 +00:00
|
|
|
* The executable is Gomoku.app/ix86/linux-gnu/gnu-gnu-gnu/Gomoku
|
|
|
|
* and the main bundle directory is Gomoku.app/.
|
2005-02-22 11:22:44 +00:00
|
|
|
* </p>
|
|
|
|
* For a tool, the structure is as follows -
|
2003-05-08 17:29:52 +00:00
|
|
|
* <p>
|
|
|
|
* The executable is xxx/Tools/ix86/linux-gnu/gnu-gnu-gnu/Control
|
|
|
|
* and the main bundle directory is xxx/Tools/Resources/Control.
|
2005-02-22 11:22:44 +00:00
|
|
|
* </p>
|
|
|
|
* <p>(when the tool has not yet been installed, it's similar -
|
2003-05-08 17:29:52 +00:00
|
|
|
* xxx/shared_obj/ix86/linux-gnu/gnu-gnu-gnu/Control
|
|
|
|
* and the main bundle directory is xxx/Resources/Control).
|
2005-02-22 11:22:44 +00:00
|
|
|
* </p>
|
2003-05-08 17:29:52 +00:00
|
|
|
* <p>(For a flattened structure, the structure is the same without the
|
|
|
|
* ix86/linux-gnu/gnu-gnu-gnu directories).
|
|
|
|
* </p>
|
|
|
|
*/
|
|
|
|
+ (NSBundle *) mainBundle
|
1998-05-13 19:25:38 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock lock];
|
2005-02-22 11:22:44 +00:00
|
|
|
if (!_mainBundle)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2002-02-09 01:06:05 +00:00
|
|
|
/* We figure out the main bundle directory by examining the location
|
|
|
|
of the executable on disk. */
|
1997-10-30 22:23:50 +00:00
|
|
|
NSString *path, *s;
|
2002-02-09 01:06:05 +00:00
|
|
|
|
|
|
|
/* We don't know at the beginning if it's a tool or an application. */
|
|
|
|
BOOL isApplication = YES;
|
|
|
|
|
|
|
|
/* If it's a tool, we will need the tool name. Since we don't
|
|
|
|
know yet if it's a tool or an application, we always store
|
|
|
|
the executable name here - just in case it turns out it's a
|
|
|
|
tool. */
|
2006-04-09 16:16:07 +00:00
|
|
|
NSString *toolName = [ExecutablePath() lastPathComponent];
|
2004-02-27 14:08:00 +00:00
|
|
|
#if defined(__WIN32__)
|
|
|
|
toolName = [toolName stringByDeletingPathExtension];
|
|
|
|
#endif
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Strip off the name of the program */
|
2006-04-09 16:16:07 +00:00
|
|
|
path = [ExecutablePath() stringByDeletingLastPathComponent];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
2002-02-09 01:06:05 +00:00
|
|
|
/* We now need to chop off the extra subdirectories, the library
|
|
|
|
combo and the target cpu/os if they exist. The executable
|
|
|
|
and this library should match so that is why we can use the
|
1997-10-30 22:23:50 +00:00
|
|
|
compiled-in settings. */
|
|
|
|
/* library combo */
|
|
|
|
s = [path lastPathComponent];
|
|
|
|
if ([s isEqual: library_combo])
|
2002-02-09 01:06:05 +00:00
|
|
|
{
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
|
|
|
}
|
1997-10-30 22:23:50 +00:00
|
|
|
/* target os */
|
|
|
|
s = [path lastPathComponent];
|
|
|
|
if ([s isEqual: gnustep_target_os])
|
2002-02-09 01:06:05 +00:00
|
|
|
{
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
|
|
|
}
|
1997-10-30 22:23:50 +00:00
|
|
|
/* target cpu */
|
|
|
|
s = [path lastPathComponent];
|
|
|
|
if ([s isEqual: gnustep_target_cpu])
|
2002-02-09 01:06:05 +00:00
|
|
|
{
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
|
|
|
}
|
1998-09-03 14:35:49 +00:00
|
|
|
/* object dir */
|
|
|
|
s = [path lastPathComponent];
|
|
|
|
if ([s hasSuffix: @"_obj"])
|
2002-02-09 01:06:05 +00:00
|
|
|
{
|
|
|
|
path = [path stringByDeletingLastPathComponent];
|
|
|
|
/* if it has an object dir it can only be a
|
|
|
|
non-yet-installed tool. */
|
|
|
|
isApplication = NO;
|
|
|
|
}
|
2002-05-21 12:53:46 +00:00
|
|
|
|
2002-02-09 01:06:05 +00:00
|
|
|
if (isApplication == YES)
|
2003-05-08 17:29:52 +00:00
|
|
|
{
|
|
|
|
s = [path lastPathComponent];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2003-05-08 17:29:52 +00:00
|
|
|
if ((([s hasSuffix: @".app"] == NO)
|
|
|
|
&& ([s hasSuffix: @".debug"] == NO)
|
|
|
|
&& ([s hasSuffix: @".profile"] == NO))
|
|
|
|
// GNUstep Web
|
|
|
|
&& (([s hasSuffix: @".gswa"] == NO)
|
|
|
|
&& ([s hasSuffix: @".woa"] == NO)))
|
|
|
|
{
|
|
|
|
isApplication = NO;
|
|
|
|
}
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2002-02-09 01:06:05 +00:00
|
|
|
if (isApplication == NO)
|
|
|
|
{
|
|
|
|
path = [path stringByAppendingPathComponent: @"Resources"];
|
|
|
|
path = [path stringByAppendingPathComponent: toolName];
|
|
|
|
}
|
1997-10-30 22:23:50 +00:00
|
|
|
|
1999-03-11 11:07:21 +00:00
|
|
|
NSDebugMLLog(@"NSBundle", @"Found main in %@\n", path);
|
2002-02-26 18:06:51 +00:00
|
|
|
/* We do alloc and init separately so initWithPath: knows we are
|
|
|
|
the _mainBundle. Please note that we do *not* autorelease
|
|
|
|
mainBundle, because we don't want it to be ever released. */
|
|
|
|
_mainBundle = [self alloc];
|
2004-11-20 20:14:24 +00:00
|
|
|
/* Please note that _mainBundle should *not* be nil. */
|
|
|
|
_mainBundle = [_mainBundle initWithPath: path];
|
|
|
|
NSAssert(_mainBundle != nil, NSInternalInconsistencyException);
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock unlock];
|
|
|
|
return _mainBundle;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2003-05-08 17:29:52 +00:00
|
|
|
/**
|
|
|
|
* Returns the bundle whose code contains the specified class.<br />
|
|
|
|
* NB: We will not find a class if the bundle has not been loaded yet!
|
|
|
|
*/
|
1997-01-06 22:30:33 +00:00
|
|
|
+ (NSBundle *) bundleForClass: (Class)aClass
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
2006-05-10 03:18:08 +00:00
|
|
|
void *key;
|
|
|
|
NSBundle *bundle;
|
1997-01-06 22:30:33 +00:00
|
|
|
NSMapEnumerator enumerate;
|
2006-05-10 03:18:08 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
if (!aClass)
|
|
|
|
return nil;
|
|
|
|
|
2000-05-27 05:05:10 +00:00
|
|
|
[load_lock lock];
|
1997-01-06 22:30:33 +00:00
|
|
|
bundle = nil;
|
|
|
|
enumerate = NSEnumerateMapTable(_bundles);
|
|
|
|
while (NSNextMapEnumeratorPair(&enumerate, &key, (void **)&bundle))
|
|
|
|
{
|
2000-10-28 21:58:48 +00:00
|
|
|
int i, j;
|
2006-05-10 03:18:08 +00:00
|
|
|
NSArray *bundleClasses = bundle->_bundleClasses;
|
2000-10-28 21:58:48 +00:00
|
|
|
BOOL found = NO;
|
|
|
|
|
|
|
|
j = [bundleClasses count];
|
|
|
|
for (i = 0; i < j && found == NO; i++)
|
|
|
|
{
|
|
|
|
if ([[bundleClasses objectAtIndex: i]
|
2000-11-01 12:31:21 +00:00
|
|
|
nonretainedObjectValue] == aClass)
|
2000-10-28 21:58:48 +00:00
|
|
|
found = YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found == YES)
|
1997-01-06 22:30:33 +00:00
|
|
|
break;
|
2000-10-28 21:58:48 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
bundle = nil;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
2006-05-10 03:18:08 +00:00
|
|
|
|
|
|
|
if (bundle == nil)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2006-05-10 03:18:08 +00:00
|
|
|
/* Is it in the main bundle or a library? */
|
1997-01-06 22:30:33 +00:00
|
|
|
if (class_is_class(aClass))
|
2006-05-10 03:18:08 +00:00
|
|
|
{
|
|
|
|
NSString *lib;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Take the path to the binary containing the class and
|
|
|
|
* convert it to the format for a library name as used
|
|
|
|
* for obtaining a library resource bundle.
|
|
|
|
*/
|
|
|
|
lib = objc_get_symbol_path (aClass, NULL);
|
|
|
|
if ([lib isEqual: ExecutablePath()] == YES)
|
|
|
|
{
|
|
|
|
lib = nil; // In program, not library.
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the library bundle ... if there wasn't one
|
|
|
|
* then we will assume the class was in the program
|
|
|
|
* executable and return the mainBundle instead.
|
|
|
|
*/
|
|
|
|
bundle = [NSBundle bundleForLibrary: lib];
|
|
|
|
if (bundle == nil)
|
|
|
|
{
|
|
|
|
bundle = [self mainBundle];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add the class to the list of classes known to be in
|
|
|
|
* the library or executable. We didn't find it there
|
|
|
|
* to start with, so we know it's safe to add now.
|
|
|
|
*/
|
|
|
|
if (bundle->_bundleClasses == nil)
|
|
|
|
{
|
|
|
|
bundle->_bundleClasses
|
|
|
|
= [[NSMutableArray alloc] initWithCapacity: 2];
|
|
|
|
}
|
|
|
|
[bundle->_bundleClasses addObject:
|
|
|
|
[NSValue valueWithNonretainedObject: aClass]];
|
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
2006-05-10 03:18:08 +00:00
|
|
|
[load_lock unlock];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
return bundle;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2001-12-17 14:31:42 +00:00
|
|
|
+ (NSBundle*) bundleWithPath: (NSString*)path
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
2002-02-26 18:06:51 +00:00
|
|
|
return AUTORELEASE([[self alloc] initWithPath: path]);
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2006-05-15 00:49:06 +00:00
|
|
|
+ (NSBundle*) bundleWithIdentifier: (NSString*)identifier
|
|
|
|
{
|
|
|
|
NSBundle *bundle = nil;
|
|
|
|
|
|
|
|
[load_lock lock];
|
|
|
|
if (_byIdentifier)
|
|
|
|
{
|
|
|
|
bundle = (NSBundle *)NSMapGet(_byIdentifier, identifier);
|
|
|
|
if (bundle != nil)
|
|
|
|
{
|
|
|
|
RETAIN(bundle); /* retain - look as if we were alloc'ed */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[load_lock unlock];
|
|
|
|
return AUTORELEASE(bundle);
|
|
|
|
}
|
|
|
|
|
2001-12-17 14:31:42 +00:00
|
|
|
- (id) initWithPath: (NSString*)path
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
2006-05-15 00:49:06 +00:00
|
|
|
NSString *identifier;
|
|
|
|
|
2004-11-20 20:14:24 +00:00
|
|
|
self = [super init];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
if (!path || [path length] == 0)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2005-04-01 10:57:35 +00:00
|
|
|
NSDebugMLog(@"No path specified for bundle");
|
2002-02-25 15:28:06 +00:00
|
|
|
[self dealloc];
|
1997-01-06 22:30:33 +00:00
|
|
|
return nil;
|
|
|
|
}
|
2005-06-21 12:57:20 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure we have an absolute and fully expanded path,
|
|
|
|
* so we can manipulate it without having to worry about
|
|
|
|
* details like that throughout the code.
|
|
|
|
*/
|
2000-02-24 22:16:53 +00:00
|
|
|
if ([path isAbsolutePath] == NO)
|
|
|
|
{
|
2005-11-20 20:26:32 +00:00
|
|
|
NSWarnMLog(@"NSBundle -initWithPath: requires absolute path names, "
|
|
|
|
@"given '%@'", path);
|
2000-02-24 22:16:53 +00:00
|
|
|
path = [[[NSFileManager defaultManager] currentDirectoryPath]
|
2002-02-25 15:28:06 +00:00
|
|
|
stringByAppendingPathComponent: path];
|
2000-02-24 22:16:53 +00:00
|
|
|
}
|
2006-05-15 00:49:06 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Standardize the path so we can be sure that cache lookup is consistent.
|
|
|
|
*/
|
|
|
|
path = [path stringByStandardizingPath];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* Check if we were already initialized for this directory */
|
2000-05-27 05:05:10 +00:00
|
|
|
[load_lock lock];
|
2002-10-30 23:04:06 +00:00
|
|
|
if (_bundles)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2006-05-15 00:49:06 +00:00
|
|
|
NSBundle *bundle = (NSBundle *)NSMapGet(_bundles, path);
|
|
|
|
|
|
|
|
if (bundle != nil)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-05-27 05:05:10 +00:00
|
|
|
RETAIN(bundle); /* retain - look as if we were alloc'ed */
|
|
|
|
[load_lock unlock];
|
1997-01-06 22:30:33 +00:00
|
|
|
[self dealloc];
|
2000-05-27 05:05:10 +00:00
|
|
|
return bundle;
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
|
|
|
}
|
2000-05-27 05:05:10 +00:00
|
|
|
[load_lock unlock];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
2000-06-06 16:50:52 +00:00
|
|
|
if (bundle_directory_readable(path) == NO)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-05-27 05:05:10 +00:00
|
|
|
NSDebugMLLog(@"NSBundle", @"Could not access path %@ for bundle", path);
|
2004-11-20 20:14:24 +00:00
|
|
|
// if this is not the main bundle ... deallocate and return.
|
|
|
|
if (self != _mainBundle)
|
|
|
|
{
|
|
|
|
[self dealloc];
|
|
|
|
return nil;
|
|
|
|
}
|
1995-09-21 17:42:46 +00:00
|
|
|
}
|
|
|
|
|
2000-05-27 05:05:10 +00:00
|
|
|
_path = [path copy];
|
2000-10-28 21:58:48 +00:00
|
|
|
|
|
|
|
if ([[[_path lastPathComponent] pathExtension] isEqual: @"framework"] == YES)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
|
|
|
_bundleType = (unsigned int)NSBUNDLE_FRAMEWORK;
|
|
|
|
}
|
2000-10-28 21:58:48 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (self == _mainBundle)
|
|
|
|
_bundleType = (unsigned int)NSBUNDLE_APPLICATION;
|
|
|
|
else
|
|
|
|
_bundleType = (unsigned int)NSBUNDLE_BUNDLE;
|
|
|
|
}
|
2000-05-27 05:05:10 +00:00
|
|
|
|
2006-05-15 00:49:06 +00:00
|
|
|
identifier = [self bundleIdentifier];
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock lock];
|
|
|
|
if (!_bundles)
|
|
|
|
{
|
|
|
|
_bundles = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
2006-05-15 00:49:06 +00:00
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
}
|
|
|
|
if (!_byIdentifier)
|
|
|
|
{
|
|
|
|
_byIdentifier = NSCreateMapTable(NSObjectMapKeyCallBacks,
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
}
|
|
|
|
if (identifier != nil)
|
|
|
|
{
|
|
|
|
NSBundle *bundle = (NSBundle *)NSMapGet(_byIdentifier, identifier);
|
|
|
|
|
|
|
|
if (bundle != nil)
|
|
|
|
{
|
|
|
|
RETAIN(bundle); /* retain - look as if we were alloc'ed */
|
|
|
|
[load_lock unlock];
|
|
|
|
[self dealloc];
|
|
|
|
return bundle;
|
|
|
|
}
|
|
|
|
NSMapInsert(_byIdentifier, identifier, self);
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
2000-05-27 05:05:10 +00:00
|
|
|
NSMapInsert(_bundles, _path, self);
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock unlock];
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
2006-05-15 00:49:06 +00:00
|
|
|
if ([self isLoaded] == YES && self != _mainBundle
|
|
|
|
&& self ->_bundleType != NSBUNDLE_LIBRARY)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Prevent unloading of bundles where code has been loaded ...
|
|
|
|
* the objc runtime does not currently support unloading of
|
|
|
|
* dynamically loaded code, so we want to prevent a bundle
|
|
|
|
* being loaded twice.
|
|
|
|
*/
|
|
|
|
RETAIN(self);
|
|
|
|
return;
|
|
|
|
}
|
2000-05-27 05:05:10 +00:00
|
|
|
if (_path != nil)
|
1999-05-06 19:37:45 +00:00
|
|
|
{
|
2006-05-15 00:49:06 +00:00
|
|
|
NSString *identifier = [self bundleIdentifier];
|
|
|
|
|
2000-05-27 05:05:10 +00:00
|
|
|
[load_lock lock];
|
1999-05-06 19:37:45 +00:00
|
|
|
NSMapRemove(_bundles, _path);
|
2006-05-15 00:49:06 +00:00
|
|
|
if (identifier != nil)
|
|
|
|
{
|
|
|
|
NSMapRemove(_byIdentifier, identifier);
|
|
|
|
}
|
2000-05-27 05:05:10 +00:00
|
|
|
[load_lock unlock];
|
1999-05-06 19:37:45 +00:00
|
|
|
RELEASE(_path);
|
|
|
|
}
|
2000-10-28 21:58:48 +00:00
|
|
|
TEST_RELEASE(_frameworkVersion);
|
1999-05-11 10:11:48 +00:00
|
|
|
TEST_RELEASE(_bundleClasses);
|
|
|
|
TEST_RELEASE(_infoDict);
|
|
|
|
TEST_RELEASE(_localizations);
|
1997-01-06 22:30:33 +00:00
|
|
|
[super dealloc];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
- (NSString*) description
|
|
|
|
{
|
|
|
|
return [[super description] stringByAppendingFormat:
|
|
|
|
@" <%@>%@", [self bundlePath], [self isLoaded] ? @" (loaded)" : @""];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) bundlePath
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
return _path;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (Class) classNamed: (NSString *)className
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
2000-10-28 21:58:48 +00:00
|
|
|
int i, j;
|
1997-01-06 22:30:33 +00:00
|
|
|
Class theClass = Nil;
|
2000-10-28 21:58:48 +00:00
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
if (!_codeLoaded)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
if (self != _mainBundle && ![self load])
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
NSLog(@"No classes in bundle");
|
|
|
|
return Nil;
|
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2000-05-11 04:03:51 +00:00
|
|
|
if (self == _mainBundle || self == _gnustep_bundle)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
theClass = NSClassFromString(className);
|
|
|
|
if (theClass && [[self class] bundleForClass:theClass] != _mainBundle)
|
|
|
|
theClass = Nil;
|
2005-02-22 11:22:44 +00:00
|
|
|
}
|
|
|
|
else
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-10-28 21:58:48 +00:00
|
|
|
BOOL found = NO;
|
|
|
|
|
|
|
|
theClass = NSClassFromString(className);
|
2006-05-10 03:18:08 +00:00
|
|
|
[load_lock lock];
|
2000-10-28 21:58:48 +00:00
|
|
|
j = [_bundleClasses count];
|
|
|
|
|
2002-01-16 13:03:45 +00:00
|
|
|
for (i = 0; i < j && found == NO; i++)
|
2000-10-28 21:58:48 +00:00
|
|
|
{
|
2002-01-16 13:03:45 +00:00
|
|
|
Class c = [[_bundleClasses objectAtIndex: i] nonretainedObjectValue];
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
if (c == theClass)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
|
|
|
found = YES;
|
|
|
|
}
|
2000-10-28 21:58:48 +00:00
|
|
|
}
|
2006-05-10 03:18:08 +00:00
|
|
|
[load_lock unlock];
|
2000-10-28 21:58:48 +00:00
|
|
|
|
|
|
|
if (found == NO)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
|
|
|
theClass = Nil;
|
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
return theClass;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (Class) principalClass
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
2006-05-10 03:18:08 +00:00
|
|
|
NSString *class_name;
|
1997-01-06 22:30:33 +00:00
|
|
|
|
|
|
|
if (_principalClass)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
|
|
|
return _principalClass;
|
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
if ([self load] == NO)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
|
|
|
return Nil;
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
class_name = [[self infoDictionary] objectForKey: @"NSPrincipalClass"];
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
if (class_name)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
|
|
|
_principalClass = NSClassFromString(class_name);
|
|
|
|
}
|
2006-05-10 03:18:08 +00:00
|
|
|
else if (self == _gnustep_bundle)
|
|
|
|
{
|
|
|
|
_principalClass = [NSObject class];
|
|
|
|
}
|
2004-11-30 22:16:32 +00:00
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
if (_principalClass == nil)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
2006-05-10 03:18:08 +00:00
|
|
|
[load_lock lock];
|
|
|
|
if (_principalClass == nil && [_bundleClasses count] > 0)
|
|
|
|
{
|
|
|
|
_principalClass = [[_bundleClasses objectAtIndex: 0]
|
|
|
|
nonretainedObjectValue];
|
|
|
|
}
|
|
|
|
[load_lock unlock];
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
return _principalClass;
|
|
|
|
}
|
|
|
|
|
2003-02-04 21:49:35 +00:00
|
|
|
/**
|
|
|
|
* Returns YES if the receiver's code is loaded, otherwise, returns NO.
|
|
|
|
*/
|
|
|
|
- (BOOL) isLoaded
|
|
|
|
{
|
|
|
|
return _codeLoaded;
|
|
|
|
}
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
- (BOOL) load
|
|
|
|
{
|
2006-05-10 03:18:08 +00:00
|
|
|
if (self == _mainBundle || self ->_bundleType == NSBUNDLE_LIBRARY)
|
2000-05-11 04:03:51 +00:00
|
|
|
{
|
|
|
|
_codeLoaded = YES;
|
|
|
|
return YES;
|
|
|
|
}
|
2006-05-10 03:18:08 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock lock];
|
2002-10-25 15:12:35 +00:00
|
|
|
|
2006-05-15 00:49:06 +00:00
|
|
|
if (_codeLoaded == NO)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2002-11-19 20:38:51 +00:00
|
|
|
NSString *object;
|
2000-10-28 21:58:48 +00:00
|
|
|
NSEnumerator *classEnumerator;
|
|
|
|
NSMutableArray *classNames;
|
|
|
|
NSValue *class;
|
|
|
|
|
2002-11-19 20:38:51 +00:00
|
|
|
object = [self executablePath];
|
2000-05-11 04:03:51 +00:00
|
|
|
if (object == nil || [object length] == 0)
|
|
|
|
{
|
|
|
|
[load_lock unlock];
|
|
|
|
return NO;
|
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
_loadingBundle = self;
|
2006-05-10 03:18:08 +00:00
|
|
|
_bundleClasses = [[NSMutableArray alloc] initWithCapacity: 2];
|
2002-10-13 10:29:54 +00:00
|
|
|
_loadingFrameworks = RETAIN([NSMutableArray arrayWithCapacity: 2]);
|
2002-10-25 15:12:35 +00:00
|
|
|
|
|
|
|
/* This code is executed twice if a class linked in the bundle call a
|
|
|
|
NSBundle method inside +load (-principalClass). To avoid this we set
|
|
|
|
_codeLoaded before loading the bundle. */
|
|
|
|
_codeLoaded = YES;
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
if (objc_load_module([object fileSystemRepresentation],
|
2002-01-16 13:03:45 +00:00
|
|
|
stderr, _bundle_load_callback, NULL, NULL))
|
1997-09-01 21:59:51 +00:00
|
|
|
{
|
2002-10-25 15:12:35 +00:00
|
|
|
_codeLoaded = NO;
|
2002-10-13 10:29:54 +00:00
|
|
|
DESTROY(_loadingFrameworks);
|
|
|
|
DESTROY(_currentFrameworkName);
|
1997-09-01 21:59:51 +00:00
|
|
|
[load_lock unlock];
|
|
|
|
return NO;
|
|
|
|
}
|
2002-10-13 10:29:54 +00:00
|
|
|
|
|
|
|
/* We now construct the list of bundles from frameworks linked with
|
|
|
|
this one */
|
|
|
|
classEnumerator = [_loadingFrameworks objectEnumerator];
|
|
|
|
while ((class = [classEnumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[NSBundle _addFrameworkFromClass: [class nonretainedObjectValue]];
|
|
|
|
}
|
|
|
|
|
2002-02-26 18:06:51 +00:00
|
|
|
/* After we load code from a bundle, we retain the bundle until
|
|
|
|
we unload it (because we never unload bundles, that is
|
|
|
|
forever). The reason why we retain it is that we need it!
|
|
|
|
We need it to answer calls like bundleForClass:; also, users
|
|
|
|
normally want all loaded bundles to appear when they call
|
|
|
|
+allBundles. */
|
|
|
|
RETAIN (self);
|
1997-01-06 22:30:33 +00:00
|
|
|
_loadingBundle = nil;
|
2002-10-13 10:29:54 +00:00
|
|
|
|
|
|
|
DESTROY(_loadingFrameworks);
|
|
|
|
DESTROY(_currentFrameworkName);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2000-10-28 21:58:48 +00:00
|
|
|
classNames = [NSMutableArray arrayWithCapacity: [_bundleClasses count]];
|
|
|
|
classEnumerator = [_bundleClasses objectEnumerator];
|
2002-01-16 13:03:45 +00:00
|
|
|
while ((class = [classEnumerator nextObject]) != nil)
|
|
|
|
{
|
2006-05-10 03:18:08 +00:00
|
|
|
[classNames addObject:
|
|
|
|
NSStringFromClass([class nonretainedObjectValue])];
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
2000-10-28 21:58:48 +00:00
|
|
|
|
1999-05-07 13:51:37 +00:00
|
|
|
[load_lock unlock];
|
2000-10-28 21:58:48 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
2005-02-22 11:22:44 +00:00
|
|
|
postNotificationName: NSBundleDidLoadNotification
|
1997-01-06 22:30:33 +00:00
|
|
|
object: self
|
2000-10-28 21:58:48 +00:00
|
|
|
userInfo: [NSDictionary dictionaryWithObject: classNames
|
2000-11-01 12:31:21 +00:00
|
|
|
forKey: NSLoadedClasses]];
|
2000-10-28 21:58:48 +00:00
|
|
|
|
1999-05-07 13:51:37 +00:00
|
|
|
return YES;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
[load_lock unlock];
|
1997-09-01 21:59:51 +00:00
|
|
|
return YES;
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
/* This method is the backbone of the resource searching for NSBundle. It
|
|
|
|
constructs an array of paths, where each path is a possible location
|
|
|
|
for a resource in the bundle. The current algorithm for searching goes:
|
|
|
|
|
2002-11-19 20:38:51 +00:00
|
|
|
<rootPath>/Resources/<bundlePath>
|
|
|
|
<rootPath>/Resources/<bundlePath>/<language.lproj>
|
|
|
|
<rootPath>/<bundlePath>
|
|
|
|
<rootPath>/<bundlePath>/<language.lproj>
|
1997-01-06 22:30:33 +00:00
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
+ (NSArray *) _bundleResourcePathsWithRootPath: (NSString *)rootPath
|
2005-10-21 02:20:41 +00:00
|
|
|
subPath: (NSString *)subPath
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
NSString* primary;
|
|
|
|
NSString* language;
|
|
|
|
NSArray* languages;
|
|
|
|
NSMutableArray* array;
|
|
|
|
NSEnumerator* enumerate;
|
|
|
|
|
1997-05-03 17:24:31 +00:00
|
|
|
array = [NSMutableArray arrayWithCapacity: 8];
|
2001-03-03 15:58:02 +00:00
|
|
|
languages = [NSUserDefaults userLanguages];
|
1997-01-06 22:30:33 +00:00
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
primary = [rootPath stringByAppendingPathComponent: @"Resources"];
|
2005-10-21 02:20:41 +00:00
|
|
|
[array addObject: _bundle_resource_path(primary, subPath, nil)];
|
|
|
|
/* This matches OS X behavior, which only searches languages that
|
|
|
|
are in the user's preference. Don't use -preferredLocalizations -
|
|
|
|
that would cause a recursive loop. */
|
1997-01-06 22:30:33 +00:00
|
|
|
enumerate = [languages objectEnumerator];
|
|
|
|
while ((language = [enumerate nextObject]))
|
2005-10-21 02:20:41 +00:00
|
|
|
[array addObject: _bundle_resource_path(primary, subPath, language)];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
primary = rootPath;
|
2005-10-21 02:20:41 +00:00
|
|
|
[array addObject: _bundle_resource_path(primary, subPath, nil)];
|
1997-01-06 22:30:33 +00:00
|
|
|
enumerate = [languages objectEnumerator];
|
|
|
|
while ((language = [enumerate nextObject]))
|
2005-10-21 02:20:41 +00:00
|
|
|
[array addObject: _bundle_resource_path(primary, subPath, language)];
|
1997-05-03 17:24:31 +00:00
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
return array;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-05-03 17:17:08 +00:00
|
|
|
+ (NSString *) pathForResource: (NSString *)name
|
2000-10-28 21:58:48 +00:00
|
|
|
ofType: (NSString *)ext
|
|
|
|
inRootPath: (NSString *)rootPath
|
2005-10-21 02:20:41 +00:00
|
|
|
inDirectory: (NSString *)subPath
|
2000-10-28 21:58:48 +00:00
|
|
|
withVersion: (int)version
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
2000-06-06 16:50:52 +00:00
|
|
|
NSString *path, *fullpath;
|
|
|
|
NSEnumerator* pathlist;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
|
|
if (!name || [name length] == 0)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
format: @"No resource name specified."];
|
|
|
|
/* NOT REACHED */
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2002-02-26 18:06:51 +00:00
|
|
|
pathlist = [[self _bundleResourcePathsWithRootPath: rootPath
|
2005-10-21 02:20:41 +00:00
|
|
|
subPath: subPath] objectEnumerator];
|
2000-06-06 16:50:52 +00:00
|
|
|
fullpath = nil;
|
2000-10-28 21:58:48 +00:00
|
|
|
while ((path = [pathlist nextObject]))
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-06-06 16:50:52 +00:00
|
|
|
if (!bundle_directory_readable(path))
|
|
|
|
continue;
|
1997-01-06 22:30:33 +00:00
|
|
|
|
|
|
|
if (ext && [ext length] != 0)
|
|
|
|
{
|
|
|
|
fullpath = [path stringByAppendingPathComponent:
|
2002-04-05 01:09:41 +00:00
|
|
|
[NSString stringWithFormat: @"%@.%@", name, ext]];
|
2002-10-30 23:47:39 +00:00
|
|
|
if (bundle_file_readable(fullpath))
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
1997-11-06 18:26:51 +00:00
|
|
|
if (gnustep_target_os)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
|
|
|
NSString* platpath;
|
|
|
|
platpath = [path stringByAppendingPathComponent:
|
2005-02-22 11:22:44 +00:00
|
|
|
[NSString stringWithFormat: @"%@-%@.%@",
|
2000-11-01 12:31:21 +00:00
|
|
|
name, gnustep_target_os, ext]];
|
|
|
|
if (bundle_file_readable(platpath))
|
1997-01-06 22:30:33 +00:00
|
|
|
fullpath = platpath;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
fullpath = nil;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
else
|
|
|
|
{
|
2000-06-06 16:50:52 +00:00
|
|
|
fullpath = _bundle_name_first_match(path, name);
|
|
|
|
if (fullpath && gnustep_target_os)
|
1997-10-18 19:49:50 +00:00
|
|
|
{
|
2000-11-01 12:31:21 +00:00
|
|
|
NSString *platpath;
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
platpath = _bundle_name_first_match(path,
|
|
|
|
[NSString stringWithFormat: @"%@-%@",
|
2000-11-01 12:31:21 +00:00
|
|
|
name, gnustep_target_os]);
|
|
|
|
if (platpath != nil)
|
2000-06-06 16:50:52 +00:00
|
|
|
fullpath = platpath;
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
2000-11-01 12:31:21 +00:00
|
|
|
if (fullpath != nil)
|
2000-06-06 16:50:52 +00:00
|
|
|
break;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2000-06-06 16:50:52 +00:00
|
|
|
return fullpath;
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
+ (NSString *) pathForResource: (NSString *)name
|
2000-10-28 21:58:48 +00:00
|
|
|
ofType: (NSString *)ext
|
|
|
|
inDirectory: (NSString *)bundlePath
|
|
|
|
withVersion: (int) version
|
1997-09-01 21:59:51 +00:00
|
|
|
{
|
|
|
|
return [self pathForResource: name
|
2000-10-28 21:58:48 +00:00
|
|
|
ofType: ext
|
|
|
|
inRootPath: bundlePath
|
|
|
|
inDirectory: nil
|
|
|
|
withVersion: version];
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSString *) pathForResource: (NSString *)name
|
2000-10-28 21:58:48 +00:00
|
|
|
ofType: (NSString *)ext
|
|
|
|
inDirectory: (NSString *)bundlePath
|
1997-09-01 21:59:51 +00:00
|
|
|
{
|
|
|
|
return [self pathForResource: name
|
2000-10-28 21:58:48 +00:00
|
|
|
ofType: ext
|
|
|
|
inRootPath: bundlePath
|
|
|
|
inDirectory: nil
|
|
|
|
withVersion: 0];
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) pathForResource: (NSString *)name
|
2001-12-17 14:31:42 +00:00
|
|
|
ofType: (NSString *)ext
|
1997-09-01 21:59:51 +00:00
|
|
|
{
|
|
|
|
return [self pathForResource: name
|
2005-02-22 11:22:44 +00:00
|
|
|
ofType: ext
|
2000-10-28 21:58:48 +00:00
|
|
|
inDirectory: nil];
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString *) pathForResource: (NSString *)name
|
2000-10-28 21:58:48 +00:00
|
|
|
ofType: (NSString *)ext
|
2005-10-21 02:20:41 +00:00
|
|
|
inDirectory: (NSString *)subPath
|
1997-09-01 21:59:51 +00:00
|
|
|
{
|
2000-10-28 21:58:48 +00:00
|
|
|
NSString *rootPath;
|
|
|
|
|
2006-02-13 03:36:19 +00:00
|
|
|
#if !defined(__MINGW32__)
|
2000-10-28 21:58:48 +00:00
|
|
|
if (_frameworkVersion)
|
|
|
|
rootPath = [NSString stringWithFormat:@"%@/Versions/%@", [self bundlePath],
|
|
|
|
_frameworkVersion];
|
|
|
|
else
|
2006-02-13 03:36:19 +00:00
|
|
|
#endif
|
2000-10-28 21:58:48 +00:00
|
|
|
rootPath = [self bundlePath];
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
return [NSBundle pathForResource: name
|
2000-10-28 21:58:48 +00:00
|
|
|
ofType: ext
|
|
|
|
inRootPath: rootPath
|
2005-10-21 02:20:41 +00:00
|
|
|
inDirectory: subPath
|
2000-10-28 21:58:48 +00:00
|
|
|
withVersion: _version];
|
1997-09-01 21:59:51 +00:00
|
|
|
}
|
|
|
|
|
2005-10-21 02:20:41 +00:00
|
|
|
+ (NSArray*) _pathsForResourcesOfType: (NSString*)extension
|
|
|
|
inRootDirectory: (NSString*)bundlePath
|
|
|
|
inSubDirectory: (NSString *)subPath
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-06-06 16:50:52 +00:00
|
|
|
BOOL allfiles;
|
1997-01-06 22:30:33 +00:00
|
|
|
NSString *path;
|
2000-06-06 16:50:52 +00:00
|
|
|
NSMutableArray *resources;
|
|
|
|
NSEnumerator *pathlist;
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2005-10-21 02:20:41 +00:00
|
|
|
pathlist = [[NSBundle _bundleResourcePathsWithRootPath: bundlePath
|
|
|
|
subPath: subPath] objectEnumerator];
|
1997-01-06 22:30:33 +00:00
|
|
|
resources = [NSMutableArray arrayWithCapacity: 2];
|
2000-06-06 16:50:52 +00:00
|
|
|
allfiles = (extension == nil || [extension length] == 0);
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
while ((path = [pathlist nextObject]))
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-06-06 16:50:52 +00:00
|
|
|
NSEnumerator *filelist;
|
|
|
|
NSString *match;
|
1997-01-06 22:30:33 +00:00
|
|
|
|
2000-06-06 16:50:52 +00:00
|
|
|
filelist = [[mgr directoryContentsAtPath: path] objectEnumerator];
|
|
|
|
while ((match = [filelist nextObject]))
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2000-06-06 16:50:52 +00:00
|
|
|
if (allfiles || [extension isEqual: [match pathExtension]])
|
2000-06-06 22:12:39 +00:00
|
|
|
[resources addObject: [path stringByAppendingPathComponent: match]];
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
}
|
2000-06-06 16:50:52 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
return resources;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2005-10-21 02:20:41 +00:00
|
|
|
+ (NSArray*) pathsForResourcesOfType: (NSString*)extension
|
2002-11-19 20:38:51 +00:00
|
|
|
inDirectory: (NSString*)bundlePath
|
2005-10-21 02:20:41 +00:00
|
|
|
{
|
|
|
|
return [self _pathsForResourcesOfType: extension
|
|
|
|
inRootDirectory: bundlePath
|
|
|
|
inSubDirectory: nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray *) pathsForResourcesOfType: (NSString *)extension
|
|
|
|
inDirectory: (NSString *)subPath
|
|
|
|
{
|
|
|
|
return [[self class] _pathsForResourcesOfType: extension
|
|
|
|
inRootDirectory: [self bundlePath]
|
|
|
|
inSubDirectory: subPath];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) pathsForResourcesOfType: (NSString*)extension
|
|
|
|
inDirectory: (NSString*)subPath
|
2002-11-19 20:38:51 +00:00
|
|
|
forLocalization: (NSString*)localizationName
|
|
|
|
{
|
2005-10-21 02:20:41 +00:00
|
|
|
NSArray *paths = nil;
|
|
|
|
NSMutableArray *result = nil;
|
|
|
|
NSEnumerator *enumerator = nil;
|
|
|
|
NSString *path = nil;
|
|
|
|
|
|
|
|
result = [NSMutableArray array];
|
|
|
|
paths = [self pathsForResourcesOfType: extension
|
|
|
|
inDirectory: subPath];
|
|
|
|
|
|
|
|
enumerator = [paths objectEnumerator];
|
|
|
|
while( (path = [enumerator nextObject]) )
|
|
|
|
{
|
|
|
|
/* Add all non-localized paths, plus ones in the particular localization
|
|
|
|
(if there is one). */
|
|
|
|
NSString *theDir = [path stringByDeletingLastPathComponent];
|
|
|
|
if ([[theDir pathExtension] isEqual: @"lproj"] == NO
|
|
|
|
|| (localizationName != nil
|
|
|
|
&& [localizationName length] != 0
|
|
|
|
&& [[theDir lastPathComponent] hasPrefix: localizationName]) )
|
|
|
|
{
|
|
|
|
[result addObject: path];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2002-11-19 20:38:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) pathForResource: (NSString*)name
|
|
|
|
ofType: (NSString*)ext
|
2005-10-21 02:20:41 +00:00
|
|
|
inDirectory: (NSString*)subPath
|
2002-11-19 20:38:51 +00:00
|
|
|
forLocalization: (NSString*)localizationName
|
|
|
|
{
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *) preferredLocalizationsFromArray: (NSArray *)localizationsArray
|
|
|
|
{
|
|
|
|
return [self preferredLocalizationsFromArray: localizationsArray
|
|
|
|
forPreferences: [NSUserDefaults userLanguages]];
|
|
|
|
}
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
+ (NSArray *) preferredLocalizationsFromArray: (NSArray *)localizationsArray
|
2002-11-19 20:38:51 +00:00
|
|
|
forPreferences: (NSArray *)preferencesArray
|
|
|
|
{
|
|
|
|
NSString *locale;
|
|
|
|
NSMutableArray* array;
|
|
|
|
NSEnumerator* enumerate;
|
|
|
|
|
|
|
|
array = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
enumerate = [preferencesArray objectEnumerator];
|
|
|
|
while ((locale = [enumerate nextObject]))
|
|
|
|
{
|
|
|
|
if ([localizationsArray indexOfObject: locale] != NSNotFound)
|
|
|
|
[array addObject: locale];
|
|
|
|
}
|
|
|
|
/* I guess this is arbitrary if we can't find a match? */
|
2002-11-20 15:14:07 +00:00
|
|
|
if ([array count] == 0 && [localizationsArray count] > 0)
|
2002-11-19 20:38:51 +00:00
|
|
|
[array addObject: [localizationsArray objectAtIndex: 0]];
|
|
|
|
return [array makeImmutableCopyOnFail: NO];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *)localizedInfoDictionary
|
|
|
|
{
|
2002-11-20 15:14:07 +00:00
|
|
|
NSString *path;
|
|
|
|
NSArray *locales;
|
|
|
|
NSString *locale = nil;
|
2002-11-19 20:38:51 +00:00
|
|
|
NSDictionary *dict = nil;
|
|
|
|
|
2002-11-20 15:14:07 +00:00
|
|
|
locales = [self preferredLocalizations];
|
|
|
|
if ([locales count] > 0)
|
|
|
|
locale = [locales objectAtIndex: 0];
|
2005-02-22 11:22:44 +00:00
|
|
|
path = [self pathForResource: @"Info-gnustep"
|
2002-11-19 20:38:51 +00:00
|
|
|
ofType: @"plist"
|
2005-02-22 11:22:44 +00:00
|
|
|
inDirectory: nil
|
2002-11-19 20:38:51 +00:00
|
|
|
forLocalization: locale];
|
|
|
|
if (path)
|
|
|
|
{
|
|
|
|
dict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
path = [self pathForResource: @"Info"
|
2002-11-19 20:38:51 +00:00
|
|
|
ofType: @"plist"
|
2005-02-22 11:22:44 +00:00
|
|
|
inDirectory: nil
|
2002-11-19 20:38:51 +00:00
|
|
|
forLocalization: locale];
|
|
|
|
if (path)
|
|
|
|
{
|
|
|
|
dict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dict == nil)
|
|
|
|
dict = [self infoDictionary];
|
|
|
|
return dict;
|
|
|
|
}
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
- (NSArray *) localizations
|
2002-11-19 20:38:51 +00:00
|
|
|
{
|
|
|
|
NSString *locale;
|
|
|
|
NSArray *localizations;
|
|
|
|
NSEnumerator* enumerate;
|
|
|
|
NSMutableArray *array = [NSMutableArray arrayWithCapacity: 2];
|
|
|
|
|
|
|
|
localizations = [self pathsForResourcesOfType: @"lproj"
|
|
|
|
inDirectory: nil];
|
|
|
|
enumerate = [localizations objectEnumerator];
|
|
|
|
while ((locale = [enumerate nextObject]))
|
|
|
|
{
|
|
|
|
locale = [[locale lastPathComponent] stringByDeletingPathExtension];
|
|
|
|
[array addObject: locale];
|
|
|
|
}
|
|
|
|
return [array makeImmutableCopyOnFail: NO];
|
|
|
|
}
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
- (NSArray *) preferredLocalizations
|
2002-11-19 20:38:51 +00:00
|
|
|
{
|
|
|
|
return [NSBundle preferredLocalizationsFromArray: [self localizations]];
|
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (NSString *) localizedStringForKey: (NSString *)key
|
1999-04-22 21:01:38 +00:00
|
|
|
value: (NSString *)value
|
|
|
|
table: (NSString *)tableName
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1999-04-22 21:01:38 +00:00
|
|
|
NSDictionary *table;
|
2000-10-28 21:58:48 +00:00
|
|
|
NSString *newString = nil;
|
1997-01-06 22:30:33 +00:00
|
|
|
|
1999-04-23 13:56:22 +00:00
|
|
|
if (_localizations == nil)
|
|
|
|
_localizations = [[NSMutableDictionary alloc] initWithCapacity: 1];
|
|
|
|
|
1999-04-22 21:01:38 +00:00
|
|
|
if (tableName == nil || [tableName isEqualToString: @""] == YES)
|
|
|
|
{
|
|
|
|
tableName = @"Localizable";
|
1999-04-23 13:56:22 +00:00
|
|
|
table = [_localizations objectForKey: tableName];
|
1999-04-22 21:01:38 +00:00
|
|
|
}
|
1999-04-23 13:56:22 +00:00
|
|
|
else if ((table = [_localizations objectForKey: tableName]) == nil
|
|
|
|
&& [@"strings" isEqual: [tableName pathExtension]] == YES)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
1999-04-22 21:01:38 +00:00
|
|
|
tableName = [tableName stringByDeletingPathExtension];
|
1999-04-23 13:56:22 +00:00
|
|
|
table = [_localizations objectForKey: tableName];
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1999-04-22 21:01:38 +00:00
|
|
|
if (table == nil)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
NSString *tablePath;
|
1999-04-23 13:56:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure we have an empty table in place in case anything
|
2006-04-09 16:16:07 +00:00
|
|
|
* we do somehow causes recursion. The recursive call will look
|
1999-04-23 13:56:22 +00:00
|
|
|
* up the string in the empty table.
|
|
|
|
*/
|
|
|
|
[_localizations setObject: _emptyTable forKey: tableName];
|
1999-04-22 21:01:38 +00:00
|
|
|
|
|
|
|
tablePath = [self pathForResource: tableName ofType: @"strings"];
|
2006-04-09 16:16:07 +00:00
|
|
|
if (tablePath != nil)
|
1999-04-22 21:01:38 +00:00
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
NSStringEncoding encoding;
|
|
|
|
NSString *tableContent;
|
|
|
|
NSData *tableData;
|
|
|
|
const unsigned char *bytes;
|
|
|
|
unsigned length;
|
|
|
|
|
|
|
|
tableData = [[NSData alloc] initWithContentsOfFile: tablePath];
|
|
|
|
bytes = [tableData bytes];
|
|
|
|
length = [tableData length];
|
|
|
|
/*
|
|
|
|
* A localisation file can be ...
|
|
|
|
* UTF16 with a leading BOM,
|
|
|
|
* UTF8 with a leading BOM,
|
|
|
|
* or ASCII (the original standard) with \U escapes.
|
|
|
|
*/
|
|
|
|
if (length > 2
|
|
|
|
&& ((bytes[0] == 0xFF && bytes[1] == 0xFE)
|
|
|
|
|| (bytes[0] == 0xFE && bytes[1] == 0xFF)))
|
|
|
|
{
|
|
|
|
encoding = NSUnicodeStringEncoding;
|
|
|
|
}
|
|
|
|
else if (length > 2
|
|
|
|
&& bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
|
1999-04-22 21:01:38 +00:00
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
encoding = NSUTF8StringEncoding;
|
1999-04-22 21:01:38 +00:00
|
|
|
}
|
2006-04-09 16:16:07 +00:00
|
|
|
else
|
1999-04-22 21:01:38 +00:00
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
encoding = NSASCIIStringEncoding;
|
1999-04-22 21:01:38 +00:00
|
|
|
}
|
2006-04-09 16:16:07 +00:00
|
|
|
tableContent = [[NSString alloc] initWithData: tableData
|
|
|
|
encoding: encoding];
|
|
|
|
if (tableContent == nil && encoding == NSASCIIStringEncoding)
|
|
|
|
{
|
|
|
|
encoding = [NSString defaultCStringEncoding];
|
|
|
|
tableContent = [[NSString alloc] initWithData: tableData
|
|
|
|
encoding: encoding];
|
|
|
|
if (tableContent != nil)
|
|
|
|
{
|
|
|
|
NSWarnMLog (@"Localisation file %@ not in portable encoding"
|
|
|
|
@" so I'm using the default encoding for the current"
|
|
|
|
@" system, which may not display messages correctly.\n"
|
|
|
|
@"The file should be ASCII (using \\U escapes for unicode"
|
|
|
|
@" characters) or Unicode (UTF16 or UTF8) with a leading "
|
|
|
|
@"byte-order-marker.\n", tablePath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tableContent == nil)
|
|
|
|
{
|
|
|
|
NSWarnMLog(@"Failed to load strings file %@ - bad character"
|
|
|
|
@" encoding", tablePath);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
table = [tableContent propertyListFromStringsFileFormat];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
NSWarnMLog(@"Failed to parse strings file %@ - %@",
|
|
|
|
tablePath, localException);
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
}
|
|
|
|
RELEASE(tableData);
|
|
|
|
RELEASE(tableContent);
|
1999-04-22 21:01:38 +00:00
|
|
|
}
|
|
|
|
else
|
2003-06-28 05:33:15 +00:00
|
|
|
{
|
|
|
|
NSDebugMLLog(@"NSBundle", @"Failed to locate strings file %@",
|
|
|
|
tableName);
|
|
|
|
}
|
1999-04-22 21:01:38 +00:00
|
|
|
/*
|
1999-04-23 13:56:22 +00:00
|
|
|
* If we couldn't found and parsed the strings table, we put it in
|
|
|
|
* the cache of strings tables in this bundle, otherwise we will just
|
|
|
|
* be keeping the empty table in the cache so we don't keep retrying.
|
1999-04-22 21:01:38 +00:00
|
|
|
*/
|
1999-04-23 13:56:22 +00:00
|
|
|
if (table != nil)
|
|
|
|
[_localizations setObject: table forKey: tableName];
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
1999-04-22 21:01:38 +00:00
|
|
|
|
|
|
|
if (key == nil || (newString = [table objectForKey: key]) == nil)
|
1997-01-06 22:30:33 +00:00
|
|
|
{
|
1999-04-22 21:01:38 +00:00
|
|
|
NSString *show = [[NSUserDefaults standardUserDefaults]
|
1997-01-06 22:30:33 +00:00
|
|
|
objectForKey: NSShowNonLocalizedStrings];
|
1999-08-01 06:21:15 +00:00
|
|
|
if (show && [show isEqual: @"YES"])
|
1999-04-23 02:54:45 +00:00
|
|
|
{
|
|
|
|
/* It would be bad to localize this string! */
|
|
|
|
NSLog(@"Non-localized string: %@\n", newString);
|
|
|
|
newString = [key uppercaseString];
|
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
else
|
1999-04-22 21:01:38 +00:00
|
|
|
{
|
|
|
|
newString = value;
|
|
|
|
if (newString == nil || [newString isEqualToString: @""] == YES)
|
|
|
|
newString = key;
|
|
|
|
}
|
|
|
|
if (newString == nil)
|
|
|
|
newString = @"";
|
1997-01-06 22:30:33 +00:00
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
1999-04-22 21:01:38 +00:00
|
|
|
return newString;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
+ (void) stripAfterLoading: (BOOL)flag
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
_strip_after_loading = flag;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2004-11-20 20:14:24 +00:00
|
|
|
- (NSString *) executablePath
|
2002-11-19 20:38:51 +00:00
|
|
|
{
|
|
|
|
NSString *object, *path;
|
2004-11-20 20:14:24 +00:00
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
if (!_mainBundle)
|
2004-11-20 20:14:24 +00:00
|
|
|
{
|
|
|
|
[NSBundle mainBundle];
|
|
|
|
}
|
|
|
|
if (self == _mainBundle)
|
|
|
|
{
|
2006-04-09 16:16:07 +00:00
|
|
|
return ExecutablePath();
|
2004-11-20 20:14:24 +00:00
|
|
|
}
|
2006-05-10 03:18:08 +00:00
|
|
|
if (self->_bundleType == NSBUNDLE_LIBRARY)
|
|
|
|
{
|
|
|
|
return objc_get_symbol_path ([self principalClass], NULL);
|
|
|
|
}
|
2002-11-19 20:38:51 +00:00
|
|
|
object = [[self infoDictionary] objectForKey: @"NSExecutable"];
|
|
|
|
if (object == nil || [object length] == 0)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
if (_bundleType == NSBUNDLE_FRAMEWORK)
|
|
|
|
{
|
2005-07-12 14:11:03 +00:00
|
|
|
/* Mangle the name before building the _currentFrameworkName,
|
|
|
|
* which really is a class name.
|
|
|
|
*/
|
|
|
|
NSString *mangledName = object;
|
|
|
|
mangledName = [mangledName stringByReplacingString: @"_"
|
|
|
|
withString: @"__"];
|
|
|
|
mangledName = [mangledName stringByReplacingString: @"-"
|
|
|
|
withString: @"_0"];
|
|
|
|
mangledName = [mangledName stringByReplacingString: @"+"
|
|
|
|
withString: @"_1"];
|
|
|
|
|
2005-10-11 19:09:26 +00:00
|
|
|
#if !defined(__MINGW32__)
|
2002-11-19 20:38:51 +00:00
|
|
|
path = [_path stringByAppendingPathComponent:@"Versions/Current"];
|
2005-07-13 14:51:57 +00:00
|
|
|
#else
|
|
|
|
path = _path;
|
|
|
|
#endif
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2002-11-19 20:38:51 +00:00
|
|
|
_currentFrameworkName = RETAIN(([NSString stringWithFormat:
|
|
|
|
@"NSFramework_%@",
|
2005-07-12 14:11:03 +00:00
|
|
|
mangledName]));
|
2002-11-19 20:38:51 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
path = _path;
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2002-11-19 20:38:51 +00:00
|
|
|
object = bundle_object_name(path, object);
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (NSString *) resourcePath
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
2000-10-28 21:58:48 +00:00
|
|
|
NSString *version = _frameworkVersion;
|
|
|
|
|
|
|
|
if (!version)
|
|
|
|
version = @"Current";
|
|
|
|
|
|
|
|
if (_bundleType == NSBUNDLE_FRAMEWORK)
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
2005-10-11 19:09:26 +00:00
|
|
|
#if !defined(__MINGW32__)
|
2002-01-16 13:03:45 +00:00
|
|
|
return [_path stringByAppendingPathComponent:
|
2005-02-22 11:22:44 +00:00
|
|
|
[NSString stringWithFormat:@"Versions/%@/Resources",
|
2002-01-16 13:03:45 +00:00
|
|
|
version]];
|
2005-07-13 14:51:57 +00:00
|
|
|
#else
|
|
|
|
/* No Versions (that require symlinks) on MINGW */
|
|
|
|
return [_path stringByAppendingPathComponent: @"Resources"];
|
|
|
|
#endif
|
2002-01-16 13:03:45 +00:00
|
|
|
}
|
2000-10-28 21:58:48 +00:00
|
|
|
else
|
2002-01-16 13:03:45 +00:00
|
|
|
{
|
|
|
|
return [_path stringByAppendingPathComponent: @"Resources"];
|
|
|
|
}
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
- (NSDictionary *) infoDictionary
|
1995-03-18 17:15:15 +00:00
|
|
|
{
|
1997-01-06 22:30:33 +00:00
|
|
|
NSString* path;
|
1995-04-03 20:07:18 +00:00
|
|
|
|
1997-01-06 22:30:33 +00:00
|
|
|
if (_infoDict)
|
|
|
|
return _infoDict;
|
1995-03-18 17:15:15 +00:00
|
|
|
|
1998-11-24 03:46:21 +00:00
|
|
|
path = [self pathForResource: @"Info-gnustep" ofType: @"plist"];
|
1997-01-06 22:30:33 +00:00
|
|
|
if (path)
|
2002-10-04 09:08:09 +00:00
|
|
|
{
|
|
|
|
_infoDict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
else
|
1999-04-13 21:56:03 +00:00
|
|
|
{
|
|
|
|
path = [self pathForResource: @"Info" ofType: @"plist"];
|
|
|
|
if (path)
|
2002-10-04 09:08:09 +00:00
|
|
|
{
|
|
|
|
_infoDict = [[NSDictionary alloc] initWithContentsOfFile: path];
|
|
|
|
}
|
1999-04-13 21:56:03 +00:00
|
|
|
else
|
2002-10-04 09:08:09 +00:00
|
|
|
{
|
|
|
|
_infoDict = RETAIN([NSDictionary dictionary]);
|
|
|
|
}
|
1999-04-13 21:56:03 +00:00
|
|
|
}
|
1997-01-06 22:30:33 +00:00
|
|
|
return _infoDict;
|
1995-03-18 17:15:15 +00:00
|
|
|
}
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
- (NSString *) builtInPlugInsPath
|
2004-11-11 18:51:37 +00:00
|
|
|
{
|
|
|
|
NSString *version = _frameworkVersion;
|
|
|
|
|
|
|
|
if (!version)
|
|
|
|
version = @"Current";
|
|
|
|
|
|
|
|
if (_bundleType == NSBUNDLE_FRAMEWORK)
|
|
|
|
{
|
2005-10-11 19:09:26 +00:00
|
|
|
#if !defined(__MINGW32__)
|
2004-11-11 18:51:37 +00:00
|
|
|
return [_path stringByAppendingPathComponent:
|
2005-02-22 11:22:44 +00:00
|
|
|
[NSString stringWithFormat:@"Versions/%@/PlugIns",
|
2004-11-11 18:51:37 +00:00
|
|
|
version]];
|
2005-07-13 14:51:57 +00:00
|
|
|
#else
|
|
|
|
return [_path stringByAppendingPathComponent: @"PlugIns"];
|
|
|
|
#endif
|
2004-11-11 18:51:37 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return [_path stringByAppendingPathComponent: @"PlugIns"];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
- (NSString*) bundleIdentifier
|
2003-03-28 03:46:31 +00:00
|
|
|
{
|
2006-05-15 00:49:06 +00:00
|
|
|
return [[self infoDictionary] objectForKey: @"CFBundleIdentifier"];
|
2003-03-28 03:46:31 +00:00
|
|
|
}
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
- (unsigned) bundleVersion
|
1997-05-03 19:22:17 +00:00
|
|
|
{
|
|
|
|
return _version;
|
|
|
|
}
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
- (void) setBundleVersion: (unsigned)version
|
1997-05-03 19:22:17 +00:00
|
|
|
{
|
|
|
|
_version = version;
|
|
|
|
}
|
|
|
|
|
1995-03-18 17:15:15 +00:00
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
1997-10-18 19:49:50 +00:00
|
|
|
@implementation NSBundle (GNUstep)
|
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
/**
|
|
|
|
* <p>Return a bundle which accesses the first existing directory from the list
|
|
|
|
* GNUSTEP_USER_ROOT/Libraries/Resources/libraryName/
|
|
|
|
* GNUSTEP_NETWORK_ROOT/Libraries/Resources/libraryName/
|
|
|
|
* GNUSTEP_LOCAL_ROOT/Libraries/Resources/libraryName/
|
|
|
|
* GNUSTEP_SYSTEM_ROOT/Libraries/Resources/libraryName/<br />
|
|
|
|
* Where libraryName is the name of a library without the <em>lib</em>
|
|
|
|
* prefix or any extensions.
|
|
|
|
* </p>
|
|
|
|
* <p>This method exists to provide resource bundles for libraries and hos no
|
|
|
|
* particular relationship to the library code itsself. The named library
|
|
|
|
* could be a dynamic library linked in to the running program, a static
|
|
|
|
* library (whose code may not even exist on the host machine except where
|
|
|
|
* it is linked in to the program), or even a library which is not linked
|
|
|
|
* into the program at all (eg. where you want to share resources provided
|
|
|
|
* for a library you do not actually use).
|
|
|
|
* </p>
|
|
|
|
* <p>The bundle for the library <em>gnustep-base</em> is a special case ...
|
|
|
|
* for this bundle the -principalClass method returns [NSObject] and the
|
|
|
|
* -executablePath method returns the path to the gnustep-base dynamic
|
|
|
|
* library (if it can be found). As a general rule, library bundles are
|
|
|
|
* not guaranteed to return values for these methods as the library may
|
|
|
|
* not exist on disk.
|
|
|
|
* </p>
|
2001-12-21 18:31:06 +00:00
|
|
|
*/
|
|
|
|
+ (NSBundle *) bundleForLibrary: (NSString *)libraryName
|
|
|
|
{
|
|
|
|
NSArray *paths;
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
NSString *path;
|
|
|
|
NSString *tail;
|
|
|
|
NSFileManager *fm = [NSFileManager defaultManager];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2006-05-10 03:18:08 +00:00
|
|
|
/*
|
|
|
|
* Eliminate any base path or extensions.
|
|
|
|
*/
|
|
|
|
libraryName = [libraryName lastPathComponent];
|
|
|
|
do
|
|
|
|
{
|
|
|
|
libraryName = [libraryName stringByDeletingPathExtension];
|
|
|
|
}
|
|
|
|
while ([[libraryName pathExtension] length] > 0);
|
|
|
|
/*
|
|
|
|
* Discard leading 'lib'
|
|
|
|
*/
|
|
|
|
if ([libraryName hasPrefix: @"lib"] == YES)
|
|
|
|
{
|
|
|
|
libraryName = [libraryName substringFromIndex: 3];
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Discard debug/profile library suffix
|
|
|
|
*/
|
|
|
|
if ([libraryName hasSuffix: @"_d"] == YES
|
|
|
|
|| [libraryName hasSuffix: @"_p"] == YES)
|
|
|
|
{
|
|
|
|
libraryName = [libraryName substringToIndex: [libraryName length] - 3];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([libraryName length] == 0)
|
2001-12-21 18:31:06 +00:00
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2001-12-21 18:31:06 +00:00
|
|
|
tail = [@"Resources" stringByAppendingPathComponent: libraryName];
|
|
|
|
|
|
|
|
paths = NSSearchPathForDirectoriesInDomains (GSLibrariesDirectory,
|
|
|
|
NSAllDomainsMask, YES);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2001-12-21 18:31:06 +00:00
|
|
|
enumerator = [paths objectEnumerator];
|
|
|
|
while ((path = [enumerator nextObject]))
|
|
|
|
{
|
|
|
|
BOOL isDir;
|
|
|
|
path = [path stringByAppendingPathComponent: tail];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2001-12-21 18:31:06 +00:00
|
|
|
if ([fm fileExistsAtPath: path isDirectory: &isDir] && isDir)
|
|
|
|
{
|
2006-05-10 03:18:08 +00:00
|
|
|
NSBundle *b = [self bundleWithPath: path];
|
|
|
|
|
|
|
|
if (b != nil && b->_bundleType == NSBUNDLE_BUNDLE)
|
|
|
|
{
|
|
|
|
b->_bundleType = NSBUNDLE_LIBRARY;
|
|
|
|
}
|
|
|
|
return b;
|
2001-12-21 18:31:06 +00:00
|
|
|
}
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
2001-12-21 18:31:06 +00:00
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2003-04-28 02:29:49 +00:00
|
|
|
+ (NSString *) pathForLibraryResource: (NSString *)name
|
1997-10-18 19:49:50 +00:00
|
|
|
ofType: (NSString *)ext
|
2001-12-17 14:31:42 +00:00
|
|
|
inDirectory: (NSString *)bundlePath
|
1997-10-18 19:49:50 +00:00
|
|
|
{
|
2001-03-26 23:09:44 +00:00
|
|
|
NSString *path = nil;
|
|
|
|
NSString *bundle_path = nil;
|
|
|
|
NSArray *paths;
|
|
|
|
NSBundle *bundle;
|
|
|
|
NSEnumerator *enumerator;
|
1997-10-18 19:49:50 +00:00
|
|
|
|
|
|
|
/* Gather up the paths */
|
2003-04-28 02:29:49 +00:00
|
|
|
paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
2001-03-26 23:09:44 +00:00
|
|
|
NSAllDomainsMask, YES);
|
1997-10-18 19:49:50 +00:00
|
|
|
|
2001-03-26 23:09:44 +00:00
|
|
|
enumerator = [paths objectEnumerator];
|
|
|
|
while ((path == nil) && (bundle_path = [enumerator nextObject]))
|
|
|
|
{
|
2002-02-26 18:06:51 +00:00
|
|
|
bundle = [self bundleWithPath: bundle_path];
|
2001-03-26 23:09:44 +00:00
|
|
|
path = [bundle pathForResource: name
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: bundlePath];
|
|
|
|
}
|
1997-10-18 19:49:50 +00:00
|
|
|
|
2001-03-26 23:09:44 +00:00
|
|
|
return path;
|
1997-10-18 19:49:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
1999-04-14 10:34:56 +00:00
|
|
|
|