2 * Copyright (c) 2015 Apple 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@
25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
29 #include "CFBundle_Internal.h"
30 #include <CoreFoundation/CFPropertyList.h>
31 #include <CoreFoundation/CFNumber.h>
32 #include <CoreFoundation/CFSet.h>
33 #include <CoreFoundation/CFURLAccess.h>
34 #include <CoreFoundation/CFError.h>
36 #include <CoreFoundation/CFPriv.h>
37 #include "CFInternal.h"
38 #include <CoreFoundation/CFByteOrder.h>
39 #include "CFBundle_BinaryTypes.h"
44 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
46 #error Unknown deployment target
49 #define AVOID_WEAK_COLLECTIONS 1
51 #if !AVOID_WEAK_COLLECTIONS
52 #include "CFHashTable.h"
53 #include "CFMapTable.h"
54 #include "CFPointerArray.h"
55 #endif /* !AVOID_WEAK_COLLECTIONS */
57 #if defined(BINARY_SUPPORT_DYLD)
61 #include <crt_externs.h>
62 #endif /* BINARY_SUPPORT_DYLD */
64 #if defined(BINARY_SUPPORT_DLFCN)
66 #endif /* BINARY_SUPPORT_DLFCN */
68 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
70 #elif DEPLOYMENT_TARGET_WINDOWS
76 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle
, Boolean alreadyLocked
);
78 #define LOG_BUNDLE_LOAD 0
80 // Public CFBundle Info plist keys
81 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey
, "CFBundleInfoDictionaryVersion")
82 CONST_STRING_DECL(kCFBundleExecutableKey
, "CFBundleExecutable")
83 CONST_STRING_DECL(kCFBundleIdentifierKey
, "CFBundleIdentifier")
84 CONST_STRING_DECL(kCFBundleVersionKey
, "CFBundleVersion")
85 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey
, "CFBundleDevelopmentRegion")
86 CONST_STRING_DECL(kCFBundleLocalizationsKey
, "CFBundleLocalizations")
88 // Private CFBundle Info plist keys, possible candidates for public constants
89 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey
, "CFBundleAllowMixedLocalizations")
90 CONST_STRING_DECL(_kCFBundleSupportedPlatformsKey
, "CFBundleSupportedPlatforms")
91 CONST_STRING_DECL(_kCFBundleResourceSpecificationKey
, "CFBundleResourceSpecification")
94 CONST_STRING_DECL(_kCFBundlePackageTypeKey
, "CFBundlePackageType")
95 CONST_STRING_DECL(_kCFBundleSignatureKey
, "CFBundleSignature")
96 CONST_STRING_DECL(_kCFBundleIconFileKey
, "CFBundleIconFile")
97 CONST_STRING_DECL(_kCFBundleDocumentTypesKey
, "CFBundleDocumentTypes")
98 CONST_STRING_DECL(_kCFBundleURLTypesKey
, "CFBundleURLTypes")
100 // Keys that are usually localized in InfoPlist.strings
101 CONST_STRING_DECL(kCFBundleNameKey
, "CFBundleName")
102 CONST_STRING_DECL(_kCFBundleDisplayNameKey
, "CFBundleDisplayName")
103 CONST_STRING_DECL(_kCFBundleShortVersionStringKey
, "CFBundleShortVersionString")
104 CONST_STRING_DECL(_kCFBundleGetInfoStringKey
, "CFBundleGetInfoString")
105 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey
, "CFBundleGetInfoHTML")
107 // Sub-keys for CFBundleDocumentTypes dictionaries
108 CONST_STRING_DECL(_kCFBundleTypeNameKey
, "CFBundleTypeName")
109 CONST_STRING_DECL(_kCFBundleTypeRoleKey
, "CFBundleTypeRole")
110 CONST_STRING_DECL(_kCFBundleTypeIconFileKey
, "CFBundleTypeIconFile")
111 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey
, "CFBundleTypeOSTypes")
112 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey
, "CFBundleTypeExtensions")
113 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey
, "CFBundleTypeMIMETypes")
115 // Sub-keys for CFBundleURLTypes dictionaries
116 CONST_STRING_DECL(_kCFBundleURLNameKey
, "CFBundleURLName")
117 CONST_STRING_DECL(_kCFBundleURLIconFileKey
, "CFBundleURLIconFile")
118 CONST_STRING_DECL(_kCFBundleURLSchemesKey
, "CFBundleURLSchemes")
120 // Compatibility key names
121 CONST_STRING_DECL(_kCFBundleOldExecutableKey
, "NSExecutable")
122 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey
, "NSInfoPlistVersion")
123 CONST_STRING_DECL(_kCFBundleOldNameKey
, "NSHumanReadableName")
124 CONST_STRING_DECL(_kCFBundleOldIconFileKey
, "NSIcon")
125 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey
, "NSTypes")
126 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey
, "NSAppVersion")
128 // Compatibility CFBundleDocumentTypes key names
129 CONST_STRING_DECL(_kCFBundleOldTypeNameKey
, "NSName")
130 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey
, "NSRole")
131 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey
, "NSIcon")
132 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key
, "NSUnixExtensions")
133 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key
, "NSDOSExtensions")
134 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey
, "NSMacOSType")
136 // Internally used keys for loaded Info plists.
137 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey
, "CFBundleInfoPlistURL")
138 CONST_STRING_DECL(_kCFBundleRawInfoPlistURLKey
, "CFBundleRawInfoPlistURL")
139 CONST_STRING_DECL(_kCFBundleNumericVersionKey
, "CFBundleNumericVersion")
140 CONST_STRING_DECL(_kCFBundleExecutablePathKey
, "CFBundleExecutablePath")
141 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey
, "CSResourcesFileMapped")
142 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey
, "CFBundleCFMLoadAsBundle")
144 // Keys used by NSBundle for loaded Info plists.
145 CONST_STRING_DECL(_kCFBundlePrincipalClassKey
, "NSPrincipalClass")
147 static char __CFBundleMainID__
[1026] = {0};
148 CF_PRIVATE
char *__CFBundleMainID
= __CFBundleMainID__
;
150 static CFTypeID __kCFBundleTypeID
= _kCFRuntimeNotATypeID
;
152 static pthread_mutex_t CFBundleGlobalDataLock
= PTHREAD_MUTEX_INITIALIZER
;
154 static CFMutableDictionaryRef _bundlesByIdentifier
= NULL
;
155 #if AVOID_WEAK_COLLECTIONS
156 static CFMutableDictionaryRef _bundlesByURL
= NULL
;
157 static CFMutableArrayRef _allBundles
= NULL
;
158 static CFMutableSetRef _bundlesToUnload
= NULL
;
159 #else /* AVOID_WEAK_COLLECTIONS */
160 static __CFHashTable
*_allBundles
= nil
;
161 static __CFHashTable
*_bundlesToUnload
= nil
;
162 #endif /* AVOID_WEAK_COLLECTIONS */
163 static Boolean _scheduledBundlesAreUnloading
= false;
165 static Boolean _initedMainBundle
= false;
166 static CFBundleRef _mainBundle
= NULL
;
168 // Forward declares functions.
169 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
);
170 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
);
171 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
);
172 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
173 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
);
174 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
);
181 #if AVOID_WEAK_COLLECTIONS
183 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
184 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
186 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
188 // Add to the _allBundles list
190 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
191 nonRetainingArrayCallbacks
.retain
= NULL
;
192 nonRetainingArrayCallbacks
.release
= NULL
;
193 _allBundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
195 CFArrayAppendValue(_allBundles
, bundle
);
197 // Add to the table that maps urls to bundles
198 if (!_bundlesByURL
) {
199 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
200 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
201 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
202 _bundlesByURL
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
204 CFDictionarySetValue(_bundlesByURL
, bundle
->_url
, bundle
);
206 // Add to the table that maps identifiers to bundles
208 CFMutableArrayRef bundlesWithThisID
= NULL
;
209 CFBundleRef existingBundle
= NULL
;
210 if (!_bundlesByIdentifier
) {
211 _bundlesByIdentifier
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
213 bundlesWithThisID
= (CFMutableArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
214 if (bundlesWithThisID
) {
215 CFIndex i
, count
= CFArrayGetCount(bundlesWithThisID
);
216 UInt32 existingVersion
, newVersion
= CFBundleGetVersionNumber(bundle
);
217 for (i
= 0; i
< count
; i
++) {
218 existingBundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, i
);
219 existingVersion
= CFBundleGetVersionNumber(existingBundle
);
220 // If you load two bundles with the same identifier and the same version, the last one wins.
221 if (newVersion
>= existingVersion
) break;
223 CFArrayInsertValueAtIndex(bundlesWithThisID
, i
, bundle
);
225 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
226 nonRetainingArrayCallbacks
.retain
= NULL
;
227 nonRetainingArrayCallbacks
.release
= NULL
;
228 bundlesWithThisID
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
229 CFArrayAppendValue(bundlesWithThisID
, bundle
);
230 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundlesWithThisID
);
231 CFRelease(bundlesWithThisID
);
234 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
237 static void _CFBundleRemoveFromTables(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef bundleID
) {
238 pthread_mutex_lock(&CFBundleGlobalDataLock
);
239 // Remove from the various lists
241 CFIndex i
= CFArrayGetFirstIndexOfValue(_allBundles
, CFRangeMake(0, CFArrayGetCount(_allBundles
)), bundle
);
242 if (i
>= 0) CFArrayRemoveValueAtIndex(_allBundles
, i
);
245 // Remove from the table that maps urls to bundles
246 if (bundleURL
&& _bundlesByURL
) {
247 CFBundleRef bundleForURL
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, bundleURL
);
248 if (bundleForURL
== bundle
) CFDictionaryRemoveValue(_bundlesByURL
, bundleURL
);
251 // Remove from the table that maps identifiers to bundles
252 if (bundleID
&& _bundlesByIdentifier
) {
253 CFMutableArrayRef bundlesWithThisID
= (CFMutableArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
254 if (bundlesWithThisID
) {
255 CFIndex count
= CFArrayGetCount(bundlesWithThisID
);
256 while (count
-- > 0) if (bundle
== (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, count
)) CFArrayRemoveValueAtIndex(bundlesWithThisID
, count
);
257 if (0 == CFArrayGetCount(bundlesWithThisID
)) CFDictionaryRemoveValue(_bundlesByIdentifier
, bundleID
);
260 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
263 static CFBundleRef
_CFBundleCopyBundleForURL(CFURLRef url
, Boolean alreadyLocked
) {
264 CFBundleRef result
= NULL
;
265 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
266 if (_bundlesByURL
) result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, url
);
267 if (result
&& !result
->_url
) {
269 CFDictionaryRemoveValue(_bundlesByURL
, url
);
271 if (result
) CFRetain(result
);
272 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
276 static CFBundleRef
_CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID
) {
277 CFBundleRef result
= NULL
, bundle
;
278 if (_bundlesByIdentifier
&& bundleID
) {
279 // Note that this array is maintained in descending order by version number
280 CFArrayRef bundlesWithThisID
= (CFArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
281 if (bundlesWithThisID
) {
282 CFIndex i
, count
= CFArrayGetCount(bundlesWithThisID
);
284 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
285 for (i
= 0; !result
&& i
< count
; i
++) {
286 bundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, i
);
287 if (CFBundleIsExecutableLoaded(bundle
)) result
= bundle
;
289 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
290 if (!result
) result
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, 0);
297 #else /* AVOID_WEAK_COLLECTIONS */
300 An explanation of what I'm doing here is probably in order.
301 8029300 has cast suspicion on the correctness of __CFMapTable with strong keys and weak values, at least under non-GC.
302 An early attempt to work around it by inserting dummy values instead of removing things succeeded, as did turning on the AVOID_WEAK_COLLECTIONS #ifdef
303 This indicates that it's not an overrelease in securityd, since AVOID_WEAK_COLLECTIONS wouldn't help in that case.
304 Therefore, these functions following this comment allow us to have _bundlesByURL be a CFDictionary on non-GC and keep __CFMapTable to GC where it's needed.
306 static inline id
_getBundlesByURL() {
307 static id _bundles
= nil
;
308 static dispatch_once_t onceToken
;
309 dispatch_once(&onceToken
, ^{
310 if (CF_USING_COLLECTABLE_MEMORY
) {
311 _bundles
= [[__CFMapTable alloc
] initWithKeyOptions
:CFPointerFunctionsStrongMemory valueOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
313 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
314 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
315 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
316 _bundles
= (id
)CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
322 #define _bundlesByURL _getBundlesByURL()
324 static void _setInBundlesByURL(CFURLRef key
, CFBundleRef bundle
) {
325 if (CF_USING_COLLECTABLE_MEMORY
) {
326 [(__CFMapTable
*)_bundlesByURL setObject
:(id
)bundle forKey
:(id
)key
];
328 CFDictionarySetValue((CFMutableDictionaryRef
)_bundlesByURL
, key
, bundle
);
332 static void _removeFromBundlesByURL(CFURLRef key
) {
333 if (CF_USING_COLLECTABLE_MEMORY
) {
334 [(__CFMapTable
*)_bundlesByURL removeObjectForKey
:(id
)key
];
336 CFDictionaryRemoveValue((CFMutableDictionaryRef
)_bundlesByURL
, key
);
340 static CFBundleRef
_getFromBundlesByURL(CFURLRef key
) {
341 if (CF_USING_COLLECTABLE_MEMORY
) {
342 return (CFBundleRef
)[(__CFMapTable
*)_bundlesByURL objectForKey
:(id
)key
];
344 return (CFBundleRef
)CFDictionaryGetValue((CFMutableDictionaryRef
)_bundlesByURL
, key
);
348 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
349 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
351 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
353 // Add to the _allBundles list
354 if (!_allBundles
) _allBundles
= [[__CFHashTable alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
355 [_allBundles addObject
:(id
)bundle
];
357 // Add to the table that maps urls to bundles
358 _setInBundlesByURL(bundle
->_url
, bundle
);
360 // Add to the table that maps identifiers to bundles
362 __CFPointerArray
*bundlesWithThisID
= nil
;
363 CFBundleRef existingBundle
= NULL
;
364 if (!_bundlesByIdentifier
) {
365 _bundlesByIdentifier
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
367 bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
368 if (bundlesWithThisID
) {
369 CFIndex i
, count
= (CFIndex
)[bundlesWithThisID count
];
370 UInt32 existingVersion
, newVersion
= CFBundleGetVersionNumber(bundle
);
371 for (i
= 0; i
< count
; i
++) {
372 existingBundle
= (CFBundleRef
)[bundlesWithThisID pointerAtIndex
:i
];
373 if (!existingBundle
) continue;
374 existingVersion
= CFBundleGetVersionNumber(existingBundle
);
375 // If you load two bundles with the same identifier and the same version, the last one wins.
376 if (newVersion
>= existingVersion
) break;
379 [bundlesWithThisID insertPointer
:bundle atIndex
:i
];
381 [bundlesWithThisID addPointer
:bundle
];
384 bundlesWithThisID
= [[__CFPointerArray alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory
];
385 [bundlesWithThisID addPointer
:bundle
];
386 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundlesWithThisID
);
387 [bundlesWithThisID release
];
390 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
393 static void _CFBundleRemoveFromTables(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef bundleID
) {
394 pthread_mutex_lock(&CFBundleGlobalDataLock
);
395 // Remove from the various lists
396 if (_allBundles
&& [_allBundles member
:(id
)bundle
]) [_allBundles removeObject
:(id
)bundle
];
398 // Remove from the table that maps urls to bundles
400 _removeFromBundlesByURL(bundleURL
);
403 // Remove from the table that maps identifiers to bundles
404 if (bundleID
&& _bundlesByIdentifier
) {
405 __CFPointerArray
*bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
406 if (bundlesWithThisID
) {
407 CFIndex count
= (CFIndex
)[bundlesWithThisID count
];
408 while (count
-- > 0) if (bundle
== (CFBundleRef
)[bundlesWithThisID pointerAtIndex
:count
]) [bundlesWithThisID removePointerAtIndex
:count
];
409 [bundlesWithThisID compact
];
410 if (0 == [bundlesWithThisID count
]) CFDictionaryRemoveValue(_bundlesByIdentifier
, bundleID
);
413 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
416 static CFBundleRef
_CFBundleCopyBundleForURL(CFURLRef url
, Boolean alreadyLocked
) {
417 CFBundleRef result
= NULL
;
418 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
419 result
= _getFromBundlesByURL(url
);
420 if (result
&& !result
->_url
) {
422 _removeFromBundlesByURL(url
);
424 if (result
) CFRetain(result
);
425 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
429 static CFBundleRef
_CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID
) {
430 CFBundleRef result
= NULL
;
431 if (_bundlesByIdentifier
&& bundleID
) {
432 // Note that this array is maintained in descending order by version number
433 __CFPointerArray
*bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
434 if (bundlesWithThisID
&& [bundlesWithThisID count
] > 0) {
435 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
436 for (id bundle in bundlesWithThisID
) {
437 if (bundle
&& CFBundleIsExecutableLoaded((CFBundleRef
)bundle
)) {
438 result
= (CFBundleRef
)bundle
;
442 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
444 for (id bundle in bundlesWithThisID
) {
446 result
= (CFBundleRef
)bundle
;
456 #endif /* AVOID_WEAK_COLLECTIONS */
458 static CFURLRef
_CFBundleCopyBundleURLForExecutablePath(CFStringRef str
) {
459 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
460 UniChar buff
[CFMaxPathSize
];
465 buffLen
= CFStringGetLength(str
);
466 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
467 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
469 #if DEPLOYMENT_TARGET_WINDOWS
470 // Is this a .dll or .exe?
471 if (buffLen
>= 5 && (_wcsnicmp((wchar_t *)&(buff
[buffLen
-4]), L
".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff
[buffLen
-4]), L
".exe", 4) == 0)) {
472 CFIndex extensionLength
= CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension
);
474 // If this is an _debug, we should strip that before looking for the bundle
475 if (buffLen
>= 7 && (_wcsnicmp((wchar_t *)&buff
[buffLen
-6], L
"_debug", 6) == 0)) buffLen
-= 6;
477 if (buffLen
+ 1 + extensionLength
< CFMaxPathSize
) {
480 CFStringGetCharacters(_CFBundleWindowsResourceDirectoryExtension
, CFRangeMake(0, extensionLength
), buff
+ buffLen
);
481 buffLen
+= extensionLength
;
482 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
483 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
490 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
); // Remove exe name
493 // See if this is a new bundle. If it is, we have to remove more path components.
494 CFIndex startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
495 if (startOfLastDir
> 0 && startOfLastDir
< buffLen
) {
496 CFStringRef lastDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
498 if (CFEqual(lastDirName
, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
499 // This is a new bundle. Back off a few more levels
501 // Remove platform folder
502 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
505 // Remove executables folder (if present)
506 CFIndex startOfNextDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
507 if (startOfNextDir
> 0 && startOfNextDir
< buffLen
) {
508 CFStringRef nextDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfNextDir
]), buffLen
- startOfNextDir
);
509 if (CFEqual(nextDirName
, _CFBundleExecutablesDirectoryName
)) buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
510 CFRelease(nextDirName
);
514 // Remove support files folder
515 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
518 CFRelease(lastDirName
);
523 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
524 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
531 static CFURLRef
_CFBundleCopyResolvedURLForExecutableURL(CFURLRef url
) {
532 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
533 CFURLRef absoluteURL
, url1
, url2
, outURL
= NULL
;
534 CFStringRef str
, str1
, str2
;
535 absoluteURL
= CFURLCopyAbsoluteURL(url
);
536 str
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
538 UniChar buff
[CFMaxPathSize
];
539 CFIndex buffLen
= CFStringGetLength(str
), len1
;
540 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
541 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
542 len1
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
543 if (len1
> 0 && len1
+ 1 < buffLen
) {
544 str1
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, buff
, len1
);
545 CFIndex skipSlashCount
= 1;
546 #if DEPLOYMENT_TARGET_WINDOWS
547 // On Windows, _CFLengthAfterDeletingLastPathComponent will return a value of 3 if the path is at the root (e.g. C:\). This includes the \, which is not the case for URLs with subdirectories
548 if (len1
== 3 && buff
[1] == ':' && buff
[2] == '\\') {
552 str2
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, buff
+ len1
+ skipSlashCount
, buffLen
- len1
- skipSlashCount
);
554 url1
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str1
, PLATFORM_PATH_STYLE
, true);
556 url2
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, str2
, PLATFORM_PATH_STYLE
, false, url1
);
558 outURL
= CFURLCopyAbsoluteURL(url2
);
564 if (str1
) CFRelease(str1
);
565 if (str2
) CFRelease(str2
);
570 outURL
= absoluteURL
;
572 CFRelease(absoluteURL
);
577 CFURLRef
_CFBundleCopyBundleURLForExecutableURL(CFURLRef url
) {
578 CFURLRef resolvedURL
, outurl
= NULL
;
580 resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
581 str
= CFURLCopyFileSystemPath(resolvedURL
, PLATFORM_PATH_STYLE
);
583 outurl
= _CFBundleCopyBundleURLForExecutablePath(str
);
586 CFRelease(resolvedURL
);
590 static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle
) {
591 uint8_t localVersion
= bundle
->_version
;
592 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
593 if (0 == localVersion
) {
594 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
595 if (!infoDict
|| 0 == CFDictionaryGetCount(infoDict
)) {
596 #if defined(BINARY_SUPPORT_DYLD)
597 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
599 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
600 if (bundle
->_binaryType
== __CFBundleCFMBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
603 bundle
->_resourceData
._executableLacksResourceFork
= true;
605 CFRelease(executableURL
);
610 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
612 CFRelease(executableURL
);
616 #endif /* BINARY_SUPPORT_DYLD */
622 CFBundleRef
_CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
623 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
625 uint8_t localVersion
= _CFBundleEffectiveLayoutVersion(bundle
);
626 if (3 == localVersion
|| 4 == localVersion
) {
634 CF_EXPORT Boolean
_CFBundleURLLooksLikeBundle(CFURLRef url
) {
635 Boolean result
= false;
636 CFBundleRef bundle
= _CFBundleCreateIfLooksLikeBundle(kCFAllocatorSystemDefault
, url
);
644 CFBundleRef
_CFBundleGetMainBundleIfLooksLikeBundle(void) {
645 CFBundleRef mainBundle
= CFBundleGetMainBundle();
646 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
650 Boolean
_CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) {
651 CFBundleRef mainBundle
= CFBundleGetMainBundle();
652 return (mainBundle
&& mainBundle
->_resourceData
._infoDictionaryFromResourceFork
);
655 CFBundleRef
_CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
656 CFBundleRef bundle
= NULL
;
657 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
658 if (bundleURL
&& resolvedURL
) {
659 // We used to call _CFBundleCreateIfLooksLikeBundle here, but switched to the regular CFBundleCreate because we want this to return a result for certain flat bundles as well.
660 bundle
= CFBundleCreate(allocator
, bundleURL
);
662 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
663 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
664 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, (uint8_t *)buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
668 if (executableURL
) CFRelease(executableURL
);
671 if (bundleURL
) CFRelease(bundleURL
);
672 if (resolvedURL
) CFRelease(resolvedURL
);
676 CFBundleRef
_CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
677 // This function is obsolete
678 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
682 CFBundleRef
_CFBundleCreateWithExecutableURLIfMightBeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
683 CFBundleRef result
= _CFBundleCreateWithExecutableURLIfLooksLikeBundle(allocator
, url
);
685 // This function applies additional requirements on a bundle to return a result
686 // The above makes sure that:
687 // 0. CFBundleCreate must succeed using a URL derived from the executable URL
688 // 1. The bundle must have an executableURL, and it must match the passed in executable URL
690 // This function additionally requires that
691 // 2. If flat, the bundle must have a non-empty Info.plist. (15663535)
693 uint8_t localVersion
= _CFBundleEffectiveLayoutVersion(result
);
694 if (3 == localVersion
|| 4 == localVersion
) {
695 CFDictionaryRef infoPlist
= CFBundleGetInfoDictionary(result
);
696 if (!infoPlist
|| (infoPlist
&& CFDictionaryGetCount(infoPlist
) == 0)) {
705 CFURLRef
_CFBundleCopyMainBundleExecutableURL(Boolean
*looksLikeBundle
) {
706 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
707 const char *processPath
;
708 CFStringRef str
= NULL
;
709 CFURLRef executableURL
= NULL
;
710 processPath
= _CFProcessPath();
712 str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, processPath
);
714 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, PLATFORM_PATH_STYLE
, false);
718 if (looksLikeBundle
) {
719 CFBundleRef mainBundle
= _mainBundle
;
720 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
721 *looksLikeBundle
= (mainBundle
? true : false);
723 return executableURL
;
726 static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef executablePath
) {
727 CFBundleGetInfoDictionary(_mainBundle
);
728 if (!_mainBundle
->_infoDict
|| CFDictionaryGetCount(_mainBundle
->_infoDict
) == 0) {
729 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
730 if (_mainBundle
->_version
== 3) _mainBundle
->_version
= 4;
731 if (_mainBundle
->_version
== 0) {
732 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
733 CFStringRef executableName
= _CFBundleCopyExecutableName(_mainBundle
, NULL
, NULL
);
734 if (!executableName
|| !executablePath
|| !CFStringHasSuffix(executablePath
, executableName
)) _mainBundle
->_version
= 4;
735 if (executableName
) CFRelease(executableName
);
737 #if defined(BINARY_SUPPORT_DYLD)
738 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
739 if (_mainBundle
->_infoDict
&& !(0)) CFRelease(_mainBundle
->_infoDict
);
740 _mainBundle
->_infoDict
= (CFDictionaryRef
)_CFBundleCreateInfoDictFromMainExecutable();
742 #endif /* BINARY_SUPPORT_DYLD */
744 #if defined(BINARY_SUPPORT_DYLD)
745 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
746 // if dyld and not main executable for bundle, prefer info dictionary from executable
747 CFStringRef executableName
= _CFBundleCopyExecutableName(_mainBundle
, NULL
, NULL
);
748 if (!executableName
|| !executablePath
|| !CFStringHasSuffix(executablePath
, executableName
)) {
749 CFDictionaryRef infoDictFromExecutable
= (CFDictionaryRef
)_CFBundleCreateInfoDictFromMainExecutable();
750 if (infoDictFromExecutable
&& CFDictionaryGetCount(infoDictFromExecutable
) > 0) {
751 if (_mainBundle
->_infoDict
) CFRelease(_mainBundle
->_infoDict
);
752 _mainBundle
->_infoDict
= infoDictFromExecutable
;
753 } else if (infoDictFromExecutable
) {
754 CFRelease(infoDictFromExecutable
);
757 if (executableName
) CFRelease(executableName
);
759 #endif /* BINARY_SUPPORT_DYLD */
761 if (!_mainBundle
->_infoDict
) _mainBundle
->_infoDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
762 if (!_mainBundle
->_executablePath
&& executablePath
) _mainBundle
->_executablePath
= (CFStringRef
)CFRetain(executablePath
);
763 CFStringRef bundleID
= (CFStringRef
)CFDictionaryGetValue(_mainBundle
->_infoDict
, kCFBundleIdentifierKey
);
765 if (!CFStringGetCString(bundleID
, __CFBundleMainID__
, sizeof(__CFBundleMainID__
) - 2, kCFStringEncodingUTF8
)) {
766 __CFBundleMainID__
[0] = '\0';
771 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle
, Boolean alreadyLocked
) {
772 CFDictionaryRef oldInfoDict
= bundle
->_infoDict
;
775 bundle
->_infoDict
= NULL
;
776 if (bundle
->_localInfoDict
) {
777 CFRelease(bundle
->_localInfoDict
);
778 bundle
->_localInfoDict
= NULL
;
780 if (bundle
->_developmentRegion
) {
781 CFRelease(bundle
->_developmentRegion
);
782 bundle
->_developmentRegion
= NULL
;
784 if (bundle
->_executablePath
) {
785 CFRelease(bundle
->_executablePath
);
786 bundle
->_executablePath
= NULL
;
788 if (bundle
->_searchLanguages
) {
789 CFRelease(bundle
->_searchLanguages
);
790 bundle
->_searchLanguages
= NULL
;
792 if (bundle
->_stringTable
) {
793 CFRelease(bundle
->_stringTable
);
794 bundle
->_stringTable
= NULL
;
796 if (bundle
== _mainBundle
) {
797 CFStringRef executablePath
= bundle
->_executablePath
;
798 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
799 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath
);
800 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
802 CFBundleGetInfoDictionary(bundle
);
805 if (!bundle
->_infoDict
) bundle
->_infoDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
806 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundlePrincipalClassKey
);
807 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundlePrincipalClassKey
, val
);
808 CFRelease(oldInfoDict
);
811 _CFBundleFlushQueryTableCache(bundle
);
814 CF_EXPORT
void _CFBundleFlushBundleCaches(CFBundleRef bundle
) {
815 _CFBundleFlushBundleCachesAlreadyLocked(bundle
, false);
818 static CFBundleRef
_CFBundleGetMainBundleAlreadyLocked(void) {
819 if (!_initedMainBundle
) {
820 const char *processPath
;
821 CFStringRef str
= NULL
;
822 CFURLRef executableURL
= NULL
, bundleURL
= NULL
;
823 _initedMainBundle
= true;
824 processPath
= _CFProcessPath();
826 str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, processPath
);
827 if (!executableURL
) executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, PLATFORM_PATH_STYLE
, false);
829 if (executableURL
) bundleURL
= _CFBundleCopyBundleURLForExecutableURL(executableURL
);
831 // make sure that main bundle has executable path
832 //??? what if we are not the main executable in the bundle?
833 // NB doFinalProcessing must be false here, see below
834 _mainBundle
= _CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
, true, false);
836 // make sure that the main bundle is listed as loaded, and mark it as executable
837 _mainBundle
->_isLoaded
= true;
838 #if defined(BINARY_SUPPORT_DYLD)
839 if (_mainBundle
->_binaryType
== __CFBundleUnknownBinary
) {
840 if (!executableURL
) {
841 _mainBundle
->_binaryType
= __CFBundleNoBinary
;
843 _mainBundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
844 if (_mainBundle
->_binaryType
!= __CFBundleCFMBinary
&& _mainBundle
->_binaryType
!= __CFBundleUnreadableBinary
) _mainBundle
->_resourceData
._executableLacksResourceFork
= true;
847 #endif /* BINARY_SUPPORT_DYLD */
848 // get cookie for already-loaded main bundle
849 #if defined(BINARY_SUPPORT_DLFCN)
850 if (!_mainBundle
->_handleCookie
) {
851 _mainBundle
->_handleCookie
= dlopen(NULL
, RTLD_NOLOAD
| RTLD_FIRST
);
853 printf("main bundle %p getting handle %p\n", _mainBundle
, _mainBundle
->_handleCookie
);
854 #endif /* LOG_BUNDLE_LOAD */
856 #elif defined(BINARY_SUPPORT_DYLD)
857 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
&& !_mainBundle
->_imageCookie
) {
858 _mainBundle
->_imageCookie
= (void *)_dyld_get_image_header(0);
860 printf("main bundle %p getting image %p\n", _mainBundle
, _mainBundle
->_imageCookie
);
861 #endif /* LOG_BUNDLE_LOAD */
863 #endif /* BINARY_SUPPORT_DLFCN */
864 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str
);
865 // Perform delayed final processing steps.
866 // This must be done after _isLoaded has been set, for security reasons (3624341).
867 if (_CFBundleNeedsInitPlugIn(_mainBundle
)) {
868 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
869 _CFBundleInitPlugIn(_mainBundle
);
870 pthread_mutex_lock(&CFBundleGlobalDataLock
);
874 if (bundleURL
) CFRelease(bundleURL
);
875 if (str
) CFRelease(str
);
876 if (executableURL
) CFRelease(executableURL
);
881 CFBundleRef
CFBundleGetMainBundle(void) {
882 CFBundleRef mainBundle
;
883 pthread_mutex_lock(&CFBundleGlobalDataLock
);
884 mainBundle
= _CFBundleGetMainBundleAlreadyLocked();
885 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
889 CFBundleRef
CFBundleGetBundleWithIdentifier(CFStringRef bundleID
) {
890 CFBundleRef result
= NULL
;
892 pthread_mutex_lock(&CFBundleGlobalDataLock
);
893 (void)_CFBundleGetMainBundleAlreadyLocked();
894 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
895 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
897 // Try to create the bundle for the caller and try again
898 void *p
= __builtin_return_address(0);
900 CFStringRef imagePath
= _CFBundleCopyLoadedImagePathForPointer(p
);
902 _CFBundleEnsureBundleExistsForImagePath(imagePath
);
903 CFRelease(imagePath
);
905 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
910 // Try to guess the bundle from the identifier and try again
911 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID
);
912 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
915 // Make sure all bundles have been created and try again.
916 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
917 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
919 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
924 static CFStringRef
__CFBundleCopyDescription(CFTypeRef cf
) {
925 char buff
[CFMaxPathSize
];
926 CFStringRef path
= NULL
, binaryType
= NULL
, retval
= NULL
;
927 if (((CFBundleRef
)cf
)->_url
&& CFURLGetFileSystemRepresentation(((CFBundleRef
)cf
)->_url
, true, (uint8_t *)buff
, CFMaxPathSize
)) path
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
928 switch (((CFBundleRef
)cf
)->_binaryType
) {
929 case __CFBundleCFMBinary
:
930 binaryType
= CFSTR("");
932 case __CFBundleDYLDExecutableBinary
:
933 binaryType
= CFSTR("executable, ");
935 case __CFBundleDYLDBundleBinary
:
936 binaryType
= CFSTR("bundle, ");
938 case __CFBundleDYLDFrameworkBinary
:
939 binaryType
= CFSTR("framework, ");
941 case __CFBundleDLLBinary
:
942 binaryType
= CFSTR("DLL, ");
944 case __CFBundleUnreadableBinary
:
945 binaryType
= CFSTR("");
948 binaryType
= CFSTR("");
951 if (((CFBundleRef
)cf
)->_plugInData
._isPlugIn
) {
952 retval
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("CFBundle/CFPlugIn %p <%@> (%@%@loaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? CFSTR("") : CFSTR("not "));
954 retval
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("CFBundle %p <%@> (%@%@loaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? CFSTR("") : CFSTR("not "));
956 if (path
) CFRelease(path
);
960 static void _CFBundleDeallocateGlue(const void *key
, const void *value
, void *context
) {
961 CFAllocatorRef allocator
= (CFAllocatorRef
)context
;
962 if (value
) CFAllocatorDeallocate(allocator
, (void *)value
);
965 static void __CFBundleDeallocate(CFTypeRef cf
) {
966 CFBundleRef bundle
= (CFBundleRef
)cf
;
968 CFStringRef bundleID
= NULL
;
970 __CFGenericValidateType(cf
, CFBundleGetTypeID());
971 bundleURL
= bundle
->_url
;
973 if (bundle
->_infoDict
) bundleID
= (CFStringRef
)CFDictionaryGetValue(bundle
->_infoDict
, kCFBundleIdentifierKey
);
974 _CFBundleRemoveFromTables(bundle
, bundleURL
, bundleID
);
975 CFBundleUnloadExecutable(bundle
);
976 _CFBundleDeallocatePlugIn(bundle
);
978 CFRelease(bundleURL
);
980 if (bundle
->_infoDict
&& !(0)) CFRelease(bundle
->_infoDict
);
981 if (bundle
->_modDate
) CFRelease(bundle
->_modDate
);
982 if (bundle
->_localInfoDict
&& !(0)) CFRelease(bundle
->_localInfoDict
);
983 if (bundle
->_searchLanguages
) CFRelease(bundle
->_searchLanguages
);
984 if (bundle
->_executablePath
) CFRelease(bundle
->_executablePath
);
985 if (bundle
->_developmentRegion
) CFRelease(bundle
->_developmentRegion
);
986 if (bundle
->_glueDict
) {
987 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
988 CFRelease(bundle
->_glueDict
);
990 if (bundle
->_stringTable
) CFRelease(bundle
->_stringTable
);
992 if (bundle
->_bundleBasePath
) CFRelease(bundle
->_bundleBasePath
);
993 if (bundle
->_queryTable
) CFRelease(bundle
->_queryTable
);
995 if (bundle
->_localizations
) CFRelease(bundle
->_localizations
);
996 if (bundle
->_resourceDirectoryContents
) CFRelease(bundle
->_resourceDirectoryContents
);
998 pthread_mutex_destroy(&(bundle
->_bundleLoadingLock
));
1001 static const CFRuntimeClass __CFBundleClass
= {
1002 _kCFRuntimeScannedObject
,
1006 __CFBundleDeallocate
,
1010 __CFBundleCopyDescription
1013 // From CFBundle_Resources.c
1014 CF_PRIVATE
void _CFBundleResourcesInitialize();
1016 CFTypeID
CFBundleGetTypeID(void) {
1017 static dispatch_once_t initOnce
;
1018 dispatch_once(&initOnce
, ^{ __kCFBundleTypeID
= _CFRuntimeRegisterClass(&__CFBundleClass
); _CFBundleResourcesInitialize(); });
1019 return __kCFBundleTypeID
;
1022 CFBundleRef
_CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL
) {
1023 CFBundleRef bundle
= NULL
;
1024 char buff
[CFMaxPathSize
];
1025 CFURLRef newURL
= NULL
;
1027 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) return NULL
;
1029 newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)buff
, strlen(buff
), true);
1030 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1031 bundle
= _CFBundleCopyBundleForURL(newURL
, false);
1032 if (bundle
) CFRelease(bundle
);
1037 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
) {
1038 CFBundleRef bundle
= NULL
;
1039 char buff
[CFMaxPathSize
];
1040 CFDateRef modDate
= NULL
; // do not actually fetch the modDate, since that can cause something like 7609956, unless absolutely found to be necessary in the future
1041 Boolean exists
= false;
1043 CFURLRef newURL
= NULL
;
1044 uint8_t localVersion
= 0;
1046 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) return NULL
;
1048 newURL
= CFURLCreateFromFileSystemRepresentation(allocator
, (uint8_t *)buff
, strlen(buff
), true);
1049 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1050 bundle
= _CFBundleCopyBundleForURL(newURL
, alreadyLocked
);
1056 localVersion
= _CFBundleGetBundleVersionForURL(newURL
);
1057 if (localVersion
== 3) {
1058 SInt32 res
= _CFGetPathProperties(allocator
, (char *)buff
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
);
1059 #if DEPLOYMENT_TARGET_WINDOWS
1060 if (!(res
== 0 && exists
&& ((mode
& S_IFMT
) == S_IFDIR
))) {
1061 // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again
1066 CFURLRef shorterPath
= CFURLCreateCopyDeletingLastPathComponent(allocator
, newURL
);
1068 newURL
= shorterPath
;
1069 res
= _CFGetFileProperties(allocator
, newURL
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
);
1073 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
1074 if (modDate
) CFRelease(modDate
);
1084 bundle
= (CFBundleRef
)_CFRuntimeCreateInstance(allocator
, CFBundleGetTypeID(), sizeof(struct __CFBundle
) - sizeof(CFRuntimeBase
), NULL
);
1090 bundle
->_url
= newURL
;
1092 bundle
->_modDate
= modDate
;
1093 bundle
->_version
= localVersion
;
1094 bundle
->_infoDict
= NULL
;
1095 bundle
->_localInfoDict
= NULL
;
1096 bundle
->_searchLanguages
= NULL
;
1097 bundle
->_executablePath
= NULL
;
1098 bundle
->_developmentRegion
= NULL
;
1099 bundle
->_developmentRegionCalculated
= 0;
1100 #if defined(BINARY_SUPPORT_DYLD)
1101 /* We'll have to figure it out later */
1102 bundle
->_binaryType
= __CFBundleUnknownBinary
;
1103 #elif defined(BINARY_SUPPORT_DLL)
1104 /* We support DLL only */
1105 bundle
->_binaryType
= __CFBundleDLLBinary
;
1106 bundle
->_hModule
= NULL
;
1108 /* We'll have to figure it out later */
1109 bundle
->_binaryType
= __CFBundleUnknownBinary
;
1110 #endif /* BINARY_SUPPORT_DYLD */
1112 bundle
->_isLoaded
= false;
1113 bundle
->_sharesStringsFiles
= false;
1115 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1116 if (!__CFgetenv("CFBundleDisableStringsSharing") &&
1117 (strncmp(buff
, "/System/Library/Frameworks", 26) == 0) &&
1118 (strncmp(buff
+ strlen(buff
) - 10, ".framework", 10) == 0)) bundle
->_sharesStringsFiles
= true;
1121 bundle
->_connectionCookie
= NULL
;
1122 bundle
->_handleCookie
= NULL
;
1123 bundle
->_imageCookie
= NULL
;
1124 bundle
->_moduleCookie
= NULL
;
1126 bundle
->_glueDict
= NULL
;
1128 bundle
->_resourceData
._executableLacksResourceFork
= false;
1129 bundle
->_resourceData
._infoDictionaryFromResourceFork
= false;
1131 bundle
->_stringTable
= NULL
;
1133 bundle
->_plugInData
._isPlugIn
= false;
1134 bundle
->_plugInData
._loadOnDemand
= false;
1135 bundle
->_plugInData
._isDoingDynamicRegistration
= false;
1136 bundle
->_plugInData
._instanceCount
= 0;
1137 bundle
->_plugInData
._factories
= NULL
;
1139 pthread_mutexattr_t mattr
;
1140 pthread_mutexattr_init(&mattr
);
1141 pthread_mutexattr_settype(&mattr
, PTHREAD_MUTEX_DEFAULT
);
1142 int32_t mret
= pthread_mutex_init(&(bundle
->_bundleLoadingLock
), &mattr
);
1143 pthread_mutexattr_destroy(&mattr
);
1145 CFLog(4, CFSTR("%s: failed to initialize bundle loading lock for bundle %@."), __PRETTY_FUNCTION__
, bundle
);
1148 bundle
->_lock
= CFLockInit
;
1149 bundle
->_resourceDirectoryContents
= NULL
;
1151 bundle
->_localizations
= NULL
;
1152 bundle
->_lookedForLocalizations
= false;
1154 bundle
->_queryLock
= CFLockInit
;
1155 bundle
->_queryTable
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1156 CFURLRef absoURL
= CFURLCopyAbsoluteURL(bundle
->_url
);
1157 bundle
->_bundleBasePath
= CFURLCopyFileSystemPath(absoURL
, PLATFORM_PATH_STYLE
);
1160 CFBundleGetInfoDictionary(bundle
);
1162 // Do this so that we can use the dispatch_once on the ivar of this bundle safely
1165 _CFBundleAddToTables(bundle
, alreadyLocked
);
1167 if (doFinalProcessing
) {
1168 if (_CFBundleNeedsInitPlugIn(bundle
)) {
1169 if (alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
1170 _CFBundleInitPlugIn(bundle
);
1171 if (alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
1178 CFBundleRef
CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
) {
1179 return _CFBundleCreate(allocator
, bundleURL
, false, true);
1182 CFArrayRef
CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc
, CFURLRef directoryURL
, CFStringRef bundleType
) {
1183 CFMutableArrayRef bundles
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
1184 CFArrayRef URLs
= _CFCreateContentsOfDirectory(alloc
, NULL
, NULL
, directoryURL
, bundleType
);
1186 CFIndex i
, c
= CFArrayGetCount(URLs
);
1188 CFBundleRef curBundle
;
1190 for (i
= 0; i
< c
; i
++) {
1191 curURL
= (CFURLRef
)CFArrayGetValueAtIndex(URLs
, i
);
1192 curBundle
= CFBundleCreate(alloc
, curURL
);
1193 if (curBundle
) CFArrayAppendValue(bundles
, curBundle
);
1201 CFURLRef
CFBundleCopyBundleURL(CFBundleRef bundle
) {
1202 if (bundle
->_url
) CFRetain(bundle
->_url
);
1203 return bundle
->_url
;
1206 #define DEVELOPMENT_STAGE 0x20
1207 #define ALPHA_STAGE 0x40
1208 #define BETA_STAGE 0x60
1209 #define RELEASE_STAGE 0x80
1211 #define MAX_VERS_LEN 10
1213 CF_INLINE Boolean
_isDigit(UniChar aChar
) {return ((aChar
>= (UniChar
)'0' && aChar
<= (UniChar
)'9') ? true : false);}
1215 CF_PRIVATE CFStringRef
_CFCreateStringFromVersionNumber(CFAllocatorRef alloc
, UInt32 vers
) {
1216 CFStringRef result
= NULL
;
1217 uint8_t major1
, major2
, minor1
, minor2
, stage
, build
;
1219 major1
= (vers
& 0xF0000000) >> 28;
1220 major2
= (vers
& 0x0F000000) >> 24;
1221 minor1
= (vers
& 0x00F00000) >> 20;
1222 minor2
= (vers
& 0x000F0000) >> 16;
1223 stage
= (vers
& 0x0000FF00) >> 8;
1224 build
= (vers
& 0x000000FF);
1226 if (stage
== RELEASE_STAGE
) {
1228 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d"), major1
, major2
, minor1
, minor2
);
1230 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d"), major2
, minor1
, minor2
);
1234 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d%c%d"), major1
, major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? 'd' : ((stage
== ALPHA_STAGE
) ? 'a' : 'b')), build
);
1236 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d%c%d"), major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? 'd' : ((stage
== ALPHA_STAGE
) ? 'a' : 'b')), build
);
1242 CF_PRIVATE UInt32
_CFVersionNumberFromString(CFStringRef versStr
) {
1243 // Parse version number from string.
1244 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1245 UInt32 major1
= 0, major2
= 0, minor1
= 0, minor2
= 0, stage
= RELEASE_STAGE
, build
= 0;
1246 UniChar versChars
[MAX_VERS_LEN
];
1247 UniChar
*chars
= NULL
;
1250 Boolean digitsDone
= false;
1252 if (!versStr
) return 0;
1253 len
= CFStringGetLength(versStr
);
1254 if (len
<= 0 || len
> MAX_VERS_LEN
) return 0;
1256 CFStringGetCharacters(versStr
, CFRangeMake(0, len
), versChars
);
1259 // Get major version number.
1260 major1
= major2
= 0;
1261 if (_isDigit(*chars
)) {
1262 major2
= *chars
- (UniChar
)'0';
1266 if (_isDigit(*chars
)) {
1268 major2
= *chars
- (UniChar
)'0';
1272 if (*chars
== (UniChar
)'.') {
1279 } else if (*chars
== (UniChar
)'.') {
1286 } else if (*chars
== (UniChar
)'.') {
1293 // Now major1 and major2 contain first and second digit of the major version number as ints.
1294 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1296 // Get the first minor version number.
1297 if (len
> 0 && !digitsDone
) {
1298 if (_isDigit(*chars
)) {
1299 minor1
= *chars
- (UniChar
)'0';
1303 if (*chars
== (UniChar
)'.') {
1315 // Now minor1 contains the first minor version number as an int.
1316 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1318 // Get the second minor version number.
1319 if (len
> 0 && !digitsDone
) {
1320 if (_isDigit(*chars
)) {
1321 minor2
= *chars
- (UniChar
)'0';
1329 // Now minor2 contains the second minor version number as an int.
1330 // Now either len is 0 or chars points at the build stage letter.
1332 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1334 if (*chars
== (UniChar
)'d') {
1335 stage
= DEVELOPMENT_STAGE
;
1336 } else if (*chars
== (UniChar
)'a') {
1337 stage
= ALPHA_STAGE
;
1338 } else if (*chars
== (UniChar
)'b') {
1340 } else if (*chars
== (UniChar
)'f') {
1341 stage
= RELEASE_STAGE
;
1349 // Now stage contains the release stage.
1350 // Now either len is 0 or chars points at the build number.
1352 // Get the first digit of the build number.
1354 if (_isDigit(*chars
)) {
1355 build
= *chars
- (UniChar
)'0';
1362 // Get the second digit of the build number.
1364 if (_isDigit(*chars
)) {
1366 build
+= *chars
- (UniChar
)'0';
1373 // Get the third digit of the build number.
1375 if (_isDigit(*chars
)) {
1377 build
+= *chars
- (UniChar
)'0';
1385 // Range check the build number and make sure we exhausted the string.
1386 if (build
> 0xFF || len
> 0) return 0;
1389 theVers
= major1
<< 28;
1390 theVers
+= major2
<< 24;
1391 theVers
+= minor1
<< 20;
1392 theVers
+= minor2
<< 16;
1393 theVers
+= stage
<< 8;
1399 UInt32
CFBundleGetVersionNumber(CFBundleRef bundle
) {
1400 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1401 CFNumberRef versionValue
= (CFNumberRef
)CFDictionaryGetValue(infoDict
, _kCFBundleNumericVersionKey
);
1402 if (!versionValue
|| CFGetTypeID(versionValue
) != CFNumberGetTypeID()) return 0;
1405 CFNumberGetValue(versionValue
, kCFNumberSInt32Type
, &vers
);
1409 CFStringRef
CFBundleGetDevelopmentRegion(CFBundleRef bundle
) {
1410 dispatch_once(&bundle
->_developmentRegionCalculated
, ^{
1411 CFStringRef devRegion
= NULL
;
1412 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1414 devRegion
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1415 if (devRegion
&& (CFGetTypeID(devRegion
) != CFStringGetTypeID() || CFStringGetLength(devRegion
) == 0)) {
1420 if (devRegion
) bundle
->_developmentRegion
= (CFStringRef
)CFRetain(devRegion
);
1422 return bundle
->_developmentRegion
;
1425 Boolean
_CFBundleGetHasChanged(CFBundleRef bundle
) {
1427 Boolean result
= false;
1428 Boolean exists
= false;
1431 if (_CFGetFileProperties(CFGetAllocator(bundle
), bundle
->_url
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
1432 // If the bundle no longer exists or is not a folder, it must have "changed"
1433 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) result
= true;
1435 // Something is wrong. The stat failed.
1438 if (bundle
->_modDate
&& !CFEqual(bundle
->_modDate
, modDate
)) {
1439 // mod date is different from when we created.
1446 void _CFBundleSetStringsFilesShared(CFBundleRef bundle
, Boolean flag
) {
1447 bundle
->_sharesStringsFiles
= flag
;
1450 Boolean
_CFBundleGetStringsFilesShared(CFBundleRef bundle
) {
1451 return bundle
->_sharesStringsFiles
;
1454 static Boolean
_urlExists(CFURLRef url
) {
1456 return url
&& (0 == _CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, NULL
, NULL
, NULL
, NULL
, NULL
)) && exists
;
1459 // This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their
1460 // original locations on disk, so checking whether a binary's path exists is no longer sufficient.
1461 // For performance reasons, we only call dlopen_preflight() after we've verified that the binary
1462 // does not exist at its original path with _urlExists().
1463 // See <rdar://problem/6956670>
1464 static Boolean
_binaryLoadable(CFURLRef url
) {
1465 Boolean loadable
= _urlExists(url
);
1466 #if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1468 uint8_t path
[PATH_MAX
];
1469 if (url
&& CFURLGetFileSystemRepresentation(url
, true, path
, sizeof(path
))) {
1470 loadable
= dlopen_preflight((char *)path
);
1477 CF_PRIVATE CFURLRef
_CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1478 CFURLRef result
= NULL
;
1481 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase1
, bundleURL
);
1482 } else if (2 == version
) {
1483 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase2
, bundleURL
);
1485 result
= (CFURLRef
)CFRetain(bundleURL
);
1491 CF_EXPORT CFURLRef
CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle
) {
1492 return _CFBundleCopySupportFilesDirectoryURLInDirectory(bundle
->_url
, bundle
->_version
);
1495 CF_PRIVATE CFURLRef
_CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1496 CFURLRef result
= NULL
;
1499 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase0
, bundleURL
);
1500 } else if (1 == version
) {
1501 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase1
, bundleURL
);
1502 } else if (2 == version
) {
1503 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase2
, bundleURL
);
1505 result
= (CFURLRef
)CFRetain(bundleURL
);
1511 CF_EXPORT CFURLRef
CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle
) {
1512 return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle
->_url
, bundle
->_version
);
1515 CF_PRIVATE CFURLRef
_CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1516 CFURLRef result
= NULL
;
1519 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase0
, bundleURL
);
1520 } else if (1 == version
) {
1521 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase1
, bundleURL
);
1522 } else if (2 == version
) {
1523 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase2
, bundleURL
);
1529 CFURLRef
_CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle
) {
1530 return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle
->_url
, bundle
->_version
);
1533 static CFURLRef
_CFBundleCopyExecutableURLRaw(CFURLRef urlPath
, CFStringRef exeName
) {
1534 // 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.
1535 CFURLRef executableURL
= NULL
;
1536 if (!urlPath
|| !exeName
) return NULL
;
1538 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1539 const uint8_t *image_suffix
= (uint8_t *)__CFgetenv("DYLD_IMAGE_SUFFIX");
1541 CFStringRef newExeName
, imageSuffix
;
1542 imageSuffix
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, (char *)image_suffix
, kCFStringEncodingUTF8
);
1543 if (CFStringHasSuffix(exeName
, CFSTR(".dylib"))) {
1544 CFStringRef bareExeName
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, exeName
, CFRangeMake(0, CFStringGetLength(exeName
)-6));
1545 newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@.dylib"), exeName
, imageSuffix
);
1546 CFRelease(bareExeName
);
1548 newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, imageSuffix
);
1550 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, newExeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1551 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1552 CFRelease(executableURL
);
1553 executableURL
= NULL
;
1555 CFRelease(newExeName
);
1556 CFRelease(imageSuffix
);
1558 if (!executableURL
) {
1559 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, exeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1560 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1561 CFRelease(executableURL
);
1562 executableURL
= NULL
;
1565 #elif DEPLOYMENT_TARGET_WINDOWS
1566 if (!executableURL
) {
1567 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, exeName
, kCFURLWindowsPathStyle
, false, urlPath
);
1568 if (executableURL
&& !_urlExists(executableURL
)) {
1569 CFRelease(executableURL
);
1570 executableURL
= NULL
;
1573 if (!executableURL
) {
1574 if (!CFStringFindWithOptions(exeName
, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName
)), kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
1576 CFStringRef extension
= CFSTR("_debug.dll");
1578 CFStringRef extension
= CFSTR(".dll");
1580 CFStringRef newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, extension
);
1581 executableURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, newExeName
, urlPath
);
1582 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1583 CFRelease(executableURL
);
1584 executableURL
= NULL
;
1586 CFRelease(newExeName
);
1589 if (!executableURL
) {
1590 if (!CFStringFindWithOptions(exeName
, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName
)), kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
1592 CFStringRef extension
= CFSTR("_debug.exe");
1594 CFStringRef extension
= CFSTR(".exe");
1596 CFStringRef newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, extension
);
1597 executableURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, newExeName
, urlPath
);
1598 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1599 CFRelease(executableURL
);
1600 executableURL
= NULL
;
1602 CFRelease(newExeName
);
1606 return executableURL
;
1609 CF_PRIVATE CFStringRef
_CFBundleCopyExecutableName(CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
) {
1610 CFStringRef executableName
= NULL
;
1612 if (!infoDict
&& bundle
) infoDict
= CFBundleGetInfoDictionary(bundle
);
1613 if (!url
&& bundle
) url
= bundle
->_url
;
1616 // Figure out the name of the executable.
1617 // First try for the new key in the plist.
1618 executableName
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
);
1619 // Second try for the old key in the plist.
1620 if (!executableName
) executableName
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleOldExecutableKey
);
1621 if (executableName
&& CFGetTypeID(executableName
) == CFStringGetTypeID() && CFStringGetLength(executableName
) > 0) {
1622 CFRetain(executableName
);
1624 executableName
= NULL
;
1627 if (!executableName
&& url
) {
1628 // Third, take the name of the bundle itself (with path extension stripped)
1629 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1630 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1631 CFRelease(absoluteURL
);
1633 CFIndex len
= CFStringGetLength(bundlePath
);
1634 CFIndex startOfBundleName
= _CFStartOfLastPathComponent2(bundlePath
);
1635 CFIndex endOfBundleName
= _CFLengthAfterDeletingPathExtension2(bundlePath
);
1637 if (startOfBundleName
<= len
&& endOfBundleName
<= len
&& startOfBundleName
< endOfBundleName
) {
1638 executableName
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, bundlePath
, CFRangeMake(startOfBundleName
, endOfBundleName
- startOfBundleName
));
1640 CFRelease(bundlePath
);
1644 return executableName
;
1647 static CFURLRef
_CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle
, CFURLRef url
, CFStringRef executableName
, Boolean ignoreCache
, Boolean useOtherPlatform
) {
1648 uint8_t version
= 0;
1649 CFDictionaryRef infoDict
= NULL
;
1650 CFStringRef executablePath
= NULL
;
1651 CFURLRef executableURL
= NULL
;
1652 Boolean foundIt
= false;
1653 Boolean lookupMainExe
= (executableName
? false : true);
1656 infoDict
= CFBundleGetInfoDictionary(bundle
);
1657 version
= bundle
->_version
;
1659 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault
, url
, &version
);
1662 // If we have a bundle instance and an info dict, see if we have already cached the path
1663 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& bundle
&& bundle
->_executablePath
) {
1664 __CFLock(&bundle
->_lock
);
1665 executablePath
= bundle
->_executablePath
;
1666 if (executablePath
) CFRetain(executablePath
);
1667 __CFUnlock(&bundle
->_lock
);
1668 if (executablePath
) {
1669 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1670 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, executablePath
, kCFURLPOSIXPathStyle
, false);
1671 #elif DEPLOYMENT_TARGET_WINDOWS
1672 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, executablePath
, kCFURLWindowsPathStyle
, false);
1674 if (executableURL
) {
1677 CFRelease(executablePath
);
1682 if (lookupMainExe
) executableName
= _CFBundleCopyExecutableName(bundle
, url
, infoDict
);
1683 if (executableName
) {
1684 #if (DEPLOYMENT_TARGET_EMBEDDED && !TARGET_IPHONE_SIMULATOR)
1685 Boolean doExecSearch
= false;
1687 Boolean doExecSearch
= true;
1689 // Now, look for the executable inside the bundle.
1690 if (doExecSearch
&& 0 != version
) {
1691 CFURLRef exeDirURL
= NULL
;
1692 CFURLRef exeSubdirURL
;
1695 exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleExecutablesURLFromBase1
, url
);
1696 } else if (2 == version
) {
1697 exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleExecutablesURLFromBase2
, url
);
1699 #if DEPLOYMENT_TARGET_WINDOWS
1700 // On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory
1701 CFStringRef extension
= CFURLCopyPathExtension(url
);
1702 if (extension
&& CFEqual(extension
, _CFBundleWindowsResourceDirectoryExtension
)) {
1703 exeDirURL
= CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault
, url
);
1705 exeDirURL
= (CFURLRef
)CFRetain(url
);
1707 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1708 exeDirURL
= (CFURLRef
)CFRetain(url
);
1711 CFStringRef platformSubDir
= useOtherPlatform
? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName();
1712 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
1713 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
1714 if (!executableURL
) {
1715 CFRelease(exeSubdirURL
);
1716 platformSubDir
= useOtherPlatform
? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName();
1717 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
1718 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
1720 if (!executableURL
) {
1721 CFRelease(exeSubdirURL
);
1722 platformSubDir
= useOtherPlatform
? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName();
1723 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
1724 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
1726 if (!executableURL
) {
1727 CFRelease(exeSubdirURL
);
1728 platformSubDir
= useOtherPlatform
? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName();
1729 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
1730 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
1732 if (!executableURL
) executableURL
= _CFBundleCopyExecutableURLRaw(exeDirURL
, executableName
);
1733 CFRelease(exeDirURL
);
1734 CFRelease(exeSubdirURL
);
1737 // If this was an old bundle, or we did not find the executable in the Executables subdirectory, look directly in the bundle wrapper.
1738 if (!executableURL
) executableURL
= _CFBundleCopyExecutableURLRaw(url
, executableName
);
1740 #if DEPLOYMENT_TARGET_WINDOWS
1741 // Windows only: If we still haven't found the exe, look in the Executables folder.
1742 // But only for the main bundle exe
1743 if (lookupMainExe
&& !executableURL
) {
1744 CFURLRef exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, CFSTR("../../Executables"), url
);
1745 executableURL
= _CFBundleCopyExecutableURLRaw(exeDirURL
, executableName
);
1746 CFRelease(exeDirURL
);
1750 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& bundle
&& executableURL
) {
1751 // We found it. Cache the path.
1752 CFURLRef absURL
= CFURLCopyAbsoluteURL(executableURL
);
1753 #if DEPLOYMENT_TARGET_WINDOWS
1754 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLWindowsPathStyle
);
1755 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1756 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLPOSIXPathStyle
);
1759 __CFLock(&bundle
->_lock
);
1760 bundle
->_executablePath
= (CFStringRef
)CFRetain(executablePath
);
1761 __CFUnlock(&bundle
->_lock
);
1762 CFRelease(executablePath
);
1764 if (lookupMainExe
&& !useOtherPlatform
&& bundle
&& !executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
1765 if (lookupMainExe
) CFRelease(executableName
);
1768 if (!bundle
&& infoDict
&& !(0)) CFRelease(infoDict
);
1769 return executableURL
;
1773 CFURLRef
_CFBundleCopyExecutableURLInDirectory(CFURLRef url
) {
1774 return _CFBundleCopyExecutableURLInDirectory2(NULL
, url
, NULL
, true, false);
1777 CFURLRef
_CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url
) {
1778 return _CFBundleCopyExecutableURLInDirectory2(NULL
, url
, NULL
, true, true);
1781 CFURLRef
CFBundleCopyExecutableURL(CFBundleRef bundle
) {
1782 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, NULL
, false, false);
1785 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
) {
1786 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, NULL
, true, false);
1789 CFURLRef
CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle
, CFStringRef executableName
) {
1790 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, executableName
, true, false);
1793 Boolean
CFBundleIsExecutableLoaded(CFBundleRef bundle
) {
1794 return bundle
->_isLoaded
;
1797 CFBundleExecutableType
CFBundleGetExecutableType(CFBundleRef bundle
) {
1798 CFBundleExecutableType result
= kCFBundleOtherExecutableType
;
1799 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
1801 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
1802 #if defined(BINARY_SUPPORT_DYLD)
1803 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
1804 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
1805 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
1807 #endif /* BINARY_SUPPORT_DYLD */
1808 if (executableURL
) CFRelease(executableURL
);
1810 if (bundle
->_binaryType
== __CFBundleCFMBinary
) {
1811 result
= kCFBundlePEFExecutableType
;
1812 } else if (bundle
->_binaryType
== __CFBundleDYLDExecutableBinary
|| bundle
->_binaryType
== __CFBundleDYLDBundleBinary
|| bundle
->_binaryType
== __CFBundleDYLDFrameworkBinary
) {
1813 result
= kCFBundleMachOExecutableType
;
1814 } else if (bundle
->_binaryType
== __CFBundleDLLBinary
) {
1815 result
= kCFBundleDLLExecutableType
;
1816 } else if (bundle
->_binaryType
== __CFBundleELFBinary
) {
1817 result
= kCFBundleELFExecutableType
;
1822 void _CFBundleSetCFMConnectionID(CFBundleRef bundle
, void *connectionID
) {
1823 bundle
->_connectionCookie
= connectionID
;
1824 bundle
->_isLoaded
= true;
1827 static CFStringRef
_CFBundleCopyLastPathComponent(CFBundleRef bundle
) {
1828 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
);
1830 return CFSTR("<unknown>");
1832 CFStringRef str
= CFURLCopyFileSystemPath(bundleURL
, kCFURLPOSIXPathStyle
);
1833 UniChar buff
[CFMaxPathSize
];
1834 CFIndex buffLen
= CFStringGetLength(str
), startOfLastDir
= 0;
1836 CFRelease(bundleURL
);
1837 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
1838 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
1840 if (buffLen
> 0) startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
1841 return CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
1846 CF_PRIVATE CFErrorRef
_CFBundleCreateErrorDebug(CFAllocatorRef allocator
, CFBundleRef bundle
, CFIndex code
, CFStringRef debugString
) {
1847 const void *userInfoKeys
[6], *userInfoValues
[6];
1848 CFIndex numKeys
= 0;
1849 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
), absoluteURL
= CFURLCopyAbsoluteURL(bundleURL
), executableURL
= CFBundleCopyExecutableURL(bundle
);
1850 CFBundleRef bdl
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation"));
1851 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
), executablePath
= executableURL
? CFURLCopyFileSystemPath(executableURL
, PLATFORM_PATH_STYLE
) : NULL
, descFormat
= NULL
, desc
= NULL
, reason
= NULL
, suggestion
= NULL
;
1854 CFStringRef name
= (CFStringRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, kCFBundleNameKey
);
1855 name
= name
? (CFStringRef
)CFRetain(name
) : _CFBundleCopyLastPathComponent(bundle
);
1856 if (CFBundleExecutableNotFoundError
== code
) {
1857 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
1858 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl
, CFSTR("The bundle\\U2019s executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
1859 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError");
1860 } else if (CFBundleExecutableNotLoadableError
== code
) {
1861 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
1862 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl
, CFSTR("The bundle\\U2019s executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
1863 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError");
1864 } else if (CFBundleExecutableArchitectureMismatchError
== code
) {
1865 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
1866 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl
, CFSTR("The bundle doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
1867 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl
, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError");
1868 } else if (CFBundleExecutableRuntimeMismatchError
== code
) {
1869 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it isn\\U2019t compatible with the current application."), "NSExecutableRuntimeMismatchError");
1870 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl
, CFSTR("The bundle isn\\U2019t compatible with this application."), "NSExecutableRuntimeMismatchError");
1871 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl
, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError");
1872 } else if (CFBundleExecutableLoadError
== code
) {
1873 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it is damaged or missing necessary resources."), "NSExecutableLoadError");
1874 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl
, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError");
1875 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError");
1876 } else if (CFBundleExecutableLinkError
== code
) {
1877 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded."), "NSExecutableLinkError");
1878 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl
, CFSTR("The bundle couldn\\U2019t be loaded."), "NSExecutableLinkError");
1879 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError");
1882 desc
= CFStringCreateWithFormat(allocator
, NULL
, descFormat
, name
);
1883 CFRelease(descFormat
);
1888 userInfoKeys
[numKeys
] = CFSTR("NSBundlePath");
1889 userInfoValues
[numKeys
] = bundlePath
;
1892 if (executablePath
) {
1893 userInfoKeys
[numKeys
] = CFSTR("NSFilePath");
1894 userInfoValues
[numKeys
] = executablePath
;
1898 userInfoKeys
[numKeys
] = kCFErrorLocalizedDescriptionKey
;
1899 userInfoValues
[numKeys
] = desc
;
1903 userInfoKeys
[numKeys
] = kCFErrorLocalizedFailureReasonKey
;
1904 userInfoValues
[numKeys
] = reason
;
1908 userInfoKeys
[numKeys
] = kCFErrorLocalizedRecoverySuggestionKey
;
1909 userInfoValues
[numKeys
] = suggestion
;
1913 userInfoKeys
[numKeys
] = CFSTR("NSDebugDescription");
1914 userInfoValues
[numKeys
] = debugString
;
1917 error
= CFErrorCreateWithUserInfoKeysAndValues(allocator
, kCFErrorDomainCocoa
, code
, userInfoKeys
, userInfoValues
, numKeys
);
1918 if (bundleURL
) CFRelease(bundleURL
);
1919 if (absoluteURL
) CFRelease(absoluteURL
);
1920 if (executableURL
) CFRelease(executableURL
);
1921 if (bundlePath
) CFRelease(bundlePath
);
1922 if (executablePath
) CFRelease(executablePath
);
1923 if (desc
) CFRelease(desc
);
1924 if (reason
) CFRelease(reason
);
1925 if (suggestion
) CFRelease(suggestion
);
1929 CFErrorRef
_CFBundleCreateError(CFAllocatorRef allocator
, CFBundleRef bundle
, CFIndex code
) {
1930 return _CFBundleCreateErrorDebug(allocator
, bundle
, code
, NULL
);
1935 Boolean
_CFBundleLoadExecutableAndReturnError(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
1936 Boolean result
= false;
1937 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
1938 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
1941 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
1942 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
1943 // make sure we know whether bundle is already loaded or not
1944 #if defined(BINARY_SUPPORT_DLFCN)
1945 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
1946 #elif defined(BINARY_SUPPORT_DYLD)
1947 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
1948 #endif /* BINARY_SUPPORT_DLFCN */
1949 #if defined(BINARY_SUPPORT_DYLD)
1950 // We might need to figure out what it is
1951 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
1952 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
1953 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
1955 #endif /* BINARY_SUPPORT_DYLD */
1956 if (executableURL
) CFRelease(executableURL
);
1958 if (bundle
->_isLoaded
) {
1959 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
1960 // Remove from the scheduled unload set if we are there.
1961 pthread_mutex_lock(&CFBundleGlobalDataLock
);
1962 #if AVOID_WEAK_COLLECTIONS
1963 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
1964 #else /* AVOID_WEAK_COLLECTIONS */
1965 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
1966 #endif /* AVOID_WEAK_COLLECTIONS */
1967 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
1971 // Unload bundles scheduled for unloading
1972 if (!_scheduledBundlesAreUnloading
) {
1973 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
1974 _CFBundleUnloadScheduledBundles();
1975 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
1978 if (bundle
->_isLoaded
) {
1979 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
1980 // Remove from the scheduled unload set if we are there.
1981 pthread_mutex_lock(&CFBundleGlobalDataLock
);
1982 #if AVOID_WEAK_COLLECTIONS
1983 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
1984 #else /* AVOID_WEAK_COLLECTIONS */
1985 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
1986 #endif /* AVOID_WEAK_COLLECTIONS */
1987 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
1990 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
1992 switch (bundle
->_binaryType
) {
1993 #if defined(BINARY_SUPPORT_DLFCN)
1994 case __CFBundleUnreadableBinary
:
1995 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
1997 #endif /* BINARY_SUPPORT_DLFCN */
1998 #if defined(BINARY_SUPPORT_DYLD)
1999 case __CFBundleDYLDBundleBinary
:
2000 #if defined(BINARY_SUPPORT_DLFCN)
2001 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
2002 #else /* BINARY_SUPPORT_DLFCN */
2003 result
= _CFBundleDYLDLoadBundle(bundle
, forceGlobal
, subError
);
2004 #endif /* BINARY_SUPPORT_DLFCN */
2006 case __CFBundleDYLDFrameworkBinary
:
2007 #if defined(BINARY_SUPPORT_DLFCN)
2008 result
= _CFBundleDlfcnLoadFramework(bundle
, subError
);
2009 #else /* BINARY_SUPPORT_DLFCN */
2010 result
= _CFBundleDYLDLoadFramework(bundle
, subError
);
2011 #endif /* BINARY_SUPPORT_DLFCN */
2013 case __CFBundleDYLDExecutableBinary
:
2015 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
2017 CFLog(__kCFLogBundle
, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle
);
2020 #endif /* BINARY_SUPPORT_DYLD */
2021 #if defined(BINARY_SUPPORT_DLFCN)
2022 case __CFBundleUnknownBinary
:
2023 case __CFBundleELFBinary
:
2024 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
2026 #endif /* BINARY_SUPPORT_DLFCN */
2027 #if defined(BINARY_SUPPORT_DLL)
2028 case __CFBundleDLLBinary
:
2029 result
= _CFBundleDLLLoad(bundle
, subError
);
2031 #endif /* BINARY_SUPPORT_DLL */
2032 case __CFBundleNoBinary
:
2034 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
2036 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for %@"), bundle
);
2041 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
2043 CFLog(__kCFLogBundle
, CFSTR("Cannot recognize type of executable for %@"), bundle
);
2047 if (result
&& bundle
->_plugInData
._isPlugIn
) _CFBundlePlugInLoaded(bundle
);
2048 if (!result
&& error
) *error
= localError
;
2052 Boolean
CFBundleLoadExecutableAndReturnError(CFBundleRef bundle
, CFErrorRef
*error
) {
2053 return _CFBundleLoadExecutableAndReturnError(bundle
, false, error
);
2056 Boolean
CFBundleLoadExecutable(CFBundleRef bundle
) {
2057 return _CFBundleLoadExecutableAndReturnError(bundle
, false, NULL
);
2060 Boolean
CFBundlePreflightExecutable(CFBundleRef bundle
, CFErrorRef
*error
) {
2061 Boolean result
= false;
2062 CFErrorRef localError
= NULL
;
2063 #if defined(BINARY_SUPPORT_DLFCN)
2064 CFErrorRef
*subError
= (error
? &localError
: NULL
);
2066 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2068 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
2069 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
2070 // make sure we know whether bundle is already loaded or not
2071 #if defined(BINARY_SUPPORT_DLFCN)
2072 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
2073 #elif defined(BINARY_SUPPORT_DYLD)
2074 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
2075 #endif /* BINARY_SUPPORT_DLFCN */
2076 #if defined(BINARY_SUPPORT_DYLD)
2077 // We might need to figure out what it is
2078 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2079 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
2080 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
2082 #endif /* BINARY_SUPPORT_DYLD */
2083 if (executableURL
) CFRelease(executableURL
);
2085 if (bundle
->_isLoaded
) {
2086 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
2089 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
2091 switch (bundle
->_binaryType
) {
2092 #if defined(BINARY_SUPPORT_DLFCN)
2093 case __CFBundleUnreadableBinary
:
2094 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
2096 #endif /* BINARY_SUPPORT_DLFCN */
2097 #if defined(BINARY_SUPPORT_DYLD)
2098 case __CFBundleDYLDBundleBinary
:
2100 #if defined(BINARY_SUPPORT_DLFCN)
2101 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
2102 #endif /* BINARY_SUPPORT_DLFCN */
2104 case __CFBundleDYLDFrameworkBinary
:
2106 #if defined(BINARY_SUPPORT_DLFCN)
2107 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
2108 #endif /* BINARY_SUPPORT_DLFCN */
2110 case __CFBundleDYLDExecutableBinary
:
2111 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
2113 #endif /* BINARY_SUPPORT_DYLD */
2114 #if defined(BINARY_SUPPORT_DLFCN)
2115 case __CFBundleUnknownBinary
:
2116 case __CFBundleELFBinary
:
2117 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
2119 #endif /* BINARY_SUPPORT_DLFCN */
2120 #if defined(BINARY_SUPPORT_DLL)
2121 case __CFBundleDLLBinary
:
2124 #endif /* BINARY_SUPPORT_DLL */
2125 case __CFBundleNoBinary
:
2126 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
2129 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
2132 if (!result
&& error
) *error
= localError
;
2136 CFArrayRef
CFBundleCopyExecutableArchitectures(CFBundleRef bundle
) {
2137 CFArrayRef result
= NULL
;
2138 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2139 if (executableURL
) {
2140 result
= _CFBundleCopyArchitecturesForExecutable(executableURL
);
2141 CFRelease(executableURL
);
2146 void CFBundleUnloadExecutable(CFBundleRef bundle
) {
2147 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
2148 if (!_scheduledBundlesAreUnloading
) _CFBundleUnloadScheduledBundles();
2150 if (!bundle
->_isLoaded
) return;
2152 // Remove from the scheduled unload set if we are there.
2153 if (!_scheduledBundlesAreUnloading
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
2154 #if AVOID_WEAK_COLLECTIONS
2155 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
2156 #else /* AVOID_WEAK_COLLECTIONS */
2157 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
2158 #endif /* AVOID_WEAK_COLLECTIONS */
2159 if (!_scheduledBundlesAreUnloading
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2161 // Give the plugIn code a chance to realize this...
2162 _CFPlugInWillUnload(bundle
);
2164 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
2165 if (!bundle
->_isLoaded
) {
2166 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
2169 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
2171 switch (bundle
->_binaryType
) {
2172 #if defined(BINARY_SUPPORT_DYLD)
2173 case __CFBundleDYLDBundleBinary
:
2174 #if defined(BINARY_SUPPORT_DLFCN)
2175 if (bundle
->_handleCookie
) _CFBundleDlfcnUnload(bundle
);
2176 #else /* BINARY_SUPPORT_DLFCN */
2177 _CFBundleDYLDUnloadBundle(bundle
);
2178 #endif /* BINARY_SUPPORT_DLFCN */
2180 case __CFBundleDYLDFrameworkBinary
:
2181 #if defined(BINARY_SUPPORT_DLFCN)
2182 if (bundle
->_handleCookie
&& _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard
)) _CFBundleDlfcnUnload(bundle
);
2183 #endif /* BINARY_SUPPORT_DLFCN */
2185 #endif /* BINARY_SUPPORT_DYLD */
2186 #if defined(BINARY_SUPPORT_DLL)
2187 case __CFBundleDLLBinary
:
2188 _CFBundleDLLUnload(bundle
);
2190 #endif /* BINARY_SUPPORT_DLL */
2192 #if defined(BINARY_SUPPORT_DLFCN)
2193 if (bundle
->_handleCookie
) _CFBundleDlfcnUnload(bundle
);
2194 #endif /* BINARY_SUPPORT_DLFCN */
2197 if (!bundle
->_isLoaded
&& bundle
->_glueDict
) {
2198 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
2199 CFRelease(bundle
->_glueDict
);
2200 bundle
->_glueDict
= NULL
;
2204 #if AVOID_WEAK_COLLECTIONS
2206 CF_PRIVATE
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
2207 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2208 if (!_bundlesToUnload
) {
2209 CFSetCallBacks nonRetainingCallbacks
= kCFTypeSetCallBacks
;
2210 nonRetainingCallbacks
.retain
= NULL
;
2211 nonRetainingCallbacks
.release
= NULL
;
2212 _bundlesToUnload
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingCallbacks
);
2214 CFSetAddValue(_bundlesToUnload
, bundle
);
2215 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2218 CF_PRIVATE
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
2219 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2220 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
2221 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2224 CF_PRIVATE
void _CFBundleUnloadScheduledBundles(void) {
2225 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2226 if (_bundlesToUnload
) {
2227 CFIndex i
, c
= CFSetGetCount(_bundlesToUnload
);
2229 CFBundleRef
*unloadThese
= (CFBundleRef
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(CFBundleRef
) * c
, 0);
2230 CFSetGetValues(_bundlesToUnload
, (const void **)unloadThese
);
2231 _scheduledBundlesAreUnloading
= true;
2232 for (i
= 0; i
< c
; i
++) {
2233 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2234 CFBundleUnloadExecutable(unloadThese
[i
]);
2236 _scheduledBundlesAreUnloading
= false;
2237 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, unloadThese
);
2240 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2243 #else /* AVOID_WEAK_COLLECTIONS */
2245 CF_PRIVATE
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
2246 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2247 if (!_bundlesToUnload
) _bundlesToUnload
= [[__CFHashTable alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
2248 [_bundlesToUnload addObject
:(id
)bundle
];
2249 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2252 CF_PRIVATE
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
2253 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2254 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
2255 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2258 CF_PRIVATE
void _CFBundleUnloadScheduledBundles(void) {
2259 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2260 if (_bundlesToUnload
&& [_bundlesToUnload count
] > 0) {
2262 CFMutableArrayRef unloadThese
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2263 for (id value in _bundlesToUnload
) CFArrayAppendValue(unloadThese
, value
);
2264 c
= CFArrayGetCount(unloadThese
);
2266 _scheduledBundlesAreUnloading
= true;
2267 for (i
= 0; i
< c
; i
++) {
2268 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2269 CFBundleUnloadExecutable((CFBundleRef
)CFArrayGetValueAtIndex(unloadThese
, i
));
2271 _scheduledBundlesAreUnloading
= false;
2273 CFRelease(unloadThese
);
2275 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2278 #endif /* AVOID_WEAK_COLLECTIONS */
2282 CF_PRIVATE _CFResourceData
*__CFBundleGetResourceData(CFBundleRef bundle
) {
2283 return &(bundle
->_resourceData
);
2286 CFPlugInRef
CFBundleGetPlugIn(CFBundleRef bundle
) {
2287 return (bundle
->_plugInData
._isPlugIn
) ? (CFPlugInRef
)bundle
: NULL
;
2290 CF_PRIVATE _CFPlugInData
*__CFBundleGetPlugInData(CFBundleRef bundle
) {
2291 return &(bundle
->_plugInData
);
2294 CF_PRIVATE Boolean
_CFBundleCouldBeBundle(CFURLRef url
) {
2295 Boolean result
= false;
2298 if (_CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) result
= (exists
&& (mode
& S_IFMT
) == S_IFDIR
&& (mode
& 0444) != 0);
2302 #define LENGTH_OF(A) (sizeof(A) / sizeof(A[0]))
2304 //If 'permissive' is set, we will maintain the historical behavior of returning frameworks with names that don't match, and frameworks for executables in Resources/
2305 static CFURLRef
__CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath
, Boolean permissive
) {
2306 // 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.
2307 #if DEPLOYMENT_TARGET_WINDOWS
2308 UniChar executablesToFrameworksPathBuff
[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
2309 UniChar executablesToPrivateFrameworksPathBuff
[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
2310 UniChar frameworksExtension
[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
2312 UniChar pathBuff
[CFMaxPathSize
] = {0};
2313 UniChar nameBuff
[CFMaxPathSize
] = {0};
2314 CFIndex length
, nameStart
, nameLength
, savedLength
;
2315 CFMutableStringRef cheapStr
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, NULL
);
2316 CFURLRef bundleURL
= NULL
;
2318 length
= CFStringGetLength(executablePath
);
2319 if (length
> CFMaxPathSize
) length
= CFMaxPathSize
;
2320 CFStringGetCharacters(executablePath
, CFRangeMake(0, length
), pathBuff
);
2322 // Save the name in nameBuff
2323 length
= _CFLengthAfterDeletingPathExtension(pathBuff
, length
);
2324 nameStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2325 nameLength
= length
- nameStart
;
2326 memmove(nameBuff
, &(pathBuff
[nameStart
]), nameLength
* sizeof(UniChar
));
2328 // Strip the name from pathBuff
2329 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2330 savedLength
= length
;
2332 #if DEPLOYMENT_TARGET_WINDOWS
2333 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
2334 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToFrameworksPathBuff
, LENGTH_OF(executablesToFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
2335 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2336 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2337 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2338 CFRelease(bundleURL
);
2342 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
2344 length
= savedLength
;
2345 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToPrivateFrameworksPathBuff
, LENGTH_OF(executablesToPrivateFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
2346 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2347 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2348 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2349 CFRelease(bundleURL
);
2355 // * Finally check the executable inside the framework case.
2357 length
= savedLength
;
2358 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
2360 CFStringRef name
= permissive
? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, (const char *)nameBuff
);
2362 while (length
> 0) {
2363 CFIndex curStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2364 if (curStart
>= length
) break;
2365 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[curStart
]), length
- curStart
, CFMaxPathSize
- curStart
);
2366 if (!permissive
&& CFEqual(cheapStr
, _CFBundleResourcesDirectoryName
)) break;
2367 if (CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName1
) || CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName2
)) {
2369 CFIndex fmwkStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2370 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[fmwkStart
]), length
- fmwkStart
, CFMaxPathSize
- fmwkStart
);
2372 if (permissive
|| CFStringHasPrefix(cheapStr
, name
)) {
2373 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2374 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2376 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2377 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2378 CFRelease(bundleURL
);
2383 } else if (CFStringHasSuffix(cheapStr
, CFSTR(".framework")) && (permissive
|| CFStringHasPrefix(cheapStr
, name
))) {
2384 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2385 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2386 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2387 CFRelease(bundleURL
);
2392 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2394 if (!permissive
) CFRelease(name
);
2396 CFStringSetExternalCharactersNoCopy(cheapStr
, NULL
, 0, 0);
2397 CFRelease(cheapStr
);
2402 //SPI version; separated out to minimize linkage changes
2403 CFURLRef
_CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath
) {
2404 return __CFBundleCopyFrameworkURLForExecutablePath(executablePath
, false);
2407 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
) {
2408 // This finds the bundle for the given path.
2409 // 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.
2411 CFURLRef curURL
= __CFBundleCopyFrameworkURLForExecutablePath(imagePath
, true);
2412 Boolean createdBundle
= false;
2415 bundle
= _CFBundleCopyBundleForURL(curURL
, true);
2417 // Ensure bundle exists by creating it if necessary
2418 // NB doFinalProcessing must be false here, see below
2419 bundle
= _CFBundleCreate(kCFAllocatorSystemDefault
, curURL
, true, false);
2420 createdBundle
= true;
2423 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
2424 if (!bundle
->_isLoaded
) {
2425 // 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)
2426 #if defined(BINARY_SUPPORT_DLFCN)
2427 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
2428 #elif defined(BINARY_SUPPORT_DYLD)
2429 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
2430 #endif /* BINARY_SUPPORT_DLFCN */
2431 #if defined(BINARY_SUPPORT_DYLD)
2432 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
2433 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
2434 #endif /* BINARY_SUPPORT_DYLD */
2436 if (!bundle
->_isLoaded
) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle
, bundle
->_handleCookie
, bundle
->_imageCookie
, bundle
->_connectionCookie
);
2437 #endif /* LOG_BUNDLE_LOAD */
2438 bundle
->_isLoaded
= true;
2440 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
2441 if (createdBundle
) {
2442 // Perform delayed final processing steps.
2443 // This must be done after _isLoaded has been set, for security reasons (3624341).
2444 if (_CFBundleNeedsInitPlugIn(bundle
)) {
2445 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2446 _CFBundleInitPlugIn(bundle
);
2447 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2450 // Release the bundle if we did not create it here
2458 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
) {
2459 // This finds the bundles for the given paths.
2460 // 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).
2461 CFIndex i
, imagePathCount
= CFArrayGetCount(imagePaths
);
2462 for (i
= 0; i
< imagePathCount
; i
++) _CFBundleEnsureBundleExistsForImagePath((CFStringRef
)CFArrayGetValueAtIndex(imagePaths
, i
));
2465 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
) {
2466 CFArrayRef imagePaths
= NULL
;
2467 // Tickle the main bundle into existence
2468 (void)_CFBundleGetMainBundleAlreadyLocked();
2469 #if defined(BINARY_SUPPORT_DYLD)
2470 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsForHint(hint
);
2471 #endif /* BINARY_SUPPORT_DYLD */
2473 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2474 CFRelease(imagePaths
);
2478 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
2479 // 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.
2480 CFArrayRef imagePaths
= NULL
;
2481 // Tickle the main bundle into existence
2482 (void)_CFBundleGetMainBundleAlreadyLocked();
2484 #if defined(BINARY_SUPPORT_DLL)
2485 // Dont know how to find static bundles for DLLs
2486 #endif /* BINARY_SUPPORT_DLL */
2488 #if defined(BINARY_SUPPORT_DYLD)
2489 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsIfChanged();
2490 #endif /* BINARY_SUPPORT_DYLD */
2492 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2493 CFRelease(imagePaths
);
2497 CFArrayRef
CFBundleGetAllBundles(void) {
2498 // To answer this properly, we have to have created the static bundles!
2499 #if !AVOID_WEAK_COLLECTIONS
2500 static CFMutableArrayRef externalAllBundles
= NULL
;
2501 #endif /* AVOID_WEAK_COLLECTIONS */
2503 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2504 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2505 #if AVOID_WEAK_COLLECTIONS
2506 bundles
= _allBundles
;
2507 #else /* AVOID_WEAK_COLLECTIONS */
2508 if (!externalAllBundles
) {
2509 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
2510 nonRetainingArrayCallbacks
.retain
= NULL
;
2511 nonRetainingArrayCallbacks
.release
= NULL
;
2512 externalAllBundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
2514 CFArrayRemoveAllValues(externalAllBundles
);
2515 for (id value in _allBundles
) CFArrayAppendValue(externalAllBundles
, value
);
2516 bundles
= externalAllBundles
;
2517 #endif /* AVOID_WEAK_COLLECTIONS */
2518 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2522 CF_EXPORT CFArrayRef
_CFBundleCopyAllBundles(void) {
2523 // To answer this properly, we have to have created the static bundles!
2524 pthread_mutex_lock(&CFBundleGlobalDataLock
);
2525 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2526 #if AVOID_WEAK_COLLECTIONS
2527 CFArrayRef bundles
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, _allBundles
);
2528 #else /* AVOID_WEAK_COLLECTIONS */
2529 CFMutableArrayRef bundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2530 for (id value in _allBundles
) CFArrayAppendValue(bundles
, value
);
2531 #endif /* AVOID_WEAK_COLLECTIONS */
2532 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
2536 CF_PRIVATE
uint8_t _CFBundleLayoutVersion(CFBundleRef bundle
) {
2537 return bundle
->_version
;
2540 CF_EXPORT CFURLRef
_CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
2541 return CFBundleCopyPrivateFrameworksURL(bundle
);
2544 CF_EXPORT CFURLRef
CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
2545 CFURLRef result
= NULL
;
2547 if (1 == bundle
->_version
) {
2548 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase1
, bundle
->_url
);
2549 } else if (2 == bundle
->_version
) {
2550 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase2
, bundle
->_url
);
2552 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase0
, bundle
->_url
);
2557 CF_EXPORT CFURLRef
_CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
2558 return CFBundleCopySharedFrameworksURL(bundle
);
2561 CF_EXPORT CFURLRef
CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
2562 CFURLRef result
= NULL
;
2564 if (1 == bundle
->_version
) {
2565 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase1
, bundle
->_url
);
2566 } else if (2 == bundle
->_version
) {
2567 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase2
, bundle
->_url
);
2569 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase0
, bundle
->_url
);
2574 CF_EXPORT CFURLRef
_CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
2575 return CFBundleCopySharedSupportURL(bundle
);
2578 CF_EXPORT CFURLRef
CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
2579 CFURLRef result
= NULL
;
2581 if (1 == bundle
->_version
) {
2582 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase1
, bundle
->_url
);
2583 } else if (2 == bundle
->_version
) {
2584 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase2
, bundle
->_url
);
2586 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase0
, bundle
->_url
);
2591 CF_PRIVATE CFURLRef
_CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
2592 return CFBundleCopyBuiltInPlugInsURL(bundle
);
2595 CF_EXPORT CFURLRef
CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
2596 CFURLRef result
= NULL
, alternateResult
= NULL
;
2598 CFAllocatorRef alloc
= CFGetAllocator(bundle
);
2599 if (1 == bundle
->_version
) {
2600 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase1
, bundle
->_url
);
2601 } else if (2 == bundle
->_version
) {
2602 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase2
, bundle
->_url
);
2604 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2606 if (!result
|| !_urlExists(result
)) {
2607 if (1 == bundle
->_version
) {
2608 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase1
, bundle
->_url
);
2609 } else if (2 == bundle
->_version
) {
2610 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase2
, bundle
->_url
);
2612 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2614 if (alternateResult
&& _urlExists(alternateResult
)) {
2615 if (result
) CFRelease(result
);
2616 result
= alternateResult
;
2618 if (alternateResult
) CFRelease(alternateResult
);