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__)
82 // Public CFBundle Info plist keys
83 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey
, "CFBundleInfoDictionaryVersion")
84 CONST_STRING_DECL(kCFBundleExecutableKey
, "CFBundleExecutable")
85 CONST_STRING_DECL(kCFBundleIdentifierKey
, "CFBundleIdentifier")
86 CONST_STRING_DECL(kCFBundleVersionKey
, "CFBundleVersion")
87 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey
, "CFBundleDevelopmentRegion")
88 CONST_STRING_DECL(kCFBundleLocalizationsKey
, "CFBundleLocalizations")
91 CONST_STRING_DECL(_kCFBundlePackageTypeKey
, "CFBundlePackageType")
92 CONST_STRING_DECL(_kCFBundleSignatureKey
, "CFBundleSignature")
93 CONST_STRING_DECL(_kCFBundleIconFileKey
, "CFBundleIconFile")
94 CONST_STRING_DECL(_kCFBundleDocumentTypesKey
, "CFBundleDocumentTypes")
95 CONST_STRING_DECL(_kCFBundleURLTypesKey
, "CFBundleURLTypes")
97 // Keys that are usually localized in InfoPlist.strings
98 CONST_STRING_DECL(kCFBundleNameKey
, "CFBundleName")
99 CONST_STRING_DECL(_kCFBundleDisplayNameKey
, "CFBundleDisplayName")
100 CONST_STRING_DECL(_kCFBundleShortVersionStringKey
, "CFBundleShortVersionString")
101 CONST_STRING_DECL(_kCFBundleGetInfoStringKey
, "CFBundleGetInfoString")
102 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey
, "CFBundleGetInfoHTML")
104 // Sub-keys for CFBundleDocumentTypes dictionaries
105 CONST_STRING_DECL(_kCFBundleTypeNameKey
, "CFBundleTypeName")
106 CONST_STRING_DECL(_kCFBundleTypeRoleKey
, "CFBundleTypeRole")
107 CONST_STRING_DECL(_kCFBundleTypeIconFileKey
, "CFBundleTypeIconFile")
108 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey
, "CFBundleTypeOSTypes")
109 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey
, "CFBundleTypeExtensions")
110 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey
, "CFBundleTypeMIMETypes")
112 // Sub-keys for CFBundleURLTypes dictionaries
113 CONST_STRING_DECL(_kCFBundleURLNameKey
, "CFBundleURLName")
114 CONST_STRING_DECL(_kCFBundleURLIconFileKey
, "CFBundleURLIconFile")
115 CONST_STRING_DECL(_kCFBundleURLSchemesKey
, "CFBundleURLSchemes")
117 // Compatibility key names
118 CONST_STRING_DECL(_kCFBundleOldExecutableKey
, "NSExecutable")
119 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey
, "NSInfoPlistVersion")
120 CONST_STRING_DECL(_kCFBundleOldNameKey
, "NSHumanReadableName")
121 CONST_STRING_DECL(_kCFBundleOldIconFileKey
, "NSIcon")
122 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey
, "NSTypes")
123 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey
, "NSAppVersion")
125 // Compatibility CFBundleDocumentTypes key names
126 CONST_STRING_DECL(_kCFBundleOldTypeNameKey
, "NSName")
127 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey
, "NSRole")
128 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey
, "NSIcon")
129 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key
, "NSUnixExtensions")
130 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key
, "NSDOSExtensions")
131 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey
, "NSMacOSType")
133 // Internally used keys for loaded Info plists.
134 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey
, "CFBundleInfoPlistURL")
135 CONST_STRING_DECL(_kCFBundleNumericVersionKey
, "CFBundleNumericVersion")
136 CONST_STRING_DECL(_kCFBundleExecutablePathKey
, "CFBundleExecutablePath")
137 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey
, "CSResourcesFileMapped")
138 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey
, "CFBundleCFMLoadAsBundle")
139 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey
, "CFBundleAllowMixedLocalizations")
141 static CFTypeID __kCFBundleTypeID
= _kCFRuntimeNotATypeID
;
149 CFDictionaryRef _infoDict
;
150 CFDictionaryRef _localInfoDict
;
151 CFArrayRef _searchLanguages
;
153 __CFPBinaryType _binaryType
;
156 Boolean _sharesStringsFiles
;
160 void *_connectionCookie
;
163 const void *_imageCookie
;
164 const void *_moduleCookie
;
166 /* CFM<->DYLD glue */
167 CFMutableDictionaryRef _glueDict
;
169 /* Resource fork goop */
170 _CFResourceData _resourceData
;
172 _CFPlugInData _plugInData
;
174 #if defined(BINARY_SUPPORT_DLL)
180 static CFSpinLock_t CFBundleGlobalDataLock
= 0;
182 static CFMutableDictionaryRef _bundlesByURL
= NULL
;
183 static CFMutableDictionaryRef _bundlesByIdentifier
= NULL
;
185 // For scheduled lazy unloading. Used by CFPlugIn.
186 static CFMutableSetRef _bundlesToUnload
= NULL
;
187 static Boolean _scheduledBundlesAreUnloading
= false;
189 // Various lists of all bundles.
190 static CFMutableArrayRef _allBundles
= NULL
;
192 static Boolean _initedMainBundle
= false;
193 static CFBundleRef _mainBundle
= NULL
;
194 static CFStringRef _defaultLocalization
= NULL
;
196 // Forward declares functions.
197 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
);
198 static CFStringRef
_CFBundleCopyExecutableName(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
);
199 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
);
200 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
);
201 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
202 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
);
203 #if defined(BINARY_SUPPORT_DYLD)
204 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
);
205 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
);
206 static CFDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable(void);
207 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
);
208 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
);
209 #endif /* BINARY_SUPPORT_DYLD */
210 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
211 static void *_CFBundleFunctionPointerForTVector(CFAllocatorRef allocator
, void *tvp
);
212 static void *_CFBundleTVectorForFunctionPointer(CFAllocatorRef allocator
, void *fp
);
213 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
215 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
216 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
218 if (!alreadyLocked
) {
219 __CFSpinLock(&CFBundleGlobalDataLock
);
222 // Add to the _allBundles list
223 if (_allBundles
== NULL
) {
224 // Create this from the default allocator
225 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
226 nonRetainingArrayCallbacks
.retain
= NULL
;
227 nonRetainingArrayCallbacks
.release
= NULL
;
228 _allBundles
= CFArrayCreateMutable(NULL
, 0, &nonRetainingArrayCallbacks
);
230 CFArrayAppendValue(_allBundles
, bundle
);
232 // Add to the table that maps urls to bundles
233 if (_bundlesByURL
== NULL
) {
234 // Create this from the default allocator
235 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
236 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
237 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
238 _bundlesByURL
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
240 CFDictionarySetValue(_bundlesByURL
, bundle
->_url
, bundle
);
242 // Add to the table that maps identifiers to bundles
244 CFBundleRef existingBundle
= NULL
;
245 Boolean addIt
= true;
246 if (_bundlesByIdentifier
== NULL
) {
247 // Create this from the default allocator
248 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
249 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
250 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
251 _bundlesByIdentifier
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
253 existingBundle
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
254 if (existingBundle
) {
255 UInt32 existingVersion
, newVersion
;
256 existingVersion
= CFBundleGetVersionNumber(existingBundle
);
257 newVersion
= CFBundleGetVersionNumber(bundle
);
258 if (newVersion
< existingVersion
) {
259 // Less than to means that if you load two bundles with the same identifier and the same version, the last one wins.
264 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundle
);
267 if (!alreadyLocked
) {
268 __CFSpinUnlock(&CFBundleGlobalDataLock
);
272 static void _CFBundleRemoveFromTables(CFBundleRef bundle
) {
273 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
275 __CFSpinLock(&CFBundleGlobalDataLock
);
277 // Remove from the various lists
278 if (_allBundles
!= NULL
) {
279 CFIndex i
= CFArrayGetFirstIndexOfValue(_allBundles
, CFRangeMake(0, CFArrayGetCount(_allBundles
)), bundle
);
281 CFArrayRemoveValueAtIndex(_allBundles
, i
);
285 // Remove from the table that maps urls to bundles
286 if (_bundlesByURL
!= NULL
) {
287 CFDictionaryRemoveValue(_bundlesByURL
, bundle
->_url
);
290 // Remove from the table that maps identifiers to bundles
291 if ((bundleID
!= NULL
) && (_bundlesByIdentifier
!= NULL
)) {
292 if (CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
) == bundle
) {
293 CFDictionaryRemoveValue(_bundlesByIdentifier
, bundleID
);
296 __CFSpinUnlock(&CFBundleGlobalDataLock
);
299 __private_extern__ CFBundleRef
_CFBundleFindByURL(CFURLRef url
, Boolean alreadyLocked
) {
300 CFBundleRef result
= NULL
;
301 if (!alreadyLocked
) {
302 __CFSpinLock(&CFBundleGlobalDataLock
);
304 if (_bundlesByURL
!= NULL
) {
305 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, url
);
307 if (!alreadyLocked
) {
308 __CFSpinUnlock(&CFBundleGlobalDataLock
);
313 static CFURLRef
_CFBundleCopyBundleURLForExecutablePath(CFStringRef str
) {
314 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
315 UniChar buff
[CFMaxPathSize
];
320 buffLen
= CFStringGetLength(str
);
321 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
322 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
323 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
); // Remove exe name
326 // See if this is a new bundle. If it is, we have to remove more path components.
327 CFIndex startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
328 if ((startOfLastDir
> 0) && (startOfLastDir
< buffLen
)) {
329 CFStringRef lastDirName
= CFStringCreateWithCharacters(NULL
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
331 if (CFEqual(lastDirName
, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
332 // This is a new bundle. Back off a few more levels
334 // Remove platform folder
335 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
338 // Remove executables folder (if present)
339 CFIndex startOfNextDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
340 if ((startOfNextDir
> 0) && (startOfNextDir
< buffLen
)) {
341 CFStringRef nextDirName
= CFStringCreateWithCharacters(NULL
, &(buff
[startOfNextDir
]), buffLen
- startOfNextDir
);
342 if (CFEqual(nextDirName
, _CFBundleExecutablesDirectoryName
)) {
343 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
345 CFRelease(nextDirName
);
349 // Remove support files folder
350 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
353 CFRelease(lastDirName
);
358 outstr
= CFStringCreateWithCharactersNoCopy(NULL
, buff
, buffLen
, kCFAllocatorNull
);
359 url
= CFURLCreateWithFileSystemPath(NULL
, outstr
, PLATFORM_PATH_STYLE
, true);
365 static CFURLRef
_CFBundleCopyResolvedURLForExecutableURL(CFURLRef url
) {
366 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
367 CFURLRef absoluteURL
, url1
, url2
, outURL
= NULL
;
368 CFStringRef str
, str1
, str2
;
369 absoluteURL
= CFURLCopyAbsoluteURL(url
);
370 str
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
372 UniChar buff
[CFMaxPathSize
];
373 CFIndex buffLen
= CFStringGetLength(str
), len1
;
374 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
375 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
376 len1
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
377 if (len1
> 0 && len1
+ 1 < buffLen
) {
378 str1
= CFStringCreateWithCharacters(NULL
, buff
, len1
);
379 str2
= CFStringCreateWithCharacters(NULL
, buff
+ len1
+ 1, buffLen
- len1
- 1);
381 url1
= CFURLCreateWithFileSystemPath(NULL
, str1
, PLATFORM_PATH_STYLE
, true);
383 url2
= CFURLCreateWithFileSystemPathRelativeToBase(NULL
, str2
, PLATFORM_PATH_STYLE
, false, url1
);
385 outURL
= CFURLCopyAbsoluteURL(url2
);
391 if (str1
) CFRelease(str1
);
392 if (str2
) CFRelease(str2
);
397 outURL
= absoluteURL
;
399 CFRelease(absoluteURL
);
404 CFURLRef
_CFBundleCopyBundleURLForExecutableURL(CFURLRef url
) {
405 CFURLRef resolvedURL
, outurl
= NULL
;
407 resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
408 str
= CFURLCopyFileSystemPath(resolvedURL
, PLATFORM_PATH_STYLE
);
410 outurl
= _CFBundleCopyBundleURLForExecutablePath(str
);
413 CFRelease(resolvedURL
);
417 CFBundleRef
_CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
418 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
420 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
421 if (bundle
&& 0 == bundle
->_version
) {
422 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
423 if (!infoDict
|| 0 == CFDictionaryGetCount(infoDict
)) {
424 #if defined(BINARY_SUPPORT_CFM) && defined(BINARY_SUPPORT_DYLD)
425 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
427 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
428 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
430 if (bundle
->_binaryType
== __CFBundleCFMBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
431 bundle
->_version
= 4;
433 bundle
->_resourceData
._executableLacksResourceFork
= true;
435 CFRelease(executableURL
);
437 bundle
->_version
= 4;
439 #elif defined(BINARY_SUPPORT_CFM)
440 bundle
->_version
= 4;
442 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
444 CFRelease(executableURL
);
446 bundle
->_version
= 4;
448 #endif /* BINARY_SUPPORT_CFM && BINARY_SUPPORT_DYLD */
451 if (bundle
&& (3 == bundle
->_version
|| 4 == bundle
->_version
)) {
458 CFBundleRef
_CFBundleGetMainBundleIfLooksLikeBundle(void) {
459 CFBundleRef mainBundle
= CFBundleGetMainBundle();
460 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) {
466 CFBundleRef
_CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
467 CFBundleRef bundle
= NULL
;
468 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
469 if (bundleURL
&& resolvedURL
) {
470 bundle
= _CFBundleCreateIfLooksLikeBundle(allocator
, bundleURL
);
472 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
473 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
474 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
478 if (executableURL
) CFRelease(executableURL
);
481 if (bundleURL
) CFRelease(bundleURL
);
482 if (resolvedURL
) CFRelease(resolvedURL
);
486 CFURLRef
_CFBundleCopyMainBundleExecutableURL(Boolean
*looksLikeBundle
) {
487 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
488 const char *processPath
;
489 CFStringRef str
= NULL
;
490 CFURLRef executableURL
= NULL
;
491 processPath
= _CFProcessPath();
493 str
= CFStringCreateWithCString(NULL
, processPath
, CFStringFileSystemEncoding());
495 executableURL
= CFURLCreateWithFileSystemPath(NULL
, str
, PLATFORM_PATH_STYLE
, false);
499 if (looksLikeBundle
) {
500 CFBundleRef mainBundle
= _mainBundle
;
501 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
502 *looksLikeBundle
= (mainBundle
? YES
: NO
);
504 return executableURL
;
507 static CFBundleRef
_CFBundleGetMainBundleAlreadyLocked(void) {
508 if (!_initedMainBundle
) {
509 const char *processPath
;
510 CFStringRef str
= NULL
;
511 CFURLRef executableURL
= NULL
, bundleURL
= NULL
;
512 #if defined(BINARY_SUPPORT_CFM)
513 Boolean versRegionOverrides
= false;
514 #endif /* BINARY_SUPPORT_CFM */
515 #if defined(__MACOS8__)
516 // do not use Posix-styled _CFProcessPath()
517 ProcessSerialNumber gProcessID
;
518 ProcessInfoRec processInfo
;
519 FSSpec processAppSpec
;
521 processInfo
.processInfoLength
= sizeof(ProcessInfoRec
);
522 processInfo
.processAppSpec
= &processAppSpec
;
524 if ((GetCurrentProcess(&gProcessID
) == noErr
) && (GetProcessInformation(&gProcessID
, &processInfo
) == noErr
)) {
525 executableURL
= _CFCreateURLFromFSSpec(NULL
, (void *)(&processAppSpec
), false);
528 _initedMainBundle
= true;
529 processPath
= _CFProcessPath();
531 str
= CFStringCreateWithCString(NULL
, processPath
, CFStringFileSystemEncoding());
532 if (!executableURL
) executableURL
= CFURLCreateWithFileSystemPath(NULL
, str
, PLATFORM_PATH_STYLE
, false);
535 bundleURL
= _CFBundleCopyBundleURLForExecutableURL(executableURL
);
537 if (bundleURL
!= NULL
) {
538 // make sure that main bundle has executable path
539 //??? what if we are not the main executable in the bundle?
540 // NB doFinalProcessing must be false here, see below
541 _mainBundle
= _CFBundleCreate(NULL
, bundleURL
, true, false);
542 if (_mainBundle
!= NULL
) {
543 CFBundleGetInfoDictionary(_mainBundle
);
544 // make sure that the main bundle is listed as loaded, and mark it as executable
545 _mainBundle
->_isLoaded
= true;
546 #if defined(BINARY_SUPPORT_DYLD)
547 if (_mainBundle
->_binaryType
== __CFBundleUnknownBinary
) {
548 if (!executableURL
) {
549 _mainBundle
->_binaryType
= __CFBundleNoBinary
;
551 _mainBundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
552 #if defined(BINARY_SUPPORT_CFM)
553 if (_mainBundle
->_binaryType
!= __CFBundleCFMBinary
&& _mainBundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
554 _mainBundle
->_resourceData
._executableLacksResourceFork
= true;
556 #endif /* BINARY_SUPPORT_CFM */
559 #endif /* BINARY_SUPPORT_DYLD */
560 if (_mainBundle
->_infoDict
== NULL
|| CFDictionaryGetCount(_mainBundle
->_infoDict
) == 0) {
561 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
562 if (_mainBundle
->_version
== 3) _mainBundle
->_version
= 4;
563 if (_mainBundle
->_version
== 0) {
564 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
565 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, _mainBundle
, NULL
, NULL
);
566 if (!executableName
|| !CFStringHasSuffix(str
, executableName
)) _mainBundle
->_version
= 4;
567 if (executableName
) CFRelease(executableName
);
569 #if defined(BINARY_SUPPORT_DYLD)
570 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
571 if (_mainBundle
->_infoDict
!= NULL
) CFRelease(_mainBundle
->_infoDict
);
572 _mainBundle
->_infoDict
= _CFBundleGrokInfoDictFromMainExecutable();
574 #endif /* BINARY_SUPPORT_DYLD */
575 #if defined(BINARY_SUPPORT_CFM)
576 if (_mainBundle
->_binaryType
== __CFBundleCFMBinary
|| _mainBundle
->_binaryType
== __CFBundleUnreadableBinary
) {
577 // if type 0 bundle and CFM binary and no Info.plist, treat as unbundled, since this also gives too many false positives
578 if (_mainBundle
->_version
== 0) _mainBundle
->_version
= 4;
579 if (_mainBundle
->_version
!= 4) {
580 // if CFM binary and no Info.plist and not main executable for bundle, treat as unbundled, since this also gives too many false positives
581 // except for Macromedia Director MX, which is unbundled but wants to be treated as bundled
582 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, _mainBundle
, NULL
, NULL
);
583 Boolean treatAsBundled
= false;
585 CFIndex strLength
= CFStringGetLength(str
);
586 if (strLength
> 10) treatAsBundled
= CFStringFindWithOptions(str
, CFSTR(" MX"), CFRangeMake(strLength
- 10, 10), 0, NULL
);
588 if (!treatAsBundled
&& (!executableName
|| !CFStringHasSuffix(str
, executableName
))) _mainBundle
->_version
= 4;
589 if (executableName
) CFRelease(executableName
);
591 if (_mainBundle
->_infoDict
!= NULL
) CFRelease(_mainBundle
->_infoDict
);
592 _mainBundle
->_infoDict
= _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFGetAllocator(_mainBundle
), executableURL
);
593 if (_mainBundle
->_binaryType
== __CFBundleUnreadableBinary
&& _mainBundle
->_infoDict
!= NULL
&& CFDictionaryGetValue(_mainBundle
->_infoDict
, kCFBundleDevelopmentRegionKey
) != NULL
) versRegionOverrides
= true;
595 #endif /* BINARY_SUPPORT_CFM */
597 if (_mainBundle
->_infoDict
== NULL
) {
598 _mainBundle
->_infoDict
= CFDictionaryCreateMutable(CFGetAllocator(_mainBundle
), 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
600 if (NULL
== CFDictionaryGetValue(_mainBundle
->_infoDict
, _kCFBundleExecutablePathKey
)) {
601 CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), _kCFBundleExecutablePathKey
, str
);
603 #if defined(BINARY_SUPPORT_DYLD)
604 // get cookie for already-loaded main bundle
605 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
&& !_mainBundle
->_imageCookie
) {
606 _mainBundle
->_imageCookie
= (void *)_dyld_get_image_header(0);
608 #endif /* BINARY_SUPPORT_DYLD */
609 #if defined(BINARY_SUPPORT_CFM)
610 if (versRegionOverrides
) {
611 // This is a hack to preserve backward compatibility for certain broken applications (2761067)
612 CFStringRef devLang
= _CFBundleCopyBundleDevelopmentRegionFromVersResource(_mainBundle
);
613 if (devLang
!= NULL
) {
614 CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), kCFBundleDevelopmentRegionKey
, devLang
);
618 #endif /* BINARY_SUPPORT_CFM */
619 // Perform delayed final processing steps.
620 // This must be done after _isLoaded has been set, for security reasons (3624341).
621 _CFBundleCheckWorkarounds(_mainBundle
);
622 if (_CFBundleNeedsInitPlugIn(_mainBundle
)) {
623 __CFSpinUnlock(&CFBundleGlobalDataLock
);
624 _CFBundleInitPlugIn(_mainBundle
);
625 __CFSpinLock(&CFBundleGlobalDataLock
);
629 if (bundleURL
) CFRelease(bundleURL
);
630 if (str
) CFRelease(str
);
631 if (executableURL
) CFRelease(executableURL
);
636 CFBundleRef
CFBundleGetMainBundle(void) {
637 CFBundleRef mainBundle
;
638 __CFSpinLock(&CFBundleGlobalDataLock
);
639 mainBundle
= _CFBundleGetMainBundleAlreadyLocked();
640 __CFSpinUnlock(&CFBundleGlobalDataLock
);
644 #if defined(BINARY_SUPPORT_DYLD)
646 static void *_CFBundleReturnAddressFromFrameAddress(void *addr
)
650 __asm__
volatile("lwz %0,0x0008(%1)" : "=r" (ret
) : "b" (addr
));
651 #elif defined(__i386__)
652 __asm__
volatile("movl 0x4(%1),%0" : "=r" (ret
) : "r" (addr
));
654 __asm__
volatile("ldw 0x4(%1),%0" : "=r" (ret
) : "r" (addr
));
656 __asm__
volatile("ta 0x3");
657 __asm__
volatile("ld [%1 + 60],%0" : "=r" (ret
) : "r" (addr
));
659 #warning Do not know how to define _CFBundleReturnAddressFromFrameAddress on this architecture
667 CFBundleRef
CFBundleGetBundleWithIdentifier(CFStringRef bundleID
) {
668 CFBundleRef result
= NULL
;
670 __CFSpinLock(&CFBundleGlobalDataLock
);
671 (void)_CFBundleGetMainBundleAlreadyLocked();
672 if (_bundlesByIdentifier
!= NULL
) {
673 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
675 #if defined(BINARY_SUPPORT_DYLD)
676 if (result
== NULL
) {
677 // Try to create the bundle for the caller and try again
678 void *p
= _CFBundleReturnAddressFromFrameAddress(__builtin_frame_address(1));
679 CFStringRef imagePath
= _CFBundleDYLDCopyLoadedImagePathForPointer(p
);
680 if (imagePath
!= NULL
) {
681 _CFBundleEnsureBundleExistsForImagePath(imagePath
);
682 CFRelease(imagePath
);
684 if (_bundlesByIdentifier
!= NULL
) {
685 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
689 if (result
== NULL
) {
690 // Try to guess the bundle from the identifier and try again
691 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID
);
692 if (_bundlesByIdentifier
!= NULL
) {
693 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
696 if (result
== NULL
) {
697 // Make sure all bundles have been created and try again.
698 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
699 if (_bundlesByIdentifier
!= NULL
) {
700 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
703 __CFSpinUnlock(&CFBundleGlobalDataLock
);
708 static CFStringRef
__CFBundleCopyDescription(CFTypeRef cf
) {
709 char buff
[CFMaxPathSize
];
710 CFStringRef path
= NULL
, binaryType
= NULL
, retval
= NULL
;
711 if (((CFBundleRef
)cf
)->_url
!= NULL
&& CFURLGetFileSystemRepresentation(((CFBundleRef
)cf
)->_url
, true, buff
, CFMaxPathSize
)) {
712 path
= CFStringCreateWithCString(NULL
, buff
, CFStringFileSystemEncoding());
714 switch (((CFBundleRef
)cf
)->_binaryType
) {
715 case __CFBundleCFMBinary
:
716 binaryType
= CFSTR("");
718 case __CFBundleDYLDExecutableBinary
:
719 binaryType
= CFSTR("executable, ");
721 case __CFBundleDYLDBundleBinary
:
722 binaryType
= CFSTR("bundle, ");
724 case __CFBundleDYLDFrameworkBinary
:
725 binaryType
= CFSTR("framework, ");
727 case __CFBundleDLLBinary
:
728 binaryType
= CFSTR("DLL, ");
730 case __CFBundleUnreadableBinary
:
731 binaryType
= CFSTR("");
734 binaryType
= CFSTR("");
737 if (((CFBundleRef
)cf
)->_plugInData
._isPlugIn
) {
738 retval
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFBundle/CFPlugIn 0x%x <%@> (%@%sloaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? "" : "not ");
740 retval
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFBundle 0x%x <%@> (%@%sloaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? "" : "not ");
742 if (path
) CFRelease(path
);
746 static void _CFBundleDeallocateGlue(const void *key
, const void *value
, void *context
) {
747 CFAllocatorRef allocator
= (CFAllocatorRef
)context
;
749 CFAllocatorDeallocate(allocator
, (void *)value
);
753 static void __CFBundleDeallocate(CFTypeRef cf
) {
754 CFBundleRef bundle
= (CFBundleRef
)cf
;
755 CFAllocatorRef allocator
;
757 __CFGenericValidateType(cf
, __kCFBundleTypeID
);
759 allocator
= CFGetAllocator(bundle
);
762 CFBundleUnloadExecutable(bundle
);
764 // Clean up plugIn stuff
765 _CFBundleDeallocatePlugIn(bundle
);
767 _CFBundleRemoveFromTables(bundle
);
769 if (bundle
->_url
!= NULL
) {
770 _CFBundleFlushCachesForURL(bundle
->_url
);
771 CFRelease(bundle
->_url
);
773 if (bundle
->_infoDict
!= NULL
) {
774 CFRelease(bundle
->_infoDict
);
776 if (bundle
->_modDate
!= NULL
) {
777 CFRelease(bundle
->_modDate
);
779 if (bundle
->_localInfoDict
!= NULL
) {
780 CFRelease(bundle
->_localInfoDict
);
782 if (bundle
->_searchLanguages
!= NULL
) {
783 CFRelease(bundle
->_searchLanguages
);
785 if (bundle
->_glueDict
!= NULL
) {
786 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)allocator
);
787 CFRelease(bundle
->_glueDict
);
789 if (bundle
->_resourceData
._stringTableCache
!= NULL
) {
790 CFRelease(bundle
->_resourceData
._stringTableCache
);
794 static const CFRuntimeClass __CFBundleClass
= {
799 __CFBundleDeallocate
,
803 __CFBundleCopyDescription
806 __private_extern__
void __CFBundleInitialize(void) {
807 __kCFBundleTypeID
= _CFRuntimeRegisterClass(&__CFBundleClass
);
810 CFTypeID
CFBundleGetTypeID(void) {
811 return __kCFBundleTypeID
;
814 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
) {
815 CFBundleRef bundle
= NULL
;
816 char buff
[CFMaxPathSize
];
817 CFDateRef modDate
= NULL
;
818 Boolean exists
= false;
820 CFURLRef newURL
= NULL
;
821 uint8_t localVersion
= 0;
823 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
825 newURL
= CFURLCreateFromFileSystemRepresentation(allocator
, buff
, strlen(buff
), true);
826 if (NULL
== newURL
) {
827 newURL
= CFRetain(bundleURL
);
829 bundle
= _CFBundleFindByURL(newURL
, alreadyLocked
);
836 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
838 if (_CFGetFileProperties(allocator
, newURL
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
839 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
840 if (NULL
!= modDate
) CFRelease(modDate
);
850 bundle
= (CFBundleRef
)_CFRuntimeCreateInstance(allocator
, __kCFBundleTypeID
, sizeof(struct __CFBundle
) - sizeof(CFRuntimeBase
), NULL
);
851 if (NULL
== bundle
) {
856 bundle
->_url
= newURL
;
858 bundle
->_modDate
= modDate
;
859 bundle
->_version
= localVersion
;
860 bundle
->_infoDict
= NULL
;
861 bundle
->_localInfoDict
= NULL
;
862 bundle
->_searchLanguages
= NULL
;
864 #if defined(BINARY_SUPPORT_DYLD)
865 /* We'll have to figure it out later */
866 bundle
->_binaryType
= __CFBundleUnknownBinary
;
867 #elif defined(BINARY_SUPPORT_CFM)
868 /* We support CFM only */
869 bundle
->_binaryType
= __CFBundleCFMBinary
;
870 #elif defined(BINARY_SUPPORT_DLL)
871 /* We support DLL only */
872 bundle
->_binaryType
= __CFBundleDLLBinary
;
873 bundle
->_hModule
= NULL
;
875 /* We'll have to figure it out later */
876 bundle
->_binaryType
= __CFBundleUnknownBinary
;
879 bundle
->_isLoaded
= false;
880 bundle
->_sharesStringsFiles
= false;
882 /* ??? For testing purposes? Or for good? */
883 #warning Ali or Doug: Decide how to finalize strings sharing
884 if (!getenv("CFBundleDisableStringsSharing") &&
885 (strncmp(buff
, "/System/Library/Frameworks", 26) == 0) &&
886 (strncmp(buff
+ strlen(buff
) - 10, ".framework", 10) == 0)) bundle
->_sharesStringsFiles
= true;
888 bundle
->_connectionCookie
= NULL
;
889 bundle
->_imageCookie
= NULL
;
890 bundle
->_moduleCookie
= NULL
;
892 bundle
->_glueDict
= NULL
;
894 #if defined(BINARY_SUPPORT_CFM)
895 bundle
->_resourceData
._executableLacksResourceFork
= false;
897 bundle
->_resourceData
._executableLacksResourceFork
= true;
900 bundle
->_resourceData
._stringTableCache
= NULL
;
902 bundle
->_plugInData
._isPlugIn
= false;
903 bundle
->_plugInData
._loadOnDemand
= false;
904 bundle
->_plugInData
._isDoingDynamicRegistration
= false;
905 bundle
->_plugInData
._instanceCount
= 0;
906 bundle
->_plugInData
._factories
= NULL
;
908 CFBundleGetInfoDictionary(bundle
);
910 _CFBundleAddToTables(bundle
, alreadyLocked
);
912 if (doFinalProcessing
) {
913 _CFBundleCheckWorkarounds(bundle
);
914 if (_CFBundleNeedsInitPlugIn(bundle
)) {
915 if (alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
916 _CFBundleInitPlugIn(bundle
);
917 if (alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
924 CFBundleRef
CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
) {return _CFBundleCreate(allocator
, bundleURL
, false, true);}
926 CFArrayRef
CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc
, CFURLRef directoryURL
, CFStringRef bundleType
) {
927 CFMutableArrayRef bundles
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
928 CFArrayRef URLs
= _CFContentsOfDirectory(alloc
, NULL
, NULL
, directoryURL
, bundleType
);
930 CFIndex i
, c
= CFArrayGetCount(URLs
);
932 CFBundleRef curBundle
;
934 for (i
=0; i
<c
; i
++) {
935 curURL
= CFArrayGetValueAtIndex(URLs
, i
);
936 curBundle
= CFBundleCreate(alloc
, curURL
);
937 if (curBundle
!= NULL
) {
938 CFArrayAppendValue(bundles
, curBundle
);
947 CFURLRef
CFBundleCopyBundleURL(CFBundleRef bundle
) {
949 CFRetain(bundle
->_url
);
954 void _CFBundleSetDefaultLocalization(CFStringRef localizationName
) {
955 CFStringRef newLocalization
= localizationName
? CFStringCreateCopy(NULL
, localizationName
) : NULL
;
956 if (_defaultLocalization
) CFRelease(_defaultLocalization
);
957 _defaultLocalization
= newLocalization
;
960 CFArrayRef
_CFBundleGetLanguageSearchList(CFBundleRef bundle
) {
961 if (bundle
->_searchLanguages
== NULL
) {
962 CFMutableArrayRef langs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
963 CFStringRef devLang
= CFBundleGetDevelopmentRegion(bundle
);
965 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, devLang
);
967 if (CFArrayGetCount(langs
) == 0) {
968 // If the user does not prefer any of our languages, and devLang is not present, try English
969 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFSTR("en_US"));
971 if (CFArrayGetCount(langs
) == 0) {
972 // if none of the preferred localizations are present, fall back on a random localization that is present
973 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
975 if (CFArrayGetCount(localizations
) > 0) {
976 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFArrayGetValueAtIndex(localizations
, 0));
978 CFRelease(localizations
);
982 if (devLang
!= NULL
&& !CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
)) {
983 // Make sure that devLang is on the list as a fallback for individual resources that are not present
984 CFArrayAppendValue(langs
, devLang
);
985 } else if (devLang
== NULL
) {
986 // Or if there is no devLang, try some variation of English that is present
987 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
989 CFStringRef en_US
= CFSTR("en_US"), en
= CFSTR("en"), English
= CFSTR("English");
990 CFRange range
= CFRangeMake(0, CFArrayGetCount(localizations
));
991 if (CFArrayContainsValue(localizations
, range
, en
)) {
992 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en
)) CFArrayAppendValue(langs
, en
);
993 } else if (CFArrayContainsValue(localizations
, range
, English
)) {
994 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), English
)) CFArrayAppendValue(langs
, English
);
995 } else if (CFArrayContainsValue(localizations
, range
, en_US
)) {
996 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en_US
)) CFArrayAppendValue(langs
, en_US
);
998 CFRelease(localizations
);
1001 if (CFArrayGetCount(langs
) == 0) {
1002 // Total backstop behavior to avoid having an empty array.
1003 if (_defaultLocalization
!= NULL
) {
1004 CFArrayAppendValue(langs
, _defaultLocalization
);
1006 CFArrayAppendValue(langs
, CFSTR("en"));
1009 bundle
->_searchLanguages
= langs
;
1011 return bundle
->_searchLanguages
;
1014 CFDictionaryRef
CFBundleCopyInfoDictionaryInDirectory(CFURLRef url
) {return _CFBundleCopyInfoDictionaryInDirectory(NULL
, url
, NULL
);}
1016 CFDictionaryRef
CFBundleGetInfoDictionary(CFBundleRef bundle
) {
1017 if (bundle
->_infoDict
== NULL
) {
1018 bundle
->_infoDict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);
1020 return bundle
->_infoDict
;
1023 CFDictionaryRef
_CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {return CFBundleGetLocalInfoDictionary(bundle
);}
1025 CFDictionaryRef
CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
1026 if (bundle
->_localInfoDict
== NULL
) {
1027 CFURLRef url
= CFBundleCopyResourceURL(bundle
, _CFBundleLocalInfoName
, _CFBundleStringTableType
, NULL
);
1031 CFStringRef errStr
= NULL
;
1033 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle
), url
, &data
, NULL
, NULL
, &errCode
)) {
1034 bundle
->_localInfoDict
= CFPropertyListCreateFromXMLData(CFGetAllocator(bundle
), data
, kCFPropertyListImmutable
, &errStr
);
1038 if (bundle
->_localInfoDict
&& CFDictionaryGetTypeID() != CFGetTypeID(bundle
->_localInfoDict
)) {
1039 CFRelease(bundle
->_localInfoDict
);
1040 bundle
->_localInfoDict
= NULL
;
1047 return bundle
->_localInfoDict
;
1050 CFPropertyListRef
_CFBundleGetValueForInfoKey(CFBundleRef bundle
, CFStringRef key
) {return (CFPropertyListRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, key
);}
1052 CFTypeRef
CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle
, CFStringRef key
) {
1053 // Look in InfoPlist.strings first. Then look in Info.plist
1054 CFTypeRef result
= NULL
;
1055 if ((bundle
!= NULL
) && (key
!= NULL
)) {
1056 CFDictionaryRef dict
= CFBundleGetLocalInfoDictionary(bundle
);
1058 result
= CFDictionaryGetValue(dict
, key
);
1060 if (result
== NULL
) {
1061 dict
= CFBundleGetInfoDictionary(bundle
);
1063 result
= CFDictionaryGetValue(dict
, key
);
1070 CFStringRef
CFBundleGetIdentifier(CFBundleRef bundle
) {
1071 CFStringRef bundleID
= NULL
;
1072 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1074 bundleID
= CFDictionaryGetValue(infoDict
, kCFBundleIdentifierKey
);
1079 #define DEVELOPMENT_STAGE 0x20
1080 #define ALPHA_STAGE 0x40
1081 #define BETA_STAGE 0x60
1082 #define RELEASE_STAGE 0x80
1084 #define MAX_VERS_LEN 10
1086 CF_INLINE Boolean
_isDigit(UniChar aChar
) {return (((aChar
>= (UniChar
)'0') && (aChar
<= (UniChar
)'9')) ? true : false);}
1088 __private_extern__ CFStringRef
_CFCreateStringFromVersionNumber(CFAllocatorRef alloc
, UInt32 vers
) {
1089 CFStringRef result
= NULL
;
1090 uint8_t major1
, major2
, minor1
, minor2
, stage
, build
;
1092 major1
= (vers
& 0xF0000000) >> 28;
1093 major2
= (vers
& 0x0F000000) >> 24;
1094 minor1
= (vers
& 0x00F00000) >> 20;
1095 minor2
= (vers
& 0x000F0000) >> 16;
1096 stage
= (vers
& 0x0000FF00) >> 8;
1097 build
= (vers
& 0x000000FF);
1099 if (stage
== RELEASE_STAGE
) {
1101 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d"), major1
, major2
, minor1
, minor2
);
1103 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d"), major2
, minor1
, minor2
);
1107 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
);
1109 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d%s%d"), major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? "d" : ((stage
== ALPHA_STAGE
) ? "a" : "b")), build
);
1115 __private_extern__ UInt32
_CFVersionNumberFromString(CFStringRef versStr
) {
1116 // Parse version number from string.
1117 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1118 UInt32 major1
= 0, major2
= 0, minor1
= 0, minor2
= 0, stage
= RELEASE_STAGE
, build
= 0;
1119 UniChar versChars
[MAX_VERS_LEN
];
1120 UniChar
*chars
= NULL
;
1123 Boolean digitsDone
= false;
1125 if (!versStr
) return 0;
1127 len
= CFStringGetLength(versStr
);
1129 if ((len
== 0) || (len
> MAX_VERS_LEN
)) return 0;
1131 CFStringGetCharacters(versStr
, CFRangeMake(0, len
), versChars
);
1134 // Get major version number.
1135 major1
= major2
= 0;
1136 if (_isDigit(*chars
)) {
1137 major2
= *chars
- (UniChar
)'0';
1141 if (_isDigit(*chars
)) {
1143 major2
= *chars
- (UniChar
)'0';
1147 if (*chars
== (UniChar
)'.') {
1154 } else if (*chars
== (UniChar
)'.') {
1161 } else if (*chars
== (UniChar
)'.') {
1168 // Now major1 and major2 contain first and second digit of the major version number as ints.
1169 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1171 // Get the first minor version number.
1172 if (len
> 0 && !digitsDone
) {
1173 if (_isDigit(*chars
)) {
1174 minor1
= *chars
- (UniChar
)'0';
1178 if (*chars
== (UniChar
)'.') {
1190 // Now minor1 contains the first minor version number as an int.
1191 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1193 // Get the second minor version number.
1194 if (len
> 0 && !digitsDone
) {
1195 if (_isDigit(*chars
)) {
1196 minor2
= *chars
- (UniChar
)'0';
1204 // Now minor2 contains the second minor version number as an int.
1205 // Now either len is 0 or chars points at the build stage letter.
1207 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1209 if (*chars
== (UniChar
)'d') {
1210 stage
= DEVELOPMENT_STAGE
;
1211 } else if (*chars
== (UniChar
)'a') {
1212 stage
= ALPHA_STAGE
;
1213 } else if (*chars
== (UniChar
)'b') {
1215 } else if (*chars
== (UniChar
)'f') {
1216 stage
= RELEASE_STAGE
;
1224 // Now stage contains the release stage.
1225 // Now either len is 0 or chars points at the build number.
1227 // Get the first digit of the build number.
1229 if (_isDigit(*chars
)) {
1230 build
= *chars
- (UniChar
)'0';
1237 // Get the second digit of the build number.
1239 if (_isDigit(*chars
)) {
1241 build
+= *chars
- (UniChar
)'0';
1248 // Get the third digit of the build number.
1250 if (_isDigit(*chars
)) {
1252 build
+= *chars
- (UniChar
)'0';
1260 // Range check the build number and make sure we exhausted the string.
1261 if ((build
> 0xFF) || (len
> 0)) return 0;
1264 theVers
= major1
<< 28;
1265 theVers
+= major2
<< 24;
1266 theVers
+= minor1
<< 20;
1267 theVers
+= minor2
<< 16;
1268 theVers
+= stage
<< 8;
1274 UInt32
CFBundleGetVersionNumber(CFBundleRef bundle
) {
1275 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1276 CFTypeRef unknownVersionValue
= CFDictionaryGetValue(infoDict
, _kCFBundleNumericVersionKey
);
1277 CFNumberRef versNum
;
1280 if (unknownVersionValue
== NULL
) {
1281 unknownVersionValue
= CFDictionaryGetValue(infoDict
, kCFBundleVersionKey
);
1283 if (unknownVersionValue
!= NULL
) {
1284 if (CFGetTypeID(unknownVersionValue
) == CFStringGetTypeID()) {
1285 // Convert a string version number into a numeric one.
1286 vers
= _CFVersionNumberFromString((CFStringRef
)unknownVersionValue
);
1288 versNum
= CFNumberCreate(CFGetAllocator(bundle
), kCFNumberSInt32Type
, &vers
);
1289 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
, versNum
);
1291 } else if (CFGetTypeID(unknownVersionValue
) == CFNumberGetTypeID()) {
1292 CFNumberGetValue((CFNumberRef
)unknownVersionValue
, kCFNumberSInt32Type
, &vers
);
1294 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
);
1300 CFStringRef
CFBundleGetDevelopmentRegion(CFBundleRef bundle
) {
1301 CFStringRef devLang
= NULL
;
1302 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1304 devLang
= CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1305 if (devLang
!= NULL
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) {
1307 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleDevelopmentRegionKey
);
1314 Boolean
_CFBundleGetHasChanged(CFBundleRef bundle
) {
1316 Boolean result
= false;
1317 Boolean exists
= false;
1320 if (_CFGetFileProperties(CFGetAllocator(bundle
), bundle
->_url
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
1321 // If the bundle no longer exists or is not a folder, it must have "changed"
1322 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
1326 // Something is wrong. The stat failed.
1329 if (bundle
->_modDate
&& !CFEqual(bundle
->_modDate
, modDate
)) {
1330 // mod date is different from when we created.
1337 void _CFBundleSetStringsFilesShared(CFBundleRef bundle
, Boolean flag
) {
1338 bundle
->_sharesStringsFiles
= flag
;
1341 Boolean
_CFBundleGetStringsFilesShared(CFBundleRef bundle
) {
1342 return bundle
->_sharesStringsFiles
;
1345 static Boolean
_urlExists(CFAllocatorRef alloc
, CFURLRef url
) {
1347 return url
&& (0 == _CFGetFileProperties(alloc
, url
, &exists
, NULL
, NULL
, NULL
, NULL
, NULL
)) && exists
;
1350 __private_extern__ CFURLRef
_CFBundleCopySupportFilesDirectoryURLInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
) {
1351 CFURLRef result
= NULL
;
1354 result
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase1
, bundleURL
);
1355 } else if (2 == version
) {
1356 result
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase2
, bundleURL
);
1358 result
= CFRetain(bundleURL
);
1364 CF_EXPORT CFURLRef
CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle
) {return _CFBundleCopySupportFilesDirectoryURLInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);}
1366 __private_extern__ CFURLRef
_CFBundleCopyResourcesDirectoryURLInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
) {
1367 CFURLRef result
= NULL
;
1370 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase0
, bundleURL
);
1371 } else if (1 == version
) {
1372 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase1
, bundleURL
);
1373 } else if (2 == version
) {
1374 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase2
, bundleURL
);
1376 result
= CFRetain(bundleURL
);
1382 CFURLRef
CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle
) {return _CFBundleCopyResourcesDirectoryURLInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);}
1384 static CFURLRef
_CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc
, CFURLRef urlPath
, CFStringRef exeName
) {
1385 // 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.
1386 CFURLRef executableURL
= NULL
;
1387 #if defined(__MACH__)
1388 const uint8_t *image_suffix
= getenv("DYLD_IMAGE_SUFFIX");
1389 #endif /* __MACH__ */
1391 if (urlPath
== NULL
|| exeName
== NULL
) return NULL
;
1393 #if defined(__MACH__)
1394 if (image_suffix
!= NULL
) {
1395 CFStringRef newExeName
, imageSuffix
;
1396 imageSuffix
= CFStringCreateWithCString(NULL
, image_suffix
, kCFStringEncodingUTF8
);
1397 if (CFStringHasSuffix(exeName
, CFSTR(".dylib"))) {
1398 CFStringRef bareExeName
= CFStringCreateWithSubstring(alloc
, exeName
, CFRangeMake(0, CFStringGetLength(exeName
)-6));
1399 newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@.dylib"), exeName
, imageSuffix
);
1400 CFRelease(bareExeName
);
1402 newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, imageSuffix
);
1404 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, newExeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1405 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1406 CFRelease(executableURL
);
1407 executableURL
= NULL
;
1409 CFRelease(newExeName
);
1410 CFRelease(imageSuffix
);
1412 #endif /* __MACH__ */
1413 if (executableURL
== NULL
) {
1414 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, exeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1415 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1416 CFRelease(executableURL
);
1417 executableURL
= NULL
;
1420 #if defined(__WIN32__)
1421 if (executableURL
== NULL
) {
1422 if (!CFStringHasSuffix(exeName
, CFSTR(".dll"))) {
1423 CFStringRef newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, CFSTR(".dll"));
1424 executableURL
= CFURLCreateWithString(alloc
, newExeName
, urlPath
);
1425 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1426 CFRelease(executableURL
);
1427 executableURL
= NULL
;
1429 CFRelease(newExeName
);
1432 if (executableURL
== NULL
) {
1433 if (!CFStringHasSuffix(exeName
, CFSTR(".exe"))) {
1434 CFStringRef newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, CFSTR(".exe"));
1435 executableURL
= CFURLCreateWithString(alloc
, newExeName
, urlPath
);
1436 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1437 CFRelease(executableURL
);
1438 executableURL
= NULL
;
1440 CFRelease(newExeName
);
1444 return executableURL
;
1447 static CFStringRef
_CFBundleCopyExecutableName(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
) {
1448 CFStringRef executableName
= NULL
;
1450 if (alloc
== NULL
&& bundle
!= NULL
) {
1451 alloc
= CFGetAllocator(bundle
);
1453 if (infoDict
== NULL
&& bundle
!= NULL
) {
1454 infoDict
= CFBundleGetInfoDictionary(bundle
);
1456 if (url
== NULL
&& bundle
!= NULL
) {
1460 if (infoDict
!= NULL
) {
1461 // Figure out the name of the executable.
1462 // First try for the new key in the plist.
1463 executableName
= CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
);
1464 if (executableName
== NULL
) {
1465 // Second try for the old key in the plist.
1466 executableName
= CFDictionaryGetValue(infoDict
, _kCFBundleOldExecutableKey
);
1468 if (executableName
!= NULL
&& CFGetTypeID(executableName
) == CFStringGetTypeID() && CFStringGetLength(executableName
) > 0) {
1469 CFRetain(executableName
);
1471 executableName
= NULL
;
1474 if (executableName
== NULL
&& url
!= NULL
) {
1475 // Third, take the name of the bundle itself (with path extension stripped)
1476 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1477 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1478 UniChar buff
[CFMaxPathSize
];
1479 CFIndex len
= CFStringGetLength(bundlePath
);
1480 CFIndex startOfBundleName
, endOfBundleName
;
1482 CFRelease(absoluteURL
);
1483 if (len
> CFMaxPathSize
) len
= CFMaxPathSize
;
1484 CFStringGetCharacters(bundlePath
, CFRangeMake(0, len
), buff
);
1485 startOfBundleName
= _CFStartOfLastPathComponent(buff
, len
);
1486 endOfBundleName
= _CFLengthAfterDeletingPathExtension(buff
, len
);
1488 if ((startOfBundleName
<= len
) && (endOfBundleName
<= len
) && (startOfBundleName
< endOfBundleName
)) {
1489 executableName
= CFStringCreateWithCharacters(alloc
, &(buff
[startOfBundleName
]), (endOfBundleName
- startOfBundleName
));
1491 CFRelease(bundlePath
);
1494 return executableName
;
1497 __private_extern__ CFURLRef
_CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle
, Boolean mayBeLocal
) {
1498 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, bundle
, NULL
, NULL
);
1499 CFURLRef resourceForkURL
= NULL
;
1500 if (executableName
!= NULL
) {
1502 resourceForkURL
= CFBundleCopyResourceURL(bundle
, executableName
, CFSTR("rsrc"), NULL
);
1504 resourceForkURL
= CFBundleCopyResourceURLForLocalization(bundle
, executableName
, CFSTR("rsrc"), NULL
, NULL
);
1506 CFRelease(executableName
);
1509 return resourceForkURL
;
1512 CFURLRef
_CFBundleCopyResourceForkURL(CFBundleRef bundle
) {return _CFBundleCopyResourceForkURLMayBeLocal(bundle
, true);}
1514 static CFURLRef
_CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFStringRef executableName
, Boolean ignoreCache
, Boolean useOtherPlatform
) {
1515 uint8_t version
= 0;
1516 CFDictionaryRef infoDict
= NULL
;
1517 CFStringRef executablePath
= NULL
;
1518 CFURLRef executableURL
= NULL
;
1519 Boolean foundIt
= false;
1520 Boolean lookupMainExe
= ((executableName
== NULL
) ? true : false);
1522 if (bundle
!= NULL
) {
1523 infoDict
= CFBundleGetInfoDictionary(bundle
);
1524 version
= bundle
->_version
;
1526 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, &version
);
1529 // If we have a bundle instance and an info dict, see if we have already cached the path
1530 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& (bundle
!= NULL
) && (infoDict
!= NULL
)) {
1531 executablePath
= CFDictionaryGetValue(infoDict
, _kCFBundleExecutablePathKey
);
1532 if (executablePath
!= NULL
) {
1533 executableURL
= CFURLCreateWithFileSystemPath(alloc
, executablePath
, kCFURLPOSIXPathStyle
, false);
1534 if (executableURL
!= NULL
) foundIt
= true;
1536 executablePath
= NULL
;
1537 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
);
1543 if (lookupMainExe
) {
1544 executableName
= _CFBundleCopyExecutableName(alloc
, bundle
, url
, infoDict
);
1546 if (executableName
!= NULL
) {
1547 // Now, look for the executable inside the bundle.
1550 CFURLRef exeSubdirURL
;
1553 exeDirURL
= CFURLCreateWithString(alloc
, _CFBundleExecutablesURLFromBase1
, url
);
1554 } else if (2 == version
) {
1555 exeDirURL
= CFURLCreateWithString(alloc
, _CFBundleExecutablesURLFromBase2
, url
);
1557 exeDirURL
= CFRetain(url
);
1559 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1560 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1561 if (executableURL
== NULL
) {
1562 CFRelease(exeSubdirURL
);
1563 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1564 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1566 if (executableURL
== NULL
) {
1567 CFRelease(exeSubdirURL
);
1568 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1569 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1571 if (executableURL
== NULL
) {
1572 CFRelease(exeSubdirURL
);
1573 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1574 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1576 if (executableURL
== NULL
) {
1577 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeDirURL
, executableName
);
1580 CFRelease(exeDirURL
);
1581 CFRelease(exeSubdirURL
);
1584 // If this was an old bundle, or we did not find the executable in the Excutables subdirectory, look directly in the bundle wrapper.
1585 if (executableURL
== NULL
) {
1586 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, url
, executableName
);
1589 #if defined(__WIN32__)
1590 // Windows only: If we still haven't found the exe, look in the Executables folder.
1591 // But only for the main bundle exe
1592 if (lookupMainExe
&& (executableURL
== NULL
)) {
1595 exeDirURL
= CFURLCreateWithString(alloc
, CFSTR("../../Executables"), url
);
1597 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeDirURL
, executableName
);
1599 CFRelease(exeDirURL
);
1603 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& (bundle
!= NULL
) && (infoDict
!= NULL
) && (executableURL
!= NULL
)) {
1604 // We found it. Cache the path.
1605 CFURLRef absURL
= CFURLCopyAbsoluteURL(executableURL
);
1606 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLPOSIXPathStyle
);
1608 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
, executablePath
);
1609 CFRelease(executablePath
);
1611 if (lookupMainExe
&& !useOtherPlatform
&& (bundle
!= NULL
) && (executableURL
== NULL
)) {
1612 bundle
->_binaryType
= __CFBundleNoBinary
;
1614 if (lookupMainExe
) {
1615 CFRelease(executableName
);
1620 if ((bundle
== NULL
) && (infoDict
!= NULL
)) {
1621 CFRelease(infoDict
);
1624 return executableURL
;
1627 CFURLRef
_CFBundleCopyExecutableURLInDirectory(CFURLRef url
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL
, NULL
, url
, NULL
, true, false);}
1629 CFURLRef
_CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL
, NULL
, url
, NULL
, true, true);}
1631 CFURLRef
CFBundleCopyExecutableURL(CFBundleRef bundle
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, NULL
, false, false);}
1633 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, NULL
, true, false);}
1635 CFURLRef
CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle
, CFStringRef executableName
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, executableName
, true, false);}
1637 Boolean
CFBundleIsExecutableLoaded(CFBundleRef bundle
) {return bundle
->_isLoaded
;}
1639 CFBundleExecutableType
CFBundleGetExecutableType(CFBundleRef bundle
) {
1640 CFBundleExecutableType result
= kCFBundleOtherExecutableType
;
1641 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
1643 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
1644 #if defined(BINARY_SUPPORT_DYLD)
1645 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
1646 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
1647 #if defined(BINARY_SUPPORT_CFM)
1648 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
1649 bundle
->_resourceData
._executableLacksResourceFork
= true;
1651 #endif /* BINARY_SUPPORT_CFM */
1653 #endif /* BINARY_SUPPORT_DYLD */
1654 if (executableURL
) CFRelease(executableURL
);
1656 if (bundle
->_binaryType
== __CFBundleCFMBinary
) {
1657 result
= kCFBundlePEFExecutableType
;
1658 } else if (bundle
->_binaryType
== __CFBundleDYLDExecutableBinary
|| bundle
->_binaryType
== __CFBundleDYLDBundleBinary
|| bundle
->_binaryType
== __CFBundleDYLDFrameworkBinary
) {
1659 result
= kCFBundleMachOExecutableType
;
1660 } else if (bundle
->_binaryType
== __CFBundleDLLBinary
) {
1661 result
= kCFBundleDLLExecutableType
;
1662 } else if (bundle
->_binaryType
== __CFBundleELFBinary
) {
1663 result
= kCFBundleELFExecutableType
;
1668 #define UNKNOWN_FILETYPE 0x0
1669 #define PEF_FILETYPE 0x1000
1670 #define XLS_FILETYPE 0x10001
1671 #define DOC_FILETYPE 0x10002
1672 #define PPT_FILETYPE 0x10003
1673 #define XLS_NAME "Workbook"
1674 #define XLS_NAME2 "Book"
1675 #define DOC_NAME "WordDocument"
1676 #define PPT_NAME "PowerPoint Document"
1677 #define PEF_MAGIC 0x4a6f7921
1678 #define PEF_CIGAM 0x21796f4a
1679 #define PLIST_SEGMENT "__TEXT"
1680 #define PLIST_SECTION "__info_plist"
1681 #define LIB_X11 "/usr/X11R6/lib/libX"
1683 static const uint32_t __CFBundleMagicNumbersArray
[] = {
1684 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0x4a6f7921, 0x21796f4a, 0x7f454c46, 0xffd8ffe0,
1685 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, 0x7b5c7274, 0x25504446,
1686 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, 0x38425053, 0x000001b3,
1687 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435, 0x53495444, 0x53747566,
1688 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x6b6f6c79, 0x3026b275, 0x0000000c,
1689 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143, 0x00010000, 0x74727565, 0x4f54544f,
1690 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70, 0x3c435058, 0x28445746, 0x424f4d53
1693 // string, with groups of 5 characters being 1 element in the array
1694 static const char * __CFBundleExtensionsArray
=
1695 "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" "elf\0\0" "jpeg\0"
1696 "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" "rtf\0\0" "pdf\0\0"
1697 "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"
1698 "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0"
1699 "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""dmg\0\0" "wmv\0\0" "jp2\0\0"
1700 "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0" "ttf\0\0" "ttf\0\0" "otf\0\0"
1701 "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0" "cpx\0\0" "dwf\0\0" "bom\0\0";
1703 #define NUM_EXTENSIONS 56
1704 #define EXTENSION_LENGTH 5
1705 #define MAGIC_BYTES_TO_READ 512
1707 #if defined(BINARY_SUPPORT_DYLD)
1709 CF_INLINE
uint32_t _CFBundleSwapInt32Conditional(uint32_t arg
, Boolean swap
) {return swap
? CFSwapInt32(arg
) : arg
;}
1710 CF_INLINE
uint32_t _CFBundleSwapInt64Conditional(uint64_t arg
, Boolean swap
) {return swap
? CFSwapInt64(arg
) : arg
;}
1712 static CFDictionaryRef
_CFBundleGrokInfoDictFromData(const char *bytes
, uint32_t length
) {
1713 CFMutableDictionaryRef result
= NULL
;
1714 CFDataRef infoData
= NULL
;
1715 if (NULL
!= bytes
&& 0 < length
) {
1716 infoData
= CFDataCreateWithBytesNoCopy(NULL
, bytes
, length
, kCFAllocatorNull
);
1719 __CFSetNastyFile(CFSTR("<plist section in main executable>"));
1721 result
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(NULL
, infoData
, kCFPropertyListMutableContainers
, NULL
);
1722 if (result
&& CFDictionaryGetTypeID() != CFGetTypeID(result
)) {
1726 CFRelease(infoData
);
1729 result
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1735 static CFDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable() {
1736 unsigned long length
= 0;
1737 char *bytes
= getsectdata(PLIST_SEGMENT
, PLIST_SECTION
, &length
);
1738 return _CFBundleGrokInfoDictFromData(bytes
, length
);
1741 static CFDictionaryRef
_CFBundleGrokInfoDictFromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
1742 struct stat statBuf
;
1743 off_t fileLength
= 0;
1744 char *maploc
= NULL
;
1747 CFDictionaryRef result
= NULL
;
1748 Boolean foundit
= false;
1749 if (fd
>= 0 && fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
1751 fileLength
= statBuf
.st_size
;
1754 fileLength
= length
;
1756 if (fileLength
> offset
+ sizeof(struct mach_header_64
)) {
1758 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->ncmds
, swapped
);
1759 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->sizeofcmds
, swapped
);
1760 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header_64
);
1761 const char *endofcmds
= startofcmds
+ sizeofcmds
;
1762 struct segment_command_64
*sgp
= (struct segment_command_64
*)startofcmds
;
1763 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
1764 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
1765 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
1766 struct section_64
*sp
= (struct section_64
*)((char *)sgp
+ sizeof(struct segment_command_64
));
1767 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
1768 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
1769 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, PLIST_SEGMENT
, sizeof(sp
->segname
))) {
1770 uint64_t sectlength64
= _CFBundleSwapInt64Conditional(sp
->size
, swapped
);
1771 uint32_t sectlength
= (uint32_t)(sectlength64
& 0xffffffff);
1772 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
1773 const char *sectbytes
= loc
+ offset
+ sectoffset
;
1774 // we don't support huge-sized plists
1775 if (sectlength64
<= 0xffffffff && loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= _CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
1778 sp
= (struct section_64
*)((char *)sp
+ sizeof(struct section_64
));
1781 sgp
= (struct segment_command_64
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
1784 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->ncmds
, swapped
);
1785 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->sizeofcmds
, swapped
);
1786 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header
);
1787 const char *endofcmds
= startofcmds
+ sizeofcmds
;
1788 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
1789 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
1790 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
1791 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
1792 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
1793 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
1794 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
1795 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, PLIST_SEGMENT
, sizeof(sp
->segname
))) {
1796 uint32_t sectlength
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
1797 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
1798 const char *sectbytes
= loc
+ offset
+ sectoffset
;
1799 if (loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= _CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
1802 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
1805 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
1809 if (maploc
) munmap(maploc
, statBuf
.st_size
);
1813 static Boolean
_CFBundleGrokX11(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
1814 static const char libX11name
[] = LIB_X11
;
1815 struct stat statBuf
;
1816 off_t fileLength
= 0;
1817 char *maploc
= NULL
;
1820 Boolean result
= false;
1821 if (fd
>= 0 && fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
1823 fileLength
= statBuf
.st_size
;
1826 fileLength
= length
;
1828 if (fileLength
> offset
+ sizeof(struct mach_header_64
)) {
1830 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->ncmds
, swapped
);
1831 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->sizeofcmds
, swapped
);
1832 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header_64
);
1833 const char *endofcmds
= startofcmds
+ sizeofcmds
;
1834 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
1835 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
1836 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
1837 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
1838 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
1839 if (0 == strncmp((char *)dlp
+ nameoffset
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
1841 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
1844 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->ncmds
, swapped
);
1845 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->sizeofcmds
, swapped
);
1846 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header
);
1847 const char *endofcmds
= startofcmds
+ sizeofcmds
;
1848 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
1849 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
1850 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
1851 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
1852 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
1853 if (0 == strncmp((char *)dlp
+ nameoffset
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
1855 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
1859 if (maploc
) munmap(maploc
, statBuf
.st_size
);
1863 static UInt32
_CFBundleGrokMachTypeForFatFile(int fd
, const void *bytes
, CFIndex length
, Boolean
*isX11
, CFDictionaryRef
*infodict
) {
1864 UInt32 machtype
= UNKNOWN_FILETYPE
, magic
, numFatHeaders
= ((struct fat_header
*)bytes
)->nfat_arch
, maxFatHeaders
= (length
- sizeof(struct fat_header
)) / sizeof(struct fat_arch
);
1865 unsigned char buffer
[sizeof(struct mach_header_64
)];
1866 const unsigned char *moreBytes
= NULL
;
1867 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
1868 struct fat_arch
*fat
= NULL
;
1870 if (isX11
) *isX11
= false;
1871 if (infodict
) *infodict
= NULL
;
1872 if (numFatHeaders
> maxFatHeaders
) numFatHeaders
= maxFatHeaders
;
1873 if (numFatHeaders
> 0) {
1874 fat
= NXFindBestFatArch(archInfo
->cputype
, archInfo
->cpusubtype
, (struct fat_arch
*)(bytes
+ sizeof(struct fat_header
)), numFatHeaders
);
1875 if (!fat
) fat
= (struct fat_arch
*)(bytes
+ sizeof(struct fat_header
));
1878 if (fd
>= 0 && lseek(fd
, fat
->offset
, SEEK_SET
) == (off_t
)fat
->offset
&& read(fd
, buffer
, sizeof(buffer
)) >= (int)sizeof(buffer
)) {
1880 } else if (bytes
&& (uint32_t)length
>= fat
->offset
+ 512) {
1881 moreBytes
= bytes
+ fat
->offset
;
1884 magic
= *((UInt32
*)moreBytes
);
1885 if (MH_MAGIC
== magic
) {
1886 machtype
= ((struct mach_header
*)moreBytes
)->filetype
;
1887 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, false);
1888 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, fat
->offset
, false, false);
1889 } else if (MH_CIGAM
== magic
) {
1890 machtype
= CFSwapInt32(((struct mach_header
*)moreBytes
)->filetype
);
1891 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, false);
1892 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, fat
->offset
, true, false);
1893 } else if (MH_MAGIC_64
== magic
) {
1894 machtype
= ((struct mach_header_64
*)moreBytes
)->filetype
;
1895 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, true);
1896 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, fat
->offset
, false, true);
1897 } else if (MH_CIGAM_64
== magic
) {
1898 machtype
= CFSwapInt32(((struct mach_header_64
*)moreBytes
)->filetype
);
1899 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, true);
1900 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, fat
->offset
, true, true);
1907 static UInt32
_CFBundleGrokMachType(int fd
, const void *bytes
, CFIndex length
, Boolean
*isX11
, CFDictionaryRef
*infodict
) {
1908 unsigned int magic
= *((UInt32
*)bytes
), machtype
= UNKNOWN_FILETYPE
;
1911 if (isX11
) *isX11
= false;
1912 if (infodict
) *infodict
= NULL
;
1913 if (MH_MAGIC
== magic
) {
1914 machtype
= ((struct mach_header
*)bytes
)->filetype
;
1915 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, false);
1916 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, 0, false, false);
1917 } else if (MH_CIGAM
== magic
) {
1918 for (i
= 0; i
< length
; i
+= 4) *(UInt32
*)(bytes
+ i
) = CFSwapInt32(*(UInt32
*)(bytes
+ i
));
1919 machtype
= ((struct mach_header
*)bytes
)->filetype
;
1920 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, false);
1921 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, 0, true, false);
1922 } else if (MH_MAGIC_64
== magic
) {
1923 machtype
= ((struct mach_header_64
*)bytes
)->filetype
;
1924 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, true);
1925 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, 0, false, true);
1926 } else if (MH_CIGAM_64
== magic
) {
1927 for (i
= 0; i
< length
; i
+= 4) *(UInt32
*)(bytes
+ i
) = CFSwapInt32(*(UInt32
*)(bytes
+ i
));
1928 machtype
= ((struct mach_header_64
*)bytes
)->filetype
;
1929 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, true);
1930 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, bytes
, length
, 0, true, true);
1931 } else if (FAT_MAGIC
== magic
) {
1932 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, isX11
, infodict
);
1933 } else if (FAT_CIGAM
== magic
) {
1934 for (i
= 0; i
< length
; i
+= 4) *(UInt32
*)(bytes
+ i
) = CFSwapInt32(*(UInt32
*)(bytes
+ i
));
1935 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, isX11
, infodict
);
1936 } else if (PEF_MAGIC
== magic
|| PEF_CIGAM
== magic
) {
1937 machtype
= PEF_FILETYPE
;
1942 #endif /* BINARY_SUPPORT_DYLD */
1944 static UInt32
_CFBundleGrokFileTypeForOLEFile(int fd
, const void *bytes
, CFIndex length
, off_t offset
) {
1945 UInt32 filetype
= UNKNOWN_FILETYPE
;
1946 static const unsigned char xlsname
[] = XLS_NAME
, xlsname2
[] = XLS_NAME2
, docname
[] = DOC_NAME
, pptname
[] = PPT_NAME
;
1947 const unsigned char *moreBytes
= NULL
;
1948 unsigned char buffer
[512];
1950 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
&& read(fd
, buffer
, sizeof(buffer
)) >= (int)sizeof(buffer
)) {
1952 } else if (bytes
&& length
>= offset
+ 512) {
1953 moreBytes
= bytes
+ offset
;
1957 Boolean foundit
= false;
1958 for (i
= 0; !foundit
&& i
< 4; i
++) {
1959 char namelength
= moreBytes
[128 * i
+ 64] / 2;
1960 if (sizeof(xlsname
) == namelength
) {
1961 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != xlsname
[j
]) foundit
= false;
1962 if (foundit
) filetype
= XLS_FILETYPE
;
1963 } else if (sizeof(xlsname2
) == namelength
) {
1964 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != xlsname2
[j
]) foundit
= false;
1965 if (foundit
) filetype
= XLS_FILETYPE
;
1966 } else if (sizeof(docname
) == namelength
) {
1967 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != docname
[j
]) foundit
= false;
1968 if (foundit
) filetype
= DOC_FILETYPE
;
1969 } else if (sizeof(pptname
) == namelength
) {
1970 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != pptname
[j
]) foundit
= false;
1971 if (foundit
) filetype
= PPT_FILETYPE
;
1978 static Boolean
_CFBundleGrokFileType(CFURLRef url
, CFDataRef data
, CFStringRef
*extension
, UInt32
*machtype
, CFDictionaryRef
*infodict
) {
1979 struct stat statBuf
;
1981 char path
[CFMaxPathSize
];
1982 const unsigned char *bytes
= NULL
;
1983 unsigned char buffer
[MAGIC_BYTES_TO_READ
];
1984 CFIndex i
, length
= 0;
1985 off_t fileLength
= 0;
1986 const char *ext
= NULL
;
1987 UInt32 mt
= UNKNOWN_FILETYPE
;
1988 #if defined(BINARY_SUPPORT_DYLD)
1989 Boolean isX11
= false;
1990 #endif /* BINARY_SUPPORT_DYLD */
1991 Boolean isFile
= false, isPlain
= true, isZero
= true, isHTML
= false;
1992 // 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
1993 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
1994 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) {
1995 // cjk: It is not at clear that not caching would be a win here, since
1996 // in most cases the sniffing of the executable is only done lazily,
1997 // the executable is likely to be immediately used again; say, the
1998 // bundle executable loaded. CFBundle does not need the data again,
1999 // but for the system as a whole not caching could be a net win or lose.
2000 // So, this is where the cache disablement would go, but I am not going
2001 // to turn it on at this point.
2002 // fcntl(fd, F_NOCACHE, 1);
2003 length
= read(fd
, buffer
, MAGIC_BYTES_TO_READ
);
2004 fileLength
= statBuf
.st_size
;
2008 length
= CFDataGetLength(data
);
2009 fileLength
= (off_t
)length
;
2010 bytes
= CFDataGetBytePtr(data
);
2011 if (length
== 0) ext
= "txt";
2015 UInt32 magic
= CFSwapInt32HostToBig(*((UInt32
*)bytes
));
2016 for (i
= 0; !ext
&& i
< NUM_EXTENSIONS
; i
++) {
2017 if (__CFBundleMagicNumbersArray
[i
] == magic
) ext
= __CFBundleExtensionsArray
+ i
* EXTENSION_LENGTH
;
2020 if (0xcafebabe == magic
&& 8 <= length
&& 0 != *((UInt16
*)(bytes
+ 4))) ext
= "class";
2021 #if defined(BINARY_SUPPORT_DYLD)
2022 else if ((int)sizeof(struct mach_header_64
) <= length
) mt
= _CFBundleGrokMachType(fd
, bytes
, length
, extension
? &isX11
: NULL
, infodict
);
2024 if (MH_OBJECT
== mt
) ext
= "o";
2025 else if (MH_EXECUTE
== mt
) ext
= isX11
? "x11app" : "tool";
2026 else if (PEF_FILETYPE
== mt
) ext
= "pef";
2027 else if (MH_CORE
== mt
) ext
= "core";
2028 else if (MH_DYLIB
== mt
) ext
= "dylib";
2029 else if (MH_BUNDLE
== mt
) ext
= "bundle";
2030 #endif /* BINARY_SUPPORT_DYLD */
2031 else if (0x7b5c7274 == magic
&& (6 > length
|| 'f' != bytes
[4])) ext
= NULL
;
2032 else if (0x00010000 == magic
&& (6 > length
|| 0 != bytes
[4])) ext
= NULL
;
2033 else if (0x47494638 == magic
&& (6 > length
|| (0x3761 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4)))))) ext
= NULL
;
2034 else if (0x0000000c == magic
&& (6 > length
|| 0x6a50 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2035 else if (0x2356524d == magic
&& (6 > length
|| 0x4c20 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2036 else if (0x28445746 == magic
&& (6 > length
|| 0x2056 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2037 else if (0x30373037 == magic
&& (6 > length
|| 0x30 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2038 else if (0x41433130 == magic
&& (6 > length
|| 0x31 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2039 else if (0x89504e47 == magic
&& (8 > length
|| 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2040 else if (0x53747566 == magic
&& (8 > length
|| 0x66497420 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2041 else if (0x3026b275 == magic
&& (8 > length
|| 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2042 else if (0x67696d70 == magic
&& (8 > length
|| 0x20786366 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2043 else if (0x424f4d53 == magic
&& (8 > length
|| 0x746f7265 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2044 else if (0x25215053 == magic
&& 14 <= length
&& 0 == strncmp(bytes
+ 4, "-AdobeFont", 10)) ext
= "pfa";
2045 else if (0x504b0304 == magic
&& 38 <= length
&& 0x4d455441 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 30))) && 0x2d494e46 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34)))) ext
= "jar";
2046 else if (0x464f524d == magic
) {
2050 UInt32 iffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2051 if (0x41494646 == iffMagic
) ext
= "aiff";
2052 else if (0x414946 == iffMagic
) ext
= "aifc";
2054 } else if (0x52494646 == magic
) {
2058 UInt32 riffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2059 if (0x57415645 == riffMagic
) ext
= "wav";
2060 else if (0x41564920 == riffMagic
) ext
= "avi";
2062 } else if (0xd0cf11e0 == magic
) {
2065 UInt32 ft
= _CFBundleGrokFileTypeForOLEFile(fd
, bytes
, length
, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 48)))));
2066 if (XLS_FILETYPE
== ft
) ext
= "xls";
2067 else if (DOC_FILETYPE
== ft
) ext
= "doc";
2068 else if (PPT_FILETYPE
== ft
) ext
= "ppt";
2070 } else if (0x62656769 == magic
) {
2073 if (76 <= length
&& 'n' == bytes
[4] && ' ' == bytes
[5] && isdigit(bytes
[6]) && isdigit(bytes
[7]) && isdigit(bytes
[8]) && ' ' == bytes
[9]) {
2074 CFIndex endOfLine
= 0;
2075 for (i
= 10; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2076 if (10 <= endOfLine
&& endOfLine
+ 62 < length
&& 'M' == bytes
[endOfLine
+ 1] && '\n' == bytes
[endOfLine
+ 62]) {
2078 for (i
= endOfLine
+ 1; ext
&& i
< endOfLine
+ 62; i
++) if (!isprint(bytes
[i
])) ext
= NULL
;
2083 if (extension
&& !ext
) {
2084 UInt16 shortMagic
= CFSwapInt16HostToBig(*((UInt16
*)bytes
));
2085 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";
2086 else if (8 <= length
&& (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "mov";
2087 else if (8 <= length
&& (0x69647363 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "qtif";
2088 else if (8 <= length
&& 0x424f424f == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) ext
= "cwk";
2089 else if (8 <= length
&& 0x62706c69 == magic
&& 0x7374 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && isdigit(bytes
[6]) && isdigit(bytes
[7])) {
2090 for (i
= 8; !ext
&& i
< 128 && i
+ 16 <= length
; i
++) {
2091 if (0 == strncmp(bytes
+ i
, "WebMainResource", 15)) ext
= "webarchive";
2093 if (!ext
) ext
= "plist";
2094 } else if (12 <= length
&& 0x66747970 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
2095 // ??? list of ftyp values needs to be checked
2096 if (0x6d703432 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) ext
= "mp4";
2097 else if (0x4d344120 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) ext
= "m4a";
2098 else if (0x4d344220 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) ext
= "m4b";
2099 else if (0x4d345020 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) ext
= "m4p";
2100 } else if (0x424d == shortMagic
&& 18 <= length
&& 40 == CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 14)))) ext
= "bmp";
2101 else if (20 <= length
&& 0 == strncmp(bytes
+ 6, "%!PS-AdobeFont", 14)) ext
= "pfb";
2102 else if (40 <= length
&& 0x42696e48 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 38)))) ext
= "hqx";
2103 else if (128 <= length
&& 0x6d42494e == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 102)))) ext
= "bin";
2104 else if (128 <= length
&& 0 == bytes
[0] && 0 < bytes
[1] && bytes
[1] < 64 && 0 == bytes
[74] && 0 == bytes
[82] && 0 == (fileLength
% 128)) {
2105 unsigned df
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 83))), rf
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 87))), blocks
= 1 + (df
+ 127) / 128 + (rf
+ 127) / 128;
2106 if (df
< 0x00800000 && rf
< 0x00800000 && 1 < blocks
&& (off_t
)(128 * blocks
) == fileLength
) ext
= "bin";
2107 } else if (265 <= length
&& 0x75737461 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 261))))) ext
= "tar";
2108 else if (0xfeff == shortMagic
|| 0xfffe == shortMagic
) ext
= "txt";
2109 else if (0x1f9d == shortMagic
) ext
= "Z";
2110 else if (0x1f8b == shortMagic
) ext
= "gz";
2111 else if (0x71c7 == shortMagic
|| 0xc771 == shortMagic
) ext
= "cpio";
2112 else if (0xf702 == shortMagic
) ext
= "dvi";
2113 else if (0x01da == shortMagic
&& (0 == bytes
[2] || 1 == bytes
[2]) && (0 < bytes
[3] && 16 > bytes
[3])) ext
= "sgi";
2114 else if (0x2321 == shortMagic
) {
2115 CFIndex endOfLine
= 0, lastSlash
= 0;
2116 for (i
= 2; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2117 if (endOfLine
> 3) {
2118 for (i
= endOfLine
- 1; 0 == lastSlash
&& i
> 1; i
--) if ('/' == bytes
[i
]) lastSlash
= i
;
2119 if (lastSlash
> 0) {
2120 if (0 == strncmp(bytes
+ lastSlash
+ 1, "perl", 4)) ext
= "pl";
2121 else if (0 == strncmp(bytes
+ lastSlash
+ 1, "python", 6)) ext
= "py";
2122 else if (0 == strncmp(bytes
+ lastSlash
+ 1, "ruby", 4)) ext
= "rb";
2126 } else if (0xffd8 == shortMagic
&& 0xff == bytes
[2]) ext
= "jpeg";
2127 else if (0x4657 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swf";
2128 else if (0x4357 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swc";
2129 else if (0x4944 == shortMagic
&& '3' == bytes
[2] && 0x20 > bytes
[3]) ext
= "mp3";
2130 else if (0x425a == shortMagic
&& isdigit(bytes
[2]) && isdigit(bytes
[3])) ext
= "bz";
2131 else if (0x425a == shortMagic
&& 'h' == bytes
[2] && isdigit(bytes
[3]) && 8 <= length
&& (0x31415926 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "bz2";
2132 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2)))) ext
= "tfm";
2133 else if ('<' == bytes
[0] && 14 <= length
) {
2134 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)) {
2136 } else if (0 == strncasecmp(bytes
+ 1, "?xml", 4)) {
2137 for (i
= 4; !ext
&& i
< 128 && i
+ 20 <= length
; i
++) {
2138 if ('<' == bytes
[i
]) {
2139 if (0 == strncasecmp(bytes
+ i
+ 1, "abiword", 7)) ext
= "abw";
2140 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype svg", 12)) ext
= "svg";
2141 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype x3d", 12)) ext
= "x3d";
2142 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) ext
= "html";
2143 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype plist", 14)) ext
= "plist";
2144 else if (0 == strncasecmp(bytes
+ i
+ 1, "!doctype posingfont", 19)) ext
= "sfont";
2147 if (!ext
) ext
= "xml";
2152 if (extension
&& !ext
) {
2153 //??? what about MacOSRoman?
2154 for (i
= 0; (isPlain
|| isZero
) && !isHTML
&& i
< length
&& i
< 512; i
++) {
2156 if (0x7f <= c
|| (0x20 > c
&& !isspace(c
))) isPlain
= false;
2157 if (0 != c
) isZero
= false;
2158 if (isPlain
&& '<' == c
&& i
+ 14 <= length
&& 0 == strncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) isHTML
= true;
2162 } else if (isPlain
) {
2163 if (16 <= length
&& 0 == strncmp(bytes
, "StartFontMetrics", 16)) ext
= "afm";
2165 } else if (isZero
&& length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= 526) {
2167 if (lseek(fd
, 512, SEEK_SET
) == 512 && read(fd
, buffer
, MAGIC_BYTES_TO_READ
) >= 14) {
2168 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 10)))) ext
= "pict";
2171 if (526 <= length
&& 0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 522)))) ext
= "pict";
2175 if (extension
&& !ext
&& !isZero
&& length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= 1024) {
2177 off_t offset
= fileLength
- 512;
2178 if (lseek(fd
, offset
, SEEK_SET
) == offset
&& read(fd
, buffer
, 512) >= 512) {
2179 if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32
*)buffer
)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 504))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 508))))) ext
= "dmg";
2182 if (512 <= length
&& (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- 512))) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- 4)))))) ext
= "dmg";
2186 if (extension
) *extension
= ext
? CFStringCreateWithCStringNoCopy(NULL
, ext
, kCFStringEncodingASCII
, kCFAllocatorNull
) : NULL
;
2187 if (machtype
) *machtype
= mt
;
2188 if (fd
>= 0) close(fd
);
2189 return (ext
!= NULL
);
2192 CFStringRef
_CFBundleCopyFileTypeForFileURL(CFURLRef url
) {
2193 CFStringRef extension
= NULL
;
2194 (void)_CFBundleGrokFileType(url
, NULL
, &extension
, NULL
, NULL
);
2198 CFStringRef
_CFBundleCopyFileTypeForFileData(CFDataRef data
) {
2199 CFStringRef extension
= NULL
;
2200 (void)_CFBundleGrokFileType(NULL
, data
, &extension
, NULL
, NULL
);
2204 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInExecutable(CFURLRef url
) {
2205 CFDictionaryRef result
= NULL
;
2206 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, &result
);
2210 #if defined(BINARY_SUPPORT_DYLD)
2212 __private_extern__ __CFPBinaryType
_CFBundleGrokBinaryType(CFURLRef executableURL
) {
2213 // 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).
2214 __CFPBinaryType result
= executableURL
? __CFBundleUnreadableBinary
: __CFBundleNoBinary
;
2215 UInt32 machtype
= UNKNOWN_FILETYPE
;
2216 if (_CFBundleGrokFileType(executableURL
, NULL
, NULL
, &machtype
, NULL
)) {
2219 result
= __CFBundleDYLDExecutableBinary
;
2222 result
= __CFBundleDYLDBundleBinary
;
2225 result
= __CFBundleDYLDFrameworkBinary
;
2227 #if defined(BINARY_SUPPORT_CFM)
2229 result
= __CFBundleCFMBinary
;
2231 #endif /* BINARY_SUPPORT_CFM */
2237 #endif /* BINARY_SUPPORT_DYLD */
2239 void _CFBundleSetCFMConnectionID(CFBundleRef bundle
, void *connectionID
) {
2240 #if defined(BINARY_SUPPORT_CFM)
2241 if (bundle
->_binaryType
== __CFBundleUnknownBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
2242 bundle
->_binaryType
= __CFBundleCFMBinary
;
2244 #endif /* BINARY_SUPPORT_CFM */
2245 bundle
->_connectionCookie
= connectionID
;
2246 bundle
->_isLoaded
= true;
2249 Boolean
CFBundleLoadExecutable(CFBundleRef bundle
) {
2250 Boolean result
= false;
2251 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2253 if (!executableURL
) {
2254 bundle
->_binaryType
= __CFBundleNoBinary
;
2256 #if defined(BINARY_SUPPORT_DYLD)
2257 // make sure we know whether bundle is already loaded or not
2258 if (!bundle
->_isLoaded
) {
2259 _CFBundleDYLDCheckLoaded(bundle
);
2261 // We might need to figure out what it is
2262 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2263 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
2264 #if defined(BINARY_SUPPORT_CFM)
2265 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
2266 bundle
->_resourceData
._executableLacksResourceFork
= true;
2268 #endif /* BINARY_SUPPORT_CFM */
2270 #endif /* BINARY_SUPPORT_DYLD */
2271 if (executableURL
) CFRelease(executableURL
);
2273 if (bundle
->_isLoaded
) {
2274 // Remove from the scheduled unload set if we are there.
2275 __CFSpinLock(&CFBundleGlobalDataLock
);
2276 if (_bundlesToUnload
) {
2277 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2279 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2283 // Unload bundles scheduled for unloading
2284 if (!_scheduledBundlesAreUnloading
) {
2285 _CFBundleUnloadScheduledBundles();
2289 switch (bundle
->_binaryType
) {
2290 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2291 case __CFBundleCFMBinary
:
2292 case __CFBundleUnreadableBinary
:
2293 result
= _CFBundleCFMLoad(bundle
);
2295 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2296 #if defined(BINARY_SUPPORT_DYLD)
2297 case __CFBundleDYLDBundleBinary
:
2298 result
= _CFBundleDYLDLoadBundle(bundle
);
2300 case __CFBundleDYLDFrameworkBinary
:
2301 result
= _CFBundleDYLDLoadFramework(bundle
);
2303 case __CFBundleDYLDExecutableBinary
:
2304 CFLog(__kCFLogBundle
, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle
);
2306 #endif /* BINARY_SUPPORT_DYLD */
2307 #if defined(BINARY_SUPPORT_DLL)
2308 case __CFBundleDLLBinary
:
2309 result
= _CFBundleDLLLoad(bundle
);
2311 #endif /* BINARY_SUPPORT_DLL */
2312 case __CFBundleNoBinary
:
2313 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for %@"), bundle
);
2316 CFLog(__kCFLogBundle
, CFSTR("Cannot recognize type of executable for %@"), bundle
);
2319 if (result
&& bundle
->_plugInData
._isPlugIn
) _CFBundlePlugInLoaded(bundle
);
2324 void CFBundleUnloadExecutable(CFBundleRef bundle
) {
2326 if (!_scheduledBundlesAreUnloading
) {
2327 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
2328 _CFBundleUnloadScheduledBundles();
2331 if (!bundle
->_isLoaded
) return;
2333 // Remove from the scheduled unload set if we are there.
2334 if (!_scheduledBundlesAreUnloading
) {
2335 __CFSpinLock(&CFBundleGlobalDataLock
);
2337 if (_bundlesToUnload
) {
2338 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2340 if (!_scheduledBundlesAreUnloading
) {
2341 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2344 // Give the plugIn code a chance to realize this...
2345 _CFPlugInWillUnload(bundle
);
2347 switch (bundle
->_binaryType
) {
2348 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2349 case __CFBundleCFMBinary
:
2350 _CFBundleCFMUnload(bundle
);
2352 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2353 #if defined(BINARY_SUPPORT_DYLD)
2354 case __CFBundleDYLDBundleBinary
:
2355 _CFBundleDYLDUnloadBundle(bundle
);
2357 #endif /* BINARY_SUPPORT_DYLD */
2358 #if defined(BINARY_SUPPORT_DLL)
2359 case __CFBundleDLLBinary
:
2360 _CFBundleDLLUnload(bundle
);
2362 #endif /* BINARY_SUPPORT_DLL */
2366 if (!bundle
->_isLoaded
&& bundle
->_glueDict
!= NULL
) {
2367 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
2368 CFRelease(bundle
->_glueDict
);
2369 bundle
->_glueDict
= NULL
;
2373 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
2374 __CFSpinLock(&CFBundleGlobalDataLock
);
2375 if (!_bundlesToUnload
) {
2376 // Create this from the default allocator
2377 CFSetCallBacks nonRetainingCallbacks
= kCFTypeSetCallBacks
;
2378 nonRetainingCallbacks
.retain
= NULL
;
2379 nonRetainingCallbacks
.release
= NULL
;
2380 _bundlesToUnload
= CFSetCreateMutable(NULL
, 0, &nonRetainingCallbacks
);
2382 CFSetAddValue(_bundlesToUnload
, bundle
);
2383 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2386 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
2387 __CFSpinLock(&CFBundleGlobalDataLock
);
2388 if (_bundlesToUnload
) {
2389 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2391 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2394 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
2395 __CFSpinLock(&CFBundleGlobalDataLock
);
2396 if (_bundlesToUnload
) {
2397 CFIndex c
= CFSetGetCount(_bundlesToUnload
);
2400 CFBundleRef
*unloadThese
= CFAllocatorAllocate(NULL
, sizeof(CFBundleRef
) * c
, 0);
2401 CFSetGetValues(_bundlesToUnload
, (const void **)unloadThese
);
2402 _scheduledBundlesAreUnloading
= true;
2403 for (i
=0; i
<c
; i
++) {
2404 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2405 CFBundleUnloadExecutable(unloadThese
[i
]);
2407 _scheduledBundlesAreUnloading
= false;
2408 CFAllocatorDeallocate(NULL
, unloadThese
);
2411 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2414 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
2416 // Load if necessary
2417 if (!bundle
->_isLoaded
) {
2418 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2421 switch (bundle
->_binaryType
) {
2422 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2423 case __CFBundleCFMBinary
:
2424 tvp
= _CFBundleCFMGetSymbolByName(bundle
, funcName
, kTVectorCFragSymbol
);
2426 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2427 #if defined(BINARY_SUPPORT_DYLD)
2428 case __CFBundleDYLDBundleBinary
:
2429 case __CFBundleDYLDFrameworkBinary
:
2430 case __CFBundleDYLDExecutableBinary
:
2431 return _CFBundleDYLDGetSymbolByName(bundle
, funcName
);
2433 #endif /* BINARY_SUPPORT_DYLD */
2434 #if defined(BINARY_SUPPORT_DLL)
2435 case __CFBundleDLLBinary
:
2436 tvp
= _CFBundleDLLGetSymbolByName(bundle
, funcName
);
2438 #endif /* BINARY_SUPPORT_DLL */
2442 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2444 if (bundle
->_glueDict
== NULL
) {
2445 bundle
->_glueDict
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, NULL
, NULL
);
2447 void *fp
= (void *)CFDictionaryGetValue(bundle
->_glueDict
, tvp
);
2449 fp
= _CFBundleFunctionPointerForTVector(CFGetAllocator(bundle
), tvp
);
2450 CFDictionarySetValue(bundle
->_glueDict
, tvp
, fp
);
2454 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2458 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
2460 // Load if necessary
2461 if (!bundle
->_isLoaded
) {
2462 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2465 switch (bundle
->_binaryType
) {
2466 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2467 case __CFBundleCFMBinary
:
2468 return _CFBundleCFMGetSymbolByName(bundle
, funcName
, kTVectorCFragSymbol
);
2470 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2471 #if defined(BINARY_SUPPORT_DYLD)
2472 case __CFBundleDYLDBundleBinary
:
2473 case __CFBundleDYLDFrameworkBinary
:
2474 case __CFBundleDYLDExecutableBinary
:
2475 fp
= _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, funcName
, true);
2477 #endif /* BINARY_SUPPORT_DYLD */
2481 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2483 if (bundle
->_glueDict
== NULL
) {
2484 bundle
->_glueDict
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, NULL
, NULL
);
2486 void *tvp
= (void *)CFDictionaryGetValue(bundle
->_glueDict
, fp
);
2488 tvp
= _CFBundleTVectorForFunctionPointer(CFGetAllocator(bundle
), fp
);
2489 CFDictionarySetValue(bundle
->_glueDict
, fp
, tvp
);
2493 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2497 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
2502 c
= CFArrayGetCount(functionNames
);
2503 for (i
= 0; i
< c
; i
++) {
2504 ftbl
[i
] = CFBundleGetFunctionPointerForName(bundle
, CFArrayGetValueAtIndex(functionNames
, i
));
2508 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
2513 c
= CFArrayGetCount(functionNames
);
2514 for (i
= 0; i
< c
; i
++) {
2515 ftbl
[i
] = _CFBundleGetCFMFunctionPointerForName(bundle
, CFArrayGetValueAtIndex(functionNames
, i
));
2519 void *CFBundleGetDataPointerForName(CFBundleRef bundle
, CFStringRef symbolName
) {
2521 // Load if necessary
2522 if (!bundle
->_isLoaded
) {
2523 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2526 switch (bundle
->_binaryType
) {
2527 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2528 case __CFBundleCFMBinary
:
2529 dp
= _CFBundleCFMGetSymbolByName(bundle
, symbolName
, kDataCFragSymbol
);
2531 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2532 #if defined(BINARY_SUPPORT_DYLD)
2533 case __CFBundleDYLDBundleBinary
:
2534 case __CFBundleDYLDFrameworkBinary
:
2535 case __CFBundleDYLDExecutableBinary
:
2536 dp
= _CFBundleDYLDGetSymbolByName(bundle
, symbolName
);
2538 #endif /* BINARY_SUPPORT_DYLD */
2539 #if defined(BINARY_SUPPORT_DLL)
2540 case __CFBundleDLLBinary
:
2541 /* MF:!!! Handle this someday */
2543 #endif /* BINARY_SUPPORT_DLL */
2550 void CFBundleGetDataPointersForNames(CFBundleRef bundle
, CFArrayRef symbolNames
, void *stbl
[]) {
2555 c
= CFArrayGetCount(symbolNames
);
2556 for (i
= 0; i
< c
; i
++) {
2557 stbl
[i
] = CFBundleGetDataPointerForName(bundle
, CFArrayGetValueAtIndex(symbolNames
, i
));
2561 __private_extern__ _CFResourceData
*__CFBundleGetResourceData(CFBundleRef bundle
) {
2562 return &(bundle
->_resourceData
);
2565 CFPlugInRef
CFBundleGetPlugIn(CFBundleRef bundle
) {
2566 if (bundle
->_plugInData
._isPlugIn
) {
2567 return (CFPlugInRef
)bundle
;
2573 __private_extern__ _CFPlugInData
*__CFBundleGetPlugInData(CFBundleRef bundle
) {
2574 return &(bundle
->_plugInData
);
2577 __private_extern__ Boolean
_CFBundleCouldBeBundle(CFURLRef url
) {
2578 Boolean result
= false;
2582 if (_CFGetFileProperties(NULL
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) {
2583 result
= (exists
&& ((mode
& S_IFMT
) == S_IFDIR
));
2584 #if !defined(__MACOS8__)
2585 result
= (result
&& ((mode
& 0444) != 0));
2591 __private_extern__ CFURLRef
_CFBundleCopyFrameworkURLForExecutablePath(CFAllocatorRef alloc
, CFStringRef executablePath
) {
2592 // 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.
2593 #if defined(__WIN32__)
2594 UniChar executablesToFrameworksPathBuff
[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 16
2595 UniChar executablesToPrivateFrameworksPathBuff
[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 23
2596 UniChar frameworksExtension
[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'}; // length 9
2599 UniChar pathBuff
[CFMaxPathSize
];
2600 UniChar nameBuff
[CFMaxPathSize
];
2601 CFIndex length
, nameStart
, nameLength
, savedLength
;
2602 CFMutableStringRef cheapStr
= CFStringCreateMutableWithExternalCharactersNoCopy(alloc
, NULL
, 0, 0, NULL
);
2603 CFURLRef bundleURL
= NULL
;
2605 length
= CFStringGetLength(executablePath
);
2606 if (length
> CFMaxPathSize
) length
= CFMaxPathSize
;
2607 CFStringGetCharacters(executablePath
, CFRangeMake(0, length
), pathBuff
);
2609 // Save the name in nameBuff
2610 length
= _CFLengthAfterDeletingPathExtension(pathBuff
, length
);
2611 nameStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2612 nameLength
= length
- nameStart
;
2613 memmove(nameBuff
, &(pathBuff
[nameStart
]), nameLength
* sizeof(UniChar
));
2615 // Strip the name from pathBuff
2616 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2617 savedLength
= length
;
2619 #if defined(__WIN32__)
2620 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
2621 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToFrameworksPathBuff
, 16) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, 9)) {
2622 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2623 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2624 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2625 CFRelease(bundleURL
);
2629 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
2630 if (bundleURL
== NULL
) {
2631 length
= savedLength
;
2632 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToPrivateFrameworksPathBuff
, 23) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, 9)) {
2633 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2634 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2635 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2636 CFRelease(bundleURL
);
2642 // * Finally check the executable inside the framework case.
2643 if (bundleURL
== NULL
) {
2644 // MF:!!! This should ensure the framework name is the same as the library name!
2647 length
= savedLength
;
2648 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
2650 while (length
> 0) {
2651 curStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2652 if (curStart
>= length
) {
2655 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[curStart
]), length
- curStart
, CFMaxPathSize
- curStart
);
2656 if (CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName1
) || CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName2
)) {
2657 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2658 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2659 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2660 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2661 CFRelease(bundleURL
);
2665 } else if (CFStringHasSuffix(cheapStr
, CFSTR(".framework"))) {
2666 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2667 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2668 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2669 CFRelease(bundleURL
);
2674 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2678 CFStringSetExternalCharactersNoCopy(cheapStr
, NULL
, 0, 0);
2679 CFRelease(cheapStr
);
2684 #if defined(BINARY_SUPPORT_DYLD)
2685 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
) {
2686 // This finds the bundle for the given path.
2687 // 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.
2689 CFURLRef curURL
= _CFBundleCopyFrameworkURLForExecutablePath(NULL
, imagePath
);
2690 Boolean doFinalProcessing
= false;
2692 if (curURL
!= NULL
) {
2693 bundle
= _CFBundleFindByURL(curURL
, true);
2694 if (bundle
== NULL
) {
2695 bundle
= _CFBundleCreate(NULL
, curURL
, true, false);
2696 doFinalProcessing
= true;
2698 if (bundle
!= NULL
&& !bundle
->_isLoaded
) {
2699 // 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)
2700 #if defined(BINARY_SUPPORT_DYLD)
2701 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2702 bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
2704 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
2705 bundle
->_resourceData
._executableLacksResourceFork
= true;
2707 if (!bundle
->_imageCookie
) _CFBundleDYLDCheckLoaded(bundle
);
2708 #endif /* BINARY_SUPPORT_DYLD */
2709 bundle
->_isLoaded
= true;
2711 // Perform delayed final processing steps.
2712 // This must be done after _isLoaded has been set.
2713 if (bundle
&& doFinalProcessing
) {
2714 _CFBundleCheckWorkarounds(bundle
);
2715 if (_CFBundleNeedsInitPlugIn(bundle
)) {
2716 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2717 _CFBundleInitPlugIn(bundle
);
2718 __CFSpinLock(&CFBundleGlobalDataLock
);
2725 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
) {
2726 // This finds the bundles for the given paths.
2727 // 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).
2728 CFIndex i
, imagePathCount
= CFArrayGetCount(imagePaths
);
2730 for (i
=0; i
<imagePathCount
; i
++) {
2731 _CFBundleEnsureBundleExistsForImagePath(CFArrayGetValueAtIndex(imagePaths
, i
));
2734 #endif /* BINARY_SUPPORT_DYLD */
2736 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
) {
2737 // Tickle the main bundle into existence
2738 (void)_CFBundleGetMainBundleAlreadyLocked();
2739 #if defined(BINARY_SUPPORT_DYLD)
2740 CFArrayRef imagePaths
= _CFBundleDYLDCopyLoadedImagePathsForHint(hint
);
2741 if (imagePaths
!= NULL
) {
2742 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2743 CFRelease(imagePaths
);
2748 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
2749 // 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.
2751 // Tickle the main bundle into existence
2752 (void)_CFBundleGetMainBundleAlreadyLocked();
2754 #if defined(BINARY_SUPPORT_DLL)
2755 #warning (MF) Dont know how to find static bundles for DLLs
2758 #if defined(BINARY_SUPPORT_CFM)
2759 // CFM bundles are supplied to us by CFM, so we do not need to figure them out ourselves
2762 #if defined(BINARY_SUPPORT_DYLD)
2763 CFArrayRef imagePaths
= _CFBundleDYLDCopyLoadedImagePathsIfChanged();
2764 if (imagePaths
!= NULL
) {
2765 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2766 CFRelease(imagePaths
);
2771 CFArrayRef
CFBundleGetAllBundles(void) {
2772 // To answer this properly, we have to have created the static bundles!
2773 __CFSpinLock(&CFBundleGlobalDataLock
);
2774 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2775 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2779 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle
) {return bundle
->_version
;}
2781 CF_EXPORT CFURLRef
_CFBundleCopyInfoPlistURL(CFBundleRef bundle
) {
2782 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2783 CFStringRef path
= CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
);
2784 return (path
? CFRetain(path
) : NULL
);
2787 CF_EXPORT CFURLRef
_CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {return CFBundleCopyPrivateFrameworksURL(bundle
);}
2789 CF_EXPORT CFURLRef
CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
2790 CFURLRef result
= NULL
;
2792 if (1 == bundle
->_version
) {
2793 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase1
, bundle
->_url
);
2794 } else if (2 == bundle
->_version
) {
2795 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase2
, bundle
->_url
);
2797 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase0
, bundle
->_url
);
2802 CF_EXPORT CFURLRef
_CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {return CFBundleCopySharedFrameworksURL(bundle
);}
2804 CF_EXPORT CFURLRef
CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
2805 CFURLRef result
= NULL
;
2807 if (1 == bundle
->_version
) {
2808 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase1
, bundle
->_url
);
2809 } else if (2 == bundle
->_version
) {
2810 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase2
, bundle
->_url
);
2812 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase0
, bundle
->_url
);
2817 CF_EXPORT CFURLRef
_CFBundleCopySharedSupportURL(CFBundleRef bundle
) {return CFBundleCopySharedSupportURL(bundle
);}
2819 CF_EXPORT CFURLRef
CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
2820 CFURLRef result
= NULL
;
2822 if (1 == bundle
->_version
) {
2823 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase1
, bundle
->_url
);
2824 } else if (2 == bundle
->_version
) {
2825 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase2
, bundle
->_url
);
2827 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase0
, bundle
->_url
);
2832 __private_extern__ CFURLRef
_CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {return CFBundleCopyBuiltInPlugInsURL(bundle
);}
2834 CF_EXPORT CFURLRef
CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
2835 CFURLRef result
= NULL
, alternateResult
= NULL
;
2837 CFAllocatorRef alloc
= CFGetAllocator(bundle
);
2838 if (1 == bundle
->_version
) {
2839 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase1
, bundle
->_url
);
2840 } else if (2 == bundle
->_version
) {
2841 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase2
, bundle
->_url
);
2843 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2845 if (!result
|| !_urlExists(alloc
, result
)) {
2846 if (1 == bundle
->_version
) {
2847 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase1
, bundle
->_url
);
2848 } else if (2 == bundle
->_version
) {
2849 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase2
, bundle
->_url
);
2851 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2853 if (alternateResult
&& _urlExists(alloc
, alternateResult
)) {
2854 if (result
) CFRelease(result
);
2855 result
= alternateResult
;
2857 if (alternateResult
) CFRelease(alternateResult
);
2865 #if defined(BINARY_SUPPORT_DYLD)
2867 static const void *__CFBundleDYLDFindImage(char *buff
) {
2868 const void *header
= NULL
;
2869 uint32_t i
, numImages
= _dyld_image_count(), numMatches
= 0;
2870 const char *curName
, *p
, *q
;
2872 for (i
= 0; !header
&& i
< numImages
; i
++) {
2873 curName
= _dyld_get_image_name(i
);
2874 if (curName
&& 0 == strncmp(curName
, buff
, CFMaxPathSize
)) {
2875 header
= _dyld_get_image_header(i
);
2880 for (i
= 0; i
< numImages
; i
++) {
2881 curName
= _dyld_get_image_name(i
);
2883 for (p
= buff
, q
= curName
; *p
&& *q
&& (q
- curName
< CFMaxPathSize
); p
++, q
++) {
2884 if (*p
!= *q
&& (q
- curName
> 11) && 0 == strncmp(q
- 11, ".framework/Versions/", 20) && *(q
+ 9) && '/' == *(q
+ 10)) q
+= 11;
2885 else if (*p
!= *q
&& (q
- curName
> 12) && 0 == strncmp(q
- 12, ".framework/Versions/", 20) && *(q
+ 8) && '/' == *(q
+ 9)) q
+= 10;
2886 if (*p
!= *q
) break;
2889 header
= _dyld_get_image_header(i
);
2895 return (numMatches
== 1) ? header
: NULL
;
2898 __private_extern__ Boolean
_CFBundleDYLDCheckLoaded(CFBundleRef bundle
) {
2899 if (!bundle
->_isLoaded
) {
2900 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2902 if (executableURL
!= NULL
) {
2903 char buff
[CFMaxPathSize
];
2905 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2906 const void *header
= __CFBundleDYLDFindImage(buff
);
2908 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2909 bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
2911 if (!bundle
->_imageCookie
) bundle
->_imageCookie
= header
;
2912 bundle
->_isLoaded
= true;
2915 CFRelease(executableURL
);
2918 return bundle
->_isLoaded
;
2921 __private_extern__ Boolean
_CFBundleDYLDLoadBundle(CFBundleRef bundle
) {
2922 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
2923 int errorNumber
= 0;
2924 const char *fileName
= NULL
;
2925 const char *errorString
= NULL
;
2927 if (!bundle
->_isLoaded
) {
2928 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2930 if (executableURL
) {
2931 char buff
[CFMaxPathSize
];
2933 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2934 NSObjectFileImage image
;
2935 NSObjectFileImageReturnCode retCode
= NSCreateObjectFileImageFromFile(buff
, &image
);
2936 if (retCode
== NSObjectFileImageSuccess
) {
2937 NSModule
module = NSLinkModule(image
, buff
, (NSLINKMODULE_OPTION_BINDNOW
| NSLINKMODULE_OPTION_PRIVATE
| NSLINKMODULE_OPTION_RETURN_ON_ERROR
));
2939 bundle
->_imageCookie
= image
;
2940 bundle
->_moduleCookie
= module;
2941 bundle
->_isLoaded
= true;
2943 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
2944 CFLog(__kCFLogBundle
, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName
, c
, errorNumber
, errorString
);
2945 if (!NSDestroyObjectFileImage(image
)) {
2946 /* MF:!!! Error destroying object file image */
2950 CFLog(__kCFLogBundle
, CFSTR("dyld returns %d when trying to load %@"), retCode
, executableURL
);
2953 CFRelease(executableURL
);
2955 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2958 return bundle
->_isLoaded
;
2961 __private_extern__ Boolean
_CFBundleDYLDLoadFramework(CFBundleRef bundle
) {
2962 // !!! Framework loading should be better. Can't unload frameworks.
2963 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
2964 int errorNumber
= 0;
2965 const char *fileName
= NULL
;
2966 const char *errorString
= NULL
;
2968 if (!bundle
->_isLoaded
) {
2969 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2971 if (executableURL
) {
2972 char buff
[CFMaxPathSize
];
2974 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2975 void *image
= (void *)NSAddImage(buff
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
2977 bundle
->_imageCookie
= image
;
2978 bundle
->_isLoaded
= true;
2980 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
2981 CFLog(__kCFLogBundle
, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName
, c
, errorNumber
, errorString
);
2984 CFRelease(executableURL
);
2986 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2989 return bundle
->_isLoaded
;
2992 __private_extern__
void _CFBundleDYLDUnloadBundle(CFBundleRef bundle
) {
2993 if (bundle
->_isLoaded
) {
2994 if (bundle
->_moduleCookie
&& !NSUnLinkModule((NSModule
)(bundle
->_moduleCookie
), NSUNLINKMODULE_OPTION_NONE
)) {
2995 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
2997 if (bundle
->_moduleCookie
&& bundle
->_imageCookie
&& !NSDestroyObjectFileImage((NSObjectFileImage
)(bundle
->_imageCookie
))) {
2998 /* MF:!!! Error destroying object file image */
3000 bundle
->_connectionCookie
= NULL
;
3001 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
3002 bundle
->_isLoaded
= false;
3007 __private_extern__
void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {return _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, symbolName
, false);}
3009 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
3010 void *result
= NULL
;
3012 NSSymbol symbol
= NULL
;
3014 // MF:!!! What if the factory was in C++ code (and is therefore mangled differently)? Huh, answer me that!
3015 // 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.
3017 /* MF:??? ASCII appropriate here? */
3018 if (CFStringGetCString(symbolName
, &(buff
[1]), 1024, kCFStringEncodingASCII
)) {
3019 if (bundle
->_moduleCookie
) {
3020 symbol
= NSLookupSymbolInModule((NSModule
)(bundle
->_moduleCookie
), buff
);
3021 } else if (bundle
->_imageCookie
) {
3022 symbol
= NSLookupSymbolInImage(bundle
->_imageCookie
, buff
, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
3024 if (NULL
== symbol
&& NULL
== bundle
->_moduleCookie
&& (NULL
== bundle
->_imageCookie
|| globalSearch
)) {
3025 char hintBuff
[1026];
3026 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, bundle
, NULL
, NULL
);
3028 if (executableName
) {
3029 if (!CFStringGetCString(executableName
, hintBuff
, 1024, kCFStringEncodingUTF8
)) hintBuff
[0] = '\0';
3030 CFRelease(executableName
);
3032 if (NSIsSymbolNameDefinedWithHint(buff
, hintBuff
)) {
3033 symbol
= NSLookupAndBindSymbolWithHint(buff
, hintBuff
);
3037 result
= NSAddressOfSymbol(symbol
);
3040 CFLog(__kCFLogBundle
, CFSTR("dyld cannot find symbol %s in %@"), buff
, bundle
);
3047 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
) {
3048 uint32_t i
, j
, n
= _dyld_image_count();
3049 Boolean foundit
= false;
3051 CFStringRef result
= NULL
;
3052 for (i
= 0; !foundit
&& i
< n
; i
++) {
3053 // will need modification for 64-bit
3054 const struct mach_header
*mh
= _dyld_get_image_header(i
);
3055 uint32_t addr
= (uint32_t)p
- _dyld_get_image_vmaddr_slide(i
);
3057 struct load_command
*lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
3058 for (j
= 0; !foundit
&& j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
)) {
3059 if (LC_SEGMENT
== lc
->cmd
&& addr
>= ((struct segment_command
*)lc
)->vmaddr
&& addr
< ((struct segment_command
*)lc
)->vmaddr
+ ((struct segment_command
*)lc
)->vmsize
) {
3061 name
= _dyld_get_image_name(i
);
3063 result
= CFStringCreateWithCString(NULL
, name
, CFStringFileSystemEncoding());
3072 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint
) {
3073 uint32_t i
, numImages
= _dyld_image_count();
3074 CFMutableArrayRef result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3075 CFRange range
= CFRangeMake(0, CFStringGetLength(hint
));
3077 for (i
=0; i
<numImages
; i
++) {
3078 const char *curName
= _dyld_get_image_name(i
), *lastComponent
= NULL
;
3079 if (curName
!= NULL
) lastComponent
= strrchr(curName
, '/');
3080 if (lastComponent
!= NULL
) {
3081 CFStringRef str
= CFStringCreateWithCString(NULL
, lastComponent
+ 1, CFStringFileSystemEncoding());
3083 if (CFStringFindWithOptions(hint
, str
, range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
3084 CFStringRef curStr
= CFStringCreateWithCString(NULL
, curName
, CFStringFileSystemEncoding());
3085 if (curStr
!= NULL
) {
3086 CFArrayAppendValue(result
, curStr
);
3097 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
3098 // 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.
3099 static uint32_t _cachedDYLDImageCount
= -1;
3101 uint32_t i
, numImages
= _dyld_image_count();
3102 CFMutableArrayRef result
= NULL
;
3104 if (numImages
!= _cachedDYLDImageCount
) {
3105 const char *curName
;
3108 result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3110 for (i
=0; i
<numImages
; i
++) {
3111 curName
= _dyld_get_image_name(i
);
3112 if (curName
!= NULL
) {
3113 curStr
= CFStringCreateWithCString(NULL
, curName
, CFStringFileSystemEncoding());
3114 if (curStr
!= NULL
) {
3115 CFArrayAppendValue(result
, curStr
);
3120 _cachedDYLDImageCount
= numImages
;
3125 #endif /* BINARY_SUPPORT_DYLD */
3128 #if defined(BINARY_SUPPORT_DLL)
3130 __private_extern__ Boolean
_CFBundleDLLLoad(CFBundleRef bundle
) {
3132 if (!bundle
->_isLoaded
) {
3133 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3135 if (executableURL
) {
3136 char buff
[CFMaxPathSize
];
3138 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
3139 bundle
->_hModule
= LoadLibrary(buff
);
3140 if (bundle
->_hModule
== NULL
) {
3142 bundle
->_isLoaded
= true;
3145 CFRelease(executableURL
);
3147 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
3151 return bundle
->_isLoaded
;
3154 __private_extern__
void _CFBundleDLLUnload(CFBundleRef bundle
) {
3155 if (bundle
->_isLoaded
) {
3156 FreeLibrary(bundle
->_hModule
);
3157 bundle
->_hModule
= NULL
;
3158 bundle
->_isLoaded
= false;
3162 __private_extern__
void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
3163 void *result
= NULL
;
3166 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingWindowsLatin1
)) {
3167 result
= GetProcAddress(bundle
->_hModule
, buff
);
3172 #endif /* BINARY_SUPPORT_DLL */
3175 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
3177 extern void _CFStringSetCompatibility(CFOptionFlags
);
3179 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
) {