PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/NSBundle.m

http://purefoundation.googlecode.com/
Objective C | 410 lines | 271 code | 72 blank | 67 comment | 31 complexity | eb4ac503f1f6c72a39d36b79ce310e77 MD5 | raw file
  1. /*
  2. * PureFoundation -- http://code.google.com/p/purefoundation/
  3. * NSBundle.m
  4. *
  5. * NSBundle
  6. *
  7. * Created by Stuart Crook on 15/02/2009.
  8. * LGPL'd. See LICENCE.txt for copyright information.
  9. */
  10. /*
  11. * The NSBundle class wraps the CFBundle class, holding a CFBundle object for the bundle in
  12. * question and routing most of its method calls through the CF equivalent. NSBundle objects
  13. * are cached in the _pfBundleStore dictionary, keyed to the CFBundle they wrap.
  14. *
  15. * Currently, none of the obj-c methods are implemented.
  16. *
  17. * We may have to look at over-riding the usual retain/release memory management, in order to
  18. * stop cahced objects being released. (Or alternatively, set the -dealloc method to remove the
  19. * object from the cache.)
  20. */
  21. #import "NSBundle.h"
  22. #import "PureFoundation.h"
  23. /*
  24. * Constants
  25. */
  26. NSString * const NSBundleDidLoadNotification = @"NSBundleDidLoadNotification";
  27. NSString * const NSLoadedClasses = @"NSLoadedClasses";
  28. /*
  29. * Class-specific storage
  30. *
  31. * We'll cache NSBundles in a non-retaining dictionary, keyed to the CFBundle they wrap,
  32. * and dish them up in place of the CFBundles the CF bundle functions return.
  33. */
  34. NSBundle *_pfMainBundle = nil;
  35. CFMutableDictionaryRef _pfBundleStore = nil;
  36. /*
  37. * Functions for wrapping, storing and retrieving bundles
  38. */
  39. NSBundle *_pfWrapBundle( CFBundleRef cfBundle )
  40. {
  41. if( cfBundle == NULL ) return NULL;
  42. NSBundle *nsBundle = (NSBundle *)CFDictionaryGetValue( _pfBundleStore, (const void *)cfBundle );
  43. if( nsBundle == NULL ) // bundle wasn't in store, so...
  44. { // create and init an NSBundle object by hand
  45. nsBundle = NSAllocateObject([NSBundle class], 0, nil);
  46. CFRetain(cfBundle);
  47. nsBundle->_cfBundle = (id)cfBundle;
  48. // other init code...
  49. CFDictionaryAddValue( _pfBundleStore, (const void *)cfBundle, (const void *)nsBundle );
  50. }
  51. return nsBundle;
  52. }
  53. /*
  54. * ivars:
  55. * NSUInteger _flags;
  56. * id _cfBundle;
  57. * NSUInteger _refCount;
  58. * Class _principalClass;
  59. * id _tmp1;
  60. * id _tmp2;
  61. * void *_reserved1;
  62. * void *_reserved0;
  63. */
  64. @implementation NSBundle
  65. + (void)initialize
  66. {
  67. if( self == [NSBundle class] )
  68. _pfBundleStore = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, NULL, NULL );
  69. }
  70. /*
  71. * Creation
  72. */
  73. + (NSBundle *)bundleWithPath:(NSString *)path { return [[[self alloc] initWithPath: path] autorelease]; }
  74. /*
  75. * I guess we should really have alloc return a dummy object, to avoid the hassle of
  76. * allocating and then releasing a bundle object
  77. */
  78. - (id)initWithPath:(NSString *)path
  79. {
  80. CFURLRef url = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, (CFStringRef)path, kCFURLPOSIXPathStyle, YES );
  81. if( url == NULL ) return nil;
  82. self = _pfWrapBundle( CFBundleCreate( kCFAllocatorDefault, url ) );
  83. if( self != NULL )
  84. {
  85. // think of some other setup to do
  86. }
  87. [(id)url release];
  88. return self;
  89. }
  90. /*
  91. * Class methods
  92. */
  93. + (NSBundle *)mainBundle
  94. {
  95. if( _pfMainBundle == nil )
  96. {
  97. _pfMainBundle = _pfWrapBundle( CFBundleGetMainBundle() );
  98. }
  99. return _pfMainBundle;
  100. }
  101. + (NSBundle *)bundleForClass:(Class)aClass {}
  102. + (NSBundle *)bundleWithIdentifier:(NSString *)identifier
  103. {
  104. return _pfWrapBundle( CFBundleGetBundleWithIdentifier((CFStringRef)identifier) );
  105. }
  106. + (NSArray *)allBundles
  107. {
  108. CFArrayRef all = CFBundleGetAllBundles();
  109. NSUInteger count = CFArrayGetCount(all);
  110. id buffer[count]; // maximum number we'l' return
  111. UInt32 packageType, packageCreator;
  112. NSUInteger finalCount = 0;
  113. id *ptr = buffer;
  114. for( id cfBundle in (NSArray *)all )
  115. {
  116. CFBundleGetPackageInfo( (CFBundleRef)cfBundle, &packageType, &packageCreator );
  117. if( packageType != 'FMWK' )
  118. {
  119. *ptr++ = _pfWrapBundle( (CFBundleRef)cfBundle );
  120. finalCount++;
  121. }
  122. }
  123. return [(id)CFArrayCreate( kCFAllocatorDefault, (const void **)buffer, finalCount, (CFArrayCallBacks *)&_PFCollectionCallBacks ) autorelease];
  124. }
  125. + (NSArray *)allFrameworks
  126. {
  127. CFArrayRef all = CFBundleGetAllBundles();
  128. NSUInteger count = CFArrayGetCount(all);
  129. id buffer[count]; // maximum number we'l' return
  130. UInt32 packageType, packageCreator;
  131. NSUInteger finalCount = 0;
  132. id *ptr = buffer;
  133. for( id cfBundle in (NSArray *)all )
  134. {
  135. CFBundleGetPackageInfo( (CFBundleRef)cfBundle, &packageType, &packageCreator );
  136. if( packageType == 'FMWK' )
  137. {
  138. *ptr++ = _pfWrapBundle( (CFBundleRef)cfBundle );
  139. finalCount++;
  140. }
  141. }
  142. return [(id)CFArrayCreate( kCFAllocatorDefault, (const void **)buffer, finalCount, (CFArrayCallBacks *)&_PFCollectionCallBacks ) autorelease];
  143. }
  144. + (NSArray *)preferredLocalizationsFromArray:(NSArray *)localizationsArray
  145. {
  146. return [(id)CFBundleCopyPreferredLocalizationsFromArray( (CFArrayRef)localizationsArray ) autorelease];
  147. }
  148. + (NSArray *)preferredLocalizationsFromArray:(NSArray *)localizationsArray forPreferences:(NSArray *)preferencesArray
  149. {
  150. return [(id)CFBundleCopyLocalizationsForPreferences( (CFArrayRef)localizationsArray, (CFArrayRef)preferencesArray ) autorelease];
  151. }
  152. + (NSString *)pathForResource:(NSString *)name ofType:(NSString *)ext inDirectory:(NSString *)bundlePath
  153. {
  154. CFURLRef bundleURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, (CFStringRef)bundlePath, kCFURLPOSIXPathStyle, YES );
  155. CFURLRef pathURL = CFBundleCopyResourceURLInDirectory( bundleURL, (CFStringRef)name, (CFStringRef)ext, NULL );
  156. CFStringRef path = CFURLCopyPath(pathURL);
  157. CFRelease(bundleURL);
  158. CFRelease(pathURL);
  159. return [(id)path autorelease];
  160. }
  161. + (NSArray *)pathsForResourcesOfType:(NSString *)ext inDirectory:(NSString *)bundlePath
  162. {
  163. CFURLRef bundleURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault, (CFStringRef)bundlePath, kCFURLPOSIXPathStyle, YES );
  164. CFArrayRef array = CFBundleCopyResourceURLsOfTypeInDirectory( bundleURL, (CFStringRef)ext, NULL );
  165. NSUInteger count = CFArrayGetCount(array);
  166. id buffer[count];
  167. id *ptr = buffer;
  168. for( id url in (NSArray *)array )
  169. *ptr++ = [(id)CFURLCopyPath((CFURLRef)url) autorelease];
  170. CFRelease(bundleURL);
  171. [(id)array release];
  172. return [(id)CFArrayCreate( kCFAllocatorDefault, (const void **)buffer, count, (CFArrayCallBacks *)&_PFCollectionCallBacks ) autorelease];
  173. }
  174. /*
  175. * Instance methods
  176. */
  177. // private function we don't use but other code might
  178. - (CFBundleRef)_cfBundle { return (CFBundleRef)_cfBundle; }
  179. - (NSArray *)executableArchitectures
  180. {
  181. return [(id)CFBundleCopyExecutableArchitectures((CFBundleRef)_cfBundle) autorelease];
  182. }
  183. - (BOOL)load
  184. {
  185. if( YES == CFBundleIsExecutableLoaded( (CFBundleRef)_cfBundle ) ) return YES;
  186. if( NO == CFBundleLoadExecutable( (CFBundleRef)_cfBundle ) ) return NO;
  187. // send notifications...
  188. return YES;
  189. }
  190. - (BOOL)loadAndReturnError:(NSError **)error
  191. {
  192. if( YES == CFBundleIsExecutableLoaded( (CFBundleRef)_cfBundle ) ) return YES;
  193. if( NO == CFBundleLoadExecutableAndReturnError( (CFBundleRef)_cfBundle, (CFErrorRef *)error) ) return NO;
  194. // send notifications
  195. return YES;
  196. }
  197. - (BOOL)isLoaded { return CFBundleIsExecutableLoaded( (CFBundleRef)_cfBundle ); }
  198. - (BOOL)unload
  199. {
  200. if( NO == CFBundleIsExecutableLoaded( (CFBundleRef)_cfBundle ) ) return YES;
  201. CFBundleUnloadExecutable( (CFBundleRef)_cfBundle );
  202. return CFBundleIsExecutableLoaded( (CFBundleRef)_cfBundle ) ? NO : YES;
  203. }
  204. - (BOOL)preflightAndReturnError:(NSError **)error
  205. {
  206. return CFBundlePreflightExecutable( (CFBundleRef)_cfBundle, (CFErrorRef *)error);
  207. }
  208. - (NSString *)bundlePath
  209. {
  210. CFURLRef url = CFBundleCopyBundleURL( (CFBundleRef)_cfBundle );
  211. CFStringRef path = CFURLCopyPath(url);
  212. CFRelease(url);
  213. return [(id)path autorelease];
  214. }
  215. - (NSString *)resourcePath
  216. {
  217. CFURLRef url = CFBundleCopyResourcesDirectoryURL( (CFBundleRef)_cfBundle );
  218. CFStringRef path = CFURLCopyPath(url);
  219. CFRelease(url);
  220. return [(id)path autorelease];
  221. }
  222. - (NSString *)executablePath
  223. {
  224. CFURLRef url = CFBundleCopyExecutableURL( (CFBundleRef)_cfBundle );
  225. CFStringRef path = CFURLCopyPath(url);
  226. CFRelease(url);
  227. return [(id)path autorelease];
  228. }
  229. - (NSString *)pathForAuxiliaryExecutable:(NSString *)executableName
  230. {
  231. CFURLRef url = CFBundleCopyAuxiliaryExecutableURL( (CFBundleRef)_cfBundle, (CFStringRef)executableName );
  232. CFStringRef path = CFURLCopyPath(url);
  233. CFRelease(url);
  234. return [(id)path autorelease];
  235. }
  236. - (NSString *)privateFrameworksPath
  237. {
  238. CFURLRef url = CFBundleCopyPrivateFrameworksURL( (CFBundleRef)_cfBundle );
  239. CFStringRef path = CFURLCopyPath(url);
  240. CFRelease(url);
  241. return [(id)path autorelease];
  242. }
  243. - (NSString *)sharedFrameworksPath
  244. {
  245. CFURLRef url = CFBundleCopySharedFrameworksURL( (CFBundleRef)_cfBundle );
  246. CFStringRef path = CFURLCopyPath(url);
  247. CFRelease(url);
  248. return [(id)path autorelease];
  249. }
  250. - (NSString *)sharedSupportPath
  251. {
  252. CFURLRef url = CFBundleCopySharedSupportURL( (CFBundleRef)_cfBundle );
  253. CFStringRef path = CFURLCopyPath(url);
  254. CFRelease(url);
  255. return [(id)path autorelease];
  256. }
  257. - (NSString *)builtInPlugInsPath
  258. {
  259. CFURLRef url = CFBundleCopyBuiltInPlugInsURL( (CFBundleRef)_cfBundle );
  260. CFStringRef path = CFURLCopyPath(url);
  261. CFRelease(url);
  262. return [(id)path autorelease];
  263. }
  264. - (NSString *)bundleIdentifier { return (NSString *)CFBundleGetIdentifier( (CFBundleRef)_cfBundle ); }
  265. - (Class)classNamed:(NSString *)className {}
  266. - (Class)principalClass {}
  267. /* In the following methods, bundlePath is an absolute path to a bundle, and may not be nil; subpath is a relative path to a subdirectory inside the relevant global or localized resource directory, and should be nil if the resource file in question is not in a subdirectory. */
  268. - (NSString *)pathForResource:(NSString *)name ofType:(NSString *)ext
  269. {
  270. CFURLRef url = CFBundleCopyResourceURL( (CFBundleRef)_cfBundle, (CFStringRef)name, (CFStringRef)ext, NULL);
  271. CFStringRef path = CFURLCopyPath(url);
  272. CFRelease(url);
  273. return [(id)path autorelease];
  274. }
  275. - (NSString *)pathForResource:(NSString *)name ofType:(NSString *)ext inDirectory:(NSString *)subpath
  276. {
  277. CFURLRef url = CFBundleCopyResourceURL( (CFBundleRef)_cfBundle, (CFStringRef)name, (CFStringRef)ext, (CFStringRef)subpath );
  278. CFStringRef path = CFURLCopyPath(url);
  279. CFRelease(url);
  280. return [(id)path autorelease];
  281. }
  282. - (NSString *)pathForResource:(NSString *)name ofType:(NSString *)ext inDirectory:(NSString *)subpath forLocalization:(NSString *)localizationName
  283. {
  284. CFURLRef url = CFBundleCopyResourceURLForLocalization( (CFBundleRef)_cfBundle, (CFStringRef)name, (CFStringRef)ext, (CFStringRef)subpath, (CFStringRef)localizationName );
  285. CFStringRef path = CFURLCopyPath(url);
  286. CFRelease(url);
  287. return [(id)path autorelease];
  288. }
  289. - (NSArray *)pathsForResourcesOfType:(NSString *)ext inDirectory:(NSString *)subpath
  290. {
  291. CFArrayRef array = CFBundleCopyResourceURLsOfType( (CFBundleRef)_cfBundle, (CFStringRef)ext, (CFStringRef)subpath );
  292. NSUInteger count = CFArrayGetCount(array);
  293. id buffer[count];
  294. id *ptr = buffer;
  295. for( id url in (NSArray *)array )
  296. *ptr++ = [(id)CFURLCopyPath((CFURLRef)url) autorelease];
  297. [(id)array release];
  298. return [(id)CFArrayCreate( kCFAllocatorDefault, (const void **)buffer, count, (CFArrayCallBacks *)&_PFCollectionCallBacks ) autorelease];
  299. }
  300. - (NSArray *)pathsForResourcesOfType:(NSString *)ext inDirectory:(NSString *)subpath forLocalization:(NSString *)localizationName
  301. {
  302. CFArrayRef array = CFBundleCopyResourceURLsOfTypeForLocalization( (CFBundleRef)_cfBundle, (CFStringRef)ext, (CFStringRef)subpath, (CFStringRef)localizationName );
  303. NSUInteger count = CFArrayGetCount(array);
  304. id buffer[count];
  305. id *ptr = buffer;
  306. for( id url in (NSArray *)array )
  307. *ptr++ = [(id)CFURLCopyPath((CFURLRef)url) autorelease];
  308. [(id)array release];
  309. return [(id)CFArrayCreate( kCFAllocatorDefault, (const void **)buffer, count, (CFArrayCallBacks *)&_PFCollectionCallBacks ) autorelease];
  310. }
  311. - (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
  312. {
  313. /*
  314. * I think this method actually does more than this, but that behaviour is controlled by user preference
  315. * keys, which we haven't implemented yet
  316. */
  317. return [(id)CFBundleCopyLocalizedString( (CFBundleRef)_cfBundle, (CFStringRef)key, (CFStringRef)value, (CFStringRef)tableName ) autorelease];
  318. }
  319. - (NSDictionary *)infoDictionary { return (NSDictionary *)CFBundleGetInfoDictionary( (CFBundleRef)_cfBundle ); }
  320. - (NSDictionary *)localizedInfoDictionary
  321. {
  322. return (NSDictionary *)CFBundleGetLocalInfoDictionary( (CFBundleRef)_cfBundle );
  323. }
  324. - (id)objectForInfoDictionaryKey:(NSString *)key
  325. {
  326. return (id)CFBundleGetValueForInfoDictionaryKey( (CFBundleRef)_cfBundle, (CFStringRef)key );
  327. }
  328. - (NSArray *)localizations { return [(id)CFBundleCopyBundleLocalizations( (CFBundleRef)_cfBundle ) autorelease]; }
  329. - (NSArray *)preferredLocalizations
  330. {
  331. // I think that this is the correct behaviour
  332. CFArrayRef localizations = CFBundleCopyBundleLocalizations( (CFBundleRef)_cfBundle );
  333. CFArrayRef preferred = CFBundleCopyPreferredLocalizationsFromArray(localizations);
  334. [(id)localizations release];
  335. return [(id)preferred autorelease];
  336. }
  337. - (NSString *)developmentLocalization { return (NSString *)CFBundleGetDevelopmentRegion( (CFBundleRef)_cfBundle ); }
  338. @end