2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Doug Davidson
28 #include "CFBundle_Internal.h"
29 #include <CoreFoundation/CFPropertyList.h>
30 #include <CoreFoundation/CFNumber.h>
31 #include <CoreFoundation/CFSet.h>
32 #include <CoreFoundation/CFURLAccess.h>
34 #include "CFInternal.h"
36 #include <CoreFoundation/CFByteOrder.h>
37 #include "CFBundle_BinaryTypes.h"
40 #if defined(BINARY_SUPPORT_DYLD)
41 // Import the mach-o headers that define the macho magic numbers
42 #include <mach-o/loader.h>
43 #include <mach-o/fat.h>
44 #include <mach-o/arch.h>
45 #include <mach-o/swap.h>
46 #include <mach-o/dyld.h>
47 #include <mach-o/getsect.h>
53 #endif /* BINARY_SUPPORT_DYLD */
55 #if defined(__MACOS8__)
58 #include <Processes.h>
60 /* Unixy & Windows Headers */
64 #if defined(__LINUX__)
68 #if defined(__WIN32__)
69 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
70 // With the MS headers, turning off Standard-C gets you macros for stat vs_stat.
71 // Strictly speaking, this is supposed to control traditional vs ANSI C features.
76 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
81 // Public CFBundle Info plist keys
82 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey
, "CFBundleInfoDictionaryVersion")
83 CONST_STRING_DECL(kCFBundleExecutableKey
, "CFBundleExecutable")
84 CONST_STRING_DECL(kCFBundleIdentifierKey
, "CFBundleIdentifier")
85 CONST_STRING_DECL(kCFBundleVersionKey
, "CFBundleVersion")
86 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey
, "CFBundleDevelopmentRegion")
87 CONST_STRING_DECL(kCFBundleLocalizationsKey
, "CFBundleLocalizations")
90 CONST_STRING_DECL(_kCFBundlePackageTypeKey
, "CFBundlePackageType")
91 CONST_STRING_DECL(_kCFBundleSignatureKey
, "CFBundleSignature")
92 CONST_STRING_DECL(_kCFBundleIconFileKey
, "CFBundleIconFile")
93 CONST_STRING_DECL(_kCFBundleDocumentTypesKey
, "CFBundleDocumentTypes")
94 CONST_STRING_DECL(_kCFBundleURLTypesKey
, "CFBundleURLTypes")
96 // Keys that are usually localized in InfoPlist.strings
97 CONST_STRING_DECL(kCFBundleNameKey
, "CFBundleName")
98 CONST_STRING_DECL(_kCFBundleDisplayNameKey
, "CFBundleDisplayName")
99 CONST_STRING_DECL(_kCFBundleShortVersionStringKey
, "CFBundleShortVersionString")
100 CONST_STRING_DECL(_kCFBundleGetInfoStringKey
, "CFBundleGetInfoString")
101 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey
, "CFBundleGetInfoHTML")
103 // Sub-keys for CFBundleDocumentTypes dictionaries
104 CONST_STRING_DECL(_kCFBundleTypeNameKey
, "CFBundleTypeName")
105 CONST_STRING_DECL(_kCFBundleTypeRoleKey
, "CFBundleTypeRole")
106 CONST_STRING_DECL(_kCFBundleTypeIconFileKey
, "CFBundleTypeIconFile")
107 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey
, "CFBundleTypeOSTypes")
108 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey
, "CFBundleTypeExtensions")
109 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey
, "CFBundleTypeMIMETypes")
111 // Sub-keys for CFBundleURLTypes dictionaries
112 CONST_STRING_DECL(_kCFBundleURLNameKey
, "CFBundleURLName")
113 CONST_STRING_DECL(_kCFBundleURLIconFileKey
, "CFBundleURLIconFile")
114 CONST_STRING_DECL(_kCFBundleURLSchemesKey
, "CFBundleURLSchemes")
116 // Compatibility key names
117 CONST_STRING_DECL(_kCFBundleOldExecutableKey
, "NSExecutable")
118 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey
, "NSInfoPlistVersion")
119 CONST_STRING_DECL(_kCFBundleOldNameKey
, "NSHumanReadableName")
120 CONST_STRING_DECL(_kCFBundleOldIconFileKey
, "NSIcon")
121 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey
, "NSTypes")
122 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey
, "NSAppVersion")
124 // Compatibility CFBundleDocumentTypes key names
125 CONST_STRING_DECL(_kCFBundleOldTypeNameKey
, "NSName")
126 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey
, "NSRole")
127 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey
, "NSIcon")
128 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key
, "NSUnixExtensions")
129 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key
, "NSDOSExtensions")
130 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey
, "NSMacOSType")
132 // Internally used keys for loaded Info plists.
133 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey
, "CFBundleInfoPlistURL")
134 CONST_STRING_DECL(_kCFBundleNumericVersionKey
, "CFBundleNumericVersion")
135 CONST_STRING_DECL(_kCFBundleExecutablePathKey
, "CFBundleExecutablePath")
136 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey
, "CSResourcesFileMapped")
137 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey
, "CFBundleCFMLoadAsBundle")
138 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey
, "CFBundleAllowMixedLocalizations")
140 static CFTypeID __kCFBundleTypeID
= _kCFRuntimeNotATypeID
;
148 CFDictionaryRef _infoDict
;
149 CFDictionaryRef _localInfoDict
;
150 CFArrayRef _searchLanguages
;
152 __CFPBinaryType _binaryType
;
155 Boolean _sharesStringsFiles
;
159 void *_connectionCookie
;
162 const void *_imageCookie
;
163 const void *_moduleCookie
;
165 /* CFM<->DYLD glue */
166 CFMutableDictionaryRef _glueDict
;
168 /* Resource fork goop */
169 _CFResourceData _resourceData
;
171 _CFPlugInData _plugInData
;
173 #if defined(BINARY_SUPPORT_DLL)
179 static CFSpinLock_t CFBundleGlobalDataLock
= 0;
181 static CFMutableDictionaryRef _bundlesByURL
= NULL
;
182 static CFMutableDictionaryRef _bundlesByIdentifier
= NULL
;
184 // For scheduled lazy unloading. Used by CFPlugIn.
185 static CFMutableSetRef _bundlesToUnload
= NULL
;
186 static Boolean _scheduledBundlesAreUnloading
= false;
188 // Various lists of all bundles.
189 static CFMutableArrayRef _allBundles
= NULL
;
191 static Boolean _initedMainBundle
= false;
192 static CFBundleRef _mainBundle
= NULL
;
193 static CFStringRef _defaultLocalization
= NULL
;
195 // Forward declares functions.
196 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
);
197 static CFStringRef
_CFBundleCopyExecutableName(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
);
198 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
);
199 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
);
200 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
201 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
);
202 #if defined(BINARY_SUPPORT_DYLD)
203 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
);
204 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
);
205 static CFDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable(void);
206 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
);
207 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
);
208 #endif /* BINARY_SUPPORT_DYLD */
209 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
210 static void *_CFBundleFunctionPointerForTVector(CFAllocatorRef allocator
, void *tvp
);
211 static void *_CFBundleTVectorForFunctionPointer(CFAllocatorRef allocator
, void *fp
);
212 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
214 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
215 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
217 if (!alreadyLocked
) {
218 __CFSpinLock(&CFBundleGlobalDataLock
);
221 // Add to the _allBundles list
222 if (_allBundles
== NULL
) {
223 // Create this from the default allocator
224 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
225 nonRetainingArrayCallbacks
.retain
= NULL
;
226 nonRetainingArrayCallbacks
.release
= NULL
;
227 _allBundles
= CFArrayCreateMutable(NULL
, 0, &nonRetainingArrayCallbacks
);
229 CFArrayAppendValue(_allBundles
, bundle
);
231 // Add to the table that maps urls to bundles
232 if (_bundlesByURL
== NULL
) {
233 // Create this from the default allocator
234 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
235 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
236 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
237 _bundlesByURL
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
239 CFDictionarySetValue(_bundlesByURL
, bundle
->_url
, bundle
);
241 // Add to the table that maps identifiers to bundles
243 CFBundleRef existingBundle
= NULL
;
244 Boolean addIt
= true;
245 if (_bundlesByIdentifier
== NULL
) {
246 // Create this from the default allocator
247 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
248 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
249 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
250 _bundlesByIdentifier
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
252 existingBundle
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
253 if (existingBundle
) {
254 UInt32 existingVersion
, newVersion
;
255 existingVersion
= CFBundleGetVersionNumber(existingBundle
);
256 newVersion
= CFBundleGetVersionNumber(bundle
);
257 if (newVersion
< existingVersion
) {
258 // Less than to means that if you load two bundles with the same identifier and the same version, the last one wins.
263 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundle
);
266 if (!alreadyLocked
) {
267 __CFSpinUnlock(&CFBundleGlobalDataLock
);
271 static void _CFBundleRemoveFromTables(CFBundleRef bundle
) {
272 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
274 __CFSpinLock(&CFBundleGlobalDataLock
);
276 // Remove from the various lists
277 if (_allBundles
!= NULL
) {
278 CFIndex i
= CFArrayGetFirstIndexOfValue(_allBundles
, CFRangeMake(0, CFArrayGetCount(_allBundles
)), bundle
);
280 CFArrayRemoveValueAtIndex(_allBundles
, i
);
284 // Remove from the table that maps urls to bundles
285 if (_bundlesByURL
!= NULL
) {
286 CFDictionaryRemoveValue(_bundlesByURL
, bundle
->_url
);
289 // Remove from the table that maps identifiers to bundles
290 if ((bundleID
!= NULL
) && (_bundlesByIdentifier
!= NULL
)) {
291 if (CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
) == bundle
) {
292 CFDictionaryRemoveValue(_bundlesByIdentifier
, bundleID
);
295 __CFSpinUnlock(&CFBundleGlobalDataLock
);
298 __private_extern__ CFBundleRef
_CFBundleFindByURL(CFURLRef url
, Boolean alreadyLocked
) {
299 CFBundleRef result
= NULL
;
300 if (!alreadyLocked
) {
301 __CFSpinLock(&CFBundleGlobalDataLock
);
303 if (_bundlesByURL
!= NULL
) {
304 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, url
);
306 if (!alreadyLocked
) {
307 __CFSpinUnlock(&CFBundleGlobalDataLock
);
312 static CFURLRef
_CFBundleCopyBundleURLForExecutablePath(CFStringRef str
) {
313 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
314 UniChar buff
[CFMaxPathSize
];
319 buffLen
= CFStringGetLength(str
);
320 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
321 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
322 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
); // Remove exe name
325 // See if this is a new bundle. If it is, we have to remove more path components.
326 CFIndex startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
327 if ((startOfLastDir
> 0) && (startOfLastDir
< buffLen
)) {
328 CFStringRef lastDirName
= CFStringCreateWithCharacters(NULL
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
330 if (CFEqual(lastDirName
, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
331 // This is a new bundle. Back off a few more levels
333 // Remove platform folder
334 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
337 // Remove executables folder (if present)
338 CFIndex startOfNextDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
339 if ((startOfNextDir
> 0) && (startOfNextDir
< buffLen
)) {
340 CFStringRef nextDirName
= CFStringCreateWithCharacters(NULL
, &(buff
[startOfNextDir
]), buffLen
- startOfNextDir
);
341 if (CFEqual(nextDirName
, _CFBundleExecutablesDirectoryName
)) {
342 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
344 CFRelease(nextDirName
);
348 // Remove support files folder
349 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
352 CFRelease(lastDirName
);
357 outstr
= CFStringCreateWithCharactersNoCopy(NULL
, buff
, buffLen
, kCFAllocatorNull
);
358 url
= CFURLCreateWithFileSystemPath(NULL
, outstr
, PLATFORM_PATH_STYLE
, true);
364 static CFURLRef
_CFBundleCopyResolvedURLForExecutableURL(CFURLRef url
) {
365 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
366 CFURLRef absoluteURL
, url1
, url2
, outURL
= NULL
;
367 CFStringRef str
, str1
, str2
;
368 absoluteURL
= CFURLCopyAbsoluteURL(url
);
369 str
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
371 UniChar buff
[CFMaxPathSize
];
372 CFIndex buffLen
= CFStringGetLength(str
), len1
;
373 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
374 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
375 len1
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
376 if (len1
> 0 && len1
+ 1 < buffLen
) {
377 str1
= CFStringCreateWithCharacters(NULL
, buff
, len1
);
378 str2
= CFStringCreateWithCharacters(NULL
, buff
+ len1
+ 1, buffLen
- len1
- 1);
380 url1
= CFURLCreateWithFileSystemPath(NULL
, str1
, PLATFORM_PATH_STYLE
, true);
382 url2
= CFURLCreateWithFileSystemPathRelativeToBase(NULL
, str2
, PLATFORM_PATH_STYLE
, false, url1
);
384 outURL
= CFURLCopyAbsoluteURL(url2
);
390 if (str1
) CFRelease(str1
);
391 if (str2
) CFRelease(str2
);
396 outURL
= absoluteURL
;
398 CFRelease(absoluteURL
);
403 CFURLRef
_CFBundleCopyBundleURLForExecutableURL(CFURLRef url
) {
404 CFURLRef resolvedURL
, outurl
= NULL
;
406 resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
407 str
= CFURLCopyFileSystemPath(resolvedURL
, PLATFORM_PATH_STYLE
);
409 outurl
= _CFBundleCopyBundleURLForExecutablePath(str
);
412 CFRelease(resolvedURL
);
416 CFBundleRef
_CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
417 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
419 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
420 if (bundle
&& 0 == bundle
->_version
) {
421 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
422 if (!infoDict
|| 0 == CFDictionaryGetCount(infoDict
)) {
423 #if defined(BINARY_SUPPORT_CFM) && defined(BINARY_SUPPORT_DYLD)
424 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
426 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
427 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
429 if (bundle
->_binaryType
== __CFBundleCFMBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
430 bundle
->_version
= 4;
432 bundle
->_resourceData
._executableLacksResourceFork
= true;
434 CFRelease(executableURL
);
436 bundle
->_version
= 4;
438 #elif defined(BINARY_SUPPORT_CFM)
439 bundle
->_version
= 4;
441 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
443 CFRelease(executableURL
);
445 bundle
->_version
= 4;
447 #endif /* BINARY_SUPPORT_CFM && BINARY_SUPPORT_DYLD */
450 if (bundle
&& (3 == bundle
->_version
|| 4 == bundle
->_version
)) {
457 CFBundleRef
_CFBundleGetMainBundleIfLooksLikeBundle(void) {
458 CFBundleRef mainBundle
= CFBundleGetMainBundle();
459 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) {
465 CFBundleRef
_CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
466 CFBundleRef bundle
= NULL
;
467 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
468 if (bundleURL
&& resolvedURL
) {
469 bundle
= _CFBundleCreateIfLooksLikeBundle(allocator
, bundleURL
);
471 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
472 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
473 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
477 if (executableURL
) CFRelease(executableURL
);
480 if (bundleURL
) CFRelease(bundleURL
);
481 if (resolvedURL
) CFRelease(resolvedURL
);
485 CFURLRef
_CFBundleCopyMainBundleExecutableURL(Boolean
*looksLikeBundle
) {
486 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
487 const char *processPath
;
488 CFStringRef str
= NULL
;
489 CFURLRef executableURL
= NULL
;
490 processPath
= _CFProcessPath();
492 str
= CFStringCreateWithCString(NULL
, processPath
, CFStringFileSystemEncoding());
494 executableURL
= CFURLCreateWithFileSystemPath(NULL
, str
, PLATFORM_PATH_STYLE
, false);
498 if (looksLikeBundle
) {
499 CFBundleRef mainBundle
= _mainBundle
;
500 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
501 *looksLikeBundle
= (mainBundle
? YES
: NO
);
503 return executableURL
;
506 static CFBundleRef
_CFBundleGetMainBundleAlreadyLocked(void) {
507 if (!_initedMainBundle
) {
508 const char *processPath
;
509 CFStringRef str
= NULL
;
510 CFURLRef executableURL
= NULL
, bundleURL
= NULL
;
511 #if defined(BINARY_SUPPORT_CFM)
512 Boolean versRegionOverrides
= false;
513 #endif /* BINARY_SUPPORT_CFM */
514 #if defined(__MACOS8__)
515 // do not use Posix-styled _CFProcessPath()
516 ProcessSerialNumber gProcessID
;
517 ProcessInfoRec processInfo
;
518 FSSpec processAppSpec
;
520 processInfo
.processInfoLength
= sizeof(ProcessInfoRec
);
521 processInfo
.processAppSpec
= &processAppSpec
;
523 if ((GetCurrentProcess(&gProcessID
) == noErr
) && (GetProcessInformation(&gProcessID
, &processInfo
) == noErr
)) {
524 executableURL
= _CFCreateURLFromFSSpec(NULL
, (void *)(&processAppSpec
), false);
527 _initedMainBundle
= true;
528 processPath
= _CFProcessPath();
530 str
= CFStringCreateWithCString(NULL
, processPath
, CFStringFileSystemEncoding());
531 if (!executableURL
) executableURL
= CFURLCreateWithFileSystemPath(NULL
, str
, PLATFORM_PATH_STYLE
, false);
534 bundleURL
= _CFBundleCopyBundleURLForExecutableURL(executableURL
);
536 if (bundleURL
!= NULL
) {
537 // make sure that main bundle has executable path
538 //??? what if we are not the main executable in the bundle?
539 // NB doFinalProcessing must be false here, see below
540 _mainBundle
= _CFBundleCreate(NULL
, bundleURL
, true, false);
541 if (_mainBundle
!= NULL
) {
542 CFBundleGetInfoDictionary(_mainBundle
);
543 // make sure that the main bundle is listed as loaded, and mark it as executable
544 _mainBundle
->_isLoaded
= true;
545 #if defined(BINARY_SUPPORT_DYLD)
546 if (_mainBundle
->_binaryType
== __CFBundleUnknownBinary
) {
547 if (!executableURL
) {
548 _mainBundle
->_binaryType
= __CFBundleNoBinary
;
550 _mainBundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
551 #if defined(BINARY_SUPPORT_CFM)
552 if (_mainBundle
->_binaryType
!= __CFBundleCFMBinary
&& _mainBundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
553 _mainBundle
->_resourceData
._executableLacksResourceFork
= true;
555 #endif /* BINARY_SUPPORT_CFM */
558 #endif /* BINARY_SUPPORT_DYLD */
559 if (_mainBundle
->_infoDict
== NULL
|| CFDictionaryGetCount(_mainBundle
->_infoDict
) == 0) {
560 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
561 if (_mainBundle
->_version
== 3) _mainBundle
->_version
= 4;
562 if (_mainBundle
->_version
== 0) {
563 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
564 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, _mainBundle
, NULL
, NULL
);
565 if (!executableName
|| !CFStringHasSuffix(str
, executableName
)) _mainBundle
->_version
= 4;
566 if (executableName
) CFRelease(executableName
);
568 #if defined(BINARY_SUPPORT_DYLD)
569 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
570 if (_mainBundle
->_infoDict
!= NULL
) CFRelease(_mainBundle
->_infoDict
);
571 _mainBundle
->_infoDict
= _CFBundleGrokInfoDictFromMainExecutable();
573 #endif /* BINARY_SUPPORT_DYLD */
574 #if defined(BINARY_SUPPORT_CFM)
575 if (_mainBundle
->_binaryType
== __CFBundleCFMBinary
|| _mainBundle
->_binaryType
== __CFBundleUnreadableBinary
) {
576 // if type 0 bundle and CFM binary and no Info.plist, treat as unbundled, since this also gives too many false positives
577 if (_mainBundle
->_version
== 0) _mainBundle
->_version
= 4;
578 if (_mainBundle
->_version
!= 4) {
579 // if CFM binary and no Info.plist and not main executable for bundle, treat as unbundled, since this also gives too many false positives
580 // except for Macromedia Director MX, which is unbundled but wants to be treated as bundled
581 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, _mainBundle
, NULL
, NULL
);
582 Boolean treatAsBundled
= false;
584 CFIndex strLength
= CFStringGetLength(str
);
585 if (strLength
> 10) treatAsBundled
= CFStringFindWithOptions(str
, CFSTR(" MX"), CFRangeMake(strLength
- 10, 10), 0, NULL
);
587 if (!treatAsBundled
&& (!executableName
|| !CFStringHasSuffix(str
, executableName
))) _mainBundle
->_version
= 4;
588 if (executableName
) CFRelease(executableName
);
590 if (_mainBundle
->_infoDict
!= NULL
) CFRelease(_mainBundle
->_infoDict
);
591 _mainBundle
->_infoDict
= _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFGetAllocator(_mainBundle
), executableURL
);
592 if (_mainBundle
->_binaryType
== __CFBundleUnreadableBinary
&& _mainBundle
->_infoDict
!= NULL
&& CFDictionaryGetValue(_mainBundle
->_infoDict
, kCFBundleDevelopmentRegionKey
) != NULL
) versRegionOverrides
= true;
594 #endif /* BINARY_SUPPORT_CFM */
596 if (_mainBundle
->_infoDict
== NULL
) {
597 _mainBundle
->_infoDict
= CFDictionaryCreateMutable(CFGetAllocator(_mainBundle
), 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
599 if (NULL
== CFDictionaryGetValue(_mainBundle
->_infoDict
, _kCFBundleExecutablePathKey
)) {
600 CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), _kCFBundleExecutablePathKey
, str
);
602 #if defined(BINARY_SUPPORT_DYLD)
603 // get cookie for already-loaded main bundle
604 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
&& !_mainBundle
->_imageCookie
) {
605 _mainBundle
->_imageCookie
= (void *)_dyld_get_image_header(0);
607 #endif /* BINARY_SUPPORT_DYLD */
608 #if defined(BINARY_SUPPORT_CFM)
609 if (versRegionOverrides
) {
610 // This is a hack to preserve backward compatibility for certain broken applications (2761067)
611 CFStringRef devLang
= _CFBundleCopyBundleDevelopmentRegionFromVersResource(_mainBundle
);
612 if (devLang
!= NULL
) {
613 CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), kCFBundleDevelopmentRegionKey
, devLang
);
617 #endif /* BINARY_SUPPORT_CFM */
618 // Perform delayed final processing steps.
619 // This must be done after _isLoaded has been set, for security reasons (3624341).
620 _CFBundleCheckWorkarounds(_mainBundle
);
621 if (_CFBundleNeedsInitPlugIn(_mainBundle
)) {
622 __CFSpinUnlock(&CFBundleGlobalDataLock
);
623 _CFBundleInitPlugIn(_mainBundle
);
624 __CFSpinLock(&CFBundleGlobalDataLock
);
628 if (bundleURL
) CFRelease(bundleURL
);
629 if (str
) CFRelease(str
);
630 if (executableURL
) CFRelease(executableURL
);
635 CFBundleRef
CFBundleGetMainBundle(void) {
636 CFBundleRef mainBundle
;
637 __CFSpinLock(&CFBundleGlobalDataLock
);
638 mainBundle
= _CFBundleGetMainBundleAlreadyLocked();
639 __CFSpinUnlock(&CFBundleGlobalDataLock
);
643 #if defined(BINARY_SUPPORT_DYLD)
645 static void *_CFBundleReturnAddressFromFrameAddress(void *addr
)
649 __asm__
volatile("lwz %0,0x0008(%1)" : "=r" (ret
) : "b" (addr
));
650 #elif defined(__i386__)
651 __asm__
volatile("movl 0x4(%1),%0" : "=r" (ret
) : "r" (addr
));
653 __asm__
volatile("ldw 0x4(%1),%0" : "=r" (ret
) : "r" (addr
));
655 __asm__
volatile("ta 0x3");
656 __asm__
volatile("ld [%1 + 60],%0" : "=r" (ret
) : "r" (addr
));
658 #warning Do not know how to define _CFBundleReturnAddressFromFrameAddress on this architecture
666 CFBundleRef
CFBundleGetBundleWithIdentifier(CFStringRef bundleID
) {
667 CFBundleRef result
= NULL
;
669 __CFSpinLock(&CFBundleGlobalDataLock
);
670 (void)_CFBundleGetMainBundleAlreadyLocked();
671 if (_bundlesByIdentifier
!= NULL
) {
672 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
674 #if defined(BINARY_SUPPORT_DYLD)
675 if (result
== NULL
) {
676 // Try to create the bundle for the caller and try again
677 void *p
= _CFBundleReturnAddressFromFrameAddress(__builtin_frame_address(1));
678 CFStringRef imagePath
= _CFBundleDYLDCopyLoadedImagePathForPointer(p
);
679 if (imagePath
!= NULL
) {
680 _CFBundleEnsureBundleExistsForImagePath(imagePath
);
681 CFRelease(imagePath
);
683 if (_bundlesByIdentifier
!= NULL
) {
684 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
688 if (result
== NULL
) {
689 // Try to guess the bundle from the identifier and try again
690 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID
);
691 if (_bundlesByIdentifier
!= NULL
) {
692 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
695 if (result
== NULL
) {
696 // Make sure all bundles have been created and try again.
697 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
698 if (_bundlesByIdentifier
!= NULL
) {
699 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
702 __CFSpinUnlock(&CFBundleGlobalDataLock
);
707 static CFStringRef
__CFBundleCopyDescription(CFTypeRef cf
) {
708 char buff
[CFMaxPathSize
];
709 CFStringRef path
= NULL
, binaryType
= NULL
, retval
= NULL
;
710 if (((CFBundleRef
)cf
)->_url
!= NULL
&& CFURLGetFileSystemRepresentation(((CFBundleRef
)cf
)->_url
, true, buff
, CFMaxPathSize
)) {
711 path
= CFStringCreateWithCString(NULL
, buff
, CFStringFileSystemEncoding());
713 switch (((CFBundleRef
)cf
)->_binaryType
) {
714 case __CFBundleCFMBinary
:
715 binaryType
= CFSTR("");
717 case __CFBundleDYLDExecutableBinary
:
718 binaryType
= CFSTR("executable, ");
720 case __CFBundleDYLDBundleBinary
:
721 binaryType
= CFSTR("bundle, ");
723 case __CFBundleDYLDFrameworkBinary
:
724 binaryType
= CFSTR("framework, ");
726 case __CFBundleDLLBinary
:
727 binaryType
= CFSTR("DLL, ");
729 case __CFBundleUnreadableBinary
:
730 binaryType
= CFSTR("");
733 binaryType
= CFSTR("");
736 if (((CFBundleRef
)cf
)->_plugInData
._isPlugIn
) {
737 retval
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFBundle/CFPlugIn 0x%x <%@> (%@%sloaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? "" : "not ");
739 retval
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFBundle 0x%x <%@> (%@%sloaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? "" : "not ");
741 if (path
) CFRelease(path
);
745 static void _CFBundleDeallocateGlue(const void *key
, const void *value
, void *context
) {
746 CFAllocatorRef allocator
= (CFAllocatorRef
)context
;
748 CFAllocatorDeallocate(allocator
, (void *)value
);
752 static void __CFBundleDeallocate(CFTypeRef cf
) {
753 CFBundleRef bundle
= (CFBundleRef
)cf
;
754 CFAllocatorRef allocator
;
756 __CFGenericValidateType(cf
, __kCFBundleTypeID
);
758 allocator
= CFGetAllocator(bundle
);
761 CFBundleUnloadExecutable(bundle
);
763 // Clean up plugIn stuff
764 _CFBundleDeallocatePlugIn(bundle
);
766 _CFBundleRemoveFromTables(bundle
);
768 if (bundle
->_url
!= NULL
) {
769 _CFBundleFlushCachesForURL(bundle
->_url
);
770 CFRelease(bundle
->_url
);
772 if (bundle
->_infoDict
!= NULL
) {
773 CFRelease(bundle
->_infoDict
);
775 if (bundle
->_modDate
!= NULL
) {
776 CFRelease(bundle
->_modDate
);
778 if (bundle
->_localInfoDict
!= NULL
) {
779 CFRelease(bundle
->_localInfoDict
);
781 if (bundle
->_searchLanguages
!= NULL
) {
782 CFRelease(bundle
->_searchLanguages
);
784 if (bundle
->_glueDict
!= NULL
) {
785 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)allocator
);
786 CFRelease(bundle
->_glueDict
);
788 if (bundle
->_resourceData
._stringTableCache
!= NULL
) {
789 CFRelease(bundle
->_resourceData
._stringTableCache
);
793 static const CFRuntimeClass __CFBundleClass
= {
798 __CFBundleDeallocate
,
802 __CFBundleCopyDescription
805 __private_extern__
void __CFBundleInitialize(void) {
806 __kCFBundleTypeID
= _CFRuntimeRegisterClass(&__CFBundleClass
);
809 CFTypeID
CFBundleGetTypeID(void) {
810 return __kCFBundleTypeID
;
813 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
) {
814 CFBundleRef bundle
= NULL
;
815 char buff
[CFMaxPathSize
];
816 CFDateRef modDate
= NULL
;
817 Boolean exists
= false;
819 CFURLRef newURL
= NULL
;
820 uint8_t localVersion
= 0;
822 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
824 newURL
= CFURLCreateFromFileSystemRepresentation(allocator
, buff
, strlen(buff
), true);
825 if (NULL
== newURL
) {
826 newURL
= CFRetain(bundleURL
);
828 bundle
= _CFBundleFindByURL(newURL
, alreadyLocked
);
835 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
837 if (_CFGetFileProperties(allocator
, newURL
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
838 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
839 if (NULL
!= modDate
) CFRelease(modDate
);
849 bundle
= (CFBundleRef
)_CFRuntimeCreateInstance(allocator
, __kCFBundleTypeID
, sizeof(struct __CFBundle
) - sizeof(CFRuntimeBase
), NULL
);
850 if (NULL
== bundle
) {
855 bundle
->_url
= newURL
;
857 bundle
->_modDate
= modDate
;
858 bundle
->_version
= localVersion
;
859 bundle
->_infoDict
= NULL
;
860 bundle
->_localInfoDict
= NULL
;
861 bundle
->_searchLanguages
= NULL
;
863 #if defined(BINARY_SUPPORT_DYLD)
864 /* We'll have to figure it out later */
865 bundle
->_binaryType
= __CFBundleUnknownBinary
;
866 #elif defined(BINARY_SUPPORT_CFM)
867 /* We support CFM only */
868 bundle
->_binaryType
= __CFBundleCFMBinary
;
869 #elif defined(BINARY_SUPPORT_DLL)
870 /* We support DLL only */
871 bundle
->_binaryType
= __CFBundleDLLBinary
;
872 bundle
->_hModule
= NULL
;
874 /* We'll have to figure it out later */
875 bundle
->_binaryType
= __CFBundleUnknownBinary
;
878 bundle
->_isLoaded
= false;
879 bundle
->_sharesStringsFiles
= false;
881 /* ??? For testing purposes? Or for good? */
882 #warning Ali or Doug: Decide how to finalize strings sharing
883 if (!getenv("CFBundleDisableStringsSharing") &&
884 (strncmp(buff
, "/System/Library/Frameworks", 26) == 0) &&
885 (strncmp(buff
+ strlen(buff
) - 10, ".framework", 10) == 0)) bundle
->_sharesStringsFiles
= true;
887 bundle
->_connectionCookie
= NULL
;
888 bundle
->_imageCookie
= NULL
;
889 bundle
->_moduleCookie
= NULL
;
891 bundle
->_glueDict
= NULL
;
893 #if defined(BINARY_SUPPORT_CFM)
894 bundle
->_resourceData
._executableLacksResourceFork
= false;
896 bundle
->_resourceData
._executableLacksResourceFork
= true;
899 bundle
->_resourceData
._stringTableCache
= NULL
;
901 bundle
->_plugInData
._isPlugIn
= false;
902 bundle
->_plugInData
._loadOnDemand
= false;
903 bundle
->_plugInData
._isDoingDynamicRegistration
= false;
904 bundle
->_plugInData
._instanceCount
= 0;
905 bundle
->_plugInData
._factories
= NULL
;
907 CFBundleGetInfoDictionary(bundle
);
909 _CFBundleAddToTables(bundle
, alreadyLocked
);
911 if (doFinalProcessing
) {
912 _CFBundleCheckWorkarounds(bundle
);
913 if (_CFBundleNeedsInitPlugIn(bundle
)) {
914 if (alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
915 _CFBundleInitPlugIn(bundle
);
916 if (alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
923 CFBundleRef
CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
) {return _CFBundleCreate(allocator
, bundleURL
, false, true);}
925 CFArrayRef
CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc
, CFURLRef directoryURL
, CFStringRef bundleType
) {
926 CFMutableArrayRef bundles
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
927 CFArrayRef URLs
= _CFContentsOfDirectory(alloc
, NULL
, NULL
, directoryURL
, bundleType
);
929 CFIndex i
, c
= CFArrayGetCount(URLs
);
931 CFBundleRef curBundle
;
933 for (i
=0; i
<c
; i
++) {
934 curURL
= CFArrayGetValueAtIndex(URLs
, i
);
935 curBundle
= CFBundleCreate(alloc
, curURL
);
936 if (curBundle
!= NULL
) {
937 CFArrayAppendValue(bundles
, curBundle
);
946 CFURLRef
CFBundleCopyBundleURL(CFBundleRef bundle
) {
948 CFRetain(bundle
->_url
);
953 void _CFBundleSetDefaultLocalization(CFStringRef localizationName
) {
954 CFStringRef newLocalization
= localizationName
? CFStringCreateCopy(NULL
, localizationName
) : NULL
;
955 if (_defaultLocalization
) CFRelease(_defaultLocalization
);
956 _defaultLocalization
= newLocalization
;
959 CFArrayRef
_CFBundleGetLanguageSearchList(CFBundleRef bundle
) {
960 if (bundle
->_searchLanguages
== NULL
) {
961 CFMutableArrayRef langs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
962 CFStringRef devLang
= CFBundleGetDevelopmentRegion(bundle
);
964 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, devLang
);
966 if (CFArrayGetCount(langs
) == 0) {
967 // If the user does not prefer any of our languages, and devLang is not present, try English
968 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFSTR("en_US"));
970 if (CFArrayGetCount(langs
) == 0) {
971 // if none of the preferred localizations are present, fall back on a random localization that is present
972 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
974 if (CFArrayGetCount(localizations
) > 0) {
975 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFArrayGetValueAtIndex(localizations
, 0));
977 CFRelease(localizations
);
981 if (devLang
!= NULL
&& !CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
)) {
982 // Make sure that devLang is on the list as a fallback for individual resources that are not present
983 CFArrayAppendValue(langs
, devLang
);
984 } else if (devLang
== NULL
) {
985 // Or if there is no devLang, try some variation of English that is present
986 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
988 CFStringRef en_US
= CFSTR("en_US"), en
= CFSTR("en"), English
= CFSTR("English");
989 CFRange range
= CFRangeMake(0, CFArrayGetCount(localizations
));
990 if (CFArrayContainsValue(localizations
, range
, en
)) {
991 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en
)) CFArrayAppendValue(langs
, en
);
992 } else if (CFArrayContainsValue(localizations
, range
, English
)) {
993 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), English
)) CFArrayAppendValue(langs
, English
);
994 } else if (CFArrayContainsValue(localizations
, range
, en_US
)) {
995 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en_US
)) CFArrayAppendValue(langs
, en_US
);
997 CFRelease(localizations
);
1000 if (CFArrayGetCount(langs
) == 0) {
1001 // Total backstop behavior to avoid having an empty array.
1002 if (_defaultLocalization
!= NULL
) {
1003 CFArrayAppendValue(langs
, _defaultLocalization
);
1005 CFArrayAppendValue(langs
, CFSTR("en"));
1008 bundle
->_searchLanguages
= langs
;
1010 return bundle
->_searchLanguages
;
1013 CFDictionaryRef
CFBundleCopyInfoDictionaryInDirectory(CFURLRef url
) {return _CFBundleCopyInfoDictionaryInDirectory(NULL
, url
, NULL
);}
1015 CFDictionaryRef
CFBundleGetInfoDictionary(CFBundleRef bundle
) {
1016 if (bundle
->_infoDict
== NULL
) {
1017 bundle
->_infoDict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);
1019 return bundle
->_infoDict
;
1022 CFDictionaryRef
_CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {return CFBundleGetLocalInfoDictionary(bundle
);}
1024 CFDictionaryRef
CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
1025 if (bundle
->_localInfoDict
== NULL
) {
1026 CFURLRef url
= CFBundleCopyResourceURL(bundle
, _CFBundleLocalInfoName
, _CFBundleStringTableType
, NULL
);
1030 CFStringRef errStr
= NULL
;
1032 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle
), url
, &data
, NULL
, NULL
, &errCode
)) {
1033 bundle
->_localInfoDict
= CFPropertyListCreateFromXMLData(CFGetAllocator(bundle
), data
, kCFPropertyListImmutable
, &errStr
);
1037 if (bundle
->_localInfoDict
&& CFDictionaryGetTypeID() != CFGetTypeID(bundle
->_localInfoDict
)) {
1038 CFRelease(bundle
->_localInfoDict
);
1039 bundle
->_localInfoDict
= NULL
;
1046 return bundle
->_localInfoDict
;
1049 CFPropertyListRef
_CFBundleGetValueForInfoKey(CFBundleRef bundle
, CFStringRef key
) {return (CFPropertyListRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, key
);}
1051 CFTypeRef
CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle
, CFStringRef key
) {
1052 // Look in InfoPlist.strings first. Then look in Info.plist
1053 CFTypeRef result
= NULL
;
1054 if ((bundle
!= NULL
) && (key
!= NULL
)) {
1055 CFDictionaryRef dict
= CFBundleGetLocalInfoDictionary(bundle
);
1057 result
= CFDictionaryGetValue(dict
, key
);
1059 if (result
== NULL
) {
1060 dict
= CFBundleGetInfoDictionary(bundle
);
1062 result
= CFDictionaryGetValue(dict
, key
);
1069 CFStringRef
CFBundleGetIdentifier(CFBundleRef bundle
) {
1070 CFStringRef bundleID
= NULL
;
1071 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1073 bundleID
= CFDictionaryGetValue(infoDict
, kCFBundleIdentifierKey
);
1078 #define DEVELOPMENT_STAGE 0x20
1079 #define ALPHA_STAGE 0x40
1080 #define BETA_STAGE 0x60
1081 #define RELEASE_STAGE 0x80
1083 #define MAX_VERS_LEN 10
1085 CF_INLINE Boolean
_isDigit(UniChar aChar
) {return (((aChar
>= (UniChar
)'0') && (aChar
<= (UniChar
)'9')) ? true : false);}
1087 __private_extern__ CFStringRef
_CFCreateStringFromVersionNumber(CFAllocatorRef alloc
, UInt32 vers
) {
1088 CFStringRef result
= NULL
;
1089 uint8_t major1
, major2
, minor1
, minor2
, stage
, build
;
1091 major1
= (vers
& 0xF0000000) >> 28;
1092 major2
= (vers
& 0x0F000000) >> 24;
1093 minor1
= (vers
& 0x00F00000) >> 20;
1094 minor2
= (vers
& 0x000F0000) >> 16;
1095 stage
= (vers
& 0x0000FF00) >> 8;
1096 build
= (vers
& 0x000000FF);
1098 if (stage
== RELEASE_STAGE
) {
1100 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d"), major1
, major2
, minor1
, minor2
);
1102 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d"), major2
, minor1
, minor2
);
1106 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
);
1108 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d%s%d"), major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? "d" : ((stage
== ALPHA_STAGE
) ? "a" : "b")), build
);
1114 __private_extern__ UInt32
_CFVersionNumberFromString(CFStringRef versStr
) {
1115 // Parse version number from string.
1116 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1117 UInt32 major1
= 0, major2
= 0, minor1
= 0, minor2
= 0, stage
= RELEASE_STAGE
, build
= 0;
1118 UniChar versChars
[MAX_VERS_LEN
];
1119 UniChar
*chars
= NULL
;
1122 Boolean digitsDone
= false;
1124 if (!versStr
) return 0;
1126 len
= CFStringGetLength(versStr
);
1128 if ((len
== 0) || (len
> MAX_VERS_LEN
)) return 0;
1130 CFStringGetCharacters(versStr
, CFRangeMake(0, len
), versChars
);
1133 // Get major version number.
1134 major1
= major2
= 0;
1135 if (_isDigit(*chars
)) {
1136 major2
= *chars
- (UniChar
)'0';
1140 if (_isDigit(*chars
)) {
1142 major2
= *chars
- (UniChar
)'0';
1146 if (*chars
== (UniChar
)'.') {
1153 } else if (*chars
== (UniChar
)'.') {
1160 } else if (*chars
== (UniChar
)'.') {
1167 // Now major1 and major2 contain first and second digit of the major version number as ints.
1168 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1170 // Get the first minor version number.
1171 if (len
> 0 && !digitsDone
) {
1172 if (_isDigit(*chars
)) {
1173 minor1
= *chars
- (UniChar
)'0';
1177 if (*chars
== (UniChar
)'.') {
1189 // Now minor1 contains the first minor version number as an int.
1190 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1192 // Get the second minor version number.
1193 if (len
> 0 && !digitsDone
) {
1194 if (_isDigit(*chars
)) {
1195 minor2
= *chars
- (UniChar
)'0';
1203 // Now minor2 contains the second minor version number as an int.
1204 // Now either len is 0 or chars points at the build stage letter.
1206 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1208 if (*chars
== (UniChar
)'d') {
1209 stage
= DEVELOPMENT_STAGE
;
1210 } else if (*chars
== (UniChar
)'a') {
1211 stage
= ALPHA_STAGE
;
1212 } else if (*chars
== (UniChar
)'b') {
1214 } else if (*chars
== (UniChar
)'f') {
1215 stage
= RELEASE_STAGE
;
1223 // Now stage contains the release stage.
1224 // Now either len is 0 or chars points at the build number.
1226 // Get the first digit of the build number.
1228 if (_isDigit(*chars
)) {
1229 build
= *chars
- (UniChar
)'0';
1236 // Get the second digit of the build number.
1238 if (_isDigit(*chars
)) {
1240 build
+= *chars
- (UniChar
)'0';
1247 // Get the third digit of the build number.
1249 if (_isDigit(*chars
)) {
1251 build
+= *chars
- (UniChar
)'0';
1259 // Range check the build number and make sure we exhausted the string.
1260 if ((build
> 0xFF) || (len
> 0)) return 0;
1263 theVers
= major1
<< 28;
1264 theVers
+= major2
<< 24;
1265 theVers
+= minor1
<< 20;
1266 theVers
+= minor2
<< 16;
1267 theVers
+= stage
<< 8;
1273 UInt32
CFBundleGetVersionNumber(CFBundleRef bundle
) {
1274 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1275 CFTypeRef unknownVersionValue
= CFDictionaryGetValue(infoDict
, _kCFBundleNumericVersionKey
);
1276 CFNumberRef versNum
;
1279 if (unknownVersionValue
== NULL
) {
1280 unknownVersionValue
= CFDictionaryGetValue(infoDict
, kCFBundleVersionKey
);
1282 if (unknownVersionValue
!= NULL
) {
1283 if (CFGetTypeID(unknownVersionValue
) == CFStringGetTypeID()) {
1284 // Convert a string version number into a numeric one.
1285 vers
= _CFVersionNumberFromString((CFStringRef
)unknownVersionValue
);
1287 versNum
= CFNumberCreate(CFGetAllocator(bundle
), kCFNumberSInt32Type
, &vers
);
1288 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
, versNum
);
1290 } else if (CFGetTypeID(unknownVersionValue
) == CFNumberGetTypeID()) {
1291 CFNumberGetValue((CFNumberRef
)unknownVersionValue
, kCFNumberSInt32Type
, &vers
);
1293 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
);
1299 CFStringRef
CFBundleGetDevelopmentRegion(CFBundleRef bundle
) {
1300 CFStringRef devLang
= NULL
;
1301 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1303 devLang
= CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1304 if (devLang
!= NULL
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) {
1306 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleDevelopmentRegionKey
);
1313 Boolean
_CFBundleGetHasChanged(CFBundleRef bundle
) {
1315 Boolean result
= false;
1316 Boolean exists
= false;
1319 if (_CFGetFileProperties(CFGetAllocator(bundle
), bundle
->_url
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
1320 // If the bundle no longer exists or is not a folder, it must have "changed"
1321 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
1325 // Something is wrong. The stat failed.
1328 if (bundle
->_modDate
&& !CFEqual(bundle
->_modDate
, modDate
)) {
1329 // mod date is different from when we created.
1336 void _CFBundleSetStringsFilesShared(CFBundleRef bundle
, Boolean flag
) {
1337 bundle
->_sharesStringsFiles
= flag
;
1340 Boolean
_CFBundleGetStringsFilesShared(CFBundleRef bundle
) {
1341 return bundle
->_sharesStringsFiles
;
1344 static Boolean
_urlExists(CFAllocatorRef alloc
, CFURLRef url
) {
1346 return url
&& (0 == _CFGetFileProperties(alloc
, url
, &exists
, NULL
, NULL
, NULL
, NULL
, NULL
)) && exists
;
1349 __private_extern__ CFURLRef
_CFBundleCopySupportFilesDirectoryURLInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
) {
1350 CFURLRef result
= NULL
;
1353 result
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase1
, bundleURL
);
1354 } else if (2 == version
) {
1355 result
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase2
, bundleURL
);
1357 result
= CFRetain(bundleURL
);
1363 CF_EXPORT CFURLRef
CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle
) {return _CFBundleCopySupportFilesDirectoryURLInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);}
1365 __private_extern__ CFURLRef
_CFBundleCopyResourcesDirectoryURLInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
) {
1366 CFURLRef result
= NULL
;
1369 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase0
, bundleURL
);
1370 } else if (1 == version
) {
1371 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase1
, bundleURL
);
1372 } else if (2 == version
) {
1373 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase2
, bundleURL
);
1375 result
= CFRetain(bundleURL
);
1381 CFURLRef
CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle
) {return _CFBundleCopyResourcesDirectoryURLInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);}
1383 static CFURLRef
_CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc
, CFURLRef urlPath
, CFStringRef exeName
) {
1384 // 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.
1385 CFURLRef executableURL
= NULL
;
1386 #if defined(__MACH__)
1387 const uint8_t *image_suffix
= getenv("DYLD_IMAGE_SUFFIX");
1388 #endif /* __MACH__ */
1390 if (urlPath
== NULL
|| exeName
== NULL
) return NULL
;
1392 #if defined(__MACH__)
1393 if (image_suffix
!= NULL
) {
1394 CFStringRef newExeName
, imageSuffix
;
1395 imageSuffix
= CFStringCreateWithCString(NULL
, image_suffix
, kCFStringEncodingUTF8
);
1396 if (CFStringHasSuffix(exeName
, CFSTR(".dylib"))) {
1397 CFStringRef bareExeName
= CFStringCreateWithSubstring(alloc
, exeName
, CFRangeMake(0, CFStringGetLength(exeName
)-6));
1398 newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@.dylib"), exeName
, imageSuffix
);
1399 CFRelease(bareExeName
);
1401 newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, imageSuffix
);
1403 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, newExeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1404 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1405 CFRelease(executableURL
);
1406 executableURL
= NULL
;
1408 CFRelease(newExeName
);
1409 CFRelease(imageSuffix
);
1411 #endif /* __MACH__ */
1412 if (executableURL
== NULL
) {
1413 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, exeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1414 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1415 CFRelease(executableURL
);
1416 executableURL
= NULL
;
1419 #if defined(__WIN32__)
1420 if (executableURL
== NULL
) {
1421 if (!CFStringHasSuffix(exeName
, CFSTR(".dll"))) {
1422 CFStringRef newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, CFSTR(".dll"));
1423 executableURL
= CFURLCreateWithString(alloc
, newExeName
, urlPath
);
1424 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1425 CFRelease(executableURL
);
1426 executableURL
= NULL
;
1428 CFRelease(newExeName
);
1431 if (executableURL
== NULL
) {
1432 if (!CFStringHasSuffix(exeName
, CFSTR(".exe"))) {
1433 CFStringRef newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, CFSTR(".exe"));
1434 executableURL
= CFURLCreateWithString(alloc
, newExeName
, urlPath
);
1435 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1436 CFRelease(executableURL
);
1437 executableURL
= NULL
;
1439 CFRelease(newExeName
);
1443 return executableURL
;
1446 static CFStringRef
_CFBundleCopyExecutableName(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
) {
1447 CFStringRef executableName
= NULL
;
1449 if (alloc
== NULL
&& bundle
!= NULL
) {
1450 alloc
= CFGetAllocator(bundle
);
1452 if (infoDict
== NULL
&& bundle
!= NULL
) {
1453 infoDict
= CFBundleGetInfoDictionary(bundle
);
1455 if (url
== NULL
&& bundle
!= NULL
) {
1459 if (infoDict
!= NULL
) {
1460 // Figure out the name of the executable.
1461 // First try for the new key in the plist.
1462 executableName
= CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
);
1463 if (executableName
== NULL
) {
1464 // Second try for the old key in the plist.
1465 executableName
= CFDictionaryGetValue(infoDict
, _kCFBundleOldExecutableKey
);
1467 if (executableName
!= NULL
&& CFGetTypeID(executableName
) == CFStringGetTypeID() && CFStringGetLength(executableName
) > 0) {
1468 CFRetain(executableName
);
1470 executableName
= NULL
;
1473 if (executableName
== NULL
&& url
!= NULL
) {
1474 // Third, take the name of the bundle itself (with path extension stripped)
1475 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1476 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1477 UniChar buff
[CFMaxPathSize
];
1478 CFIndex len
= CFStringGetLength(bundlePath
);
1479 CFIndex startOfBundleName
, endOfBundleName
;
1481 CFRelease(absoluteURL
);
1482 if (len
> CFMaxPathSize
) len
= CFMaxPathSize
;
1483 CFStringGetCharacters(bundlePath
, CFRangeMake(0, len
), buff
);
1484 startOfBundleName
= _CFStartOfLastPathComponent(buff
, len
);
1485 endOfBundleName
= _CFLengthAfterDeletingPathExtension(buff
, len
);
1487 if ((startOfBundleName
<= len
) && (endOfBundleName
<= len
) && (startOfBundleName
< endOfBundleName
)) {
1488 executableName
= CFStringCreateWithCharacters(alloc
, &(buff
[startOfBundleName
]), (endOfBundleName
- startOfBundleName
));
1490 CFRelease(bundlePath
);
1493 return executableName
;
1496 __private_extern__ CFURLRef
_CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle
, Boolean mayBeLocal
) {
1497 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, bundle
, NULL
, NULL
);
1498 CFURLRef resourceForkURL
= NULL
;
1499 if (executableName
!= NULL
) {
1501 resourceForkURL
= CFBundleCopyResourceURL(bundle
, executableName
, CFSTR("rsrc"), NULL
);
1503 resourceForkURL
= CFBundleCopyResourceURLForLocalization(bundle
, executableName
, CFSTR("rsrc"), NULL
, NULL
);
1505 CFRelease(executableName
);
1508 return resourceForkURL
;
1511 CFURLRef
_CFBundleCopyResourceForkURL(CFBundleRef bundle
) {return _CFBundleCopyResourceForkURLMayBeLocal(bundle
, true);}
1513 static CFURLRef
_CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFStringRef executableName
, Boolean ignoreCache
, Boolean useOtherPlatform
) {
1514 uint8_t version
= 0;
1515 CFDictionaryRef infoDict
= NULL
;
1516 CFStringRef executablePath
= NULL
;
1517 CFURLRef executableURL
= NULL
;
1518 Boolean foundIt
= false;
1519 Boolean lookupMainExe
= ((executableName
== NULL
) ? true : false);
1521 if (bundle
!= NULL
) {
1522 infoDict
= CFBundleGetInfoDictionary(bundle
);
1523 version
= bundle
->_version
;
1525 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, &version
);
1528 // If we have a bundle instance and an info dict, see if we have already cached the path
1529 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& (bundle
!= NULL
) && (infoDict
!= NULL
)) {
1530 executablePath
= CFDictionaryGetValue(infoDict
, _kCFBundleExecutablePathKey
);
1531 if (executablePath
!= NULL
) {
1532 executableURL
= CFURLCreateWithFileSystemPath(alloc
, executablePath
, kCFURLPOSIXPathStyle
, false);
1533 if (executableURL
!= NULL
) foundIt
= true;
1535 executablePath
= NULL
;
1536 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
);
1542 if (lookupMainExe
) {
1543 executableName
= _CFBundleCopyExecutableName(alloc
, bundle
, url
, infoDict
);
1545 if (executableName
!= NULL
) {
1546 // Now, look for the executable inside the bundle.
1549 CFURLRef exeSubdirURL
;
1552 exeDirURL
= CFURLCreateWithString(alloc
, _CFBundleExecutablesURLFromBase1
, url
);
1553 } else if (2 == version
) {
1554 exeDirURL
= CFURLCreateWithString(alloc
, _CFBundleExecutablesURLFromBase2
, url
);
1556 exeDirURL
= CFRetain(url
);
1558 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1559 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1560 if (executableURL
== NULL
) {
1561 CFRelease(exeSubdirURL
);
1562 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1563 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1565 if (executableURL
== NULL
) {
1566 CFRelease(exeSubdirURL
);
1567 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1568 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1570 if (executableURL
== NULL
) {
1571 CFRelease(exeSubdirURL
);
1572 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1573 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1575 if (executableURL
== NULL
) {
1576 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeDirURL
, executableName
);
1579 CFRelease(exeDirURL
);
1580 CFRelease(exeSubdirURL
);
1583 // If this was an old bundle, or we did not find the executable in the Excutables subdirectory, look directly in the bundle wrapper.
1584 if (executableURL
== NULL
) {
1585 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, url
, executableName
);
1588 #if defined(__WIN32__)
1589 // Windows only: If we still haven't found the exe, look in the Executables folder.
1590 // But only for the main bundle exe
1591 if (lookupMainExe
&& (executableURL
== NULL
)) {
1594 exeDirURL
= CFURLCreateWithString(alloc
, CFSTR("../../Executables"), url
);
1596 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeDirURL
, executableName
);
1598 CFRelease(exeDirURL
);
1602 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& (bundle
!= NULL
) && (infoDict
!= NULL
) && (executableURL
!= NULL
)) {
1603 // We found it. Cache the path.
1604 CFURLRef absURL
= CFURLCopyAbsoluteURL(executableURL
);
1605 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLPOSIXPathStyle
);
1607 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
, executablePath
);
1608 CFRelease(executablePath
);
1610 if (lookupMainExe
&& !useOtherPlatform
&& (bundle
!= NULL
) && (executableURL
== NULL
)) {
1611 bundle
->_binaryType
= __CFBundleNoBinary
;
1613 if (lookupMainExe
) {
1614 CFRelease(executableName
);
1619 if ((bundle
== NULL
) && (infoDict
!= NULL
)) {
1620 CFRelease(infoDict
);
1623 return executableURL
;
1626 CFURLRef
_CFBundleCopyExecutableURLInDirectory(CFURLRef url
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL
, NULL
, url
, NULL
, true, false);}
1628 CFURLRef
_CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL
, NULL
, url
, NULL
, true, true);}
1630 CFURLRef
CFBundleCopyExecutableURL(CFBundleRef bundle
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, NULL
, false, false);}
1632 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, NULL
, true, false);}
1634 CFURLRef
CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle
, CFStringRef executableName
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, executableName
, true, false);}
1636 Boolean
CFBundleIsExecutableLoaded(CFBundleRef bundle
) {return bundle
->_isLoaded
;}
1638 CFBundleExecutableType
CFBundleGetExecutableType(CFBundleRef bundle
) {
1639 CFBundleExecutableType result
= kCFBundleOtherExecutableType
;
1640 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
1642 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
1643 #if defined(BINARY_SUPPORT_DYLD)
1644 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
1645 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
1646 #if defined(BINARY_SUPPORT_CFM)
1647 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
1648 bundle
->_resourceData
._executableLacksResourceFork
= true;
1650 #endif /* BINARY_SUPPORT_CFM */
1652 #endif /* BINARY_SUPPORT_DYLD */
1653 if (executableURL
) CFRelease(executableURL
);
1655 if (bundle
->_binaryType
== __CFBundleCFMBinary
) {
1656 result
= kCFBundlePEFExecutableType
;
1657 } else if (bundle
->_binaryType
== __CFBundleDYLDExecutableBinary
|| bundle
->_binaryType
== __CFBundleDYLDBundleBinary
|| bundle
->_binaryType
== __CFBundleDYLDFrameworkBinary
) {
1658 result
= kCFBundleMachOExecutableType
;
1659 } else if (bundle
->_binaryType
== __CFBundleDLLBinary
) {
1660 result
= kCFBundleDLLExecutableType
;
1661 } else if (bundle
->_binaryType
== __CFBundleELFBinary
) {
1662 result
= kCFBundleELFExecutableType
;
1667 #define UNKNOWN_FILETYPE 0x0
1668 #define PEF_FILETYPE 0x1000
1669 #define XLS_FILETYPE 0x10001
1670 #define DOC_FILETYPE 0x10002
1671 #define PPT_FILETYPE 0x10003
1672 #define XLS_NAME "Workbook"
1673 #define XLS_NAME2 "Book"
1674 #define DOC_NAME "WordDocument"
1675 #define PPT_NAME "PowerPoint Document"
1676 #define PEF_MAGIC 0x4a6f7921
1677 #define PEF_CIGAM 0x21796f4a
1678 #define PLIST_SEGMENT "__TEXT"
1679 #define PLIST_SECTION "__info_plist"
1680 #define LIB_X11 "/usr/X11R6/lib/libX"
1682 static const uint32_t __CFBundleMagicNumbersArray
[] = {
1683 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0x4a6f7921, 0x21796f4a, 0x7f454c46, 0xffd8ffe0,
1684 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, 0x7b5c7274, 0x25504446,
1685 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, 0x38425053, 0x000001b3,
1686 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435, 0x53495444, 0x53747566,
1687 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x6b6f6c79, 0x3026b275, 0x0000000c,
1688 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143, 0x00010000, 0x74727565, 0x4f54544f,
1689 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70, 0x3c435058, 0x28445746, 0x424f4d53
1692 // string, with groups of 5 characters being 1 element in the array
1693 static const char * __CFBundleExtensionsArray
=
1694 "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" "elf\0\0" "jpeg\0"
1695 "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" "rtf\0\0" "pdf\0\0"
1696 "ra\0\0\0""rm\0\0\0""au\0\0\0""au\0\0\0""iff\0\0" "riff\0" "psd\0\0" "mpeg\0"
1697 "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0"
1698 "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""dmg\0\0" "wmv\0\0" "jp2\0\0"
1699 "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0" "ttf\0\0" "ttf\0\0" "otf\0\0"
1700 "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0" "cpx\0\0" "dwf\0\0" "bom\0\0";
1702 #define NUM_EXTENSIONS 56
1703 #define EXTENSION_LENGTH 5
1704 #define MAGIC_BYTES_TO_READ 512
1706 #if defined(BINARY_SUPPORT_DYLD)
1708 CF_INLINE
uint32_t _CFBundleSwapInt32Conditional(uint32_t arg
, Boolean swap
) {return swap
? CFSwapInt32(arg
) : arg
;}
1709 CF_INLINE
uint32_t _CFBundleSwapInt64Conditional(uint64_t arg
, Boolean swap
) {return swap
? CFSwapInt64(arg
) : arg
;}
1711 static CFDictionaryRef
_CFBundleGrokInfoDictFromData(const char *bytes
, uint32_t length
) {
1712 CFMutableDictionaryRef result
= NULL
;
1713 CFDataRef infoData
= NULL
;
1714 if (NULL
!= bytes
&& 0 < length
) {
1715 infoData
= CFDataCreateWithBytesNoCopy(NULL
, bytes
, length
, kCFAllocatorNull
);
1718 __CFSetNastyFile(CFSTR("<plist section in main executable>"));
1720 result
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(NULL
, infoData
, kCFPropertyListMutableContainers
, NULL
);
1721 if (result
&& CFDictionaryGetTypeID() != CFGetTypeID(result
)) {
1725 CFRelease(infoData
);
1728 result
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1734 static CFDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable() {
1735 unsigned long length
= 0;
1736 char *bytes
= getsectdata(PLIST_SEGMENT
, PLIST_SECTION
, &length
);
1737 return _CFBundleGrokInfoDictFromData(bytes
, length
);
1740 static CFDictionaryRef
_CFBundleGrokInfoDictFromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
1741 struct stat statBuf
;
1742 off_t fileLength
= 0;
1743 char *maploc
= NULL
;
1746 CFDictionaryRef result
= NULL
;
1747 Boolean foundit
= false;
1748 if (fd
>= 0 && fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
1750 fileLength
= statBuf
.st_size
;
1753 fileLength
= length
;
1755 if (fileLength
> offset
+ sizeof(struct mach_header_64
)) {
1757 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->ncmds
, swapped
);
1758 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->sizeofcmds
, swapped
);
1759 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header_64
);
1760 const char *endofcmds
= startofcmds
+ sizeofcmds
;
1761 struct segment_command_64
*sgp
= (struct segment_command_64
*)startofcmds
;
1762 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
1763 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
1764 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
1765 struct section_64
*sp
= (struct section_64
*)((char *)sgp
+ sizeof(struct segment_command_64
));
1766 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
1767 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
1768 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, PLIST_SEGMENT
, sizeof(sp
->segname
))) {
1769 uint64_t sectlength64
= _CFBundleSwapInt64Conditional(sp
->size
, swapped
);
1770 uint32_t sectlength
= (uint32_t)(sectlength64
& 0xffffffff);
1771 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
1772 const char *sectbytes
= loc
+ offset
+ sectoffset
;
1773 // we don't support huge-sized plists
1774 if (sectlength64
<= 0xffffffff && loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= _CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
1777 sp
= (struct section_64
*)((char *)sp
+ sizeof(struct section_64
));
1780 sgp
= (struct segment_command_64
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
1783 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->ncmds
, swapped
);
1784 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->sizeofcmds
, swapped
);
1785 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header
);
1786 const char *endofcmds
= startofcmds
+ sizeofcmds
;
1787 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
1788 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
1789 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
1790 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
1791 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
1792 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
1793 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
1794 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, PLIST_SEGMENT
, sizeof(sp
->segname
))) {
1795 uint32_t sectlength
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
1796 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
1797 const char *sectbytes
= loc
+ offset
+ sectoffset
;
1798 if (loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= _CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
1801 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
1804 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
1808 if (maploc
) munmap(maploc
, statBuf
.st_size
);
1812 static Boolean
_CFBundleGrokX11(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
1813 static const char libX11name
[] = LIB_X11
;
1814 struct stat statBuf
;
1815 off_t fileLength
= 0;
1816 char *maploc
= NULL
;
1819 Boolean result
= false;
1820 if (fd
>= 0 && fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
1822 fileLength
= statBuf
.st_size
;
1825 fileLength
= length
;
1827 if (fileLength
> offset
+ sizeof(struct mach_header_64
)) {
1829 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->ncmds
, swapped
);
1830 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->sizeofcmds
, swapped
);
1831 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header_64
);
1832 const char *endofcmds
= startofcmds
+ sizeofcmds
;
1833 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
1834 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
1835 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
1836 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
1837 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
1838 if (0 == strncmp((char *)dlp
+ nameoffset
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
1840 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
1843 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->ncmds
, swapped
);
1844 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->sizeofcmds
, swapped
);
1845 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header
);
1846 const char *endofcmds
= startofcmds
+ sizeofcmds
;
1847 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
1848 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
1849 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
1850 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
1851 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
1852 if (0 == strncmp((char *)dlp
+ nameoffset
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
1854 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
1858 if (maploc
) munmap(maploc
, statBuf
.st_size
);
1862 static UInt32
_CFBundleGrokMachTypeForFatFile(int fd
, const void *bytes
, CFIndex length
, Boolean
*isX11
, CFDictionaryRef
*infodict
) {
1863 UInt32 machtype
= UNKNOWN_FILETYPE
, magic
, numFatHeaders
= ((struct fat_header
*)bytes
)->nfat_arch
, maxFatHeaders
= (length
- sizeof(struct fat_header
)) / sizeof(struct fat_arch
);
1864 unsigned char buffer
[sizeof(struct mach_header_64
)];
1865 const unsigned char *moreBytes
= NULL
;
1866 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
1867 struct fat_arch
*fat
= NULL
;
1869 if (isX11
) *isX11
= false;
1870 if (infodict
) *infodict
= NULL
;
1871 if (numFatHeaders
> maxFatHeaders
) numFatHeaders
= maxFatHeaders
;
1872 if (numFatHeaders
> 0) {
1873 fat
= NXFindBestFatArch(archInfo
->cputype
, archInfo
->cpusubtype
, (struct fat_arch
*)(bytes
+ sizeof(struct fat_header
)), numFatHeaders
);
1874 if (!fat
) fat
= (struct fat_arch
*)(bytes
+ sizeof(struct fat_header
));
1877 if (fd
>= 0 && lseek(fd
, fat
->offset
, SEEK_SET
) == (off_t
)fat
->offset
&& read(fd
, buffer
, sizeof(buffer
)) >= (int)sizeof(buffer
)) {
1879 } else if (bytes
&& (uint32_t)length
>= fat
->offset
+ 512) {
1880 moreBytes
= bytes
+ fat
->offset
;
1883 magic
= *((UInt32
*)moreBytes
);
1884 if (MH_MAGIC
== magic
) {
1885 machtype
= ((struct mach_header
*)moreBytes
)->filetype
;
1886 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, false);
1887 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, fat
->offset
, false, false);
1888 } else if (MH_CIGAM
== magic
) {
1889 machtype
= CFSwapInt32(((struct mach_header
*)moreBytes
)->filetype
);
1890 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, false);
1891 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, fat
->offset
, true, false);
1892 } else if (MH_MAGIC_64
== magic
) {
1893 machtype
= ((struct mach_header_64
*)moreBytes
)->filetype
;
1894 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, true);
1895 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, fat
->offset
, false, true);
1896 } else if (MH_CIGAM_64
== magic
) {
1897 machtype
= CFSwapInt32(((struct mach_header_64
*)moreBytes
)->filetype
);
1898 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, true);
1899 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, fat
->offset
, true, true);
1906 static UInt32
_CFBundleGrokMachType(int fd
, const void *bytes
, CFIndex length
, Boolean
*isX11
, CFDictionaryRef
*infodict
) {
1907 unsigned int magic
= *((UInt32
*)bytes
), machtype
= UNKNOWN_FILETYPE
;
1910 if (isX11
) *isX11
= false;
1911 if (infodict
) *infodict
= NULL
;
1912 if (MH_MAGIC
== magic
) {
1913 machtype
= ((struct mach_header
*)bytes
)->filetype
;
1914 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, false);
1915 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, 0, false, false);
1916 } else if (MH_CIGAM
== magic
) {
1917 for (i
= 0; i
< length
; i
+= 4) *(UInt32
*)(bytes
+ i
) = CFSwapInt32(*(UInt32
*)(bytes
+ i
));
1918 machtype
= ((struct mach_header
*)bytes
)->filetype
;
1919 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, false);
1920 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, 0, true, false);
1921 } else if (MH_MAGIC_64
== magic
) {
1922 machtype
= ((struct mach_header_64
*)bytes
)->filetype
;
1923 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, true);
1924 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, 0, false, true);
1925 } else if (MH_CIGAM_64
== magic
) {
1926 for (i
= 0; i
< length
; i
+= 4) *(UInt32
*)(bytes
+ i
) = CFSwapInt32(*(UInt32
*)(bytes
+ i
));
1927 machtype
= ((struct mach_header_64
*)bytes
)->filetype
;
1928 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, true);
1929 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, 0, true, true);
1930 } else if (FAT_MAGIC
== magic
) {
1931 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, isX11
, infodict
);
1932 } else if (FAT_CIGAM
== magic
) {
1933 for (i
= 0; i
< length
; i
+= 4) *(UInt32
*)(bytes
+ i
) = CFSwapInt32(*(UInt32
*)(bytes
+ i
));
1934 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, isX11
, infodict
);
1935 } else if (PEF_MAGIC
== magic
|| PEF_CIGAM
== magic
) {
1936 machtype
= PEF_FILETYPE
;
1941 #endif /* BINARY_SUPPORT_DYLD */
1943 static UInt32
_CFBundleGrokFileTypeForOLEFile(int fd
, const void *bytes
, CFIndex length
, off_t offset
) {
1944 UInt32 filetype
= UNKNOWN_FILETYPE
;
1945 static const unsigned char xlsname
[] = XLS_NAME
, xlsname2
[] = XLS_NAME2
, docname
[] = DOC_NAME
, pptname
[] = PPT_NAME
;
1946 const unsigned char *moreBytes
= NULL
;
1947 unsigned char buffer
[512];
1949 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
&& read(fd
, buffer
, sizeof(buffer
)) >= (int)sizeof(buffer
)) {
1951 } else if (bytes
&& length
>= offset
+ 512) {
1952 moreBytes
= bytes
+ offset
;
1956 Boolean foundit
= false;
1957 for (i
= 0; !foundit
&& i
< 4; i
++) {
1958 char namelength
= moreBytes
[128 * i
+ 64] / 2;
1959 if (sizeof(xlsname
) == namelength
) {
1960 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != xlsname
[j
]) foundit
= false;
1961 if (foundit
) filetype
= XLS_FILETYPE
;
1962 } else if (sizeof(xlsname2
) == namelength
) {
1963 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != xlsname2
[j
]) foundit
= false;
1964 if (foundit
) filetype
= XLS_FILETYPE
;
1965 } else if (sizeof(docname
) == namelength
) {
1966 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != docname
[j
]) foundit
= false;
1967 if (foundit
) filetype
= DOC_FILETYPE
;
1968 } else if (sizeof(pptname
) == namelength
) {
1969 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != pptname
[j
]) foundit
= false;
1970 if (foundit
) filetype
= PPT_FILETYPE
;
1977 static Boolean
_CFBundleGrokFileType(CFURLRef url
, CFDataRef data
, CFStringRef
*extension
, UInt32
*machtype
, CFDictionaryRef
*infodict
) {
1978 struct stat statBuf
;
1980 char path
[CFMaxPathSize
];
1981 const unsigned char *bytes
= NULL
;
1982 unsigned char buffer
[MAGIC_BYTES_TO_READ
];
1983 CFIndex i
, length
= 0;
1984 off_t fileLength
= 0;
1985 const char *ext
= NULL
;
1986 UInt32 mt
= UNKNOWN_FILETYPE
;
1987 #if defined(BINARY_SUPPORT_DYLD)
1988 Boolean isX11
= false;
1989 #endif /* BINARY_SUPPORT_DYLD */
1990 Boolean isFile
= false, isPlain
= true, isZero
= true, isHTML
= false;
1991 // extensions returned: o, tool, x11app, pef, core, dylib, bundle, elf, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, pdf, ra, rm, au, aiff, aifc, wav, avi, wmv, ogg, flac, psd, mpeg, mid, zip, jar, sit, cpio, html, ps, mov, qtif, ttf, otf, sfont, bmp, hqx, bin, class, tar, txt, gz, Z, uu, bz, bz2, sh, pl, py, rb, dvi, sgi, tga, mp3, xml, plist, xls, doc, ppt, mp4, m4a, m4b, m4p, dmg, cwk, webarchive, dwg, dgn, pfa, pfb, afm, tfm, xcf, cpx, dwf, swf, swc, abw, bom
1992 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
1993 if (url
&& CFURLGetFileSystemRepresentation(url
, true, path
, CFMaxPathSize
) && stat(path
, &statBuf
) == 0 && (statBuf
.st_mode
& S_IFMT
) == S_IFREG
&& (fd
= open(path
, O_RDONLY
, 0777)) >= 0) {
1994 // cjk: It is not at clear that not caching would be a win here, since
1995 // in most cases the sniffing of the executable is only done lazily,
1996 // the executable is likely to be immediately used again; say, the
1997 // bundle executable loaded. CFBundle does not need the data again,
1998 // but for the system as a whole not caching could be a net win or lose.
1999 // So, this is where the cache disablement would go, but I am not going
2000 // to turn it on at this point.
2001 // fcntl(fd, F_NOCACHE, 1);
2002 length
= read(fd
, buffer
, MAGIC_BYTES_TO_READ
);
2003 fileLength
= statBuf
.st_size
;
2007 length
= CFDataGetLength(data
);
2008 fileLength
= (off_t
)length
;
2009 bytes
= CFDataGetBytePtr(data
);
2010 if (length
== 0) ext
= "txt";
2014 UInt32 magic
= CFSwapInt32HostToBig(*((UInt32
*)bytes
));
2015 for (i
= 0; !ext
&& i
< NUM_EXTENSIONS
; i
++) {
2016 if (__CFBundleMagicNumbersArray
[i
] == magic
) ext
= __CFBundleExtensionsArray
+ i
* EXTENSION_LENGTH
;
2019 if (0xcafebabe == magic
&& 8 <= length
&& 0 != *((UInt16
*)(bytes
+ 4))) ext
= "class";
2020 #if defined(BINARY_SUPPORT_DYLD)
2021 else if ((int)sizeof(struct mach_header_64
) <= length
) mt
= _CFBundleGrokMachType(fd
, bytes
, length
, extension
? &isX11
: NULL
, infodict
);
2023 if (MH_OBJECT
== mt
) ext
= "o";
2024 else if (MH_EXECUTE
== mt
) ext
= isX11
? "x11app" : "tool";
2025 else if (PEF_FILETYPE
== mt
) ext
= "pef";
2026 else if (MH_CORE
== mt
) ext
= "core";
2027 else if (MH_DYLIB
== mt
) ext
= "dylib";
2028 else if (MH_BUNDLE
== mt
) ext
= "bundle";
2029 #endif /* BINARY_SUPPORT_DYLD */
2030 else if (0x7b5c7274 == magic
&& (6 > length
|| 'f' != bytes
[4])) ext
= NULL
;
2031 else if (0x00010000 == magic
&& (6 > length
|| 0 != bytes
[4])) ext
= NULL
;
2032 else if (0x47494638 == magic
&& (6 > length
|| (0x3761 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4)))))) ext
= NULL
;
2033 else if (0x0000000c == magic
&& (6 > length
|| 0x6a50 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2034 else if (0x2356524d == magic
&& (6 > length
|| 0x4c20 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2035 else if (0x28445746 == magic
&& (6 > length
|| 0x2056 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2036 else if (0x30373037 == magic
&& (6 > length
|| 0x30 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2037 else if (0x41433130 == magic
&& (6 > length
|| 0x31 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2038 else if (0x89504e47 == magic
&& (8 > length
|| 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2039 else if (0x53747566 == magic
&& (8 > length
|| 0x66497420 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2040 else if (0x3026b275 == magic
&& (8 > length
|| 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2041 else if (0x67696d70 == magic
&& (8 > length
|| 0x20786366 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2042 else if (0x424f4d53 == magic
&& (8 > length
|| 0x746f7265 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2043 else if (0x25215053 == magic
&& 14 <= length
&& 0 == strncmp(bytes
+ 4, "-AdobeFont", 10)) ext
= "pfa";
2044 else if (0x504b0304 == magic
&& 38 <= length
&& 0x4d455441 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 30))) && 0x2d494e46 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34)))) ext
= "jar";
2045 else if (0x464f524d == magic
) {
2049 UInt32 iffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2050 if (0x41494646 == iffMagic
) ext
= "aiff";
2051 else if (0x414946 == iffMagic
) ext
= "aifc";
2053 } else if (0x52494646 == magic
) {
2057 UInt32 riffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2058 if (0x57415645 == riffMagic
) ext
= "wav";
2059 else if (0x41564920 == riffMagic
) ext
= "avi";
2061 } else if (0xd0cf11e0 == magic
) {
2064 UInt32 ft
= _CFBundleGrokFileTypeForOLEFile(fd
, bytes
, length
, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 48)))));
2065 if (XLS_FILETYPE
== ft
) ext
= "xls";
2066 else if (DOC_FILETYPE
== ft
) ext
= "doc";
2067 else if (PPT_FILETYPE
== ft
) ext
= "ppt";
2069 } else if (0x62656769 == magic
) {
2072 if (76 <= length
&& 'n' == bytes
[4] && ' ' == bytes
[5] && isdigit(bytes
[6]) && isdigit(bytes
[7]) && isdigit(bytes
[8]) && ' ' == bytes
[9]) {
2073 CFIndex endOfLine
= 0;
2074 for (i
= 10; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2075 if (10 <= endOfLine
&& endOfLine
+ 62 < length
&& 'M' == bytes
[endOfLine
+ 1] && '\n' == bytes
[endOfLine
+ 62]) {
2077 for (i
= endOfLine
+ 1; ext
&& i
< endOfLine
+ 62; i
++) if (!isprint(bytes
[i
])) ext
= NULL
;
2082 if (extension
&& !ext
) {
2083 UInt16 shortMagic
= CFSwapInt16HostToBig(*((UInt16
*)bytes
));
2084 if (5 <= length
&& 0 == bytes
[3] && 0 == bytes
[4] && ((1 == bytes
[1] && 1 == (0xf7 & bytes
[2])) || (0 == bytes
[1] && (2 == (0xf7 & bytes
[2]) || (3 == (0xf7 & bytes
[2])))))) ext
= "tga";
2085 else if (8 <= length
&& (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "mov";
2086 else if (8 <= length
&& (0x69647363 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "qtif";
2087 else if (8 <= length
&& 0x424f424f == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) ext
= "cwk";
2088 else if (8 <= length
&& 0x62706c69 == magic
&& 0x7374 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && isdigit(bytes
[6]) && isdigit(bytes
[7])) {
2089 for (i
= 8; !ext
&& i
< 128 && i
+ 16 <= length
; i
++) {
2090 if (0 == strncmp(bytes
+ i
, "WebMainResource", 15)) ext
= "webarchive";
2092 if (!ext
) ext
= "plist";
2093 } else if (12 <= length
&& 0x66747970 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
2094 // ??? list of ftyp values needs to be checked
2095 if (0x6d703432 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) ext
= "mp4";
2096 else if (0x4d344120 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) ext
= "m4a";
2097 else if (0x4d344220 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) ext
= "m4b";
2098 else if (0x4d345020 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) ext
= "m4p";
2099 } else if (0x424d == shortMagic
&& 18 <= length
&& 40 == CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 14)))) ext
= "bmp";
2100 else if (20 <= length
&& 0 == strncmp(bytes
+ 6, "%!PS-AdobeFont", 14)) ext
= "pfb";
2101 else if (40 <= length
&& 0x42696e48 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 38)))) ext
= "hqx";
2102 else if (128 <= length
&& 0x6d42494e == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 102)))) ext
= "bin";
2103 else if (128 <= length
&& 0 == bytes
[0] && 0 < bytes
[1] && bytes
[1] < 64 && 0 == bytes
[74] && 0 == bytes
[82] && 0 == (fileLength
% 128)) {
2104 unsigned df
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 83))), rf
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 87))), blocks
= 1 + (df
+ 127) / 128 + (rf
+ 127) / 128;
2105 if (df
< 0x00800000 && rf
< 0x00800000 && 1 < blocks
&& (off_t
)(128 * blocks
) == fileLength
) ext
= "bin";
2106 } else if (265 <= length
&& 0x75737461 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 261))))) ext
= "tar";
2107 else if (0xfeff == shortMagic
|| 0xfffe == shortMagic
) ext
= "txt";
2108 else if (0x1f9d == shortMagic
) ext
= "Z";
2109 else if (0x1f8b == shortMagic
) ext
= "gz";
2110 else if (0x71c7 == shortMagic
|| 0xc771 == shortMagic
) ext
= "cpio";
2111 else if (0xf702 == shortMagic
) ext
= "dvi";
2112 else if (0x01da == shortMagic
&& (0 == bytes
[2] || 1 == bytes
[2]) && (0 < bytes
[3] && 16 > bytes
[3])) ext
= "sgi";
2113 else if (0x2321 == shortMagic
) {
2114 CFIndex endOfLine
= 0, lastSlash
= 0;
2115 for (i
= 2; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2116 if (endOfLine
> 3) {
2117 for (i
= endOfLine
- 1; 0 == lastSlash
&& i
> 1; i
--) if ('/' == bytes
[i
]) lastSlash
= i
;
2118 if (lastSlash
> 0) {
2119 if (0 == strncmp(bytes
+ lastSlash
+ 1, "perl", 4)) ext
= "pl";
2120 else if (0 == strncmp(bytes
+ lastSlash
+ 1, "python", 6)) ext
= "py";
2121 else if (0 == strncmp(bytes
+ lastSlash
+ 1, "ruby", 4)) ext
= "rb";
2125 } else if (0xffd8 == shortMagic
&& 0xff == bytes
[2]) ext
= "jpeg";
2126 else if (0x4657 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swf";
2127 else if (0x4357 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swc";
2128 else if (0x4944 == shortMagic
&& '3' == bytes
[2] && 0x20 > bytes
[3]) ext
= "mp3";
2129 else if (0x425a == shortMagic
&& isdigit(bytes
[2]) && isdigit(bytes
[3])) ext
= "bz";
2130 else if (0x425a == shortMagic
&& 'h' == bytes
[2] && isdigit(bytes
[3]) && 8 <= length
&& (0x31415926 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "bz2";
2131 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2)))) ext
= "tfm";
2132 else if ('<' == bytes
[0] && 14 <= length
) {
2133 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)) {
2135 } else if (0 == strncasecmp(bytes
+ 1, "?xml", 4)) {
2136 for (i
= 4; !ext
&& i
< 128 && i
+ 20 <= length
; i
++) {
2137 if ('<' == bytes
[i
]) {
2138 if (0 == strncasecmp(bytes
+ i
+ 1, "abiword", 7)) ext
= "abw";
2139 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype svg", 12)) ext
= "svg";
2140 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype x3d", 12)) ext
= "x3d";
2141 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) ext
= "html";
2142 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype plist", 14)) ext
= "plist";
2143 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype posingfont", 19)) ext
= "sfont";
2146 if (!ext
) ext
= "xml";
2151 if (extension
&& !ext
) {
2152 //??? what about MacOSRoman?
2153 for (i
= 0; (isPlain
|| isZero
) && !isHTML
&& i
< length
&& i
< 512; i
++) {
2155 if (0x7f <= c
|| (0x20 > c
&& !isspace(c
))) isPlain
= false;
2156 if (0 != c
) isZero
= false;
2157 if (isPlain
&& '<' == c
&& i
+ 14 <= length
&& 0 == strncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) isHTML
= true;
2161 } else if (isPlain
) {
2162 if (16 <= length
&& 0 == strncmp(bytes
, "StartFontMetrics", 16)) ext
= "afm";
2164 } else if (isZero
&& length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= 526) {
2166 if (lseek(fd
, 512, SEEK_SET
) == 512 && read(fd
, buffer
, MAGIC_BYTES_TO_READ
) >= 14) {
2167 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 10)))) ext
= "pict";
2170 if (526 <= length
&& 0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 522)))) ext
= "pict";
2174 if (extension
&& !ext
&& !isZero
&& length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= 1024) {
2176 off_t offset
= fileLength
- 512;
2177 if (lseek(fd
, offset
, SEEK_SET
) == offset
&& read(fd
, buffer
, 512) >= 512) {
2178 if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32
*)buffer
)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 504))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 508))))) ext
= "dmg";
2181 if (512 <= length
&& (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- 512))) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- 4)))))) ext
= "dmg";
2185 if (extension
) *extension
= ext
? CFStringCreateWithCStringNoCopy(NULL
, ext
, kCFStringEncodingASCII
, kCFAllocatorNull
) : NULL
;
2186 if (machtype
) *machtype
= mt
;
2187 if (fd
>= 0) close(fd
);
2188 return (ext
!= NULL
);
2191 CFStringRef
_CFBundleCopyFileTypeForFileURL(CFURLRef url
) {
2192 CFStringRef extension
= NULL
;
2193 (void)_CFBundleGrokFileType(url
, NULL
, &extension
, NULL
, NULL
);
2197 CFStringRef
_CFBundleCopyFileTypeForFileData(CFDataRef data
) {
2198 CFStringRef extension
= NULL
;
2199 (void)_CFBundleGrokFileType(NULL
, data
, &extension
, NULL
, NULL
);
2203 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInExecutable(CFURLRef url
) {
2204 CFDictionaryRef result
= NULL
;
2205 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, &result
);
2209 #if defined(BINARY_SUPPORT_DYLD)
2211 __private_extern__ __CFPBinaryType
_CFBundleGrokBinaryType(CFURLRef executableURL
) {
2212 // 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).
2213 __CFPBinaryType result
= executableURL
? __CFBundleUnreadableBinary
: __CFBundleNoBinary
;
2214 UInt32 machtype
= UNKNOWN_FILETYPE
;
2215 if (_CFBundleGrokFileType(executableURL
, NULL
, NULL
, &machtype
, NULL
)) {
2218 result
= __CFBundleDYLDExecutableBinary
;
2221 result
= __CFBundleDYLDBundleBinary
;
2224 result
= __CFBundleDYLDFrameworkBinary
;
2226 #if defined(BINARY_SUPPORT_CFM)
2228 result
= __CFBundleCFMBinary
;
2230 #endif /* BINARY_SUPPORT_CFM */
2236 #endif /* BINARY_SUPPORT_DYLD */
2238 void _CFBundleSetCFMConnectionID(CFBundleRef bundle
, void *connectionID
) {
2239 #if defined(BINARY_SUPPORT_CFM)
2240 if (bundle
->_binaryType
== __CFBundleUnknownBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
2241 bundle
->_binaryType
= __CFBundleCFMBinary
;
2243 #endif /* BINARY_SUPPORT_CFM */
2244 bundle
->_connectionCookie
= connectionID
;
2245 bundle
->_isLoaded
= true;
2248 Boolean
CFBundleLoadExecutable(CFBundleRef bundle
) {
2249 Boolean result
= false;
2250 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2252 if (!executableURL
) {
2253 bundle
->_binaryType
= __CFBundleNoBinary
;
2255 #if defined(BINARY_SUPPORT_DYLD)
2256 // make sure we know whether bundle is already loaded or not
2257 if (!bundle
->_isLoaded
) {
2258 _CFBundleDYLDCheckLoaded(bundle
);
2260 // We might need to figure out what it is
2261 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2262 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
2263 #if defined(BINARY_SUPPORT_CFM)
2264 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
2265 bundle
->_resourceData
._executableLacksResourceFork
= true;
2267 #endif /* BINARY_SUPPORT_CFM */
2269 #endif /* BINARY_SUPPORT_DYLD */
2270 if (executableURL
) CFRelease(executableURL
);
2272 if (bundle
->_isLoaded
) {
2273 // Remove from the scheduled unload set if we are there.
2274 __CFSpinLock(&CFBundleGlobalDataLock
);
2275 if (_bundlesToUnload
) {
2276 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2278 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2282 // Unload bundles scheduled for unloading
2283 if (!_scheduledBundlesAreUnloading
) {
2284 _CFBundleUnloadScheduledBundles();
2288 switch (bundle
->_binaryType
) {
2289 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2290 case __CFBundleCFMBinary
:
2291 case __CFBundleUnreadableBinary
:
2292 result
= _CFBundleCFMLoad(bundle
);
2294 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2295 #if defined(BINARY_SUPPORT_DYLD)
2296 case __CFBundleDYLDBundleBinary
:
2297 result
= _CFBundleDYLDLoadBundle(bundle
);
2299 case __CFBundleDYLDFrameworkBinary
:
2300 result
= _CFBundleDYLDLoadFramework(bundle
);
2302 case __CFBundleDYLDExecutableBinary
:
2303 CFLog(__kCFLogBundle
, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle
);
2305 #endif /* BINARY_SUPPORT_DYLD */
2306 #if defined(BINARY_SUPPORT_DLL)
2307 case __CFBundleDLLBinary
:
2308 result
= _CFBundleDLLLoad(bundle
);
2310 #endif /* BINARY_SUPPORT_DLL */
2311 case __CFBundleNoBinary
:
2312 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for %@"), bundle
);
2315 CFLog(__kCFLogBundle
, CFSTR("Cannot recognize type of executable for %@"), bundle
);
2322 void CFBundleUnloadExecutable(CFBundleRef bundle
) {
2324 if (!_scheduledBundlesAreUnloading
) {
2325 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
2326 _CFBundleUnloadScheduledBundles();
2329 if (!bundle
->_isLoaded
) return;
2331 // Remove from the scheduled unload set if we are there.
2332 if (!_scheduledBundlesAreUnloading
) {
2333 __CFSpinLock(&CFBundleGlobalDataLock
);
2335 if (_bundlesToUnload
) {
2336 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2338 if (!_scheduledBundlesAreUnloading
) {
2339 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2342 // Give the plugIn code a chance to realize this...
2343 _CFPlugInWillUnload(bundle
);
2345 switch (bundle
->_binaryType
) {
2346 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2347 case __CFBundleCFMBinary
:
2348 _CFBundleCFMUnload(bundle
);
2350 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2351 #if defined(BINARY_SUPPORT_DYLD)
2352 case __CFBundleDYLDBundleBinary
:
2353 _CFBundleDYLDUnloadBundle(bundle
);
2355 #endif /* BINARY_SUPPORT_DYLD */
2356 #if defined(BINARY_SUPPORT_DLL)
2357 case __CFBundleDLLBinary
:
2358 _CFBundleDLLUnload(bundle
);
2360 #endif /* BINARY_SUPPORT_DLL */
2364 if (!bundle
->_isLoaded
&& bundle
->_glueDict
!= NULL
) {
2365 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
2366 CFRelease(bundle
->_glueDict
);
2367 bundle
->_glueDict
= NULL
;
2371 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
2372 __CFSpinLock(&CFBundleGlobalDataLock
);
2373 if (!_bundlesToUnload
) {
2374 // Create this from the default allocator
2375 CFSetCallBacks nonRetainingCallbacks
= kCFTypeSetCallBacks
;
2376 nonRetainingCallbacks
.retain
= NULL
;
2377 nonRetainingCallbacks
.release
= NULL
;
2378 _bundlesToUnload
= CFSetCreateMutable(NULL
, 0, &nonRetainingCallbacks
);
2380 CFSetAddValue(_bundlesToUnload
, bundle
);
2381 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2384 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
2385 __CFSpinLock(&CFBundleGlobalDataLock
);
2386 if (_bundlesToUnload
) {
2387 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2389 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2392 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
2393 __CFSpinLock(&CFBundleGlobalDataLock
);
2394 if (_bundlesToUnload
) {
2395 CFIndex c
= CFSetGetCount(_bundlesToUnload
);
2398 CFBundleRef
*unloadThese
= CFAllocatorAllocate(NULL
, sizeof(CFBundleRef
) * c
, 0);
2399 CFSetGetValues(_bundlesToUnload
, (const void **)unloadThese
);
2400 _scheduledBundlesAreUnloading
= true;
2401 for (i
=0; i
<c
; i
++) {
2402 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2403 CFBundleUnloadExecutable(unloadThese
[i
]);
2405 _scheduledBundlesAreUnloading
= false;
2406 CFAllocatorDeallocate(NULL
, unloadThese
);
2409 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2412 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
2414 // Load if necessary
2415 if (!bundle
->_isLoaded
) {
2416 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2419 switch (bundle
->_binaryType
) {
2420 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2421 case __CFBundleCFMBinary
:
2422 tvp
= _CFBundleCFMGetSymbolByName(bundle
, funcName
, kTVectorCFragSymbol
);
2424 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2425 #if defined(BINARY_SUPPORT_DYLD)
2426 case __CFBundleDYLDBundleBinary
:
2427 case __CFBundleDYLDFrameworkBinary
:
2428 case __CFBundleDYLDExecutableBinary
:
2429 return _CFBundleDYLDGetSymbolByName(bundle
, funcName
);
2431 #endif /* BINARY_SUPPORT_DYLD */
2432 #if defined(BINARY_SUPPORT_DLL)
2433 case __CFBundleDLLBinary
:
2434 tvp
= _CFBundleDLLGetSymbolByName(bundle
, funcName
);
2436 #endif /* BINARY_SUPPORT_DLL */
2440 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2442 if (bundle
->_glueDict
== NULL
) {
2443 bundle
->_glueDict
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, NULL
, NULL
);
2445 void *fp
= (void *)CFDictionaryGetValue(bundle
->_glueDict
, tvp
);
2447 fp
= _CFBundleFunctionPointerForTVector(CFGetAllocator(bundle
), tvp
);
2448 CFDictionarySetValue(bundle
->_glueDict
, tvp
, fp
);
2452 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2456 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
2458 // Load if necessary
2459 if (!bundle
->_isLoaded
) {
2460 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2463 switch (bundle
->_binaryType
) {
2464 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2465 case __CFBundleCFMBinary
:
2466 return _CFBundleCFMGetSymbolByName(bundle
, funcName
, kTVectorCFragSymbol
);
2468 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2469 #if defined(BINARY_SUPPORT_DYLD)
2470 case __CFBundleDYLDBundleBinary
:
2471 case __CFBundleDYLDFrameworkBinary
:
2472 case __CFBundleDYLDExecutableBinary
:
2473 fp
= _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, funcName
, true);
2475 #endif /* BINARY_SUPPORT_DYLD */
2479 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2481 if (bundle
->_glueDict
== NULL
) {
2482 bundle
->_glueDict
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, NULL
, NULL
);
2484 void *tvp
= (void *)CFDictionaryGetValue(bundle
->_glueDict
, fp
);
2486 tvp
= _CFBundleTVectorForFunctionPointer(CFGetAllocator(bundle
), fp
);
2487 CFDictionarySetValue(bundle
->_glueDict
, fp
, tvp
);
2491 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2495 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
2500 c
= CFArrayGetCount(functionNames
);
2501 for (i
= 0; i
< c
; i
++) {
2502 ftbl
[i
] = CFBundleGetFunctionPointerForName(bundle
, CFArrayGetValueAtIndex(functionNames
, i
));
2506 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
2511 c
= CFArrayGetCount(functionNames
);
2512 for (i
= 0; i
< c
; i
++) {
2513 ftbl
[i
] = _CFBundleGetCFMFunctionPointerForName(bundle
, CFArrayGetValueAtIndex(functionNames
, i
));
2517 void *CFBundleGetDataPointerForName(CFBundleRef bundle
, CFStringRef symbolName
) {
2519 // Load if necessary
2520 if (!bundle
->_isLoaded
) {
2521 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2524 switch (bundle
->_binaryType
) {
2525 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2526 case __CFBundleCFMBinary
:
2527 dp
= _CFBundleCFMGetSymbolByName(bundle
, symbolName
, kDataCFragSymbol
);
2529 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2530 #if defined(BINARY_SUPPORT_DYLD)
2531 case __CFBundleDYLDBundleBinary
:
2532 case __CFBundleDYLDFrameworkBinary
:
2533 case __CFBundleDYLDExecutableBinary
:
2534 dp
= _CFBundleDYLDGetSymbolByName(bundle
, symbolName
);
2536 #endif /* BINARY_SUPPORT_DYLD */
2537 #if defined(BINARY_SUPPORT_DLL)
2538 case __CFBundleDLLBinary
:
2539 /* MF:!!! Handle this someday */
2541 #endif /* BINARY_SUPPORT_DLL */
2548 void CFBundleGetDataPointersForNames(CFBundleRef bundle
, CFArrayRef symbolNames
, void *stbl
[]) {
2553 c
= CFArrayGetCount(symbolNames
);
2554 for (i
= 0; i
< c
; i
++) {
2555 stbl
[i
] = CFBundleGetDataPointerForName(bundle
, CFArrayGetValueAtIndex(symbolNames
, i
));
2559 __private_extern__ _CFResourceData
*__CFBundleGetResourceData(CFBundleRef bundle
) {
2560 return &(bundle
->_resourceData
);
2563 CFPlugInRef
CFBundleGetPlugIn(CFBundleRef bundle
) {
2564 if (bundle
->_plugInData
._isPlugIn
) {
2565 return (CFPlugInRef
)bundle
;
2571 __private_extern__ _CFPlugInData
*__CFBundleGetPlugInData(CFBundleRef bundle
) {
2572 return &(bundle
->_plugInData
);
2575 __private_extern__ Boolean
_CFBundleCouldBeBundle(CFURLRef url
) {
2576 Boolean result
= false;
2580 if (_CFGetFileProperties(NULL
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) {
2581 result
= (exists
&& ((mode
& S_IFMT
) == S_IFDIR
));
2582 #if !defined(__MACOS8__)
2583 result
= (result
&& ((mode
& 0444) != 0));
2589 __private_extern__ CFURLRef
_CFBundleCopyFrameworkURLForExecutablePath(CFAllocatorRef alloc
, CFStringRef executablePath
) {
2590 // 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.
2591 #if defined(__WIN32__)
2592 UniChar executablesToFrameworksPathBuff
[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 16
2593 UniChar executablesToPrivateFrameworksPathBuff
[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 23
2594 UniChar frameworksExtension
[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'}; // length 9
2597 UniChar pathBuff
[CFMaxPathSize
];
2598 UniChar nameBuff
[CFMaxPathSize
];
2599 CFIndex length
, nameStart
, nameLength
, savedLength
;
2600 CFMutableStringRef cheapStr
= CFStringCreateMutableWithExternalCharactersNoCopy(alloc
, NULL
, 0, 0, NULL
);
2601 CFURLRef bundleURL
= NULL
;
2603 length
= CFStringGetLength(executablePath
);
2604 if (length
> CFMaxPathSize
) length
= CFMaxPathSize
;
2605 CFStringGetCharacters(executablePath
, CFRangeMake(0, length
), pathBuff
);
2607 // Save the name in nameBuff
2608 length
= _CFLengthAfterDeletingPathExtension(pathBuff
, length
);
2609 nameStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2610 nameLength
= length
- nameStart
;
2611 memmove(nameBuff
, &(pathBuff
[nameStart
]), nameLength
* sizeof(UniChar
));
2613 // Strip the name from pathBuff
2614 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2615 savedLength
= length
;
2617 #if defined(__WIN32__)
2618 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
2619 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToFrameworksPathBuff
, 16) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, 9)) {
2620 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2621 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2622 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2623 CFRelease(bundleURL
);
2627 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
2628 if (bundleURL
== NULL
) {
2629 length
= savedLength
;
2630 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToPrivateFrameworksPathBuff
, 23) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, 9)) {
2631 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2632 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2633 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2634 CFRelease(bundleURL
);
2640 // * Finally check the executable inside the framework case.
2641 if (bundleURL
== NULL
) {
2642 // MF:!!! This should ensure the framework name is the same as the library name!
2645 length
= savedLength
;
2646 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
2648 while (length
> 0) {
2649 curStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2650 if (curStart
>= length
) {
2653 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[curStart
]), length
- curStart
, CFMaxPathSize
- curStart
);
2654 if (CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName1
) || CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName2
)) {
2655 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2656 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2657 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2658 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2659 CFRelease(bundleURL
);
2663 } else if (CFStringHasSuffix(cheapStr
, CFSTR(".framework"))) {
2664 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2665 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2666 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2667 CFRelease(bundleURL
);
2672 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2676 CFStringSetExternalCharactersNoCopy(cheapStr
, NULL
, 0, 0);
2677 CFRelease(cheapStr
);
2682 #if defined(BINARY_SUPPORT_DYLD)
2683 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
) {
2684 // This finds the bundle for the given path.
2685 // 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.
2687 CFURLRef curURL
= _CFBundleCopyFrameworkURLForExecutablePath(NULL
, imagePath
);
2689 if (curURL
!= NULL
) {
2690 bundle
= _CFBundleFindByURL(curURL
, true);
2691 if (bundle
== NULL
) {
2692 bundle
= _CFBundleCreate(NULL
, curURL
, true, true);
2694 if (bundle
!= NULL
&& !bundle
->_isLoaded
) {
2695 // 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)
2696 #if defined(BINARY_SUPPORT_DYLD)
2697 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2698 bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
2700 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
2701 bundle
->_resourceData
._executableLacksResourceFork
= true;
2703 if (!bundle
->_imageCookie
) _CFBundleDYLDCheckLoaded(bundle
);
2704 #endif /* BINARY_SUPPORT_DYLD */
2705 bundle
->_isLoaded
= true;
2711 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
) {
2712 // This finds the bundles for the given paths.
2713 // 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).
2714 CFIndex i
, imagePathCount
= CFArrayGetCount(imagePaths
);
2716 for (i
=0; i
<imagePathCount
; i
++) {
2717 _CFBundleEnsureBundleExistsForImagePath(CFArrayGetValueAtIndex(imagePaths
, i
));
2720 #endif /* BINARY_SUPPORT_DYLD */
2722 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
) {
2723 // Tickle the main bundle into existence
2724 (void)_CFBundleGetMainBundleAlreadyLocked();
2725 #if defined(BINARY_SUPPORT_DYLD)
2726 CFArrayRef imagePaths
= _CFBundleDYLDCopyLoadedImagePathsForHint(hint
);
2727 if (imagePaths
!= NULL
) {
2728 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2729 CFRelease(imagePaths
);
2734 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
2735 // 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.
2737 // Tickle the main bundle into existence
2738 (void)_CFBundleGetMainBundleAlreadyLocked();
2740 #if defined(BINARY_SUPPORT_DLL)
2741 #warning (MF) Dont know how to find static bundles for DLLs
2744 #if defined(BINARY_SUPPORT_CFM)
2745 // CFM bundles are supplied to us by CFM, so we do not need to figure them out ourselves
2748 #if defined(BINARY_SUPPORT_DYLD)
2749 CFArrayRef imagePaths
= _CFBundleDYLDCopyLoadedImagePathsIfChanged();
2750 if (imagePaths
!= NULL
) {
2751 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2752 CFRelease(imagePaths
);
2757 CFArrayRef
CFBundleGetAllBundles(void) {
2758 // To answer this properly, we have to have created the static bundles!
2759 __CFSpinLock(&CFBundleGlobalDataLock
);
2760 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2761 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2765 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle
) {return bundle
->_version
;}
2767 CF_EXPORT CFURLRef
_CFBundleCopyInfoPlistURL(CFBundleRef bundle
) {
2768 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2769 CFStringRef path
= CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
);
2770 return (path
? CFRetain(path
) : NULL
);
2773 CF_EXPORT CFURLRef
_CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {return CFBundleCopyPrivateFrameworksURL(bundle
);}
2775 CF_EXPORT CFURLRef
CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
2776 CFURLRef result
= NULL
;
2778 if (1 == bundle
->_version
) {
2779 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase1
, bundle
->_url
);
2780 } else if (2 == bundle
->_version
) {
2781 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase2
, bundle
->_url
);
2783 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase0
, bundle
->_url
);
2788 CF_EXPORT CFURLRef
_CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {return CFBundleCopySharedFrameworksURL(bundle
);}
2790 CF_EXPORT CFURLRef
CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
2791 CFURLRef result
= NULL
;
2793 if (1 == bundle
->_version
) {
2794 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase1
, bundle
->_url
);
2795 } else if (2 == bundle
->_version
) {
2796 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase2
, bundle
->_url
);
2798 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase0
, bundle
->_url
);
2803 CF_EXPORT CFURLRef
_CFBundleCopySharedSupportURL(CFBundleRef bundle
) {return CFBundleCopySharedSupportURL(bundle
);}
2805 CF_EXPORT CFURLRef
CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
2806 CFURLRef result
= NULL
;
2808 if (1 == bundle
->_version
) {
2809 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase1
, bundle
->_url
);
2810 } else if (2 == bundle
->_version
) {
2811 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase2
, bundle
->_url
);
2813 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase0
, bundle
->_url
);
2818 __private_extern__ CFURLRef
_CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {return CFBundleCopyBuiltInPlugInsURL(bundle
);}
2820 CF_EXPORT CFURLRef
CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
2821 CFURLRef result
= NULL
, alternateResult
= NULL
;
2823 CFAllocatorRef alloc
= CFGetAllocator(bundle
);
2824 if (1 == bundle
->_version
) {
2825 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase1
, bundle
->_url
);
2826 } else if (2 == bundle
->_version
) {
2827 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase2
, bundle
->_url
);
2829 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2831 if (!result
|| !_urlExists(alloc
, result
)) {
2832 if (1 == bundle
->_version
) {
2833 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase1
, bundle
->_url
);
2834 } else if (2 == bundle
->_version
) {
2835 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase2
, bundle
->_url
);
2837 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2839 if (alternateResult
&& _urlExists(alloc
, alternateResult
)) {
2840 if (result
) CFRelease(result
);
2841 result
= alternateResult
;
2843 if (alternateResult
) CFRelease(alternateResult
);
2851 #if defined(BINARY_SUPPORT_DYLD)
2853 static const void *__CFBundleDYLDFindImage(char *buff
) {
2854 const void *header
= NULL
;
2855 uint32_t i
, numImages
= _dyld_image_count(), numMatches
= 0;
2856 const char *curName
, *p
, *q
;
2858 for (i
= 0; !header
&& i
< numImages
; i
++) {
2859 curName
= _dyld_get_image_name(i
);
2860 if (curName
&& 0 == strncmp(curName
, buff
, CFMaxPathSize
)) {
2861 header
= _dyld_get_image_header(i
);
2866 for (i
= 0; i
< numImages
; i
++) {
2867 curName
= _dyld_get_image_name(i
);
2869 for (p
= buff
, q
= curName
; *p
&& *q
&& (q
- curName
< CFMaxPathSize
); p
++, q
++) {
2870 if (*p
!= *q
&& (q
- curName
> 11) && 0 == strncmp(q
- 11, ".framework/Versions/", 20) && *(q
+ 9) && '/' == *(q
+ 10)) q
+= 11;
2871 else if (*p
!= *q
&& (q
- curName
> 12) && 0 == strncmp(q
- 12, ".framework/Versions/", 20) && *(q
+ 8) && '/' == *(q
+ 9)) q
+= 10;
2872 if (*p
!= *q
) break;
2875 header
= _dyld_get_image_header(i
);
2881 return (numMatches
== 1) ? header
: NULL
;
2884 __private_extern__ Boolean
_CFBundleDYLDCheckLoaded(CFBundleRef bundle
) {
2885 if (!bundle
->_isLoaded
) {
2886 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2888 if (executableURL
!= NULL
) {
2889 char buff
[CFMaxPathSize
];
2891 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2892 const void *header
= __CFBundleDYLDFindImage(buff
);
2894 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2895 bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
2897 if (!bundle
->_imageCookie
) bundle
->_imageCookie
= header
;
2898 bundle
->_isLoaded
= true;
2901 CFRelease(executableURL
);
2904 return bundle
->_isLoaded
;
2907 __private_extern__ Boolean
_CFBundleDYLDLoadBundle(CFBundleRef bundle
) {
2908 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
2909 int errorNumber
= 0;
2910 const char *fileName
= NULL
;
2911 const char *errorString
= NULL
;
2913 if (!bundle
->_isLoaded
) {
2914 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2916 if (executableURL
) {
2917 char buff
[CFMaxPathSize
];
2919 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2920 NSObjectFileImage image
;
2921 NSObjectFileImageReturnCode retCode
= NSCreateObjectFileImageFromFile(buff
, &image
);
2922 if (retCode
== NSObjectFileImageSuccess
) {
2923 NSModule
module = NSLinkModule(image
, buff
, (NSLINKMODULE_OPTION_BINDNOW
| NSLINKMODULE_OPTION_PRIVATE
| NSLINKMODULE_OPTION_RETURN_ON_ERROR
));
2925 bundle
->_imageCookie
= image
;
2926 bundle
->_moduleCookie
= module;
2927 bundle
->_isLoaded
= true;
2929 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
2930 CFLog(__kCFLogBundle
, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName
, c
, errorNumber
, errorString
);
2931 if (!NSDestroyObjectFileImage(image
)) {
2932 /* MF:!!! Error destroying object file image */
2936 CFLog(__kCFLogBundle
, CFSTR("dyld returns %d when trying to load %@"), retCode
, executableURL
);
2939 CFRelease(executableURL
);
2941 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2944 return bundle
->_isLoaded
;
2947 __private_extern__ Boolean
_CFBundleDYLDLoadFramework(CFBundleRef bundle
) {
2948 // !!! Framework loading should be better. Can't unload frameworks.
2949 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
2950 int errorNumber
= 0;
2951 const char *fileName
= NULL
;
2952 const char *errorString
= NULL
;
2954 if (!bundle
->_isLoaded
) {
2955 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2957 if (executableURL
) {
2958 char buff
[CFMaxPathSize
];
2960 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2961 void *image
= (void *)NSAddImage(buff
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
2963 bundle
->_imageCookie
= image
;
2964 bundle
->_isLoaded
= true;
2966 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
2967 CFLog(__kCFLogBundle
, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName
, c
, errorNumber
, errorString
);
2970 CFRelease(executableURL
);
2972 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2975 return bundle
->_isLoaded
;
2978 __private_extern__
void _CFBundleDYLDUnloadBundle(CFBundleRef bundle
) {
2979 if (bundle
->_isLoaded
) {
2980 if (bundle
->_moduleCookie
&& !NSUnLinkModule((NSModule
)(bundle
->_moduleCookie
), NSUNLINKMODULE_OPTION_NONE
)) {
2981 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
2983 if (bundle
->_moduleCookie
&& bundle
->_imageCookie
&& !NSDestroyObjectFileImage((NSObjectFileImage
)(bundle
->_imageCookie
))) {
2984 /* MF:!!! Error destroying object file image */
2986 bundle
->_connectionCookie
= NULL
;
2987 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
2988 bundle
->_isLoaded
= false;
2993 __private_extern__
void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {return _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, symbolName
, false);}
2995 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
2996 void *result
= NULL
;
2998 NSSymbol symbol
= NULL
;
3000 // MF:!!! What if the factory was in C++ code (and is therefore mangled differently)? Huh, answer me that!
3001 // 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.
3003 /* MF:??? ASCII appropriate here? */
3004 if (CFStringGetCString(symbolName
, &(buff
[1]), 1024, kCFStringEncodingASCII
)) {
3005 if (bundle
->_moduleCookie
) {
3006 symbol
= NSLookupSymbolInModule((NSModule
)(bundle
->_moduleCookie
), buff
);
3007 } else if (bundle
->_imageCookie
) {
3008 symbol
= NSLookupSymbolInImage(bundle
->_imageCookie
, buff
, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
3010 if (NULL
== symbol
&& NULL
== bundle
->_moduleCookie
&& (NULL
== bundle
->_imageCookie
|| globalSearch
)) {
3011 char hintBuff
[1026];
3012 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, bundle
, NULL
, NULL
);
3014 if (executableName
) {
3015 if (!CFStringGetCString(executableName
, hintBuff
, 1024, kCFStringEncodingUTF8
)) hintBuff
[0] = '\0';
3016 CFRelease(executableName
);
3018 if (NSIsSymbolNameDefinedWithHint(buff
, hintBuff
)) {
3019 symbol
= NSLookupAndBindSymbolWithHint(buff
, hintBuff
);
3023 result
= NSAddressOfSymbol(symbol
);
3026 CFLog(__kCFLogBundle
, CFSTR("dyld cannot find symbol %s in %@"), buff
, bundle
);
3033 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
) {
3034 uint32_t i
, j
, n
= _dyld_image_count();
3035 Boolean foundit
= false;
3037 CFStringRef result
= NULL
;
3038 for (i
= 0; !foundit
&& i
< n
; i
++) {
3039 // will need modification for 64-bit
3040 const struct mach_header
*mh
= _dyld_get_image_header(i
);
3041 uint32_t addr
= (uint32_t)p
- _dyld_get_image_vmaddr_slide(i
);
3043 struct load_command
*lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
3044 for (j
= 0; !foundit
&& j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
)) {
3045 if (LC_SEGMENT
== lc
->cmd
&& addr
>= ((struct segment_command
*)lc
)->vmaddr
&& addr
< ((struct segment_command
*)lc
)->vmaddr
+ ((struct segment_command
*)lc
)->vmsize
) {
3047 name
= _dyld_get_image_name(i
);
3049 result
= CFStringCreateWithCString(NULL
, name
, CFStringFileSystemEncoding());
3058 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint
) {
3059 uint32_t i
, numImages
= _dyld_image_count();
3060 CFMutableArrayRef result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3061 CFRange range
= CFRangeMake(0, CFStringGetLength(hint
));
3063 for (i
=0; i
<numImages
; i
++) {
3064 const char *curName
= _dyld_get_image_name(i
), *lastComponent
= NULL
;
3065 if (curName
!= NULL
) lastComponent
= strrchr(curName
, '/');
3066 if (lastComponent
!= NULL
) {
3067 CFStringRef str
= CFStringCreateWithCString(NULL
, lastComponent
+ 1, CFStringFileSystemEncoding());
3069 if (CFStringFindWithOptions(hint
, str
, range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
3070 CFStringRef curStr
= CFStringCreateWithCString(NULL
, curName
, CFStringFileSystemEncoding());
3071 if (curStr
!= NULL
) {
3072 CFArrayAppendValue(result
, curStr
);
3083 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
3084 // 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.
3085 static uint32_t _cachedDYLDImageCount
= -1;
3087 uint32_t i
, numImages
= _dyld_image_count();
3088 CFMutableArrayRef result
= NULL
;
3090 if (numImages
!= _cachedDYLDImageCount
) {
3091 const char *curName
;
3094 result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3096 for (i
=0; i
<numImages
; i
++) {
3097 curName
= _dyld_get_image_name(i
);
3098 if (curName
!= NULL
) {
3099 curStr
= CFStringCreateWithCString(NULL
, curName
, CFStringFileSystemEncoding());
3100 if (curStr
!= NULL
) {
3101 CFArrayAppendValue(result
, curStr
);
3106 _cachedDYLDImageCount
= numImages
;
3111 #endif /* BINARY_SUPPORT_DYLD */
3114 #if defined(BINARY_SUPPORT_DLL)
3116 __private_extern__ Boolean
_CFBundleDLLLoad(CFBundleRef bundle
) {
3118 if (!bundle
->_isLoaded
) {
3119 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3121 if (executableURL
) {
3122 char buff
[CFMaxPathSize
];
3124 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
3125 bundle
->_hModule
= LoadLibrary(buff
);
3126 if (bundle
->_hModule
== NULL
) {
3128 bundle
->_isLoaded
= true;
3131 CFRelease(executableURL
);
3133 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
3137 return bundle
->_isLoaded
;
3140 __private_extern__
void _CFBundleDLLUnload(CFBundleRef bundle
) {
3141 if (bundle
->_isLoaded
) {
3142 FreeLibrary(bundle
->_hModule
);
3143 bundle
->_hModule
= NULL
;
3144 bundle
->_isLoaded
= false;
3148 __private_extern__
void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
3149 void *result
= NULL
;
3152 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingWindowsLatin1
)) {
3153 result
= GetProcAddress(bundle
->_hModule
, buff
);
3158 #endif /* BINARY_SUPPORT_DLL */
3161 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
3163 extern void _CFStringSetCompatibility(CFOptionFlags
);
3165 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
) {