2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
30 #include "CFBundle_Internal.h"
31 #include <CoreFoundation/CFPropertyList.h>
32 #include <CoreFoundation/CFNumber.h>
33 #include <CoreFoundation/CFSet.h>
34 #include <CoreFoundation/CFURLAccess.h>
36 #include "CFInternal.h"
38 #include <CoreFoundation/CFByteOrder.h>
39 #include "CFBundle_BinaryTypes.h"
41 #if defined(BINARY_SUPPORT_DYLD)
42 // Import the mach-o headers that define the macho magic numbers
43 #include <mach-o/loader.h>
44 #include <mach-o/fat.h>
45 #include <mach-o/arch.h>
46 #include <mach-o/swap.h>
47 #include <mach-o/dyld.h>
48 #include <mach-o/getsect.h>
55 #endif /* BINARY_SUPPORT_DYLD */
57 #if defined(__MACOS8__)
60 #include <Processes.h>
62 /* Unixy & Windows Headers */
66 #if defined(__LINUX__)
70 #if defined(__WIN32__)
76 // Public CFBundle Info plist keys
77 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey, "CFBundleInfoDictionaryVersion")
78 CONST_STRING_DECL(kCFBundleExecutableKey, "CFBundleExecutable")
79 CONST_STRING_DECL(kCFBundleIdentifierKey, "CFBundleIdentifier")
80 CONST_STRING_DECL(kCFBundleVersionKey, "CFBundleVersion")
81 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey, "CFBundleDevelopmentRegion")
82 CONST_STRING_DECL(kCFBundleLocalizationsKey, "CFBundleLocalizations")
85 CONST_STRING_DECL(_kCFBundlePackageTypeKey, "CFBundlePackageType")
86 CONST_STRING_DECL(_kCFBundleSignatureKey, "CFBundleSignature")
87 CONST_STRING_DECL(_kCFBundleIconFileKey, "CFBundleIconFile")
88 CONST_STRING_DECL(_kCFBundleDocumentTypesKey, "CFBundleDocumentTypes")
89 CONST_STRING_DECL(_kCFBundleURLTypesKey, "CFBundleURLTypes")
91 // Keys that are usually localized in InfoPlist.strings
92 CONST_STRING_DECL(kCFBundleNameKey, "CFBundleName")
93 CONST_STRING_DECL(_kCFBundleDisplayNameKey, "CFBundleDisplayName")
94 CONST_STRING_DECL(_kCFBundleShortVersionStringKey, "CFBundleShortVersionString")
95 CONST_STRING_DECL(_kCFBundleGetInfoStringKey, "CFBundleGetInfoString")
96 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey, "CFBundleGetInfoHTML")
98 // Sub-keys for CFBundleDocumentTypes dictionaries
99 CONST_STRING_DECL(_kCFBundleTypeNameKey, "CFBundleTypeName")
100 CONST_STRING_DECL(_kCFBundleTypeRoleKey, "CFBundleTypeRole")
101 CONST_STRING_DECL(_kCFBundleTypeIconFileKey, "CFBundleTypeIconFile")
102 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey, "CFBundleTypeOSTypes")
103 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey, "CFBundleTypeExtensions")
104 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey, "CFBundleTypeMIMETypes")
106 // Sub-keys for CFBundleURLTypes dictionaries
107 CONST_STRING_DECL(_kCFBundleURLNameKey, "CFBundleURLName")
108 CONST_STRING_DECL(_kCFBundleURLIconFileKey, "CFBundleURLIconFile")
109 CONST_STRING_DECL(_kCFBundleURLSchemesKey, "CFBundleURLSchemes")
111 // Compatibility key names
112 CONST_STRING_DECL(_kCFBundleOldExecutableKey, "NSExecutable")
113 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey, "NSInfoPlistVersion")
114 CONST_STRING_DECL(_kCFBundleOldNameKey, "NSHumanReadableName")
115 CONST_STRING_DECL(_kCFBundleOldIconFileKey, "NSIcon")
116 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey, "NSTypes")
117 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey, "NSAppVersion")
119 // Compatibility CFBundleDocumentTypes key names
120 CONST_STRING_DECL(_kCFBundleOldTypeNameKey, "NSName")
121 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey, "NSRole")
122 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey, "NSIcon")
123 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key, "NSUnixExtensions")
124 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key, "NSDOSExtensions")
125 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey, "NSMacOSType")
127 // Internally used keys for loaded Info plists.
128 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey, "CFBundleInfoPlistURL")
129 CONST_STRING_DECL(_kCFBundleNumericVersionKey, "CFBundleNumericVersion")
130 CONST_STRING_DECL(_kCFBundleExecutablePathKey, "CFBundleExecutablePath")
131 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey, "CSResourcesFileMapped")
132 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey, "CFBundleCFMLoadAsBundle")
133 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey, "CFBundleAllowMixedLocalizations")
135 static CFTypeID __kCFBundleTypeID = _kCFRuntimeNotATypeID;
143 CFDictionaryRef _infoDict;
144 CFDictionaryRef _localInfoDict;
145 CFArrayRef _searchLanguages;
147 __CFPBinaryType _binaryType;
150 Boolean _sharesStringsFiles;
154 void *_connectionCookie;
160 /* CFM<->DYLD glue */
161 CFMutableDictionaryRef _glueDict;
163 /* Resource fork goop */
164 _CFResourceData _resourceData;
166 _CFPlugInData _plugInData;
168 #if defined(BINARY_SUPPORT_DLL)
174 static CFSpinLock_t CFBundleGlobalDataLock = 0;
176 static CFMutableDictionaryRef _bundlesByURL = NULL;
177 static CFMutableDictionaryRef _bundlesByIdentifier = NULL;
179 // For scheduled lazy unloading. Used by CFPlugIn.
180 static CFMutableSetRef _bundlesToUnload = NULL;
181 static Boolean _scheduledBundlesAreUnloading = false;
183 // Various lists of all bundles.
184 static CFMutableArrayRef _allBundles = NULL;
186 static Boolean _initedMainBundle = false;
187 static CFBundleRef _mainBundle = NULL;
188 static CFStringRef _defaultLocalization = NULL;
190 // Forward declares functions.
191 static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked);
192 static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict);
193 static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle);
194 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath);
195 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths);
196 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint);
197 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
198 static void _CFBundleCheckWorkarounds(CFBundleRef bundle);
199 #if defined(BINARY_SUPPORT_DYLD)
200 static CFDictionaryRef _CFBundleGrokInfoDictFromMainExecutable(void);
201 static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p);
202 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch);
203 #endif /* BINARY_SUPPORT_DYLD */
204 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
205 static void *_CFBundleFunctionPointerForTVector(CFAllocatorRef allocator, void *tvp);
206 static void *_CFBundleTVectorForFunctionPointer(CFAllocatorRef allocator, void *fp);
207 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
209 static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) {
210 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
212 if (!alreadyLocked) {
213 __CFSpinLock(&CFBundleGlobalDataLock);
216 // Add to the _allBundles list
217 if (_allBundles == NULL) {
218 // Create this from the default allocator
219 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
220 nonRetainingArrayCallbacks.retain = NULL;
221 nonRetainingArrayCallbacks.release = NULL;
222 _allBundles = CFArrayCreateMutable(NULL, 0, &nonRetainingArrayCallbacks);
224 CFArrayAppendValue(_allBundles, bundle);
226 // Add to the table that maps urls to bundles
227 if (_bundlesByURL == NULL) {
228 // Create this from the default allocator
229 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
230 nonRetainingDictionaryValueCallbacks.retain = NULL;
231 nonRetainingDictionaryValueCallbacks.release = NULL;
232 _bundlesByURL = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
234 CFDictionarySetValue(_bundlesByURL, bundle->_url, bundle);
236 // Add to the table that maps identifiers to bundles
238 CFBundleRef existingBundle = NULL;
239 Boolean addIt = true;
240 if (_bundlesByIdentifier == NULL) {
241 // Create this from the default allocator
242 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
243 nonRetainingDictionaryValueCallbacks.retain = NULL;
244 nonRetainingDictionaryValueCallbacks.release = NULL;
245 _bundlesByIdentifier = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
247 existingBundle = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
248 if (existingBundle) {
249 UInt32 existingVersion, newVersion;
250 existingVersion = CFBundleGetVersionNumber(existingBundle);
251 newVersion = CFBundleGetVersionNumber(bundle);
252 if (newVersion < existingVersion) {
253 // Less than to means that if you load two bundles with the same identifier and the same version, the last one wins.
258 CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundle);
261 if (!alreadyLocked) {
262 __CFSpinUnlock(&CFBundleGlobalDataLock);
266 static void _CFBundleRemoveFromTables(CFBundleRef bundle) {
267 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
269 __CFSpinLock(&CFBundleGlobalDataLock);
271 // Remove from the various lists
272 if (_allBundles != NULL) {
273 CFIndex i = CFArrayGetFirstIndexOfValue(_allBundles, CFRangeMake(0, CFArrayGetCount(_allBundles)), bundle);
275 CFArrayRemoveValueAtIndex(_allBundles, i);
279 // Remove from the table that maps urls to bundles
280 if (_bundlesByURL != NULL) {
281 CFDictionaryRemoveValue(_bundlesByURL, bundle->_url);
284 // Remove from the table that maps identifiers to bundles
285 if ((bundleID != NULL) && (_bundlesByIdentifier != NULL)) {
286 if (CFDictionaryGetValue(_bundlesByIdentifier, bundleID) == bundle) {
287 CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID);
290 __CFSpinUnlock(&CFBundleGlobalDataLock);
293 __private_extern__ CFBundleRef _CFBundleFindByURL(CFURLRef url, Boolean alreadyLocked) {
294 CFBundleRef result = NULL;
295 if (!alreadyLocked) {
296 __CFSpinLock(&CFBundleGlobalDataLock);
298 if (_bundlesByURL != NULL) {
299 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url);
301 if (!alreadyLocked) {
302 __CFSpinUnlock(&CFBundleGlobalDataLock);
307 static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) {
308 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
309 UniChar buff[CFMaxPathSize];
314 buffLen = CFStringGetLength(str);
315 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
316 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); // Remove exe name
319 // See if this is a new bundle. If it is, we have to remove more path components.
320 CFIndex startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen);
321 if ((startOfLastDir > 0) && (startOfLastDir < buffLen)) {
322 CFStringRef lastDirName = CFStringCreateWithCharacters(NULL, &(buff[startOfLastDir]), buffLen - startOfLastDir);
324 if (CFEqual(lastDirName, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
325 // This is a new bundle. Back off a few more levels
327 // Remove platform folder
328 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
331 // Remove executables folder (if present)
332 CFIndex startOfNextDir = _CFStartOfLastPathComponent(buff, buffLen);
333 if ((startOfNextDir > 0) && (startOfNextDir < buffLen)) {
334 CFStringRef nextDirName = CFStringCreateWithCharacters(NULL, &(buff[startOfNextDir]), buffLen - startOfNextDir);
335 if (CFEqual(nextDirName, _CFBundleExecutablesDirectoryName)) {
336 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
338 CFRelease(nextDirName);
342 // Remove support files folder
343 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
346 CFRelease(lastDirName);
351 outstr = CFStringCreateWithCharactersNoCopy(NULL, buff, buffLen, kCFAllocatorNull);
352 url = CFURLCreateWithFileSystemPath(NULL, outstr, PLATFORM_PATH_STYLE, true);
358 static CFURLRef _CFBundleCopyResolvedURLForExecutableURL(CFURLRef url) {
359 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
360 CFURLRef absoluteURL, url1, url2, outURL = NULL;
361 CFStringRef str, str1, str2;
362 absoluteURL = CFURLCopyAbsoluteURL(url);
363 str = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
365 UniChar buff[CFMaxPathSize];
366 CFIndex buffLen = CFStringGetLength(str), len1;
367 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
368 len1 = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
369 if (len1 > 0 && len1 + 1 < buffLen) {
370 str1 = CFStringCreateWithCharacters(NULL, buff, len1);
371 str2 = CFStringCreateWithCharacters(NULL, buff + len1 + 1, buffLen - len1 - 1);
373 url1 = CFURLCreateWithFileSystemPath(NULL, str1, PLATFORM_PATH_STYLE, true);
375 url2 = CFURLCreateWithFileSystemPathRelativeToBase(NULL, str2, PLATFORM_PATH_STYLE, false, url1);
377 outURL = CFURLCopyAbsoluteURL(url2);
383 if (str1) CFRelease(str1);
384 if (str2) CFRelease(str2);
389 outURL = absoluteURL;
391 CFRelease(absoluteURL);
396 CFURLRef _CFBundleCopyBundleURLForExecutableURL(CFURLRef url) {
397 CFURLRef resolvedURL, outurl = NULL;
399 resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url);
400 str = CFURLCopyFileSystemPath(resolvedURL, PLATFORM_PATH_STYLE);
402 outurl = _CFBundleCopyBundleURLForExecutablePath(str);
405 CFRelease(resolvedURL);
409 CFBundleRef _CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) {
410 CFBundleRef bundle = CFBundleCreate(allocator, url);
412 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
413 if (bundle && 0 == bundle->_version) {
414 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
415 if (!infoDict || 0 == CFDictionaryGetCount(infoDict)) {
416 #if defined(BINARY_SUPPORT_CFM) && defined(BINARY_SUPPORT_DYLD)
417 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
419 if (bundle->_binaryType == __CFBundleUnknownBinary) {
420 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
422 if (bundle->_binaryType == __CFBundleCFMBinary || bundle->_binaryType == __CFBundleUnreadableBinary) {
423 bundle->_version = 4;
425 bundle->_resourceData._executableLacksResourceFork = true;
427 CFRelease(executableURL);
429 bundle->_version = 4;
431 #elif defined(BINARY_SUPPORT_CFM)
432 bundle->_version = 4;
434 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
436 CFRelease(executableURL);
438 bundle->_version = 4;
440 #endif /* BINARY_SUPPORT_CFM && BINARY_SUPPORT_DYLD */
443 if (bundle && (3 == bundle->_version || 4 == bundle->_version)) {
450 CFBundleRef _CFBundleGetMainBundleIfLooksLikeBundle(void) {
451 CFBundleRef mainBundle = CFBundleGetMainBundle();
452 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) {
458 CFBundleRef _CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) {
459 CFBundleRef bundle = NULL;
460 CFURLRef bundleURL = _CFBundleCopyBundleURLForExecutableURL(url), resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url);
461 if (bundleURL && resolvedURL) {
462 bundle = _CFBundleCreateIfLooksLikeBundle(allocator, bundleURL);
464 CFURLRef executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle);
465 char buff1[CFMaxPathSize], buff2[CFMaxPathSize];
466 if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) {
470 if (executableURL) CFRelease(executableURL);
473 if (bundleURL) CFRelease(bundleURL);
474 if (resolvedURL) CFRelease(resolvedURL);
478 static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) {
479 if (!_initedMainBundle) {
480 const char *processPath;
481 CFStringRef str = NULL;
482 CFURLRef executableURL = NULL, bundleURL = NULL;
483 #if defined(BINARY_SUPPORT_CFM)
484 Boolean versRegionOverrides = false;
485 #endif /* BINARY_SUPPORT_CFM */
486 #if defined(__MACOS8__)
487 // do not use Posix-styled _CFProcessPath()
488 ProcessSerialNumber gProcessID;
489 ProcessInfoRec processInfo;
490 FSSpec processAppSpec;
492 processInfo.processInfoLength = sizeof(ProcessInfoRec);
493 processInfo.processAppSpec = &processAppSpec;
495 if ((GetCurrentProcess(&gProcessID) == noErr) && (GetProcessInformation(&gProcessID, &processInfo) == noErr)) {
496 executableURL = _CFCreateURLFromFSSpec(NULL, (void *)(&processAppSpec), false);
499 _initedMainBundle = true;
500 processPath = _CFProcessPath();
502 str = CFStringCreateWithCString(NULL, processPath, CFStringFileSystemEncoding());
503 if (!executableURL) executableURL = CFURLCreateWithFileSystemPath(NULL, str, PLATFORM_PATH_STYLE, false);
506 bundleURL = _CFBundleCopyBundleURLForExecutableURL(executableURL);
508 if (bundleURL != NULL) {
509 // make sure that main bundle has executable path
510 //??? what if we are not the main executable in the bundle?
511 _mainBundle = _CFBundleCreate(NULL, bundleURL, true);
512 if (_mainBundle != NULL) {
513 CFBundleGetInfoDictionary(_mainBundle);
514 // make sure that the main bundle is listed as loaded, and mark it as executable
515 _mainBundle->_isLoaded = true;
516 #if defined(BINARY_SUPPORT_DYLD)
517 if (_mainBundle->_binaryType == __CFBundleUnknownBinary) {
518 if (!executableURL) {
519 _mainBundle->_binaryType = __CFBundleNoBinary;
521 _mainBundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
522 #if defined(BINARY_SUPPORT_CFM)
523 if (_mainBundle->_binaryType != __CFBundleCFMBinary && _mainBundle->_binaryType != __CFBundleUnreadableBinary) {
524 _mainBundle->_resourceData._executableLacksResourceFork = true;
526 #endif /* BINARY_SUPPORT_CFM */
529 #endif /* BINARY_SUPPORT_DYLD */
530 if (_mainBundle->_infoDict == NULL || CFDictionaryGetCount(_mainBundle->_infoDict) == 0) {
531 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
532 if (_mainBundle->_version == 3) _mainBundle->_version = 4;
533 if (_mainBundle->_version == 0) {
534 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
535 CFStringRef executableName = _CFBundleCopyExecutableName(NULL, _mainBundle, NULL, NULL);
536 if (!executableName || !CFStringHasSuffix(str, executableName)) _mainBundle->_version = 4;
537 if (executableName) CFRelease(executableName);
539 #if defined(BINARY_SUPPORT_DYLD)
540 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) {
541 if (_mainBundle->_infoDict != NULL) CFRelease(_mainBundle->_infoDict);
542 _mainBundle->_infoDict = _CFBundleGrokInfoDictFromMainExecutable();
544 #endif /* BINARY_SUPPORT_DYLD */
545 #if defined(BINARY_SUPPORT_CFM)
546 if (_mainBundle->_binaryType == __CFBundleCFMBinary || _mainBundle->_binaryType == __CFBundleUnreadableBinary) {
547 // if type 0 bundle and CFM binary and no Info.plist, treat as unbundled, since this also gives too many false positives
548 if (_mainBundle->_version == 0) _mainBundle->_version = 4;
549 if (_mainBundle->_infoDict != NULL) CFRelease(_mainBundle->_infoDict);
550 _mainBundle->_infoDict = _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFGetAllocator(_mainBundle), executableURL);
551 if (_mainBundle->_binaryType == __CFBundleUnreadableBinary && _mainBundle->_infoDict != NULL && CFDictionaryGetValue(_mainBundle->_infoDict, kCFBundleDevelopmentRegionKey) != NULL) versRegionOverrides = true;
553 #endif /* BINARY_SUPPORT_CFM */
555 if (_mainBundle->_infoDict == NULL) {
556 _mainBundle->_infoDict = CFDictionaryCreateMutable(CFGetAllocator(_mainBundle), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
558 if (NULL == CFDictionaryGetValue(_mainBundle->_infoDict, _kCFBundleExecutablePathKey)) {
559 CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), _kCFBundleExecutablePathKey, str);
561 #if defined(BINARY_SUPPORT_DYLD)
562 // get cookie for already-loaded main bundle
563 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary && !_mainBundle->_imageCookie) {
564 _mainBundle->_imageCookie = (void *)_dyld_get_image_header(0);
566 #endif /* BINARY_SUPPORT_DYLD */
567 #if defined(BINARY_SUPPORT_CFM)
568 if (versRegionOverrides) {
569 // This is a hack to preserve backward compatibility for certain broken applications (2761067)
570 CFStringRef devLang = _CFBundleCopyBundleDevelopmentRegionFromVersResource(_mainBundle);
571 if (devLang != NULL) {
572 CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), kCFBundleDevelopmentRegionKey, devLang);
576 #endif /* BINARY_SUPPORT_CFM */
579 if (bundleURL) CFRelease(bundleURL);
580 if (str) CFRelease(str);
581 if (executableURL) CFRelease(executableURL);
586 CFBundleRef CFBundleGetMainBundle(void) {
587 CFBundleRef mainBundle;
588 __CFSpinLock(&CFBundleGlobalDataLock);
589 mainBundle = _CFBundleGetMainBundleAlreadyLocked();
590 __CFSpinUnlock(&CFBundleGlobalDataLock);
594 #if defined(BINARY_SUPPORT_DYLD)
596 static void *_CFBundleReturnAddressFromFrameAddress(void *addr)
600 __asm__ volatile("lwz %0,0x0008(%1)" : "=r" (ret) : "b" (addr));
601 #elif defined(__i386__)
602 __asm__ volatile("movl 0x4(%1),%0" : "=r" (ret) : "r" (addr));
604 __asm__ volatile("ldw 0x4(%1),%0" : "=r" (ret) : "r" (addr));
606 __asm__ volatile("ta 0x3");
607 __asm__ volatile("ld [%1 + 60],%0" : "=r" (ret) : "r" (addr));
609 #warning Do not know how to define _CFBundleReturnAddressFromFrameAddress on this architecture
617 CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) {
618 CFBundleRef result = NULL;
620 __CFSpinLock(&CFBundleGlobalDataLock);
621 (void)_CFBundleGetMainBundleAlreadyLocked();
622 if (_bundlesByIdentifier != NULL) {
623 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
625 #if defined(BINARY_SUPPORT_DYLD)
626 if (result == NULL) {
627 // Try to create the bundle for the caller and try again
628 void *p = _CFBundleReturnAddressFromFrameAddress(__builtin_frame_address(1));
629 CFStringRef imagePath = _CFBundleDYLDCopyLoadedImagePathForPointer(p);
630 if (imagePath != NULL) {
631 _CFBundleEnsureBundleExistsForImagePath(imagePath);
632 CFRelease(imagePath);
634 if (_bundlesByIdentifier != NULL) {
635 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
639 if (result == NULL) {
640 // Try to guess the bundle from the identifier and try again
641 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID);
642 if (_bundlesByIdentifier != NULL) {
643 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
646 if (result == NULL) {
647 // Make sure all bundles have been created and try again.
648 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
649 if (_bundlesByIdentifier != NULL) {
650 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
653 __CFSpinUnlock(&CFBundleGlobalDataLock);
658 static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) {
659 char buff[CFMaxPathSize];
660 CFStringRef path = NULL, binaryType = NULL, retval = NULL;
661 if (((CFBundleRef)cf)->_url != NULL && CFURLGetFileSystemRepresentation(((CFBundleRef)cf)->_url, true, buff, CFMaxPathSize)) {
662 path = CFStringCreateWithCString(NULL, buff, CFStringFileSystemEncoding());
664 switch (((CFBundleRef)cf)->_binaryType) {
665 case __CFBundleCFMBinary:
666 binaryType = CFSTR("");
668 case __CFBundleDYLDExecutableBinary:
669 binaryType = CFSTR("executable, ");
671 case __CFBundleDYLDBundleBinary:
672 binaryType = CFSTR("bundle, ");
674 case __CFBundleDYLDFrameworkBinary:
675 binaryType = CFSTR("framework, ");
677 case __CFBundleDLLBinary:
678 binaryType = CFSTR("DLL, ");
680 case __CFBundleUnreadableBinary:
681 binaryType = CFSTR("");
684 binaryType = CFSTR("");
687 if (((CFBundleRef)cf)->_plugInData._isPlugIn) {
688 retval = CFStringCreateWithFormat(NULL, NULL, CFSTR("CFBundle/CFPlugIn 0x%x <%@> (%@%sloaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? "" : "not ");
690 retval = CFStringCreateWithFormat(NULL, NULL, CFSTR("CFBundle 0x%x <%@> (%@%sloaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? "" : "not ");
692 if (path) CFRelease(path);
696 static void _CFBundleDeallocateGlue(const void *key, const void *value, void *context) {
697 CFAllocatorRef allocator = (CFAllocatorRef)context;
699 CFAllocatorDeallocate(allocator, (void *)value);
703 static void __CFBundleDeallocate(CFTypeRef cf) {
704 CFBundleRef bundle = (CFBundleRef)cf;
705 CFAllocatorRef allocator;
707 __CFGenericValidateType(cf, __kCFBundleTypeID);
709 allocator = CFGetAllocator(bundle);
712 CFBundleUnloadExecutable(bundle);
714 // Clean up plugIn stuff
715 _CFBundleDeallocatePlugIn(bundle);
717 _CFBundleRemoveFromTables(bundle);
719 if (bundle->_url != NULL) {
720 CFRelease(bundle->_url);
722 if (bundle->_infoDict != NULL) {
723 CFRelease(bundle->_infoDict);
725 if (bundle->_modDate != NULL) {
726 CFRelease(bundle->_modDate);
728 if (bundle->_localInfoDict != NULL) {
729 CFRelease(bundle->_localInfoDict);
731 if (bundle->_searchLanguages != NULL) {
732 CFRelease(bundle->_searchLanguages);
734 if (bundle->_glueDict != NULL) {
735 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)allocator);
736 CFRelease(bundle->_glueDict);
738 if (bundle->_resourceData._stringTableCache != NULL) {
739 CFRelease(bundle->_resourceData._stringTableCache);
743 static const CFRuntimeClass __CFBundleClass = {
748 __CFBundleDeallocate,
752 __CFBundleCopyDescription
755 __private_extern__ void __CFBundleInitialize(void) {
756 __kCFBundleTypeID = _CFRuntimeRegisterClass(&__CFBundleClass);
759 CFTypeID CFBundleGetTypeID(void) {
760 return __kCFBundleTypeID;
763 static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked) {
764 CFBundleRef bundle = NULL;
765 char buff[CFMaxPathSize];
766 CFDateRef modDate = NULL;
767 Boolean exists = false;
769 CFURLRef newURL = NULL;
770 uint8_t localVersion = 0;
772 if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL;
774 newURL = CFURLCreateFromFileSystemRepresentation(allocator, buff, strlen(buff), true);
775 if (NULL == newURL) {
776 newURL = CFRetain(bundleURL);
778 bundle = _CFBundleFindByURL(newURL, alreadyLocked);
785 if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) {
787 if (_CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) {
788 if (!exists || ((mode & S_IFMT) != S_IFDIR)) {
789 if (NULL != modDate) CFRelease(modDate);
799 bundle = (CFBundleRef)_CFRuntimeCreateInstance(allocator, __kCFBundleTypeID, sizeof(struct __CFBundle) - sizeof(CFRuntimeBase), NULL);
800 if (NULL == bundle) {
805 bundle->_url = newURL;
807 bundle->_modDate = modDate;
808 bundle->_version = localVersion;
809 bundle->_infoDict = NULL;
810 bundle->_localInfoDict = NULL;
811 bundle->_searchLanguages = NULL;
813 #if defined(BINARY_SUPPORT_DYLD)
814 /* We'll have to figure it out later */
815 bundle->_binaryType = __CFBundleUnknownBinary;
816 #elif defined(BINARY_SUPPORT_CFM)
817 /* We support CFM only */
818 bundle->_binaryType = __CFBundleCFMBinary;
819 #elif defined(BINARY_SUPPORT_DLL)
820 /* We support DLL only */
821 bundle->_binaryType = __CFBundleDLLBinary;
822 bundle->_hModule = NULL;
824 /* We'll have to figure it out later */
825 bundle->_binaryType = __CFBundleUnknownBinary;
828 bundle->_isLoaded = false;
829 bundle->_sharesStringsFiles = false;
831 /* ??? For testing purposes? Or for good? */
832 if (!getenv("CFBundleDisableStringsSharing") &&
833 (strncmp(buff, "/System/Library/Frameworks", 26) == 0) &&
834 (strncmp(buff + strlen(buff) - 10, ".framework", 10) == 0)) bundle->_sharesStringsFiles = true;
836 bundle->_connectionCookie = NULL;
837 bundle->_imageCookie = NULL;
838 bundle->_moduleCookie = NULL;
840 bundle->_glueDict = NULL;
842 #if defined(BINARY_SUPPORT_CFM)
843 bundle->_resourceData._executableLacksResourceFork = false;
845 bundle->_resourceData._executableLacksResourceFork = true;
848 bundle->_resourceData._stringTableCache = NULL;
850 bundle->_plugInData._isPlugIn = false;
851 bundle->_plugInData._loadOnDemand = false;
852 bundle->_plugInData._isDoingDynamicRegistration = false;
853 bundle->_plugInData._instanceCount = 0;
854 bundle->_plugInData._factories = NULL;
856 CFBundleGetInfoDictionary(bundle);
858 _CFBundleAddToTables(bundle, alreadyLocked);
860 _CFBundleInitPlugIn(bundle);
862 _CFBundleCheckWorkarounds(bundle);
867 CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL) {return _CFBundleCreate(allocator, bundleURL, false);}
869 CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc, CFURLRef directoryURL, CFStringRef bundleType) {
870 CFMutableArrayRef bundles = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
871 CFArrayRef URLs = _CFContentsOfDirectory(alloc, NULL, NULL, directoryURL, bundleType);
873 CFIndex i, c = CFArrayGetCount(URLs);
875 CFBundleRef curBundle;
877 for (i=0; i<c; i++) {
878 curURL = CFArrayGetValueAtIndex(URLs, i);
879 curBundle = CFBundleCreate(alloc, curURL);
880 if (curBundle != NULL) {
881 CFArrayAppendValue(bundles, curBundle);
890 CFURLRef CFBundleCopyBundleURL(CFBundleRef bundle) {
892 CFRetain(bundle->_url);
897 void _CFBundleSetDefaultLocalization(CFStringRef localizationName) {
898 CFStringRef newLocalization = localizationName ? CFStringCreateCopy(NULL, localizationName) : NULL;
899 if (_defaultLocalization) CFRelease(_defaultLocalization);
900 _defaultLocalization = newLocalization;
903 __private_extern__ CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle) {
904 if (bundle->_searchLanguages == NULL) {
905 CFMutableArrayRef langs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
906 CFStringRef devLang = CFBundleGetDevelopmentRegion(bundle);
908 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, devLang);
910 if (CFArrayGetCount(langs) == 0) {
911 // If the user does not prefer any of our languages, and devLang is not present, try English
912 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, CFSTR("en_US"));
914 if (CFArrayGetCount(langs) == 0) {
915 // if none of the preferred localizations are present, fall back on a random localization that is present
916 CFArrayRef localizations = CFBundleCopyBundleLocalizations(bundle);
918 if (CFArrayGetCount(localizations) > 0) {
919 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, CFArrayGetValueAtIndex(localizations, 0));
921 CFRelease(localizations);
925 if (devLang != NULL && !CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang)) {
926 // Make sure that devLang is on the list as a fallback for individual resources that are not present
927 CFArrayAppendValue(langs, devLang);
928 } else if (devLang == NULL) {
929 // Or if there is no devLang, try some variation of English that is present
930 CFArrayRef localizations = CFBundleCopyBundleLocalizations(bundle);
932 CFStringRef en_US = CFSTR("en_US"), en = CFSTR("en"), English = CFSTR("English");
933 CFRange range = CFRangeMake(0, CFArrayGetCount(localizations));
934 if (CFArrayContainsValue(localizations, range, en)) {
935 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), en)) CFArrayAppendValue(langs, en);
936 } else if (CFArrayContainsValue(localizations, range, English)) {
937 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), English)) CFArrayAppendValue(langs, English);
938 } else if (CFArrayContainsValue(localizations, range, en_US)) {
939 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), en_US)) CFArrayAppendValue(langs, en_US);
941 CFRelease(localizations);
944 if (CFArrayGetCount(langs) == 0) {
945 // Total backstop behavior to avoid having an empty array.
946 if (_defaultLocalization != NULL) {
947 CFArrayAppendValue(langs, _defaultLocalization);
949 CFArrayAppendValue(langs, CFSTR("en"));
952 bundle->_searchLanguages = langs;
954 return bundle->_searchLanguages;
957 CFDictionaryRef CFBundleCopyInfoDictionaryInDirectory(CFURLRef url) {return _CFBundleCopyInfoDictionaryInDirectory(NULL, url, NULL);}
959 CFDictionaryRef CFBundleGetInfoDictionary(CFBundleRef bundle) {
960 if (bundle->_infoDict == NULL) {
961 bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle), bundle->_url, bundle->_version);
963 return bundle->_infoDict;
966 CFDictionaryRef _CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {return CFBundleGetLocalInfoDictionary(bundle);}
968 CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {
969 if (bundle->_localInfoDict == NULL) {
970 CFURLRef url = CFBundleCopyResourceURL(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL);
974 CFStringRef errStr = NULL;
976 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), url, &data, NULL, NULL, &errCode)) {
977 bundle->_localInfoDict = CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), data, kCFPropertyListImmutable, &errStr);
986 return bundle->_localInfoDict;
989 CFPropertyListRef _CFBundleGetValueForInfoKey(CFBundleRef bundle, CFStringRef key) {return (CFPropertyListRef)CFBundleGetValueForInfoDictionaryKey(bundle, key);}
991 CFTypeRef CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle, CFStringRef key) {
992 // Look in InfoPlist.strings first. Then look in Info.plist
993 CFTypeRef result = NULL;
994 if ((bundle!= NULL) && (key != NULL)) {
995 CFDictionaryRef dict = CFBundleGetLocalInfoDictionary(bundle);
997 result = CFDictionaryGetValue(dict, key);
999 if (result == NULL) {
1000 dict = CFBundleGetInfoDictionary(bundle);
1002 result = CFDictionaryGetValue(dict, key);
1009 CFStringRef CFBundleGetIdentifier(CFBundleRef bundle) {
1010 CFStringRef bundleID = NULL;
1011 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1013 bundleID = CFDictionaryGetValue(infoDict, kCFBundleIdentifierKey);
1018 #define DEVELOPMENT_STAGE 0x20
1019 #define ALPHA_STAGE 0x40
1020 #define BETA_STAGE 0x60
1021 #define RELEASE_STAGE 0x80
1023 #define MAX_VERS_LEN 10
1025 CF_INLINE Boolean _isDigit(UniChar aChar) {return (((aChar >= (UniChar)'0') && (aChar <= (UniChar)'9')) ? true : false);}
1027 __private_extern__ CFStringRef _CFCreateStringFromVersionNumber(CFAllocatorRef alloc, UInt32 vers) {
1028 CFStringRef result = NULL;
1029 uint8_t major1, major2, minor1, minor2, stage, build;
1031 major1 = (vers & 0xF0000000) >> 28;
1032 major2 = (vers & 0x0F000000) >> 24;
1033 minor1 = (vers & 0x00F00000) >> 20;
1034 minor2 = (vers & 0x000F0000) >> 16;
1035 stage = (vers & 0x0000FF00) >> 8;
1036 build = (vers & 0x000000FF);
1038 if (stage == RELEASE_STAGE) {
1040 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d"), major1, major2, minor1, minor2);
1042 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d"), major2, minor1, minor2);
1046 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d%s%d"), major1, major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? "d" : ((stage == ALPHA_STAGE) ? "a" : "b")), build);
1048 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d%s%d"), major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? "d" : ((stage == ALPHA_STAGE) ? "a" : "b")), build);
1054 __private_extern__ UInt32 _CFVersionNumberFromString(CFStringRef versStr) {
1055 // Parse version number from string.
1056 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1057 UInt32 major1 = 0, major2 = 0, minor1 = 0, minor2 = 0, stage = RELEASE_STAGE, build = 0;
1058 UniChar versChars[MAX_VERS_LEN];
1059 UniChar *chars = NULL;
1062 Boolean digitsDone = false;
1064 if (!versStr) return 0;
1066 len = CFStringGetLength(versStr);
1068 if ((len == 0) || (len > MAX_VERS_LEN)) return 0;
1070 CFStringGetCharacters(versStr, CFRangeMake(0, len), versChars);
1073 // Get major version number.
1074 major1 = major2 = 0;
1075 if (_isDigit(*chars)) {
1076 major2 = *chars - (UniChar)'0';
1080 if (_isDigit(*chars)) {
1082 major2 = *chars - (UniChar)'0';
1086 if (*chars == (UniChar)'.') {
1093 } else if (*chars == (UniChar)'.') {
1100 } else if (*chars == (UniChar)'.') {
1107 // Now major1 and major2 contain first and second digit of the major version number as ints.
1108 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1110 // Get the first minor version number.
1111 if (len > 0 && !digitsDone) {
1112 if (_isDigit(*chars)) {
1113 minor1 = *chars - (UniChar)'0';
1117 if (*chars == (UniChar)'.') {
1129 // Now minor1 contains the first minor version number as an int.
1130 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1132 // Get the second minor version number.
1133 if (len > 0 && !digitsDone) {
1134 if (_isDigit(*chars)) {
1135 minor2 = *chars - (UniChar)'0';
1143 // Now minor2 contains the second minor version number as an int.
1144 // Now either len is 0 or chars points at the build stage letter.
1146 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1148 if (*chars == (UniChar)'d') {
1149 stage = DEVELOPMENT_STAGE;
1150 } else if (*chars == (UniChar)'a') {
1151 stage = ALPHA_STAGE;
1152 } else if (*chars == (UniChar)'b') {
1154 } else if (*chars == (UniChar)'f') {
1155 stage = RELEASE_STAGE;
1163 // Now stage contains the release stage.
1164 // Now either len is 0 or chars points at the build number.
1166 // Get the first digit of the build number.
1168 if (_isDigit(*chars)) {
1169 build = *chars - (UniChar)'0';
1176 // Get the second digit of the build number.
1178 if (_isDigit(*chars)) {
1180 build += *chars - (UniChar)'0';
1187 // Get the third digit of the build number.
1189 if (_isDigit(*chars)) {
1191 build += *chars - (UniChar)'0';
1199 // Range check the build number and make sure we exhausted the string.
1200 if ((build > 0xFF) || (len > 0)) return 0;
1203 theVers = major1 << 28;
1204 theVers += major2 << 24;
1205 theVers += minor1 << 20;
1206 theVers += minor2 << 16;
1207 theVers += stage << 8;
1213 UInt32 CFBundleGetVersionNumber(CFBundleRef bundle) {
1214 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1215 CFTypeRef unknownVersionValue = CFDictionaryGetValue(infoDict, _kCFBundleNumericVersionKey);
1216 CFNumberRef versNum;
1219 if (unknownVersionValue == NULL) {
1220 unknownVersionValue = CFDictionaryGetValue(infoDict, kCFBundleVersionKey);
1222 if (unknownVersionValue != NULL) {
1223 if (CFGetTypeID(unknownVersionValue) == CFStringGetTypeID()) {
1224 // Convert a string version number into a numeric one.
1225 vers = _CFVersionNumberFromString((CFStringRef)unknownVersionValue);
1227 versNum = CFNumberCreate(CFGetAllocator(bundle), kCFNumberSInt32Type, &vers);
1228 CFDictionarySetValue((CFMutableDictionaryRef)infoDict, _kCFBundleNumericVersionKey, versNum);
1230 } else if (CFGetTypeID(unknownVersionValue) == CFNumberGetTypeID()) {
1231 CFNumberGetValue((CFNumberRef)unknownVersionValue, kCFNumberSInt32Type, &vers);
1233 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleNumericVersionKey);
1239 CFStringRef CFBundleGetDevelopmentRegion(CFBundleRef bundle) {
1240 CFStringRef devLang = NULL;
1241 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1243 devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
1244 if (devLang != NULL && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) {
1246 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleDevelopmentRegionKey);
1253 Boolean _CFBundleGetHasChanged(CFBundleRef bundle) {
1255 Boolean result = false;
1256 Boolean exists = false;
1259 if (_CFGetFileProperties(CFGetAllocator(bundle), bundle->_url, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) {
1260 // If the bundle no longer exists or is not a folder, it must have "changed"
1261 if (!exists || ((mode & S_IFMT) != S_IFDIR)) {
1265 // Something is wrong. The stat failed.
1268 if (bundle->_modDate && !CFEqual(bundle->_modDate, modDate)) {
1269 // mod date is different from when we created.
1276 void _CFBundleSetStringsFilesShared(CFBundleRef bundle, Boolean flag) {
1277 bundle->_sharesStringsFiles = flag;
1280 Boolean _CFBundleGetStringsFilesShared(CFBundleRef bundle) {
1281 return bundle->_sharesStringsFiles;
1284 static Boolean _urlExists(CFAllocatorRef alloc, CFURLRef url) {
1286 return url && (0 == _CFGetFileProperties(alloc, url, &exists, NULL, NULL, NULL, NULL, NULL)) && exists;
1289 __private_extern__ CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version) {
1290 CFURLRef result = NULL;
1293 result = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase1, bundleURL);
1294 } else if (2 == version) {
1295 result = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase2, bundleURL);
1297 result = CFRetain(bundleURL);
1303 CF_EXPORT CFURLRef CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle) {return _CFBundleCopySupportFilesDirectoryURLInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version);}
1305 __private_extern__ CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version) {
1306 CFURLRef result = NULL;
1309 result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase0, bundleURL);
1310 } else if (1 == version) {
1311 result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase1, bundleURL);
1312 } else if (2 == version) {
1313 result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase2, bundleURL);
1315 result = CFRetain(bundleURL);
1321 CFURLRef CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) {return _CFBundleCopyResourcesDirectoryURLInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version);}
1323 static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, CFURLRef urlPath, CFStringRef exeName) {
1324 // Given an url to a folder and a name, this returns the url to the executable in that folder with that name, if it exists, and NULL otherwise. This function deals with appending the ".exe" or ".dll" on Windows.
1325 CFURLRef executableURL = NULL;
1326 #if defined(__MACH__)
1327 const uint8_t *image_suffix = getenv("DYLD_IMAGE_SUFFIX");
1328 #endif /* __MACH__ */
1330 if (urlPath == NULL || exeName == NULL) return NULL;
1332 #if defined(__MACH__)
1333 if (image_suffix != NULL) {
1334 CFStringRef newExeName, imageSuffix;
1335 imageSuffix = CFStringCreateWithCString(NULL, image_suffix, kCFStringEncodingUTF8);
1336 if (CFStringHasSuffix(exeName, CFSTR(".dylib"))) {
1337 CFStringRef bareExeName = CFStringCreateWithSubstring(alloc, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6));
1338 newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix);
1339 CFRelease(bareExeName);
1341 newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, imageSuffix);
1343 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, newExeName, kCFURLPOSIXPathStyle, false, urlPath);
1344 if (executableURL != NULL && !_urlExists(alloc, executableURL)) {
1345 CFRelease(executableURL);
1346 executableURL = NULL;
1348 CFRelease(newExeName);
1349 CFRelease(imageSuffix);
1351 #endif /* __MACH__ */
1352 if (executableURL == NULL) {
1353 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, exeName, kCFURLPOSIXPathStyle, false, urlPath);
1354 if (executableURL != NULL && !_urlExists(alloc, executableURL)) {
1355 CFRelease(executableURL);
1356 executableURL = NULL;
1359 #if defined(__WIN32__)
1360 if (executableURL == NULL) {
1361 if (!CFStringHasSuffix(exeName, CFSTR(".dll"))) {
1362 CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR(".dll"));
1363 executableURL = CFURLCreateWithString(alloc, newExeName, urlPath);
1364 if (executableURL != NULL && !_urlExists(alloc, executableURL)) {
1365 CFRelease(executableURL);
1366 executableURL = NULL;
1368 CFRelease(newExeName);
1371 if (executableURL == NULL) {
1372 if (!CFStringHasSuffix(exeName, CFSTR(".exe"))) {
1373 CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR(".exe"));
1374 executableURL = CFURLCreateWithString(alloc, newExeName, urlPath);
1375 if (executableURL != NULL && !_urlExists(alloc, executableURL)) {
1376 CFRelease(executableURL);
1377 executableURL = NULL;
1379 CFRelease(newExeName);
1383 return executableURL;
1386 static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) {
1387 CFStringRef executableName = NULL;
1389 if (alloc == NULL && bundle != NULL) {
1390 alloc = CFGetAllocator(bundle);
1392 if (infoDict == NULL && bundle != NULL) {
1393 infoDict = CFBundleGetInfoDictionary(bundle);
1395 if (url == NULL && bundle != NULL) {
1399 if (infoDict != NULL) {
1400 // Figure out the name of the executable.
1401 // First try for the new key in the plist.
1402 executableName = CFDictionaryGetValue(infoDict, kCFBundleExecutableKey);
1403 if (executableName == NULL) {
1404 // Second try for the old key in the plist.
1405 executableName = CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey);
1407 if (executableName != NULL && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) {
1408 CFRetain(executableName);
1410 executableName = NULL;
1413 if (executableName == NULL && url != NULL) {
1414 // Third, take the name of the bundle itself (with path extension stripped)
1415 CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url);
1416 CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
1417 UniChar buff[CFMaxPathSize];
1418 CFIndex len = CFStringGetLength(bundlePath);
1419 CFIndex startOfBundleName, endOfBundleName;
1421 CFRelease(absoluteURL);
1422 CFStringGetCharacters(bundlePath, CFRangeMake(0, len), buff);
1423 startOfBundleName = _CFStartOfLastPathComponent(buff, len);
1424 endOfBundleName = _CFLengthAfterDeletingPathExtension(buff, len);
1426 if ((startOfBundleName <= len) && (endOfBundleName <= len) && (startOfBundleName < endOfBundleName)) {
1427 executableName = CFStringCreateWithCharacters(alloc, &(buff[startOfBundleName]), (endOfBundleName - startOfBundleName));
1429 CFRelease(bundlePath);
1432 return executableName;
1435 __private_extern__ CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boolean mayBeLocal) {
1436 CFStringRef executableName = _CFBundleCopyExecutableName(NULL, bundle, NULL, NULL);
1437 CFURLRef resourceForkURL = NULL;
1438 if (executableName != NULL) {
1440 resourceForkURL = CFBundleCopyResourceURL(bundle, executableName, CFSTR("rsrc"), NULL);
1442 resourceForkURL = CFBundleCopyResourceURLForLocalization(bundle, executableName, CFSTR("rsrc"), NULL, NULL);
1444 CFRelease(executableName);
1447 return resourceForkURL;
1450 CFURLRef _CFBundleCopyResourceForkURL(CFBundleRef bundle) {return _CFBundleCopyResourceForkURLMayBeLocal(bundle, true);}
1452 static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFStringRef executableName, Boolean ignoreCache, Boolean useOtherPlatform) {
1453 uint8_t version = 0;
1454 CFDictionaryRef infoDict = NULL;
1455 CFStringRef executablePath = NULL;
1456 CFURLRef executableURL = NULL;
1457 Boolean isDir = false;
1458 Boolean foundIt = false;
1459 Boolean lookupMainExe = ((executableName == NULL) ? true : false);
1461 if (bundle != NULL) {
1462 infoDict = CFBundleGetInfoDictionary(bundle);
1463 version = bundle->_version;
1465 infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, &version);
1468 // If we have a bundle instance and an info dict, see if we have already cached the path
1469 if (lookupMainExe && !ignoreCache && !useOtherPlatform && (bundle != NULL) && (infoDict != NULL)) {
1470 executablePath = CFDictionaryGetValue(infoDict, _kCFBundleExecutablePathKey);
1471 if (executablePath != NULL) {
1472 executableURL = CFURLCreateWithFileSystemPath(alloc, executablePath, kCFURLPOSIXPathStyle, false);
1473 if (executableURL != NULL) foundIt = true;
1475 executablePath = NULL;
1476 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleExecutablePathKey);
1482 if (lookupMainExe) {
1483 executableName = _CFBundleCopyExecutableName(alloc, bundle, url, infoDict);
1485 if (executableName != NULL) {
1486 // Now, look for the executable inside the bundle.
1489 CFURLRef exeSubdirURL;
1492 exeDirURL = CFURLCreateWithString(alloc, _CFBundleExecutablesURLFromBase1, url);
1493 } else if (2 == version) {
1494 exeDirURL = CFURLCreateWithString(alloc, _CFBundleExecutablesURLFromBase2, url);
1496 exeDirURL = CFRetain(url);
1498 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL);
1499 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName);
1500 if (executableURL == NULL) {
1501 CFRelease(exeSubdirURL);
1502 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL);
1503 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName);
1505 if (executableURL == NULL) {
1506 CFRelease(exeSubdirURL);
1507 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL);
1508 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName);
1510 if (executableURL == NULL) {
1511 CFRelease(exeSubdirURL);
1512 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL);
1513 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName);
1515 if (executableURL == NULL) {
1516 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeDirURL, executableName);
1519 CFRelease(exeDirURL);
1520 CFRelease(exeSubdirURL);
1523 // If this was an old bundle, or we did not find the executable in the Excutables subdirectory, look directly in the bundle wrapper.
1524 if (executableURL == NULL) {
1525 executableURL = _CFBundleCopyExecutableURLRaw(alloc, url, executableName);
1528 #if defined(__WIN32__)
1529 // Windows only: If we still haven't found the exe, look in the Executables folder.
1530 // But only for the main bundle exe
1531 if (lookupMainExe && (executableURL == NULL)) {
1534 exeDirURL = CFURLCreateWithString(alloc, CFSTR("../../Executables"), url);
1536 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeDirURL, executableName);
1538 CFRelease(exeDirURL);
1542 if (lookupMainExe && !ignoreCache && !useOtherPlatform && (bundle != NULL) && (infoDict != NULL) && (executableURL != NULL)) {
1543 // We found it. Cache the path.
1544 CFURLRef absURL = CFURLCopyAbsoluteURL(executableURL);
1545 executablePath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
1547 CFDictionarySetValue((CFMutableDictionaryRef)infoDict, _kCFBundleExecutablePathKey, executablePath);
1548 CFRelease(executablePath);
1550 if (lookupMainExe && !useOtherPlatform && (bundle != NULL) && (executableURL == NULL)) {
1551 bundle->_binaryType = __CFBundleNoBinary;
1553 if (lookupMainExe) {
1554 CFRelease(executableName);
1559 if ((bundle == NULL) && (infoDict != NULL)) {
1560 CFRelease(infoDict);
1563 return executableURL;
1566 CFURLRef _CFBundleCopyExecutableURLInDirectory(CFURLRef url) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL, NULL, url, NULL, true, false);}
1568 CFURLRef _CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL, NULL, url, NULL, true, true);}
1570 CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, NULL, false, false);}
1572 static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, NULL, true, false);}
1574 CFURLRef CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle, CFStringRef executableName) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, executableName, true, false);}
1576 Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle) {return bundle->_isLoaded;}
1578 #define UNKNOWN_FILETYPE 0x0
1579 #define PEF_FILETYPE 0x1000
1580 #define XLS_FILETYPE 0x10001
1581 #define DOC_FILETYPE 0x10002
1582 #define PPT_FILETYPE 0x10003
1583 #define XLS_NAME "Workbook"
1584 #define DOC_NAME "WordDocument"
1585 #define PPT_NAME "PowerPoint Document"
1586 #define PEF_MAGIC 0x4a6f7921
1587 #define PEF_CIGAM 0x21796f4a
1588 #define PLIST_SEGMENT "__TEXT"
1589 #define PLIST_SECTION "__info_plist"
1590 #define LIB_X11 "/usr/X11R6/lib/libX"
1592 static const uint32_t __CFBundleMagicNumbersArray[] = {
1593 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0x4a6f7921, 0x21796f4a, 0xffd8ffe0, 0x4d4d002a,
1594 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, 0x7b5c7274, 0x25504446, 0x2e7261fd,
1595 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864,
1596 0x504b0304, 0x53495421, 0x53495432, 0x53495435, 0x53495444, 0x53747566, 0x3c212d2d, 0x25215053,
1597 0xd0cf11e0, 0x62656769, 0x6b6f6c79, 0x3026b275, 0x0000000c
1600 // string, with groups of 5 characters being 1 element in the array
1601 static const char * __CFBundleExtensionsArray =
1602 "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" "jpeg\0" "tiff\0"
1603 "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" "rtf\0\0" "pdf\0\0" "ra\0\0\0"
1604 "au\0\0\0""au\0\0\0""iff\0\0" "riff\0" "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0"
1605 "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "html\0" "ps\0\0\0"
1606 "ole\0\0" "uu\0\0\0""dmg\0\0" "wmv\0\0" "jp2\0\0";
1608 #define NUM_EXTENSIONS 37
1609 #define EXTENSION_LENGTH 5
1610 #define MAGIC_BYTES_TO_READ 512
1612 #if defined(BINARY_SUPPORT_DYLD)
1614 CF_INLINE uint32_t _CFBundleSwapInt32Conditional(uint32_t arg, Boolean swap) {return swap ? CFSwapInt32(arg) : arg;}
1616 static CFDictionaryRef _CFBundleGrokInfoDictFromData(char *bytes, unsigned long length) {
1617 CFMutableDictionaryRef result = NULL;
1618 CFDataRef infoData = NULL;
1619 if (NULL != bytes && 0 < length) {
1620 infoData = CFDataCreateWithBytesNoCopy(NULL, bytes, length, kCFAllocatorNull);
1623 __CFSetNastyFile(CFSTR("<plist section in main executable>"));
1625 result = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(NULL, infoData, kCFPropertyListMutableContainers, NULL);
1626 if (result && CFDictionaryGetTypeID() != CFGetTypeID(result)) {
1630 CFRelease(infoData);
1633 result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1639 static CFDictionaryRef _CFBundleGrokInfoDictFromMainExecutable() {
1640 unsigned long length = 0;
1641 char *bytes = getsectdata(PLIST_SEGMENT, PLIST_SECTION, &length);
1642 return _CFBundleGrokInfoDictFromData(bytes, length);
1645 static CFDictionaryRef _CFBundleGrokInfoDictFromFile(int fd, unsigned long offset, Boolean swapped) {
1646 struct stat statBuf;
1649 CFDictionaryRef result = NULL;
1650 Boolean foundit = false;
1651 if (fstat(fd, &statBuf) == 0 && (maploc = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != (void *)-1) {
1652 unsigned long ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(maploc + offset))->ncmds, swapped);
1653 unsigned long sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(maploc + offset))->sizeofcmds, swapped);
1654 char *startofcmds = maploc + offset + sizeof(struct mach_header);
1655 char *endofcmds = startofcmds + sizeofcmds;
1656 struct segment_command *sgp = (struct segment_command *)startofcmds;
1657 if (endofcmds > maploc + statBuf.st_size) endofcmds = maploc + statBuf.st_size;
1658 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) {
1659 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) {
1660 struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command));
1661 unsigned long nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped);
1662 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) {
1663 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, PLIST_SEGMENT, sizeof(sp->segname))) {
1664 unsigned long length = _CFBundleSwapInt32Conditional(sp->size, swapped);
1665 unsigned long sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped);
1666 char *bytes = maploc + offset + sectoffset;
1667 if (maploc <= bytes && bytes + length <= maploc + statBuf.st_size) result = _CFBundleGrokInfoDictFromData(bytes, length);
1670 sp = (struct section *)((char *)sp + sizeof(struct section));
1673 sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped));
1675 munmap(maploc, statBuf.st_size);
1680 static Boolean _CFBundleGrokX11(int fd, unsigned long offset, Boolean swapped) {
1681 static const char libX11name[] = LIB_X11;
1682 struct stat statBuf;
1685 Boolean result = false;
1686 if (fstat(fd, &statBuf) == 0 && (maploc = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != (void *)-1) {
1687 unsigned long ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(maploc + offset))->ncmds, swapped);
1688 unsigned long sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(maploc + offset))->sizeofcmds, swapped);
1689 char *startofcmds = maploc + offset + sizeof(struct mach_header);
1690 char *endofcmds = startofcmds + sizeofcmds;
1691 struct dylib_command *dlp = (struct dylib_command *)startofcmds;
1692 if (endofcmds > maploc + statBuf.st_size) endofcmds = maploc + statBuf.st_size;
1693 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) {
1694 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) {
1695 unsigned long nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped);
1696 if (0 == strncmp((char *)dlp + nameoffset, libX11name, sizeof(libX11name) - 1)) result = true;
1698 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped));
1700 munmap(maploc, statBuf.st_size);
1706 static UInt32 _CFBundleGrokMachTypeForFatFile(int fd, void *bytes, CFIndex length, Boolean *isX11, CFDictionaryRef *infodict) {
1707 UInt32 machtype = UNKNOWN_FILETYPE, magic, numFatHeaders = ((struct fat_header *)bytes)->nfat_arch, maxFatHeaders = (length - sizeof(struct fat_header)) / sizeof(struct fat_arch);
1708 unsigned char moreBytes[sizeof(struct mach_header)];
1709 const NXArchInfo *archInfo = NXGetLocalArchInfo();
1710 struct fat_arch *fat = NULL;
1712 if (isX11) *isX11 = false;
1713 if (infodict) *infodict = NULL;
1714 if (numFatHeaders > maxFatHeaders) numFatHeaders = maxFatHeaders;
1715 if (numFatHeaders > 0) {
1716 fat = NXFindBestFatArch(archInfo->cputype, archInfo->cpusubtype, (struct fat_arch *)(bytes + sizeof(struct fat_header)), numFatHeaders);
1717 if (!fat) fat = (struct fat_arch *)(bytes + sizeof(struct fat_header));
1720 if (lseek(fd, fat->offset, SEEK_SET) == (off_t)fat->offset && read(fd, moreBytes, sizeof(struct mach_header)) >= (int)sizeof(struct mach_header)) {
1721 magic = *((UInt32 *)moreBytes);
1722 if (MH_MAGIC == magic) {
1723 machtype = ((struct mach_header *)moreBytes)->filetype;
1724 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, fat->offset, false);
1725 if (isX11) *isX11 = _CFBundleGrokX11(fd, fat->offset, false);
1726 } else if (MH_CIGAM == magic) {
1727 machtype = CFSwapInt32(((struct mach_header *)moreBytes)->filetype);
1728 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, fat->offset, true);
1729 if (isX11) *isX11 = _CFBundleGrokX11(fd, fat->offset, true);
1736 static UInt32 _CFBundleGrokMachType(int fd, void *bytes, CFIndex length, Boolean *isX11, CFDictionaryRef *infodict) {
1737 unsigned int magic = *((UInt32 *)bytes), machtype = UNKNOWN_FILETYPE;
1740 if (isX11) *isX11 = false;
1741 if (infodict) *infodict = NULL;
1742 if (MH_MAGIC == magic) {
1743 machtype = ((struct mach_header *)bytes)->filetype;
1744 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, 0, false);
1745 if (isX11) *isX11 = _CFBundleGrokX11(fd, 0, false);
1746 } else if (MH_CIGAM == magic) {
1747 for (i = 0; i < length; i += 4) *(UInt32 *)(bytes + i) = CFSwapInt32(*(UInt32 *)(bytes + i));
1748 machtype = ((struct mach_header *)bytes)->filetype;
1749 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, 0, true);
1750 if (isX11) *isX11 = _CFBundleGrokX11(fd, 0, true);
1751 } else if (FAT_MAGIC == magic) {
1752 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, isX11, infodict);
1753 } else if (FAT_CIGAM == magic) {
1754 for (i = 0; i < length; i += 4) *(UInt32 *)(bytes + i) = CFSwapInt32(*(UInt32 *)(bytes + i));
1755 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, isX11, infodict);
1756 } else if (PEF_MAGIC == magic || PEF_CIGAM == magic) {
1757 machtype = PEF_FILETYPE;
1762 #endif /* BINARY_SUPPORT_DYLD */
1764 static UInt32 _CFBundleGrokFileTypeForOLEFile(int fd, unsigned long offset) {
1765 UInt32 filetype = UNKNOWN_FILETYPE;
1766 static const unsigned char xlsname[] = XLS_NAME, docname[] = DOC_NAME, pptname[] = PPT_NAME;
1767 unsigned char moreBytes[512];
1769 if (lseek(fd, offset, SEEK_SET) == (off_t)offset && read(fd, moreBytes, sizeof(moreBytes)) >= (int)sizeof(moreBytes)) {
1771 Boolean foundit = false;
1772 for (i = 0; !foundit && i < 4; i++) {
1773 char namelength = moreBytes[128 * i + 64] / 2;
1774 if (sizeof(xlsname) == namelength) {
1775 for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != xlsname[j]) foundit = false;
1776 if (foundit) filetype = XLS_FILETYPE;
1777 } else if (sizeof(docname) == namelength) {
1778 for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != docname[j]) foundit = false;
1779 if (foundit) filetype = DOC_FILETYPE;
1780 } else if (sizeof(pptname) == namelength) {
1781 for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != pptname[j]) foundit = false;
1782 if (foundit) filetype = PPT_FILETYPE;
1789 static Boolean _CFBundleGrokFileType(CFURLRef url, CFStringRef *extension, UInt32 *machtype, CFDictionaryRef *infodict) {
1790 struct stat statBuf;
1792 char path[CFMaxPathSize];
1793 unsigned char bytes[MAGIC_BYTES_TO_READ];
1794 CFIndex i, length = 0;
1795 const char *ext = NULL;
1796 UInt32 mt = UNKNOWN_FILETYPE;
1797 Boolean isX11 = false, isPlain = true, isZero = true;
1798 // extensions returned: o, tool, x11app, pef, core, dylib, bundle, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, pdf, ra, au, aiff, aifc, wav, avi, wmv, psd, mpeg, mid, zip, jar, sit, html, ps, mov, qtif, bmp, hqx, bin, class, tar, txt, gz, Z, uu, sh, pl, py, rb, dvi, sgi, mp3, xml, plist, xls, doc, ppt, mp4, m4a, m4b, m4p, dmg
1799 if (url && CFURLGetFileSystemRepresentation(url, true, path, CFMaxPathSize) && (fd = open(path, O_RDONLY, 0777)) >= 0 && fstat(fd, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG) {
1800 if ((length = read(fd, bytes, MAGIC_BYTES_TO_READ)) >= 4) {
1801 UInt32 magic = CFSwapInt32HostToBig(*((UInt32 *)bytes));
1802 for (i = 0; !ext && i < NUM_EXTENSIONS; i++) {
1803 if (__CFBundleMagicNumbersArray[i] == magic) ext = __CFBundleExtensionsArray + i * EXTENSION_LENGTH;
1806 if (0xcafebabe == magic && 8 <= length && 0 != *((UInt16 *)(bytes + 4))) {
1808 #if defined(BINARY_SUPPORT_DYLD)
1809 } else if ((int)sizeof(struct mach_header) <= length) {
1810 mt = _CFBundleGrokMachType(fd, bytes, length, extension ? &isX11 : NULL, infodict);
1811 #endif /* BINARY_SUPPORT_DYLD */
1813 #if defined(BINARY_SUPPORT_DYLD)
1814 if (MH_OBJECT == mt) {
1816 } else if (MH_EXECUTE == mt) {
1817 ext = isX11 ? "x11app" : "tool";
1818 } else if (PEF_FILETYPE == mt) {
1820 } else if (MH_CORE == mt) {
1822 } else if (MH_DYLIB == mt) {
1824 } else if (MH_BUNDLE == mt) {
1827 #endif /* BINARY_SUPPORT_DYLD */
1828 if (0x7b5c7274 == magic && (6 > length || 'f' != bytes[4])) {
1830 } else if (0x47494638 == magic && (6 > length || (0x3761 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4)))))) {
1832 } else if (0x0000000c == magic && (6 > length || 0x6a50 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) {
1834 } else if (0x89504e47 == magic && (8 > length || 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) {
1836 } else if (0x53747566 == magic && (8 > length || 0x66497420 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) {
1838 } else if (0x3026b275 == magic && (8 > length || 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) {
1839 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
1841 } else if (0x504b0304 == magic && 38 <= length && 0x4d455441 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 30))) && 0x2d494e46 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34)))) {
1843 } else if (0x464f524d == magic) {
1847 UInt32 iffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)));
1848 if (0x41494646 == iffMagic) {
1850 } else if (0x414946 == iffMagic) {
1854 } else if (0x52494646 == magic) {
1858 UInt32 riffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)));
1859 if (0x57415645 == riffMagic) {
1861 } else if (0x41564920 == riffMagic) {
1865 } else if (0xd0cf11e0 == magic) {
1869 UInt32 ft = _CFBundleGrokFileTypeForOLEFile(fd, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 48)))));
1870 if (XLS_FILETYPE == ft) {
1872 } else if (DOC_FILETYPE == ft) {
1874 } else if (PPT_FILETYPE == ft) {
1878 } else if (0x62656769 == magic) {
1881 if (76 <= length && 'n' == bytes[4] && ' ' == bytes[5] && isdigit(bytes[6]) && isdigit(bytes[7]) && isdigit(bytes[8]) && ' ' == bytes[9]) {
1882 CFIndex endOfLine = 0;
1883 for (i = 10; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i;
1884 if (10 <= endOfLine && endOfLine + 62 < length && 'M' == bytes[endOfLine + 1] && '\n' == bytes[endOfLine + 62]) {
1886 for (i = endOfLine + 1; ext && i < endOfLine + 62; i++) if (!isprint(bytes[i])) ext = NULL;
1891 if (extension && !ext) {
1892 UInt16 shortMagic = CFSwapInt16HostToBig(*((UInt16 *)bytes));
1893 if (8 <= length && 0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) {
1895 } else if (8 <= length && 0x69647363 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) {
1897 } else if (12 <= length && 0x66747970 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) {
1898 // ??? list of ftyp values needs to be checked
1899 if (0x6d703432 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) {
1901 } else if (0x4d344120 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) {
1903 } else if (0x4d344220 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) {
1905 } else if (0x4d345020 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) {
1908 } else if (0x424d == shortMagic && 18 <= length && 40 == CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 14)))) {
1910 } else if (40 <= length && 0x42696e48 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 38)))) {
1912 } else if (128 <= length && 0x6d42494e == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 102)))) {
1914 } else if (128 <= length && 0 == bytes[0] && 0 < bytes[1] && bytes[1] < 64 && 0 == bytes[74] && 0 == bytes[82] && 0 == (statBuf.st_size % 128)) {
1915 unsigned df = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 83))), rf = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 87))), blocks = 1 + (df + 127) / 128 + (rf + 127) / 128;
1916 if (df < 0x00800000 && rf < 0x00800000 && 1 < blocks && (off_t)(128 * blocks) == statBuf.st_size) {
1919 } else if (265 <= length && 0x75737461 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 261))))) {
1921 } else if (0xfeff == shortMagic || 0xfffe == shortMagic) {
1923 } else if (0x1f9d == shortMagic) {
1925 } else if (0x1f8b == shortMagic) {
1927 } else if (0xf702 == shortMagic) {
1929 } else if (0x01da == shortMagic && (0 == bytes[2] || 1 == bytes[2]) && (0 < bytes[3] && 16 > bytes[3])) {
1931 } else if (0x2321 == shortMagic) {
1932 CFIndex endOfLine = 0, lastSlash = 0;
1933 for (i = 2; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i;
1934 if (endOfLine > 3) {
1935 for (i = endOfLine - 1; 0 == lastSlash && i > 1; i--) if ('/' == bytes[i]) lastSlash = i;
1936 if (lastSlash > 0) {
1937 if (0 == strncmp(bytes + lastSlash + 1, "perl", 4)) {
1939 } else if (0 == strncmp(bytes + lastSlash + 1, "python", 6)) {
1941 } else if (0 == strncmp(bytes + lastSlash + 1, "ruby", 4)) {
1948 } else if (0xffd8 == shortMagic && 0xff == bytes[2]) {
1950 } else if (0x4944 == shortMagic && '3' == bytes[2] && 0x20 > bytes[3]) {
1952 } else if ('<' == bytes[0] && 14 <= length) {
1953 if (0 == strncasecmp(bytes + 1, "!doctype html", 13) || 0 == strncasecmp(bytes + 1, "head", 4) || 0 == strncasecmp(bytes + 1, "title", 5) || 0 == strncasecmp(bytes + 1, "html", 4)) {
1955 } else if (0 == strncasecmp(bytes + 1, "?xml", 4)) {
1956 if (116 <= length && 0 == strncasecmp(bytes + 100, "PropertyList.dtd", 16)) {
1965 if (extension && !ext) {
1966 //??? what about MacOSRoman?
1967 for (i = 0; (isPlain || isZero) && i < length && i < 512; i++) {
1969 if (0x7f <= c || (0x20 > c && !isspace(c))) isPlain = false;
1970 if (0 != c) isZero = false;
1974 } else if (isZero && length >= MAGIC_BYTES_TO_READ && statBuf.st_size >= 526) {
1975 if (lseek(fd, 512, SEEK_SET) == 512 && read(fd, bytes, 512) >= 14) {
1976 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 10)))) {
1982 if (extension && !ext && !isZero && length >= MAGIC_BYTES_TO_READ && statBuf.st_size >= 1024) {
1983 off_t offset = statBuf.st_size - 512;
1984 if (lseek(fd, offset, SEEK_SET) == offset && read(fd, bytes, 512) >= 512) {
1985 if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)bytes)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 504))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 508))))) {
1991 if (extension) *extension = ext ? CFStringCreateWithCStringNoCopy(NULL, ext, kCFStringEncodingASCII, kCFAllocatorNull) : NULL;
1992 if (machtype) *machtype = mt;
1994 return (ext != NULL);
1997 CFStringRef _CFBundleCopyFileTypeForFileURL(CFURLRef url) {
1998 CFStringRef extension = NULL;
1999 (void)_CFBundleGrokFileType(url, &extension, NULL, NULL);
2003 __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url) {
2004 CFDictionaryRef result = NULL;
2005 (void)_CFBundleGrokFileType(url, NULL, NULL, &result);
2009 #if defined(BINARY_SUPPORT_DYLD)
2011 __private_extern__ __CFPBinaryType _CFBundleGrokBinaryType(CFURLRef executableURL) {
2012 // Attempt to grok the type of the binary by looking for DYLD magic numbers. If one of the DYLD magic numbers is found, find out what type of Mach-o file it is. Otherwise, look for the PEF magic numbers to see if it is CFM (if we understand CFM).
2013 __CFPBinaryType result = executableURL ? __CFBundleUnreadableBinary : __CFBundleNoBinary;
2014 UInt32 machtype = UNKNOWN_FILETYPE;
2015 if (_CFBundleGrokFileType(executableURL, NULL, &machtype, NULL)) {
2018 result = __CFBundleDYLDExecutableBinary;
2021 result = __CFBundleDYLDBundleBinary;
2024 result = __CFBundleDYLDFrameworkBinary;
2026 #if defined(BINARY_SUPPORT_CFM)
2028 result = __CFBundleCFMBinary;
2030 #endif /* BINARY_SUPPORT_CFM */
2036 #endif /* BINARY_SUPPORT_DYLD */
2038 void _CFBundleSetCFMConnectionID(CFBundleRef bundle, void *connectionID) {
2039 #if defined(BINARY_SUPPORT_CFM)
2040 if (bundle->_binaryType == __CFBundleUnknownBinary || bundle->_binaryType == __CFBundleUnreadableBinary) {
2041 bundle->_binaryType = __CFBundleCFMBinary;
2043 #endif /* BINARY_SUPPORT_CFM */
2044 bundle->_connectionCookie = connectionID;
2045 bundle->_isLoaded = true;
2048 Boolean CFBundleLoadExecutable(CFBundleRef bundle) {
2049 Boolean result = false;
2050 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2052 if (!executableURL) {
2053 bundle->_binaryType = __CFBundleNoBinary;
2055 #if defined(BINARY_SUPPORT_DYLD)
2056 // make sure we know whether bundle is already loaded or not
2057 if (!bundle->_isLoaded) {
2058 _CFBundleDYLDCheckLoaded(bundle);
2060 // We might need to figure out what it is
2061 if (bundle->_binaryType == __CFBundleUnknownBinary) {
2062 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
2063 #if defined(BINARY_SUPPORT_CFM)
2064 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) {
2065 bundle->_resourceData._executableLacksResourceFork = true;
2067 #endif /* BINARY_SUPPORT_CFM */
2069 #endif /* BINARY_SUPPORT_DYLD */
2070 if (executableURL) CFRelease(executableURL);
2072 if (bundle->_isLoaded) {
2073 // Remove from the scheduled unload set if we are there.
2074 __CFSpinLock(&CFBundleGlobalDataLock);
2075 if (_bundlesToUnload) {
2076 CFSetRemoveValue(_bundlesToUnload, bundle);
2078 __CFSpinUnlock(&CFBundleGlobalDataLock);
2082 // Unload bundles scheduled for unloading
2083 if (!_scheduledBundlesAreUnloading) {
2084 _CFBundleUnloadScheduledBundles();
2088 switch (bundle->_binaryType) {
2089 #if defined(BINARY_SUPPORT_CFM)
2090 case __CFBundleCFMBinary:
2091 case __CFBundleUnreadableBinary:
2092 result = _CFBundleCFMLoad(bundle);
2094 #endif /* BINARY_SUPPORT_CFM */
2095 #if defined(BINARY_SUPPORT_DYLD)
2096 case __CFBundleDYLDBundleBinary:
2097 result = _CFBundleDYLDLoadBundle(bundle);
2099 case __CFBundleDYLDFrameworkBinary:
2100 result = _CFBundleDYLDLoadFramework(bundle);
2102 case __CFBundleDYLDExecutableBinary:
2103 CFLog(__kCFLogBundle, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle);
2105 #endif /* BINARY_SUPPORT_DYLD */
2106 #if defined(BINARY_SUPPORT_DLL)
2107 case __CFBundleDLLBinary:
2108 result = _CFBundleDLLLoad(bundle);
2110 #endif /* BINARY_SUPPORT_DLL */
2111 case __CFBundleNoBinary:
2112 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for %@"), bundle);
2115 CFLog(__kCFLogBundle, CFSTR("Cannot recognize type of executable for %@"), bundle);
2122 void CFBundleUnloadExecutable(CFBundleRef bundle) {
2124 if (!_scheduledBundlesAreUnloading) {
2125 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
2126 _CFBundleUnloadScheduledBundles();
2129 if (!bundle->_isLoaded) return;
2131 // Remove from the scheduled unload set if we are there.
2132 if (!_scheduledBundlesAreUnloading) {
2133 __CFSpinLock(&CFBundleGlobalDataLock);
2135 if (_bundlesToUnload) {
2136 CFSetRemoveValue(_bundlesToUnload, bundle);
2138 if (!_scheduledBundlesAreUnloading) {
2139 __CFSpinUnlock(&CFBundleGlobalDataLock);
2142 // Give the plugIn code a chance to realize this...
2143 _CFPlugInWillUnload(bundle);
2145 switch (bundle->_binaryType) {
2146 #if defined(BINARY_SUPPORT_CFM)
2147 case __CFBundleCFMBinary:
2148 _CFBundleCFMUnload(bundle);
2150 #endif /* BINARY_SUPPORT_CFM */
2151 #if defined(BINARY_SUPPORT_DYLD)
2152 case __CFBundleDYLDBundleBinary:
2153 _CFBundleDYLDUnloadBundle(bundle);
2155 #endif /* BINARY_SUPPORT_DYLD */
2156 #if defined(BINARY_SUPPORT_DLL)
2157 case __CFBundleDLLBinary:
2158 _CFBundleDLLUnload(bundle);
2160 #endif /* BINARY_SUPPORT_DLL */
2164 if (!bundle->_isLoaded && bundle->_glueDict != NULL) {
2165 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle));
2166 CFRelease(bundle->_glueDict);
2167 bundle->_glueDict = NULL;
2171 __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) {
2172 __CFSpinLock(&CFBundleGlobalDataLock);
2173 if (!_bundlesToUnload) {
2174 // Create this from the default allocator
2175 CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks;
2176 nonRetainingCallbacks.retain = NULL;
2177 nonRetainingCallbacks.release = NULL;
2178 _bundlesToUnload = CFSetCreateMutable(NULL, 0, &nonRetainingCallbacks);
2180 CFSetAddValue(_bundlesToUnload, bundle);
2181 __CFSpinUnlock(&CFBundleGlobalDataLock);
2184 __private_extern__ void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) {
2185 __CFSpinLock(&CFBundleGlobalDataLock);
2186 if (_bundlesToUnload) {
2187 CFSetRemoveValue(_bundlesToUnload, bundle);
2189 __CFSpinUnlock(&CFBundleGlobalDataLock);
2192 __private_extern__ void _CFBundleUnloadScheduledBundles(void) {
2193 __CFSpinLock(&CFBundleGlobalDataLock);
2194 if (_bundlesToUnload) {
2195 CFIndex c = CFSetGetCount(_bundlesToUnload);
2198 CFBundleRef *unloadThese = CFAllocatorAllocate(NULL, sizeof(CFBundleRef) * c, 0);
2199 CFSetGetValues(_bundlesToUnload, (const void **)unloadThese);
2200 _scheduledBundlesAreUnloading = true;
2201 for (i=0; i<c; i++) {
2202 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2203 CFBundleUnloadExecutable(unloadThese[i]);
2205 _scheduledBundlesAreUnloading = false;
2206 CFAllocatorDeallocate(NULL, unloadThese);
2209 __CFSpinUnlock(&CFBundleGlobalDataLock);
2212 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) {
2214 // Load if necessary
2215 if (!bundle->_isLoaded) {
2216 if (!CFBundleLoadExecutable(bundle)) return NULL;
2219 switch (bundle->_binaryType) {
2220 #if defined(BINARY_SUPPORT_CFM)
2221 case __CFBundleCFMBinary:
2222 tvp = _CFBundleCFMGetSymbolByName(bundle, funcName, kTVectorCFragSymbol);
2224 #endif /* BINARY_SUPPORT_CFM */
2225 #if defined(BINARY_SUPPORT_DYLD)
2226 case __CFBundleDYLDBundleBinary:
2227 case __CFBundleDYLDFrameworkBinary:
2228 case __CFBundleDYLDExecutableBinary:
2229 return _CFBundleDYLDGetSymbolByName(bundle, funcName);
2231 #endif /* BINARY_SUPPORT_DYLD */
2232 #if defined(BINARY_SUPPORT_DLL)
2233 case __CFBundleDLLBinary:
2234 tvp = _CFBundleDLLGetSymbolByName(bundle, funcName);
2236 #endif /* BINARY_SUPPORT_DLL */
2240 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2242 if (bundle->_glueDict == NULL) {
2243 bundle->_glueDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, NULL, NULL);
2245 void *fp = (void *)CFDictionaryGetValue(bundle->_glueDict, tvp);
2247 fp = _CFBundleFunctionPointerForTVector(CFGetAllocator(bundle), tvp);
2248 CFDictionarySetValue(bundle->_glueDict, tvp, fp);
2252 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2256 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) {
2258 // Load if necessary
2259 if (!bundle->_isLoaded) {
2260 if (!CFBundleLoadExecutable(bundle)) return NULL;
2263 switch (bundle->_binaryType) {
2264 #if defined(BINARY_SUPPORT_CFM)
2265 case __CFBundleCFMBinary:
2266 return _CFBundleCFMGetSymbolByName(bundle, funcName, kTVectorCFragSymbol);
2268 #endif /* BINARY_SUPPORT_CFM */
2269 #if defined(BINARY_SUPPORT_DYLD)
2270 case __CFBundleDYLDBundleBinary:
2271 case __CFBundleDYLDFrameworkBinary:
2272 case __CFBundleDYLDExecutableBinary:
2273 fp = _CFBundleDYLDGetSymbolByNameWithSearch(bundle, funcName, true);
2275 #endif /* BINARY_SUPPORT_DYLD */
2279 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2281 if (bundle->_glueDict == NULL) {
2282 bundle->_glueDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, NULL, NULL);
2284 void *tvp = (void *)CFDictionaryGetValue(bundle->_glueDict, fp);
2286 tvp = _CFBundleTVectorForFunctionPointer(CFGetAllocator(bundle), fp);
2287 CFDictionarySetValue(bundle->_glueDict, fp, tvp);
2291 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2295 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) {
2300 c = CFArrayGetCount(functionNames);
2301 for (i = 0; i < c; i++) {
2302 ftbl[i] = CFBundleGetFunctionPointerForName(bundle, CFArrayGetValueAtIndex(functionNames, i));
2306 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) {
2311 c = CFArrayGetCount(functionNames);
2312 for (i = 0; i < c; i++) {
2313 ftbl[i] = _CFBundleGetCFMFunctionPointerForName(bundle, CFArrayGetValueAtIndex(functionNames, i));
2317 void *CFBundleGetDataPointerForName(CFBundleRef bundle, CFStringRef symbolName) {
2319 // Load if necessary
2320 if (!bundle->_isLoaded) {
2321 if (!CFBundleLoadExecutable(bundle)) return NULL;
2324 switch (bundle->_binaryType) {
2325 #if defined(BINARY_SUPPORT_CFM)
2326 case __CFBundleCFMBinary:
2327 dp = _CFBundleCFMGetSymbolByName(bundle, symbolName, kDataCFragSymbol);
2329 #endif /* BINARY_SUPPORT_CFM */
2330 #if defined(BINARY_SUPPORT_DYLD)
2331 case __CFBundleDYLDBundleBinary:
2332 case __CFBundleDYLDFrameworkBinary:
2333 case __CFBundleDYLDExecutableBinary:
2334 dp = _CFBundleDYLDGetSymbolByName(bundle, symbolName);
2336 #endif /* BINARY_SUPPORT_DYLD */
2337 #if defined(BINARY_SUPPORT_DLL)
2338 case __CFBundleDLLBinary:
2339 /* MF:!!! Handle this someday */
2341 #endif /* BINARY_SUPPORT_DLL */
2348 void CFBundleGetDataPointersForNames(CFBundleRef bundle, CFArrayRef symbolNames, void *stbl[]) {
2353 c = CFArrayGetCount(symbolNames);
2354 for (i = 0; i < c; i++) {
2355 stbl[i] = CFBundleGetDataPointerForName(bundle, CFArrayGetValueAtIndex(symbolNames, i));
2359 __private_extern__ _CFResourceData *__CFBundleGetResourceData(CFBundleRef bundle) {
2360 return &(bundle->_resourceData);
2363 CFPlugInRef CFBundleGetPlugIn(CFBundleRef bundle) {
2364 if (bundle->_plugInData._isPlugIn) {
2365 return (CFPlugInRef)bundle;
2371 __private_extern__ _CFPlugInData *__CFBundleGetPlugInData(CFBundleRef bundle) {
2372 return &(bundle->_plugInData);
2375 __private_extern__ Boolean _CFBundleCouldBeBundle(CFURLRef url) {
2376 Boolean result = false;
2380 if (_CFGetFileProperties(NULL, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) {
2381 result = (exists && ((mode & S_IFMT) == S_IFDIR));
2382 #if !defined(__MACOS8__)
2383 result = (result && ((mode & 0444) != 0));
2389 __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocatorRef alloc, CFStringRef executablePath) {
2390 // MF:!!! Implement me. We need to be able to find the bundle from the exe, dealing with old vs. new as well as the Executables dir business on Windows.
2391 #if defined(__WIN32__)
2392 UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 16
2393 UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 23
2394 UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'}; // length 9
2397 UniChar pathBuff[CFMaxPathSize];
2398 UniChar nameBuff[CFMaxPathSize];
2399 CFIndex length, nameStart, nameLength, savedLength;
2400 CFMutableStringRef cheapStr = CFStringCreateMutableWithExternalCharactersNoCopy(alloc, NULL, 0, 0, NULL);
2401 CFURLRef bundleURL = NULL;
2403 length = CFStringGetLength(executablePath);
2404 CFStringGetCharacters(executablePath, CFRangeMake(0, length), pathBuff);
2406 // Save the name in nameBuff
2407 length = _CFLengthAfterDeletingPathExtension(pathBuff, length);
2408 nameStart = _CFStartOfLastPathComponent(pathBuff, length);
2409 nameLength = length - nameStart;
2410 memmove(nameBuff, &(pathBuff[nameStart]), nameLength * sizeof(UniChar));
2412 // Strip the name from pathBuff
2413 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2414 savedLength = length;
2416 #if defined(__WIN32__)
2417 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
2418 _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, 16);
2419 _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength);
2420 _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, 9);
2422 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2423 bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true);
2424 if (!_CFBundleCouldBeBundle(bundleURL)) {
2425 CFRelease(bundleURL);
2428 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
2429 if (bundleURL == NULL) {
2430 length = savedLength;
2431 _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, 23);
2432 _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength);
2433 _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, 9);
2435 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2436 bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true);
2437 if (!_CFBundleCouldBeBundle(bundleURL)) {
2438 CFRelease(bundleURL);
2443 // * Finally check the executable inside the framework case.
2444 if (bundleURL == NULL) {
2445 // MF:!!! This should ensure the framework name is the same as the library name!
2448 length = savedLength;
2449 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
2451 while (length > 0) {
2452 curStart = _CFStartOfLastPathComponent(pathBuff, length);
2453 if (curStart >= length) {
2456 CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[curStart]), length - curStart, CFMaxPathSize - curStart);
2457 if (CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName1) || CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName2)) {
2458 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2459 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2460 bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true);
2461 if (!_CFBundleCouldBeBundle(bundleURL)) {
2462 CFRelease(bundleURL);
2466 } else if (CFStringHasSuffix(cheapStr, CFSTR(".framework"))) {
2467 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2468 bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true);
2469 if (!_CFBundleCouldBeBundle(bundleURL)) {
2470 CFRelease(bundleURL);
2475 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2479 CFStringSetExternalCharactersNoCopy(cheapStr, NULL, 0, 0);
2480 CFRelease(cheapStr);
2485 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath) {
2486 // This finds the bundle for the given path.
2487 // If an image path corresponds to a bundle, we see if there is already a bundle instance. If there is and it is NOT in the _dynamicBundles array, it is added to the staticBundles. Do not add the main bundle to the list here.
2489 CFURLRef curURL = _CFBundleCopyFrameworkURLForExecutablePath(NULL, imagePath);
2491 if (curURL != NULL) {
2492 bundle = _CFBundleFindByURL(curURL, true);
2493 if (bundle == NULL) {
2494 bundle = _CFBundleCreate(NULL, curURL, true);
2496 if (bundle != NULL && !bundle->_isLoaded) {
2497 // make sure that these bundles listed as loaded, and mark them frameworks (we probably can't see anything else here, and we cannot unload them)
2498 #if defined(BINARY_SUPPORT_DYLD)
2499 if (bundle->_binaryType == __CFBundleUnknownBinary) {
2500 bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
2502 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) {
2503 bundle->_resourceData._executableLacksResourceFork = true;
2505 if (!bundle->_imageCookie) _CFBundleDYLDCheckLoaded(bundle);
2506 #endif /* BINARY_SUPPORT_DYLD */
2507 bundle->_isLoaded = true;
2513 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths) {
2514 // This finds the bundles for the given paths.
2515 // If an image path corresponds to a bundle, we see if there is already a bundle instance. If there is and it is NOT in the _dynamicBundles array, it is added to the staticBundles. Do not add the main bundle to the list here (even if it appears in imagePaths).
2516 CFIndex i, imagePathCount = CFArrayGetCount(imagePaths);
2518 for (i=0; i<imagePathCount; i++) {
2519 _CFBundleEnsureBundleExistsForImagePath(CFArrayGetValueAtIndex(imagePaths, i));
2523 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint) {
2524 CFArrayRef imagePaths;
2525 // Tickle the main bundle into existence
2526 (void)_CFBundleGetMainBundleAlreadyLocked();
2527 #if defined(BINARY_SUPPORT_DYLD)
2528 imagePaths = _CFBundleDYLDCopyLoadedImagePathsForHint(hint);
2529 if (imagePaths != NULL) {
2530 _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
2531 CFRelease(imagePaths);
2536 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
2537 // This method returns all the statically linked bundles. This includes the main bundle as well as any frameworks that the process was linked against at launch time. It does not include frameworks or opther bundles that were loaded dynamically.
2539 CFArrayRef imagePaths;
2541 // Tickle the main bundle into existence
2542 (void)_CFBundleGetMainBundleAlreadyLocked();
2544 #if defined(BINARY_SUPPORT_DLL)
2545 #warning (MF) Dont know how to find static bundles for DLLs
2548 #if defined(BINARY_SUPPORT_CFM)
2549 // CFM bundles are supplied to us by CFM, so we do not need to figure them out ourselves
2552 #if defined(BINARY_SUPPORT_DYLD)
2553 imagePaths = _CFBundleDYLDCopyLoadedImagePathsIfChanged();
2554 if (imagePaths != NULL) {
2555 _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
2556 CFRelease(imagePaths);
2561 CFArrayRef CFBundleGetAllBundles(void) {
2562 // To answer this properly, we have to have created the static bundles!
2563 __CFSpinLock(&CFBundleGlobalDataLock);
2564 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2565 __CFSpinUnlock(&CFBundleGlobalDataLock);
2569 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle) {return bundle->_version;}
2571 CF_EXPORT CFURLRef _CFBundleCopyInfoPlistURL(CFBundleRef bundle) {
2572 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
2573 CFStringRef path = CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey);
2574 return (path ? CFRetain(path) : NULL);
2577 CF_EXPORT CFURLRef _CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {return CFBundleCopyPrivateFrameworksURL(bundle);}
2579 CF_EXPORT CFURLRef CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {
2580 CFURLRef result = NULL;
2582 if (1 == bundle->_version) {
2583 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase1, bundle->_url);
2584 } else if (2 == bundle->_version) {
2585 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase2, bundle->_url);
2587 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase0, bundle->_url);
2592 CF_EXPORT CFURLRef _CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {return CFBundleCopySharedFrameworksURL(bundle);}
2594 CF_EXPORT CFURLRef CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {
2595 CFURLRef result = NULL;
2597 if (1 == bundle->_version) {
2598 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase1, bundle->_url);
2599 } else if (2 == bundle->_version) {
2600 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase2, bundle->_url);
2602 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase0, bundle->_url);
2607 CF_EXPORT CFURLRef _CFBundleCopySharedSupportURL(CFBundleRef bundle) {return CFBundleCopySharedSupportURL(bundle);}
2609 CF_EXPORT CFURLRef CFBundleCopySharedSupportURL(CFBundleRef bundle) {
2610 CFURLRef result = NULL;
2612 if (1 == bundle->_version) {
2613 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase1, bundle->_url);
2614 } else if (2 == bundle->_version) {
2615 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase2, bundle->_url);
2617 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase0, bundle->_url);
2622 __private_extern__ CFURLRef _CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {return CFBundleCopyBuiltInPlugInsURL(bundle);}
2624 CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {
2625 CFURLRef result = NULL, alternateResult = NULL;
2627 CFAllocatorRef alloc = CFGetAllocator(bundle);
2628 if (1 == bundle->_version) {
2629 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase1, bundle->_url);
2630 } else if (2 == bundle->_version) {
2631 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase2, bundle->_url);
2633 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase0, bundle->_url);
2635 if (!result || !_urlExists(alloc, result)) {
2636 if (1 == bundle->_version) {
2637 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase1, bundle->_url);
2638 } else if (2 == bundle->_version) {
2639 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase2, bundle->_url);
2641 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase0, bundle->_url);
2643 if (alternateResult && _urlExists(alloc, alternateResult)) {
2644 if (result) CFRelease(result);
2645 result = alternateResult;
2647 if (alternateResult) CFRelease(alternateResult);
2655 #if defined(BINARY_SUPPORT_DYLD)
2657 static void *__CFBundleDYLDFindImage(char *buff) {
2658 void *header = NULL;
2659 unsigned long i, numImages = _dyld_image_count(), numMatches = 0;
2660 char *curName, *p, *q;
2662 for (i = 0; !header && i < numImages; i++) {
2663 curName = _dyld_get_image_name(i);
2664 if (curName && 0 == strncmp(curName, buff, CFMaxPathSize)) {
2665 header = _dyld_get_image_header(i);
2670 for (i = 0; i < numImages; i++) {
2671 curName = _dyld_get_image_name(i);
2673 for (p = buff, q = curName; *p && *q && (q - curName < CFMaxPathSize); p++, q++) {
2674 if (*p != *q && (q - curName > 11) && 0 == strncmp(q - 11, ".framework/Versions/", 20) && *(q + 9) && '/' == *(q + 10)) q += 11;
2675 else if (*p != *q && (q - curName > 12) && 0 == strncmp(q - 12, ".framework/Versions/", 20) && *(q + 8) && '/' == *(q + 9)) q += 10;
2676 if (*p != *q) break;
2679 header = _dyld_get_image_header(i);
2685 return (numMatches == 1) ? header : NULL;
2688 __private_extern__ Boolean _CFBundleDYLDCheckLoaded(CFBundleRef bundle) {
2689 if (!bundle->_isLoaded) {
2690 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2692 if (executableURL != NULL) {
2693 char buff[CFMaxPathSize];
2695 if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) {
2696 void *header = __CFBundleDYLDFindImage(buff);
2698 if (bundle->_binaryType == __CFBundleUnknownBinary) {
2699 bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
2701 if (!bundle->_imageCookie) bundle->_imageCookie = header;
2702 bundle->_isLoaded = true;
2705 CFRelease(executableURL);
2708 return bundle->_isLoaded;
2711 __private_extern__ Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle) {
2712 NSLinkEditErrors c = NSLinkEditUndefinedError;
2713 int errorNumber = 0;
2714 const char *fileName = NULL;
2715 const char *errorString = NULL;
2717 if (!bundle->_isLoaded) {
2718 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2720 if (executableURL) {
2721 char buff[CFMaxPathSize];
2723 if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) {
2724 NSObjectFileImage image;
2725 NSObjectFileImageReturnCode retCode = NSCreateObjectFileImageFromFile(buff, &image);
2726 if (retCode == NSObjectFileImageSuccess) {
2727 NSModule module = NSLinkModule(image, buff, (NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR));
2729 bundle->_imageCookie = image;
2730 bundle->_moduleCookie = module;
2731 bundle->_isLoaded = true;
2733 NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
2734 CFLog(__kCFLogBundle, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName, c, errorNumber, errorString);
2735 if (!NSDestroyObjectFileImage(image)) {
2736 /* MF:!!! Error destroying object file image */
2740 CFLog(__kCFLogBundle, CFSTR("dyld returns %d when trying to load %@"), retCode, executableURL);
2743 CFRelease(executableURL);
2745 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
2748 return bundle->_isLoaded;
2751 __private_extern__ Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle) {
2752 // !!! Framework loading should be better. Can't unload frameworks.
2753 NSLinkEditErrors c = NSLinkEditUndefinedError;
2754 int errorNumber = 0;
2755 const char *fileName = NULL;
2756 const char *errorString = NULL;
2758 if (!bundle->_isLoaded) {
2759 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2761 if (executableURL) {
2762 char buff[CFMaxPathSize];
2764 if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) {
2765 void *image = (void *)NSAddImage(buff, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
2767 bundle->_imageCookie = image;
2768 bundle->_isLoaded = true;
2770 NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
2771 CFLog(__kCFLogBundle, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName, c, errorNumber, errorString);
2774 CFRelease(executableURL);
2776 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
2779 return bundle->_isLoaded;
2782 __private_extern__ void _CFBundleDYLDUnloadBundle(CFBundleRef bundle) {
2783 if (bundle->_isLoaded) {
2784 if (bundle->_moduleCookie && !NSUnLinkModule(bundle->_moduleCookie, NSUNLINKMODULE_OPTION_NONE)) {
2785 CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle);
2787 if (bundle->_moduleCookie && bundle->_imageCookie && !NSDestroyObjectFileImage(bundle->_imageCookie)) {
2788 /* MF:!!! Error destroying object file image */
2790 bundle->_connectionCookie = bundle->_imageCookie = bundle->_moduleCookie = NULL;
2791 bundle->_isLoaded = false;
2796 __private_extern__ void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {return _CFBundleDYLDGetSymbolByNameWithSearch(bundle, symbolName, false);}
2798 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) {
2799 void *result = NULL;
2801 NSSymbol symbol = NULL;
2803 // MF:!!! What if the factory was in C++ code (and is therefore mangled differently)? Huh, answer me that!
2804 // MF: The current answer to the mangling question is that you cannot look up C++ functions with this API. Thus things like plugin factories must be extern "C" in plugin code.
2806 /* MF:??? ASCII appropriate here? */
2807 if (CFStringGetCString(symbolName, &(buff[1]), 1024, kCFStringEncodingASCII)) {
2808 if (bundle->_moduleCookie) {
2809 symbol = NSLookupSymbolInModule(bundle->_moduleCookie, buff);
2810 } else if (bundle->_imageCookie) {
2811 symbol = NSLookupSymbolInImage(bundle->_imageCookie, buff, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
2813 if (NULL == symbol && NULL == bundle->_moduleCookie && (NULL == bundle->_imageCookie || globalSearch)) {
2814 char hintBuff[1026];
2815 CFStringRef executableName = _CFBundleCopyExecutableName(NULL, bundle, NULL, NULL);
2817 if (executableName) {
2818 if (!CFStringGetCString(executableName, hintBuff, 1024, kCFStringEncodingUTF8)) hintBuff[0] = '\0';
2819 CFRelease(executableName);
2821 if (NSIsSymbolNameDefinedWithHint(buff, hintBuff)) {
2822 symbol = NSLookupAndBindSymbolWithHint(buff, hintBuff);
2826 result = NSAddressOfSymbol(symbol);
2829 CFLog(__kCFLogBundle, CFSTR("dyld cannot find symbol %s in %@"), buff, bundle);
2836 static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p) {
2837 unsigned long i, j, n = _dyld_image_count();
2838 Boolean foundit = false;
2840 CFStringRef result = NULL;
2841 for (i = 0; !foundit && i < n; i++) {
2842 struct mach_header *mh = _dyld_get_image_header(i);
2843 unsigned long addr = (unsigned long)p - _dyld_get_image_vmaddr_slide(i);
2845 struct load_command *lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
2846 for (j = 0; !foundit && j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) {
2847 if (LC_SEGMENT == lc->cmd && addr >= ((struct segment_command *)lc)->vmaddr && addr < ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) {
2849 name = _dyld_get_image_name(i);
2851 result = CFStringCreateWithCString(NULL, name, CFStringFileSystemEncoding());
2860 __private_extern__ CFArrayRef _CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint) {
2861 unsigned long i, numImages = _dyld_image_count();
2862 CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2863 CFRange range = CFRangeMake(0, CFStringGetLength(hint));
2865 for (i=0; i<numImages; i++) {
2866 char *curName = _dyld_get_image_name(i), *lastComponent = NULL;
2867 if (curName != NULL) lastComponent = strrchr(curName, '/');
2868 if (lastComponent != NULL) {
2869 CFStringRef str = CFStringCreateWithCString(NULL, lastComponent + 1, CFStringFileSystemEncoding());
2871 if (CFStringFindWithOptions(hint, str, range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) {
2872 CFStringRef curStr = CFStringCreateWithCString(NULL, curName, CFStringFileSystemEncoding());
2873 if (curStr != NULL) {
2874 CFArrayAppendValue(result, curStr);
2885 __private_extern__ CFArrayRef _CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
2886 // This returns an array of the paths of all the dyld images in the process. These paths may not be absolute, they may point at things that are not bundles, they may be staticly linked bundles or dynamically loaded bundles, they may be NULL.
2887 static unsigned long _cachedDYLDImageCount = -1;
2889 unsigned long i, numImages = _dyld_image_count();
2890 CFMutableArrayRef result = NULL;
2892 if (numImages != _cachedDYLDImageCount) {
2896 result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
2898 for (i=0; i<numImages; i++) {
2899 curName = _dyld_get_image_name(i);
2900 if (curName != NULL) {
2901 curStr = CFStringCreateWithCString(NULL, curName, CFStringFileSystemEncoding());
2902 if (curStr != NULL) {
2903 CFArrayAppendValue(result, curStr);
2908 _cachedDYLDImageCount = numImages;
2913 #endif /* BINARY_SUPPORT_DYLD */
2916 #if defined(BINARY_SUPPORT_DLL)
2918 __private_extern__ Boolean _CFBundleDLLLoad(CFBundleRef bundle) {
2920 if (!bundle->_isLoaded) {
2921 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2923 if (executableURL) {
2924 char buff[CFMaxPathSize];
2926 if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) {
2927 bundle->_hModule = LoadLibrary(buff);
2928 if (bundle->_hModule == NULL) {
2930 bundle->_isLoaded = true;
2933 CFRelease(executableURL);
2935 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
2939 return bundle->_isLoaded;
2942 __private_extern__ void _CFBundleDLLUnload(CFBundleRef bundle) {
2943 if (bundle->_isLoaded) {
2944 FreeLibrary(bundle->_hModule);
2945 bundle->_hModule = NULL;
2946 bundle->_isLoaded = false;
2950 __private_extern__ void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {
2951 void *result = NULL;
2954 if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingWindowsLatin1)) {
2955 result = GetProcAddress(bundle->_hModule, buff);
2960 #endif /* BINARY_SUPPORT_DLL */
2963 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
2965 extern void _CFStringSetCompatibility(CFOptionFlags);
2967 static void _CFBundleCheckWorkarounds(CFBundleRef bundle) {