2 * Copyright (c) 2011 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-2011, Apple Inc. All rights reserved.
26 Responsibility: David Smith
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 #define AVOID_WEAK_COLLECTIONS 1
46 #if !defined(AVOID_WEAK_COLLECTIONS)
47 #include "CFHashTable.h"
48 #include "CFMapTable.h"
49 #include "CFPointerArray.h"
50 #endif /* !AVOID_WEAK_COLLECTIONS */
52 #if defined(BINARY_SUPPORT_DYLD)
53 // Import the mach-o headers that define the macho magic numbers
54 #include <mach-o/loader.h>
55 #include <mach-o/fat.h>
56 #include <mach-o/arch.h>
57 #include <mach-o/dyld.h>
58 #include <mach-o/getsect.h>
62 #include <crt_externs.h>
63 #if defined(USE_DYLD_PRIV)
64 #include <mach-o/dyld_priv.h>
65 #endif /* USE_DYLD_PRIV */
66 #endif /* BINARY_SUPPORT_DYLD */
68 #if defined(BINARY_SUPPORT_DLFCN)
70 #endif /* BINARY_SUPPORT_DLFCN */
72 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
74 #elif DEPLOYMENT_TARGET_WINDOWS
79 #define stat(x,y) _NS_stat(x,y)
82 #error Unknown or unspecified DEPLOYMENT_TARGET
85 extern void _processInfoDictionary(CFMutableDictionaryRef dict
, CFStringRef platformSuffix
, CFStringRef productSuffix
);
86 extern CFStringRef
_CFGetProductName(void);
87 extern CFStringRef
_CFGetPlatformName(void);
88 extern CFStringRef
_CFGetAlternatePlatformName(void);
90 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle
, Boolean alreadyLocked
);
92 #define LOG_BUNDLE_LOAD 0
94 // Public CFBundle Info plist keys
95 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey
, "CFBundleInfoDictionaryVersion")
96 CONST_STRING_DECL(kCFBundleExecutableKey
, "CFBundleExecutable")
97 CONST_STRING_DECL(kCFBundleIdentifierKey
, "CFBundleIdentifier")
98 CONST_STRING_DECL(kCFBundleVersionKey
, "CFBundleVersion")
99 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey
, "CFBundleDevelopmentRegion")
100 CONST_STRING_DECL(kCFBundleLocalizationsKey
, "CFBundleLocalizations")
102 // Private CFBundle Info plist keys, possible candidates for public constants
103 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey
, "CFBundleAllowMixedLocalizations")
104 CONST_STRING_DECL(_kCFBundleSupportedPlatformsKey
, "CFBundleSupportedPlatforms")
105 CONST_STRING_DECL(_kCFBundleResourceSpecificationKey
, "CFBundleResourceSpecification")
108 CONST_STRING_DECL(_kCFBundlePackageTypeKey
, "CFBundlePackageType")
109 CONST_STRING_DECL(_kCFBundleSignatureKey
, "CFBundleSignature")
110 CONST_STRING_DECL(_kCFBundleIconFileKey
, "CFBundleIconFile")
111 CONST_STRING_DECL(_kCFBundleDocumentTypesKey
, "CFBundleDocumentTypes")
112 CONST_STRING_DECL(_kCFBundleURLTypesKey
, "CFBundleURLTypes")
114 // Keys that are usually localized in InfoPlist.strings
115 CONST_STRING_DECL(kCFBundleNameKey
, "CFBundleName")
116 CONST_STRING_DECL(_kCFBundleDisplayNameKey
, "CFBundleDisplayName")
117 CONST_STRING_DECL(_kCFBundleShortVersionStringKey
, "CFBundleShortVersionString")
118 CONST_STRING_DECL(_kCFBundleGetInfoStringKey
, "CFBundleGetInfoString")
119 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey
, "CFBundleGetInfoHTML")
121 // Sub-keys for CFBundleDocumentTypes dictionaries
122 CONST_STRING_DECL(_kCFBundleTypeNameKey
, "CFBundleTypeName")
123 CONST_STRING_DECL(_kCFBundleTypeRoleKey
, "CFBundleTypeRole")
124 CONST_STRING_DECL(_kCFBundleTypeIconFileKey
, "CFBundleTypeIconFile")
125 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey
, "CFBundleTypeOSTypes")
126 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey
, "CFBundleTypeExtensions")
127 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey
, "CFBundleTypeMIMETypes")
129 // Sub-keys for CFBundleURLTypes dictionaries
130 CONST_STRING_DECL(_kCFBundleURLNameKey
, "CFBundleURLName")
131 CONST_STRING_DECL(_kCFBundleURLIconFileKey
, "CFBundleURLIconFile")
132 CONST_STRING_DECL(_kCFBundleURLSchemesKey
, "CFBundleURLSchemes")
134 // Compatibility key names
135 CONST_STRING_DECL(_kCFBundleOldExecutableKey
, "NSExecutable")
136 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey
, "NSInfoPlistVersion")
137 CONST_STRING_DECL(_kCFBundleOldNameKey
, "NSHumanReadableName")
138 CONST_STRING_DECL(_kCFBundleOldIconFileKey
, "NSIcon")
139 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey
, "NSTypes")
140 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey
, "NSAppVersion")
142 // Compatibility CFBundleDocumentTypes key names
143 CONST_STRING_DECL(_kCFBundleOldTypeNameKey
, "NSName")
144 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey
, "NSRole")
145 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey
, "NSIcon")
146 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key
, "NSUnixExtensions")
147 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key
, "NSDOSExtensions")
148 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey
, "NSMacOSType")
150 // Internally used keys for loaded Info plists.
151 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey
, "CFBundleInfoPlistURL")
152 CONST_STRING_DECL(_kCFBundleRawInfoPlistURLKey
, "CFBundleRawInfoPlistURL")
153 CONST_STRING_DECL(_kCFBundleNumericVersionKey
, "CFBundleNumericVersion")
154 CONST_STRING_DECL(_kCFBundleExecutablePathKey
, "CFBundleExecutablePath")
155 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey
, "CSResourcesFileMapped")
156 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey
, "CFBundleCFMLoadAsBundle")
158 // Keys used by NSBundle for loaded Info plists.
159 CONST_STRING_DECL(_kCFBundleInitialPathKey
, "NSBundleInitialPath")
160 CONST_STRING_DECL(_kCFBundleResolvedPathKey
, "NSBundleResolvedPath")
161 CONST_STRING_DECL(_kCFBundlePrincipalClassKey
, "NSPrincipalClass")
163 static char __CFBundleMainID__
[1026] = {0};
164 __private_extern__
char *__CFBundleMainID
= __CFBundleMainID__
;
166 static CFTypeID __kCFBundleTypeID
= _kCFRuntimeNotATypeID
;
174 __strong CFDictionaryRef _infoDict
; // the ref stored in here must always be allocated with kCFAllocatorSystemDefaultGCRefZero
175 __strong CFDictionaryRef _localInfoDict
; // the ref stored in here must always be allocated with kCFAllocatorSystemDefaultGCRefZero
176 CFArrayRef _searchLanguages
;
178 __CFPBinaryType _binaryType
;
181 Boolean _sharesStringsFiles
;
185 void *_connectionCookie
;
188 const void *_imageCookie
;
189 const void *_moduleCookie
;
194 /* CFM<->DYLD glue */
195 CFMutableDictionaryRef _glueDict
;
197 /* Resource fork goop */
198 _CFResourceData _resourceData
;
200 _CFPlugInData _plugInData
;
202 CFSpinLock_t _bundleLoadingLock
;
204 #if defined(BINARY_SUPPORT_DLL)
206 #endif /* BINARY_SUPPORT_DLL */
210 static CFSpinLock_t CFBundleGlobalDataLock
= CFSpinLockInit
;
212 static CFMutableDictionaryRef _bundlesByIdentifier
= NULL
;
213 #if defined(AVOID_WEAK_COLLECTIONS)
214 static CFMutableDictionaryRef _bundlesByURL
= NULL
;
215 static CFMutableArrayRef _allBundles
= NULL
;
216 static CFMutableSetRef _bundlesToUnload
= NULL
;
217 #else /* AVOID_WEAK_COLLECTIONS */
218 static __CFHashTable
*_allBundles
= nil
;
219 static __CFHashTable
*_bundlesToUnload
= nil
;
220 #endif /* AVOID_WEAK_COLLECTIONS */
221 static Boolean _scheduledBundlesAreUnloading
= false;
223 static Boolean _initedMainBundle
= false;
224 static CFBundleRef _mainBundle
= NULL
;
225 static CFStringRef _defaultLocalization
= NULL
;
227 // Forward declares functions.
228 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
);
229 static CFStringRef
_CFBundleCopyExecutableName(CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
);
230 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
);
231 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
);
232 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
233 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
);
234 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
);
235 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
);
236 #if defined(BINARY_SUPPORT_DYLD)
237 static CFMutableDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable(void);
238 static Boolean
_CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion
, uint32_t *objcFlags
);
239 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
);
240 #if !defined(BINARY_SUPPORT_DLFCN)
241 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
);
242 #endif /* !BINARY_SUPPORT_DLFCN */
243 #endif /* BINARY_SUPPORT_DYLD */
244 #if defined(BINARY_SUPPORT_DLFCN)
245 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
);
246 #if !defined(BINARY_SUPPORT_DYLD)
247 static CFStringRef
_CFBundleDlfcnCopyLoadedImagePathForPointer(void *p
);
248 #endif /* !BINARY_SUPPORT_DYLD */
249 #endif /* BINARY_SUPPORT_DLFCN */
252 #if defined(AVOID_WEAK_COLLECTIONS)
254 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
255 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
257 if (!alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
259 // Add to the _allBundles list
261 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
262 nonRetainingArrayCallbacks
.retain
= NULL
;
263 nonRetainingArrayCallbacks
.release
= NULL
;
264 _allBundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
266 CFArrayAppendValue(_allBundles
, bundle
);
268 // Add to the table that maps urls to bundles
269 if (!_bundlesByURL
) {
270 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
271 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
272 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
273 _bundlesByURL
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
275 CFDictionarySetValue(_bundlesByURL
, bundle
->_url
, bundle
);
277 // Add to the table that maps identifiers to bundles
279 CFMutableArrayRef bundlesWithThisID
= NULL
;
280 CFBundleRef existingBundle
= NULL
;
281 if (!_bundlesByIdentifier
) {
282 _bundlesByIdentifier
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
284 bundlesWithThisID
= (CFMutableArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
285 if (bundlesWithThisID
) {
286 CFIndex i
, count
= CFArrayGetCount(bundlesWithThisID
);
287 UInt32 existingVersion
, newVersion
= CFBundleGetVersionNumber(bundle
);
288 for (i
= 0; i
< count
; i
++) {
289 existingBundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, i
);
290 existingVersion
= CFBundleGetVersionNumber(existingBundle
);
291 // If you load two bundles with the same identifier and the same version, the last one wins.
292 if (newVersion
>= existingVersion
) break;
294 CFArrayInsertValueAtIndex(bundlesWithThisID
, i
, bundle
);
296 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
297 nonRetainingArrayCallbacks
.retain
= NULL
;
298 nonRetainingArrayCallbacks
.release
= NULL
;
299 bundlesWithThisID
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
300 CFArrayAppendValue(bundlesWithThisID
, bundle
);
301 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundlesWithThisID
);
302 CFRelease(bundlesWithThisID
);
305 if (!alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
308 static void _CFBundleRemoveFromTables(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef bundleID
) {
309 __CFSpinLock(&CFBundleGlobalDataLock
);
310 // Remove from the various lists
312 CFIndex i
= CFArrayGetFirstIndexOfValue(_allBundles
, CFRangeMake(0, CFArrayGetCount(_allBundles
)), bundle
);
313 if (i
>= 0) CFArrayRemoveValueAtIndex(_allBundles
, i
);
316 // Remove from the table that maps urls to bundles
317 if (bundleURL
&& _bundlesByURL
) {
318 CFBundleRef bundleForURL
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, bundleURL
);
319 if (bundleForURL
== bundle
) CFDictionaryRemoveValue(_bundlesByURL
, bundleURL
);
322 // Remove from the table that maps identifiers to bundles
323 if (bundleID
&& _bundlesByIdentifier
) {
324 CFMutableArrayRef bundlesWithThisID
= (CFMutableArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
325 if (bundlesWithThisID
) {
326 CFIndex count
= CFArrayGetCount(bundlesWithThisID
);
327 while (count
-- > 0) if (bundle
== (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, count
)) CFArrayRemoveValueAtIndex(bundlesWithThisID
, count
);
328 if (0 == CFArrayGetCount(bundlesWithThisID
)) CFDictionaryRemoveValue(_bundlesByIdentifier
, bundleID
);
331 __CFSpinUnlock(&CFBundleGlobalDataLock
);
334 static CFBundleRef
_CFBundleCopyBundleForURL(CFURLRef url
, Boolean alreadyLocked
) {
335 CFBundleRef result
= NULL
;
336 if (!alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
337 if (_bundlesByURL
) result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, url
);
338 if (result
&& !result
->_url
) {
340 CFDictionaryRemoveValue(_bundlesByURL
, url
);
342 if (result
) CFRetain(result
);
343 if (!alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
347 static CFBundleRef
_CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID
) {
348 CFBundleRef result
= NULL
, bundle
;
349 if (_bundlesByIdentifier
&& bundleID
) {
350 // Note that this array is maintained in descending order by version number
351 CFArrayRef bundlesWithThisID
= (CFArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
352 if (bundlesWithThisID
) {
353 CFIndex i
, count
= CFArrayGetCount(bundlesWithThisID
);
355 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
356 for (i
= 0; !result
&& i
< count
; i
++) {
357 bundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, i
);
358 if (CFBundleIsExecutableLoaded(bundle
)) result
= bundle
;
360 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
361 if (!result
) result
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, 0);
368 #else /* AVOID_WEAK_COLLECTIONS */
371 An explanation of what I'm doing here is probably in order.
372 8029300 has cast suspicion on the correctness of __CFMapTable with strong keys and weak values, at least under non-GC.
373 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
374 This indicates that it's not an overrelease in securityd, since AVOID_WEAK_COLLECTIONS wouldn't help in that case.
375 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.
377 static inline id
_getBundlesByURL() {
378 static id _bundles
= nil
;
379 static dispatch_once_t onceToken
;
380 dispatch_once(&onceToken
, ^{
381 if (CF_USING_COLLECTABLE_MEMORY
) {
382 _bundles
= [[__CFMapTable alloc
] initWithKeyOptions
:CFPointerFunctionsStrongMemory valueOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
384 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
385 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
386 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
387 _bundles
= (id
)CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
393 #define _bundlesByURL _getBundlesByURL()
395 static void _setInBundlesByURL(CFURLRef key
, CFBundleRef bundle
) {
396 if (CF_USING_COLLECTABLE_MEMORY
) {
397 [(__CFMapTable
*)_bundlesByURL setObject
:(id
)bundle forKey
:(id
)key
];
399 CFDictionarySetValue((CFMutableDictionaryRef
)_bundlesByURL
, key
, bundle
);
403 static void _removeFromBundlesByURL(CFURLRef key
) {
404 if (CF_USING_COLLECTABLE_MEMORY
) {
405 [(__CFMapTable
*)_bundlesByURL removeObjectForKey
:(id
)key
];
407 CFDictionaryRemoveValue((CFMutableDictionaryRef
)_bundlesByURL
, key
);
411 static CFBundleRef
_getFromBundlesByURL(CFURLRef key
) {
412 if (CF_USING_COLLECTABLE_MEMORY
) {
413 return (CFBundleRef
)[(__CFMapTable
*)_bundlesByURL objectForKey
:(id
)key
];
415 return (CFBundleRef
)CFDictionaryGetValue((CFMutableDictionaryRef
)_bundlesByURL
, key
);
419 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
420 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
422 if (!alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
424 // Add to the _allBundles list
425 if (!_allBundles
) _allBundles
= [[__CFHashTable alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
426 [_allBundles addObject
:(id
)bundle
];
428 // Add to the table that maps urls to bundles
429 _setInBundlesByURL(bundle
->_url
, bundle
);
431 // Add to the table that maps identifiers to bundles
433 __CFPointerArray
*bundlesWithThisID
= nil
;
434 CFBundleRef existingBundle
= NULL
;
435 if (!_bundlesByIdentifier
) {
436 _bundlesByIdentifier
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
438 bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
439 if (bundlesWithThisID
) {
440 CFIndex i
, count
= (CFIndex
)[bundlesWithThisID count
];
441 UInt32 existingVersion
, newVersion
= CFBundleGetVersionNumber(bundle
);
442 for (i
= 0; i
< count
; i
++) {
443 existingBundle
= (CFBundleRef
)[bundlesWithThisID pointerAtIndex
:i
];
444 if (!existingBundle
) continue;
445 existingVersion
= CFBundleGetVersionNumber(existingBundle
);
446 // If you load two bundles with the same identifier and the same version, the last one wins.
447 if (newVersion
>= existingVersion
) break;
450 [bundlesWithThisID insertPointer
:bundle atIndex
:i
];
452 [bundlesWithThisID addPointer
:bundle
];
455 bundlesWithThisID
= [[__CFPointerArray alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory
];
456 [bundlesWithThisID addPointer
:bundle
];
457 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundlesWithThisID
);
458 [bundlesWithThisID release
];
461 if (!alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
464 static void _CFBundleRemoveFromTables(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef bundleID
) {
465 __CFSpinLock(&CFBundleGlobalDataLock
);
466 // Remove from the various lists
467 if (_allBundles
&& [_allBundles member
:(id
)bundle
]) [_allBundles removeObject
:(id
)bundle
];
469 // Remove from the table that maps urls to bundles
471 _removeFromBundlesByURL(bundleURL
);
474 // Remove from the table that maps identifiers to bundles
475 if (bundleID
&& _bundlesByIdentifier
) {
476 __CFPointerArray
*bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
477 if (bundlesWithThisID
) {
478 CFIndex count
= (CFIndex
)[bundlesWithThisID count
];
479 while (count
-- > 0) if (bundle
== (CFBundleRef
)[bundlesWithThisID pointerAtIndex
:count
]) [bundlesWithThisID removePointerAtIndex
:count
];
480 [bundlesWithThisID compact
];
481 if (0 == [bundlesWithThisID count
]) CFDictionaryRemoveValue(_bundlesByIdentifier
, bundleID
);
484 __CFSpinUnlock(&CFBundleGlobalDataLock
);
487 static CFBundleRef
_CFBundleCopyBundleForURL(CFURLRef url
, Boolean alreadyLocked
) {
488 CFBundleRef result
= NULL
;
489 if (!alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
490 result
= _getFromBundlesByURL(url
);
491 if (result
&& !result
->_url
) {
493 _removeFromBundlesByURL(url
);
495 if (result
) CFRetain(result
);
496 if (!alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
500 static CFBundleRef
_CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID
) {
501 CFBundleRef result
= NULL
;
502 if (_bundlesByIdentifier
&& bundleID
) {
503 // Note that this array is maintained in descending order by version number
504 __CFPointerArray
*bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
505 if (bundlesWithThisID
&& [bundlesWithThisID count
] > 0) {
506 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
507 for (id bundle in bundlesWithThisID
) {
508 if (bundle
&& CFBundleIsExecutableLoaded((CFBundleRef
)bundle
)) {
509 result
= (CFBundleRef
)bundle
;
513 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
515 for (id bundle in bundlesWithThisID
) {
517 result
= (CFBundleRef
)bundle
;
527 #endif /* AVOID_WEAK_COLLECTIONS */
529 #if 0 && DEPLOYMENT_TARGET_WINDOWS
530 static CFStringRef
_CFBundleCopyWrapperInBinaryDirectory(CFStringRef strippedExeName
) {
531 char buff
[CFMaxPathSize
];
535 CFArrayRef binaryDirs
= _CFGetWindowsBinaryDirectories();
536 int count
= CFArrayGetCount(binaryDirs
);
539 for (i
= 0; i
< count
; i
++) {
540 str
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@\\%@.app"), CFArrayGetValueAtIndex(binaryDirs
,i
), strippedExeName
);
541 buffLen
= CFStringGetLength(str
);
542 CFStringGetFileSystemRepresentation(str
, buff
, CFMaxPathSize
);
543 if (stat(buff
, &garbage
) == 0) return str
;
548 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
550 #error Unknown or unspecified DEPLOYMENT_TARGET
553 static CFURLRef
_CFBundleCopyBundleURLForExecutablePath(CFStringRef str
) {
554 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
555 UniChar buff
[CFMaxPathSize
];
560 buffLen
= CFStringGetLength(str
);
561 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
562 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
564 #if 0 && DEPLOYMENT_TARGET_WINDOWS
565 CFIndex startOfBinaryName
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
) + 1; // Remove exe name
566 CFIndex endOfBinaryName
= _CFLengthAfterDeletingPathExtension(buff
, buffLen
);
567 if (startOfBinaryName
> 0 && startOfBinaryName
< buffLen
&& endOfBinaryName
> 0 && endOfBinaryName
<= buffLen
) {
568 CFStringRef strippedExeName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfBinaryName
]), endOfBinaryName
- startOfBinaryName
);
569 CFStringRef wrapperInBinaryDirectory
= _CFBundleCopyWrapperInBinaryDirectory(strippedExeName
);
570 if (wrapperInBinaryDirectory
) {
571 buffLen
= CFStringGetLength(wrapperInBinaryDirectory
);
572 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
573 CFStringGetCharacters(wrapperInBinaryDirectory
, CFRangeMake(0, buffLen
), buff
);
574 CFRelease(wrapperInBinaryDirectory
);
575 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
576 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
581 #elif DEPLOYMENT_TARGET_WINDOWS
582 // Is this a .dll or .exe?
583 if (buffLen
>= 5 && (_wcsnicmp((wchar_t *)&(buff
[buffLen
-4]), L
".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff
[buffLen
-4]), L
".exe", 4) == 0)) {
584 CFIndex extensionLength
= CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension
);
586 // If this is an _debug, we should strip that before looking for the bundle
587 if (buffLen
>= 7 && (_wcsnicmp((wchar_t *)&buff
[buffLen
-6], L
"_debug", 6) == 0)) buffLen
-= 6;
589 if (buffLen
+ 1 + extensionLength
< CFMaxPathSize
) {
592 CFStringGetCharacters(_CFBundleWindowsResourceDirectoryExtension
, CFRangeMake(0, extensionLength
), buff
+ buffLen
);
593 buffLen
+= extensionLength
;
594 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
595 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
599 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
601 #error Unknown or unspecified DEPLOYMENT_TARGET
605 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
); // Remove exe name
607 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
609 // See if this is a new bundle. If it is, we have to remove more path components.
610 CFIndex startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
611 if (startOfLastDir
> 0 && startOfLastDir
< buffLen
) {
612 CFStringRef lastDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
614 if (CFEqual(lastDirName
, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
615 // This is a new bundle. Back off a few more levels
617 // Remove platform folder
618 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
621 // Remove executables folder (if present)
622 CFIndex startOfNextDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
623 if (startOfNextDir
> 0 && startOfNextDir
< buffLen
) {
624 CFStringRef nextDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfNextDir
]), buffLen
- startOfNextDir
);
625 if (CFEqual(nextDirName
, _CFBundleExecutablesDirectoryName
)) buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
626 CFRelease(nextDirName
);
630 // Remove support files folder
631 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
632 #elif 0 && DEPLOYMENT_TARGET_WINDOWS
634 // See if this is a new bundle. If it is, we have to remove more path components.
635 CFIndex startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
636 if (startOfLastDir
> 0 && startOfLastDir
< buffLen
) {
637 CFStringRef lastDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
639 if (CFEqual(lastDirName
, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
640 // This is a new bundle. Back off a few more levels
642 // Remove platform folder
643 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
646 // Remove executables folder (if present)
647 CFIndex startOfNextDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
648 if (startOfNextDir
> 0 && startOfNextDir
< buffLen
) {
649 CFStringRef nextDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfNextDir
]), buffLen
- startOfNextDir
);
650 if (CFEqual(nextDirName
, _CFBundleExecutablesDirectoryName
)) buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
651 CFRelease(nextDirName
);
653 #error Unknown or unspecified DEPLOYMENT_TARGET
657 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
658 CFRelease(lastDirName
);
661 #elif 0 && DEPLOYMENT_TARGET_WINDOWS
663 // Remove support files folder
664 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
667 CFRelease(lastDirName
);
671 #error Unknown or unspecified DEPLOYMENT_TARGET
675 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
676 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
683 static CFURLRef
_CFBundleCopyResolvedURLForExecutableURL(CFURLRef url
) {
684 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
685 CFURLRef absoluteURL
, url1
, url2
, outURL
= NULL
;
686 CFStringRef str
, str1
, str2
;
687 absoluteURL
= CFURLCopyAbsoluteURL(url
);
688 str
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
690 UniChar buff
[CFMaxPathSize
];
691 CFIndex buffLen
= CFStringGetLength(str
), len1
;
692 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
693 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
694 len1
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
695 if (len1
> 0 && len1
+ 1 < buffLen
) {
696 str1
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, buff
, len1
);
697 CFIndex skipSlashCount
= 1;
698 #if DEPLOYMENT_TARGET_WINDOWS
699 // 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
700 if (len1
== 3 && buff
[1] == ':' && buff
[2] == '\\') {
704 str2
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, buff
+ len1
+ skipSlashCount
, buffLen
- len1
- skipSlashCount
);
706 url1
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str1
, PLATFORM_PATH_STYLE
, true);
708 url2
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, str2
, PLATFORM_PATH_STYLE
, false, url1
);
710 outURL
= CFURLCopyAbsoluteURL(url2
);
716 if (str1
) CFRelease(str1
);
717 if (str2
) CFRelease(str2
);
722 outURL
= absoluteURL
;
724 CFRelease(absoluteURL
);
729 CFURLRef
_CFBundleCopyBundleURLForExecutableURL(CFURLRef url
) {
730 CFURLRef resolvedURL
, outurl
= NULL
;
732 resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
733 str
= CFURLCopyFileSystemPath(resolvedURL
, PLATFORM_PATH_STYLE
);
735 outurl
= _CFBundleCopyBundleURLForExecutablePath(str
);
738 CFRelease(resolvedURL
);
742 static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle
) {
743 uint8_t localVersion
= bundle
->_version
;
744 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
745 if (0 == localVersion
) {
746 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
747 if (!infoDict
|| 0 == CFDictionaryGetCount(infoDict
)) {
748 #if defined(BINARY_SUPPORT_DYLD)
749 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
751 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
752 if (bundle
->_binaryType
== __CFBundleCFMBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
755 bundle
->_resourceData
._executableLacksResourceFork
= true;
757 CFRelease(executableURL
);
762 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
764 CFRelease(executableURL
);
768 #endif /* BINARY_SUPPORT_DYLD */
774 CFBundleRef
_CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
775 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
777 uint8_t localVersion
= _CFBundleEffectiveLayoutVersion(bundle
);
778 if (3 == localVersion
|| 4 == localVersion
) {
786 CFBundleRef
_CFBundleGetMainBundleIfLooksLikeBundle(void) {
787 CFBundleRef mainBundle
= CFBundleGetMainBundle();
788 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
792 Boolean
_CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) {
793 CFBundleRef mainBundle
= CFBundleGetMainBundle();
794 return (mainBundle
&& mainBundle
->_resourceData
._infoDictionaryFromResourceFork
);
797 CFBundleRef
_CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
798 CFBundleRef bundle
= NULL
;
799 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
800 if (bundleURL
&& resolvedURL
) {
801 bundle
= _CFBundleCreateIfLooksLikeBundle(allocator
, bundleURL
);
803 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
804 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
805 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, (uint8_t *)buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
809 if (executableURL
) CFRelease(executableURL
);
812 if (bundleURL
) CFRelease(bundleURL
);
813 if (resolvedURL
) CFRelease(resolvedURL
);
817 CFBundleRef
_CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
818 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
820 Boolean mightBeBundle
= true, isDir
= false;
821 uint8_t localVersion
= _CFBundleEffectiveLayoutVersion(bundle
);
822 if (3 == localVersion
) {
823 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
824 CFURLRef executableURL
, supportFilesURL
, resourceSpecificationFileURL
;
825 CFArrayRef supportedPlatforms
;
826 CFStringRef resourceSpecificationFile
;
828 mightBeBundle
= false;
829 if (infoDict
&& CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
) && (executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
))) {
830 supportedPlatforms
= _CFBundleGetSupportedPlatforms(bundle
);
831 resourceSpecificationFile
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleResourceSpecificationKey
);
832 if (supportedPlatforms
&& CFArrayGetCount(supportedPlatforms
) > 0 && CFArrayGetFirstIndexOfValue(supportedPlatforms
, CFRangeMake(0, CFArrayGetCount(supportedPlatforms
)), CFSTR("iPhoneOS")) >= 0) {
833 mightBeBundle
= true;
834 } else if (resourceSpecificationFile
&& CFGetTypeID(resourceSpecificationFile
) == CFStringGetTypeID() && (supportFilesURL
= CFBundleCopySupportFilesDirectoryURL(bundle
))) {
835 resourceSpecificationFileURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, resourceSpecificationFile
, kCFURLPOSIXPathStyle
, false, supportFilesURL
);
836 if (resourceSpecificationFileURL
) {
837 if (_CFIsResourceAtURL(resourceSpecificationFileURL
, &isDir
) && !isDir
) mightBeBundle
= true;
838 CFRelease(resourceSpecificationFileURL
);
840 CFRelease(supportFilesURL
);
842 CFRelease(executableURL
);
844 } else if (4 == localVersion
) {
845 mightBeBundle
= false;
847 if (!mightBeBundle
) {
855 CFBundleRef
_CFBundleCreateWithExecutableURLIfMightBeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
856 CFBundleRef bundle
= NULL
;
857 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
858 if (bundleURL
&& resolvedURL
) {
859 bundle
= _CFBundleCreateIfMightBeBundle(allocator
, bundleURL
);
861 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
862 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
863 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, (uint8_t *)buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
867 if (executableURL
) CFRelease(executableURL
);
870 if (bundleURL
) CFRelease(bundleURL
);
871 if (resolvedURL
) CFRelease(resolvedURL
);
875 CFURLRef
_CFBundleCopyMainBundleExecutableURL(Boolean
*looksLikeBundle
) {
876 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
877 const char *processPath
;
878 CFStringRef str
= NULL
;
879 CFURLRef executableURL
= NULL
;
880 processPath
= _CFProcessPath();
882 str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, processPath
);
884 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, PLATFORM_PATH_STYLE
, false);
888 if (looksLikeBundle
) {
889 CFBundleRef mainBundle
= _mainBundle
;
890 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
891 *looksLikeBundle
= (mainBundle
? true : false);
893 return executableURL
;
896 static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef executablePath
) {
897 CFBundleGetInfoDictionary(_mainBundle
);
898 if (!_mainBundle
->_infoDict
|| CFDictionaryGetCount(_mainBundle
->_infoDict
) == 0) {
899 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
900 if (_mainBundle
->_version
== 3) _mainBundle
->_version
= 4;
901 if (_mainBundle
->_version
== 0) {
902 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
903 CFStringRef executableName
= _CFBundleCopyExecutableName(_mainBundle
, NULL
, NULL
);
904 if (!executableName
|| !executablePath
|| !CFStringHasSuffix(executablePath
, executableName
)) _mainBundle
->_version
= 4;
905 if (executableName
) CFRelease(executableName
);
907 #if defined(BINARY_SUPPORT_DYLD)
908 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
909 if (_mainBundle
->_infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(_mainBundle
->_infoDict
);
910 _mainBundle
->_infoDict
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromMainExecutable();
912 #endif /* BINARY_SUPPORT_DYLD */
914 #if defined(BINARY_SUPPORT_DYLD)
915 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
916 // if dyld and not main executable for bundle, prefer info dictionary from executable
917 CFStringRef executableName
= _CFBundleCopyExecutableName(_mainBundle
, NULL
, NULL
);
918 if (!executableName
|| !executablePath
|| !CFStringHasSuffix(executablePath
, executableName
)) {
919 CFDictionaryRef infoDictFromExecutable
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromMainExecutable();
920 if (infoDictFromExecutable
&& CFDictionaryGetCount(infoDictFromExecutable
) > 0) {
921 if (_mainBundle
->_infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(_mainBundle
->_infoDict
);
922 _mainBundle
->_infoDict
= infoDictFromExecutable
;
925 if (executableName
) CFRelease(executableName
);
927 #endif /* BINARY_SUPPORT_DYLD */
929 if (!_mainBundle
->_infoDict
) _mainBundle
->_infoDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
930 if (!CFDictionaryGetValue(_mainBundle
->_infoDict
, _kCFBundleExecutablePathKey
)) CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), _kCFBundleExecutablePathKey
, executablePath
);
931 CFStringRef bundleID
= (CFStringRef
)CFDictionaryGetValue(_mainBundle
->_infoDict
, kCFBundleIdentifierKey
);
933 if (!CFStringGetCString(bundleID
, __CFBundleMainID__
, sizeof(__CFBundleMainID__
) - 2, kCFStringEncodingUTF8
)) {
934 __CFBundleMainID__
[0] = '\0';
939 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle
, Boolean alreadyLocked
) {
940 CFDictionaryRef oldInfoDict
= bundle
->_infoDict
;
943 _CFBundleFlushCachesForURL(bundle
->_url
);
944 bundle
->_infoDict
= NULL
;
945 if (bundle
->_localInfoDict
) {
946 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(bundle
->_localInfoDict
);
947 bundle
->_localInfoDict
= NULL
;
949 if (bundle
->_searchLanguages
) {
950 CFRelease(bundle
->_searchLanguages
);
951 bundle
->_searchLanguages
= NULL
;
953 if (bundle
->_resourceData
._stringTableCache
) {
954 CFRelease(bundle
->_resourceData
._stringTableCache
);
955 bundle
->_resourceData
._stringTableCache
= NULL
;
957 if (bundle
== _mainBundle
) {
958 CFStringRef executablePath
= oldInfoDict
? (CFStringRef
)CFDictionaryGetValue(oldInfoDict
, _kCFBundleExecutablePathKey
) : NULL
;
959 if (!alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
960 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath
);
961 if (!alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
963 CFBundleGetInfoDictionary(bundle
);
966 if (!bundle
->_infoDict
) bundle
->_infoDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
967 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundleInitialPathKey
);
968 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundleInitialPathKey
, val
);
969 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundleResolvedPathKey
);
970 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundleResolvedPathKey
, val
);
971 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundlePrincipalClassKey
);
972 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundlePrincipalClassKey
, val
);
973 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(oldInfoDict
);
977 CF_EXPORT
void _CFBundleFlushBundleCaches(CFBundleRef bundle
) {
978 _CFBundleFlushBundleCachesAlreadyLocked(bundle
, false);
981 static CFBundleRef
_CFBundleGetMainBundleAlreadyLocked(void) {
982 if (!_initedMainBundle
) {
983 const char *processPath
;
984 CFStringRef str
= NULL
;
985 CFURLRef executableURL
= NULL
, bundleURL
= NULL
;
986 _initedMainBundle
= true;
987 processPath
= _CFProcessPath();
989 str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, processPath
);
990 if (!executableURL
) executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, PLATFORM_PATH_STYLE
, false);
992 if (executableURL
) bundleURL
= _CFBundleCopyBundleURLForExecutableURL(executableURL
);
994 // make sure that main bundle has executable path
995 //??? what if we are not the main executable in the bundle?
996 // NB doFinalProcessing must be false here, see below
997 _mainBundle
= _CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
, true, false);
999 // make sure that the main bundle is listed as loaded, and mark it as executable
1000 _mainBundle
->_isLoaded
= true;
1001 #if defined(BINARY_SUPPORT_DYLD)
1002 if (_mainBundle
->_binaryType
== __CFBundleUnknownBinary
) {
1003 if (!executableURL
) {
1004 _mainBundle
->_binaryType
= __CFBundleNoBinary
;
1006 _mainBundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
1007 if (_mainBundle
->_binaryType
!= __CFBundleCFMBinary
&& _mainBundle
->_binaryType
!= __CFBundleUnreadableBinary
) _mainBundle
->_resourceData
._executableLacksResourceFork
= true;
1010 #endif /* BINARY_SUPPORT_DYLD */
1011 // get cookie for already-loaded main bundle
1012 #if defined(BINARY_SUPPORT_DLFCN)
1013 if (!_mainBundle
->_handleCookie
) {
1014 _mainBundle
->_handleCookie
= dlopen(NULL
, RTLD_NOLOAD
| RTLD_FIRST
);
1016 printf("main bundle %p getting handle %p\n", _mainBundle
, _mainBundle
->_handleCookie
);
1017 #endif /* LOG_BUNDLE_LOAD */
1019 #elif defined(BINARY_SUPPORT_DYLD)
1020 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
&& !_mainBundle
->_imageCookie
) {
1021 _mainBundle
->_imageCookie
= (void *)_dyld_get_image_header(0);
1023 printf("main bundle %p getting image %p\n", _mainBundle
, _mainBundle
->_imageCookie
);
1024 #endif /* LOG_BUNDLE_LOAD */
1026 #endif /* BINARY_SUPPORT_DLFCN */
1027 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str
);
1028 // Perform delayed final processing steps.
1029 // This must be done after _isLoaded has been set, for security reasons (3624341).
1030 _CFBundleCheckWorkarounds(_mainBundle
);
1031 if (_CFBundleNeedsInitPlugIn(_mainBundle
)) {
1032 __CFSpinUnlock(&CFBundleGlobalDataLock
);
1033 _CFBundleInitPlugIn(_mainBundle
);
1034 __CFSpinLock(&CFBundleGlobalDataLock
);
1038 if (bundleURL
) CFRelease(bundleURL
);
1039 if (str
) CFRelease(str
);
1040 if (executableURL
) CFRelease(executableURL
);
1045 CFBundleRef
CFBundleGetMainBundle(void) {
1046 CFBundleRef mainBundle
;
1047 __CFSpinLock(&CFBundleGlobalDataLock
);
1048 mainBundle
= _CFBundleGetMainBundleAlreadyLocked();
1049 __CFSpinUnlock(&CFBundleGlobalDataLock
);
1053 CFBundleRef
CFBundleGetBundleWithIdentifier(CFStringRef bundleID
) {
1054 CFBundleRef result
= NULL
;
1056 __CFSpinLock(&CFBundleGlobalDataLock
);
1057 (void)_CFBundleGetMainBundleAlreadyLocked();
1058 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
1059 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1061 // Try to create the bundle for the caller and try again
1062 void *p
= __builtin_return_address(0);
1064 CFStringRef imagePath
= NULL
;
1065 #if defined(BINARY_SUPPORT_DYLD)
1066 if (!imagePath
) imagePath
= _CFBundleDYLDCopyLoadedImagePathForPointer(p
);
1067 #elif defined(BINARY_SUPPORT_DLFCN)
1068 if (!imagePath
) imagePath
= _CFBundleDlfcnCopyLoadedImagePathForPointer(p
);
1069 #endif /* BINARY_SUPPORT_DYLD */
1071 _CFBundleEnsureBundleExistsForImagePath(imagePath
);
1072 CFRelease(imagePath
);
1074 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
1077 #elif DEPLOYMENT_TARGET_WINDOWS
1079 #error Unknown or unspecified DEPLOYMENT_TARGET
1082 // Try to guess the bundle from the identifier and try again
1083 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID
);
1084 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
1087 // Make sure all bundles have been created and try again.
1088 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
1089 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
1091 __CFSpinUnlock(&CFBundleGlobalDataLock
);
1096 static CFStringRef
__CFBundleCopyDescription(CFTypeRef cf
) {
1097 char buff
[CFMaxPathSize
];
1098 CFStringRef path
= NULL
, binaryType
= NULL
, retval
= NULL
;
1099 if (((CFBundleRef
)cf
)->_url
&& CFURLGetFileSystemRepresentation(((CFBundleRef
)cf
)->_url
, true, (uint8_t *)buff
, CFMaxPathSize
)) path
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
1100 switch (((CFBundleRef
)cf
)->_binaryType
) {
1101 case __CFBundleCFMBinary
:
1102 binaryType
= CFSTR("");
1104 case __CFBundleDYLDExecutableBinary
:
1105 binaryType
= CFSTR("executable, ");
1107 case __CFBundleDYLDBundleBinary
:
1108 binaryType
= CFSTR("bundle, ");
1110 case __CFBundleDYLDFrameworkBinary
:
1111 binaryType
= CFSTR("framework, ");
1113 case __CFBundleDLLBinary
:
1114 binaryType
= CFSTR("DLL, ");
1116 case __CFBundleUnreadableBinary
:
1117 binaryType
= CFSTR("");
1120 binaryType
= CFSTR("");
1123 if (((CFBundleRef
)cf
)->_plugInData
._isPlugIn
) {
1124 retval
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("CFBundle/CFPlugIn %p <%@> (%@%@loaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? CFSTR("") : CFSTR("not "));
1126 retval
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("CFBundle %p <%@> (%@%@loaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? CFSTR("") : CFSTR("not "));
1128 if (path
) CFRelease(path
);
1132 static void _CFBundleDeallocateGlue(const void *key
, const void *value
, void *context
) {
1133 CFAllocatorRef allocator
= (CFAllocatorRef
)context
;
1134 if (value
) CFAllocatorDeallocate(allocator
, (void *)value
);
1137 static void __CFBundleDeallocate(CFTypeRef cf
) {
1138 CFBundleRef bundle
= (CFBundleRef
)cf
;
1140 CFStringRef bundleID
= NULL
;
1142 __CFGenericValidateType(cf
, __kCFBundleTypeID
);
1143 bundleURL
= bundle
->_url
;
1144 bundle
->_url
= NULL
;
1145 if (bundle
->_infoDict
) bundleID
= (CFStringRef
)CFDictionaryGetValue(bundle
->_infoDict
, kCFBundleIdentifierKey
);
1146 _CFBundleRemoveFromTables(bundle
, bundleURL
, bundleID
);
1147 CFBundleUnloadExecutable(bundle
);
1148 _CFBundleDeallocatePlugIn(bundle
);
1150 _CFBundleFlushCachesForURL(bundleURL
);
1151 CFRelease(bundleURL
);
1153 if (bundle
->_infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(bundle
->_infoDict
);
1154 if (bundle
->_modDate
) CFRelease(bundle
->_modDate
);
1155 if (bundle
->_localInfoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(bundle
->_localInfoDict
);
1156 if (bundle
->_searchLanguages
) CFRelease(bundle
->_searchLanguages
);
1157 if (bundle
->_glueDict
) {
1158 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
1159 CFRelease(bundle
->_glueDict
);
1161 if (bundle
->_resourceData
._stringTableCache
) CFRelease(bundle
->_resourceData
._stringTableCache
);
1164 static const CFRuntimeClass __CFBundleClass
= {
1165 _kCFRuntimeScannedObject
,
1169 __CFBundleDeallocate
,
1173 __CFBundleCopyDescription
1176 // From CFBundle_Resources.c
1177 void _CFBundleResourcesInitialize();
1179 __private_extern__
void __CFBundleInitialize(void) {
1180 __kCFBundleTypeID
= _CFRuntimeRegisterClass(&__CFBundleClass
);
1181 _CFBundleResourcesInitialize();
1184 CFTypeID
CFBundleGetTypeID(void) {
1185 return __kCFBundleTypeID
;
1188 CFBundleRef
_CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL
) {
1189 CFBundleRef bundle
= NULL
;
1190 char buff
[CFMaxPathSize
];
1191 CFURLRef newURL
= NULL
;
1193 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) return NULL
;
1195 newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)buff
, strlen(buff
), true);
1196 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1197 bundle
= _CFBundleCopyBundleForURL(newURL
, false);
1198 if (bundle
) CFRelease(bundle
);
1203 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
) {
1204 allocator
= _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator
);
1205 CFBundleRef bundle
= NULL
;
1206 char buff
[CFMaxPathSize
];
1207 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
1208 Boolean exists
= false;
1210 CFURLRef newURL
= NULL
;
1211 uint8_t localVersion
= 0;
1213 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) return NULL
;
1215 newURL
= CFURLCreateFromFileSystemRepresentation(allocator
, (uint8_t *)buff
, strlen(buff
), true);
1216 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1217 bundle
= _CFBundleCopyBundleForURL(newURL
, alreadyLocked
);
1223 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
1225 SInt32 res
= _CFGetPathProperties(allocator
, (char *)buff
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
);
1226 #if DEPLOYMENT_TARGET_WINDOWS
1227 if (!(res
== 0 && exists
&& ((mode
& S_IFMT
) == S_IFDIR
))) {
1228 // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again
1233 CFURLRef shorterPath
= CFURLCreateCopyDeletingLastPathComponent(allocator
, newURL
);
1235 newURL
= shorterPath
;
1236 res
= _CFGetFileProperties(allocator
, newURL
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
);
1240 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
1241 if (modDate
) CFRelease(modDate
);
1251 bundle
= (CFBundleRef
)_CFRuntimeCreateInstance(allocator
, __kCFBundleTypeID
, sizeof(struct __CFBundle
) - sizeof(CFRuntimeBase
), NULL
);
1257 bundle
->_url
= newURL
;
1259 bundle
->_modDate
= modDate
;
1260 bundle
->_version
= localVersion
;
1261 bundle
->_infoDict
= NULL
;
1262 bundle
->_localInfoDict
= NULL
;
1263 bundle
->_searchLanguages
= NULL
;
1265 #if defined(BINARY_SUPPORT_DYLD)
1266 /* We'll have to figure it out later */
1267 bundle
->_binaryType
= __CFBundleUnknownBinary
;
1268 #elif defined(BINARY_SUPPORT_DLL)
1269 /* We support DLL only */
1270 bundle
->_binaryType
= __CFBundleDLLBinary
;
1271 bundle
->_hModule
= NULL
;
1273 /* We'll have to figure it out later */
1274 bundle
->_binaryType
= __CFBundleUnknownBinary
;
1275 #endif /* BINARY_SUPPORT_DYLD */
1277 bundle
->_isLoaded
= false;
1278 bundle
->_sharesStringsFiles
= false;
1280 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1281 if (!__CFgetenv("CFBundleDisableStringsSharing") &&
1282 (strncmp(buff
, "/System/Library/Frameworks", 26) == 0) &&
1283 (strncmp(buff
+ strlen(buff
) - 10, ".framework", 10) == 0)) bundle
->_sharesStringsFiles
= true;
1284 #elif DEPLOYMENT_TARGET_WINDOWS
1286 #error Unknown or unspecified DEPLOYMENT_TARGET
1289 bundle
->_connectionCookie
= NULL
;
1290 bundle
->_handleCookie
= NULL
;
1291 bundle
->_imageCookie
= NULL
;
1292 bundle
->_moduleCookie
= NULL
;
1294 bundle
->_glueDict
= NULL
;
1296 bundle
->_resourceData
._executableLacksResourceFork
= false;
1297 bundle
->_resourceData
._infoDictionaryFromResourceFork
= false;
1298 bundle
->_resourceData
._stringTableCache
= NULL
;
1300 bundle
->_plugInData
._isPlugIn
= false;
1301 bundle
->_plugInData
._loadOnDemand
= false;
1302 bundle
->_plugInData
._isDoingDynamicRegistration
= false;
1303 bundle
->_plugInData
._instanceCount
= 0;
1304 bundle
->_plugInData
._factories
= NULL
;
1306 bundle
->_bundleLoadingLock
= CFSpinLockInit
;
1308 CFBundleGetInfoDictionary(bundle
);
1310 _CFBundleAddToTables(bundle
, alreadyLocked
);
1312 if (doFinalProcessing
) {
1313 _CFBundleCheckWorkarounds(bundle
);
1314 if (_CFBundleNeedsInitPlugIn(bundle
)) {
1315 if (alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
1316 _CFBundleInitPlugIn(bundle
);
1317 if (alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
1324 CFBundleRef
CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
) {
1325 return _CFBundleCreate(allocator
, bundleURL
, false, true);
1328 CFArrayRef
CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc
, CFURLRef directoryURL
, CFStringRef bundleType
) {
1329 alloc
= _CFConvertAllocatorToNonGCRefZeroEquivalent(alloc
);
1330 CFMutableArrayRef bundles
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
1331 CFArrayRef URLs
= _CFContentsOfDirectory(alloc
, NULL
, NULL
, directoryURL
, bundleType
);
1333 CFIndex i
, c
= CFArrayGetCount(URLs
);
1335 CFBundleRef curBundle
;
1337 for (i
= 0; i
< c
; i
++) {
1338 curURL
= (CFURLRef
)CFArrayGetValueAtIndex(URLs
, i
);
1339 curBundle
= CFBundleCreate(alloc
, curURL
);
1340 if (curBundle
) CFArrayAppendValue(bundles
, curBundle
);
1348 CFURLRef
CFBundleCopyBundleURL(CFBundleRef bundle
) {
1349 if (bundle
->_url
) CFRetain(bundle
->_url
);
1350 return bundle
->_url
;
1353 void _CFBundleSetDefaultLocalization(CFStringRef localizationName
) {
1354 CFStringRef newLocalization
= localizationName
? (CFStringRef
)CFStringCreateCopy(kCFAllocatorSystemDefault
, localizationName
) : NULL
;
1355 if (_defaultLocalization
) CFRelease(_defaultLocalization
);
1356 _defaultLocalization
= newLocalization
;
1359 CFArrayRef
_CFBundleGetLanguageSearchList(CFBundleRef bundle
) {
1360 if (!bundle
->_searchLanguages
) {
1361 CFMutableArrayRef langs
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1362 CFStringRef devLang
= CFBundleGetDevelopmentRegion(bundle
);
1364 #if DEPLOYMENT_TARGET_WINDOWS
1365 if (_defaultLocalization
) CFArrayAppendValue(langs
, _defaultLocalization
);
1367 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, devLang
);
1369 if (CFArrayGetCount(langs
) == 0) {
1370 // If the user does not prefer any of our languages, and devLang is not present, try English
1371 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFSTR("en_US"));
1373 if (CFArrayGetCount(langs
) == 0) {
1374 // if none of the preferred localizations are present, fall back on a random localization that is present
1375 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
1376 if (localizations
) {
1377 if (CFArrayGetCount(localizations
) > 0) _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, (CFStringRef
)CFArrayGetValueAtIndex(localizations
, 0));
1378 CFRelease(localizations
);
1382 if (devLang
&& !CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
)) {
1383 // Make sure that devLang is on the list as a fallback for individual resources that are not present
1384 CFArrayAppendValue(langs
, devLang
);
1385 } else if (!devLang
) {
1386 // Or if there is no devLang, try some variation of English that is present
1387 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
1388 if (localizations
) {
1389 CFStringRef en_US
= CFSTR("en_US"), en
= CFSTR("en"), English
= CFSTR("English");
1390 CFRange range
= CFRangeMake(0, CFArrayGetCount(localizations
));
1391 if (CFArrayContainsValue(localizations
, range
, en
)) {
1392 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en
)) CFArrayAppendValue(langs
, en
);
1393 } else if (CFArrayContainsValue(localizations
, range
, English
)) {
1394 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), English
)) CFArrayAppendValue(langs
, English
);
1395 } else if (CFArrayContainsValue(localizations
, range
, en_US
)) {
1396 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en_US
)) CFArrayAppendValue(langs
, en_US
);
1398 CFRelease(localizations
);
1401 if (CFArrayGetCount(langs
) == 0) {
1402 // Total backstop behavior to avoid having an empty array.
1403 if (_defaultLocalization
) {
1404 CFArrayAppendValue(langs
, _defaultLocalization
);
1406 CFArrayAppendValue(langs
, CFSTR("en"));
1409 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, (void *)langs
, (void * volatile *)&(bundle
->_searchLanguages
))) CFRelease(langs
);
1411 return bundle
->_searchLanguages
;
1414 CFDictionaryRef
CFBundleCopyInfoDictionaryInDirectory(CFURLRef url
) {
1415 CFDictionaryRef dict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, NULL
);
1416 if (dict
&& _CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRetain(dict
); // conditionally put on a retain for a Copy function
1420 CFDictionaryRef
CFBundleGetInfoDictionary(CFBundleRef bundle
) {
1421 if (!bundle
->_infoDict
) bundle
->_infoDict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(kCFAllocatorSystemDefaultGCRefZero
, bundle
->_url
, bundle
->_version
);
1422 return bundle
->_infoDict
;
1425 CFDictionaryRef
_CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
1426 return CFBundleGetLocalInfoDictionary(bundle
);
1429 CFDictionaryRef
CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
1430 static CFSpinLock_t CFBundleLocalInfoLock
= CFSpinLockInit
;
1431 CFDictionaryRef localInfoDict
= bundle
->_localInfoDict
;
1432 if (!localInfoDict
) {
1433 CFURLRef url
= CFBundleCopyResourceURL(bundle
, _CFBundleLocalInfoName
, _CFBundleStringTableType
, NULL
);
1437 CFStringRef errStr
= NULL
;
1439 if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, url
, &data
, NULL
, NULL
, &errCode
)) {
1440 localInfoDict
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero
, data
, kCFPropertyListMutableContainers
, &errStr
);
1441 if (errStr
) CFRelease(errStr
);
1442 if (localInfoDict
&& CFDictionaryGetTypeID() != CFGetTypeID(localInfoDict
)) {
1443 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(localInfoDict
);
1444 localInfoDict
= NULL
;
1450 if (localInfoDict
) _processInfoDictionary((CFMutableDictionaryRef
)localInfoDict
, _CFGetPlatformName(), _CFGetProductName());
1451 __CFSpinLock(&CFBundleLocalInfoLock
);
1452 if (!bundle
->_localInfoDict
) {
1453 bundle
->_localInfoDict
= localInfoDict
;
1455 if (localInfoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(localInfoDict
);
1456 localInfoDict
= bundle
->_localInfoDict
;
1458 __CFSpinUnlock(&CFBundleLocalInfoLock
);
1460 return localInfoDict
;
1463 CFPropertyListRef
_CFBundleGetValueForInfoKey(CFBundleRef bundle
, CFStringRef key
) {
1464 return (CFPropertyListRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, key
);
1467 CFTypeRef
CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle
, CFStringRef key
) {
1468 // Look in InfoPlist.strings first. Then look in Info.plist
1469 CFTypeRef result
= NULL
;
1470 if (bundle
&& key
) {
1471 CFDictionaryRef dict
= CFBundleGetLocalInfoDictionary(bundle
);
1472 if (dict
) result
= CFDictionaryGetValue(dict
, key
);
1474 dict
= CFBundleGetInfoDictionary(bundle
);
1475 if (dict
) result
= CFDictionaryGetValue(dict
, key
);
1481 CFStringRef
CFBundleGetIdentifier(CFBundleRef bundle
) {
1482 CFStringRef bundleID
= NULL
;
1483 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1484 if (infoDict
) bundleID
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleIdentifierKey
);
1488 #define DEVELOPMENT_STAGE 0x20
1489 #define ALPHA_STAGE 0x40
1490 #define BETA_STAGE 0x60
1491 #define RELEASE_STAGE 0x80
1493 #define MAX_VERS_LEN 10
1495 CF_INLINE Boolean
_isDigit(UniChar aChar
) {return ((aChar
>= (UniChar
)'0' && aChar
<= (UniChar
)'9') ? true : false);}
1497 __private_extern__ CFStringRef
_CFCreateStringFromVersionNumber(CFAllocatorRef alloc
, UInt32 vers
) {
1498 CFStringRef result
= NULL
;
1499 uint8_t major1
, major2
, minor1
, minor2
, stage
, build
;
1501 major1
= (vers
& 0xF0000000) >> 28;
1502 major2
= (vers
& 0x0F000000) >> 24;
1503 minor1
= (vers
& 0x00F00000) >> 20;
1504 minor2
= (vers
& 0x000F0000) >> 16;
1505 stage
= (vers
& 0x0000FF00) >> 8;
1506 build
= (vers
& 0x000000FF);
1508 if (stage
== RELEASE_STAGE
) {
1510 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d"), major1
, major2
, minor1
, minor2
);
1512 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d"), major2
, minor1
, minor2
);
1516 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
);
1518 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d%C%d"), major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? 'd' : ((stage
== ALPHA_STAGE
) ? 'a' : 'b')), build
);
1524 __private_extern__ UInt32
_CFVersionNumberFromString(CFStringRef versStr
) {
1525 // Parse version number from string.
1526 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1527 UInt32 major1
= 0, major2
= 0, minor1
= 0, minor2
= 0, stage
= RELEASE_STAGE
, build
= 0;
1528 UniChar versChars
[MAX_VERS_LEN
];
1529 UniChar
*chars
= NULL
;
1532 Boolean digitsDone
= false;
1534 if (!versStr
) return 0;
1535 len
= CFStringGetLength(versStr
);
1536 if (len
<= 0 || len
> MAX_VERS_LEN
) return 0;
1538 CFStringGetCharacters(versStr
, CFRangeMake(0, len
), versChars
);
1541 // Get major version number.
1542 major1
= major2
= 0;
1543 if (_isDigit(*chars
)) {
1544 major2
= *chars
- (UniChar
)'0';
1548 if (_isDigit(*chars
)) {
1550 major2
= *chars
- (UniChar
)'0';
1554 if (*chars
== (UniChar
)'.') {
1561 } else if (*chars
== (UniChar
)'.') {
1568 } else if (*chars
== (UniChar
)'.') {
1575 // Now major1 and major2 contain first and second digit of the major version number as ints.
1576 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1578 // Get the first minor version number.
1579 if (len
> 0 && !digitsDone
) {
1580 if (_isDigit(*chars
)) {
1581 minor1
= *chars
- (UniChar
)'0';
1585 if (*chars
== (UniChar
)'.') {
1597 // Now minor1 contains the first minor version number as an int.
1598 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1600 // Get the second minor version number.
1601 if (len
> 0 && !digitsDone
) {
1602 if (_isDigit(*chars
)) {
1603 minor2
= *chars
- (UniChar
)'0';
1611 // Now minor2 contains the second minor version number as an int.
1612 // Now either len is 0 or chars points at the build stage letter.
1614 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1616 if (*chars
== (UniChar
)'d') {
1617 stage
= DEVELOPMENT_STAGE
;
1618 } else if (*chars
== (UniChar
)'a') {
1619 stage
= ALPHA_STAGE
;
1620 } else if (*chars
== (UniChar
)'b') {
1622 } else if (*chars
== (UniChar
)'f') {
1623 stage
= RELEASE_STAGE
;
1631 // Now stage contains the release stage.
1632 // Now either len is 0 or chars points at the build number.
1634 // Get the first digit of the build number.
1636 if (_isDigit(*chars
)) {
1637 build
= *chars
- (UniChar
)'0';
1644 // Get the second digit of the build number.
1646 if (_isDigit(*chars
)) {
1648 build
+= *chars
- (UniChar
)'0';
1655 // Get the third digit of the build number.
1657 if (_isDigit(*chars
)) {
1659 build
+= *chars
- (UniChar
)'0';
1667 // Range check the build number and make sure we exhausted the string.
1668 if (build
> 0xFF || len
> 0) return 0;
1671 theVers
= major1
<< 28;
1672 theVers
+= major2
<< 24;
1673 theVers
+= minor1
<< 20;
1674 theVers
+= minor2
<< 16;
1675 theVers
+= stage
<< 8;
1681 UInt32
CFBundleGetVersionNumber(CFBundleRef bundle
) {
1682 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1683 CFTypeRef unknownVersionValue
= CFDictionaryGetValue(infoDict
, _kCFBundleNumericVersionKey
);
1684 CFNumberRef versNum
;
1687 if (!unknownVersionValue
) unknownVersionValue
= CFDictionaryGetValue(infoDict
, kCFBundleVersionKey
);
1688 if (unknownVersionValue
) {
1689 if (CFGetTypeID(unknownVersionValue
) == CFStringGetTypeID()) {
1690 // Convert a string version number into a numeric one.
1691 vers
= _CFVersionNumberFromString((CFStringRef
)unknownVersionValue
);
1693 versNum
= CFNumberCreate(CFGetAllocator(bundle
), kCFNumberSInt32Type
, &vers
);
1694 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
, versNum
);
1696 } else if (CFGetTypeID(unknownVersionValue
) == CFNumberGetTypeID()) {
1697 CFNumberGetValue((CFNumberRef
)unknownVersionValue
, kCFNumberSInt32Type
, &vers
);
1699 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
);
1705 CFStringRef
CFBundleGetDevelopmentRegion(CFBundleRef bundle
) {
1706 CFStringRef devLang
= NULL
;
1707 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1709 devLang
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1710 if (devLang
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) {
1712 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleDevelopmentRegionKey
);
1719 Boolean
_CFBundleGetHasChanged(CFBundleRef bundle
) {
1721 Boolean result
= false;
1722 Boolean exists
= false;
1725 if (_CFGetFileProperties(CFGetAllocator(bundle
), bundle
->_url
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
1726 // If the bundle no longer exists or is not a folder, it must have "changed"
1727 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) result
= true;
1729 // Something is wrong. The stat failed.
1732 if (bundle
->_modDate
&& !CFEqual(bundle
->_modDate
, modDate
)) {
1733 // mod date is different from when we created.
1740 void _CFBundleSetStringsFilesShared(CFBundleRef bundle
, Boolean flag
) {
1741 bundle
->_sharesStringsFiles
= flag
;
1744 Boolean
_CFBundleGetStringsFilesShared(CFBundleRef bundle
) {
1745 return bundle
->_sharesStringsFiles
;
1748 static Boolean
_urlExists(CFURLRef url
) {
1750 return url
&& (0 == _CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, NULL
, NULL
, NULL
, NULL
, NULL
)) && exists
;
1753 // This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their
1754 // original locations on disk, so checking whether a binary's path exists is no longer sufficient.
1755 // For performance reasons, we only call dlopen_preflight() after we've verified that the binary
1756 // does not exist at its original path with _urlExists().
1757 // See <rdar://problem/6956670>
1758 static Boolean
_binaryLoadable(CFURLRef url
) {
1759 Boolean loadable
= _urlExists(url
);
1760 #if DEPLOYMENT_TARGET_EMBEDDED
1762 uint8_t path
[PATH_MAX
];
1763 if (url
&& CFURLGetFileSystemRepresentation(url
, true, path
, sizeof(path
))) {
1764 loadable
= dlopen_preflight((char *)path
);
1771 __private_extern__ CFURLRef
_CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1772 CFURLRef result
= NULL
;
1775 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase1
, bundleURL
);
1776 } else if (2 == version
) {
1777 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase2
, bundleURL
);
1779 result
= (CFURLRef
)CFRetain(bundleURL
);
1785 CF_EXPORT CFURLRef
CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle
) {
1786 return _CFBundleCopySupportFilesDirectoryURLInDirectory(bundle
->_url
, bundle
->_version
);
1789 __private_extern__ CFURLRef
_CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1790 CFURLRef result
= NULL
;
1793 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase0
, bundleURL
);
1794 } else if (1 == version
) {
1795 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase1
, bundleURL
);
1796 } else if (2 == version
) {
1797 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase2
, bundleURL
);
1799 result
= (CFURLRef
)CFRetain(bundleURL
);
1805 CFURLRef
CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle
) {
1806 return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle
->_url
, bundle
->_version
);
1809 __private_extern__ CFURLRef
_CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1810 CFURLRef result
= NULL
;
1813 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase0
, bundleURL
);
1814 } else if (1 == version
) {
1815 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase1
, bundleURL
);
1816 } else if (2 == version
) {
1817 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase2
, bundleURL
);
1823 CFURLRef
_CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle
) {
1824 return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle
->_url
, bundle
->_version
);
1827 static CFURLRef
_CFBundleCopyExecutableURLRaw(CFURLRef urlPath
, CFStringRef exeName
) {
1828 // 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.
1829 CFURLRef executableURL
= NULL
;
1830 if (!urlPath
|| !exeName
) return NULL
;
1832 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1833 const uint8_t *image_suffix
= (uint8_t *)__CFgetenv("DYLD_IMAGE_SUFFIX");
1835 CFStringRef newExeName
, imageSuffix
;
1836 imageSuffix
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, (char *)image_suffix
, kCFStringEncodingUTF8
);
1837 if (CFStringHasSuffix(exeName
, CFSTR(".dylib"))) {
1838 CFStringRef bareExeName
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, exeName
, CFRangeMake(0, CFStringGetLength(exeName
)-6));
1839 newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@.dylib"), exeName
, imageSuffix
);
1840 CFRelease(bareExeName
);
1842 newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, imageSuffix
);
1844 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, newExeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1845 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1846 CFRelease(executableURL
);
1847 executableURL
= NULL
;
1849 CFRelease(newExeName
);
1850 CFRelease(imageSuffix
);
1852 if (!executableURL
) {
1853 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, exeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1854 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1855 CFRelease(executableURL
);
1856 executableURL
= NULL
;
1859 #elif DEPLOYMENT_TARGET_WINDOWS
1860 if (!executableURL
) {
1861 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, exeName
, kCFURLWindowsPathStyle
, false, urlPath
);
1862 if (executableURL
&& !_urlExists(executableURL
)) {
1863 CFRelease(executableURL
);
1864 executableURL
= NULL
;
1867 if (!executableURL
) {
1868 if (!CFStringFindWithOptions(exeName
, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName
)), kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
1870 CFStringRef extension
= CFSTR("_debug.dll");
1872 CFStringRef extension
= CFSTR(".dll");
1874 CFStringRef newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, extension
);
1875 executableURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, newExeName
, urlPath
);
1876 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1877 CFRelease(executableURL
);
1878 executableURL
= NULL
;
1880 CFRelease(newExeName
);
1883 if (!executableURL
) {
1884 if (!CFStringFindWithOptions(exeName
, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName
)), kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
1886 CFStringRef extension
= CFSTR("_debug.exe");
1888 CFStringRef extension
= CFSTR(".exe");
1890 CFStringRef newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, extension
);
1891 executableURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, newExeName
, urlPath
);
1892 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1893 CFRelease(executableURL
);
1894 executableURL
= NULL
;
1896 CFRelease(newExeName
);
1900 #error Unknown or unspecified DEPLOYMENT_TARGET
1902 return executableURL
;
1905 static CFStringRef
_CFBundleCopyExecutableName(CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
) {
1906 CFStringRef executableName
= NULL
;
1908 if (!infoDict
&& bundle
) infoDict
= CFBundleGetInfoDictionary(bundle
);
1909 if (!url
&& bundle
) url
= bundle
->_url
;
1912 // Figure out the name of the executable.
1913 // First try for the new key in the plist.
1914 executableName
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
);
1915 // Second try for the old key in the plist.
1916 if (!executableName
) executableName
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleOldExecutableKey
);
1917 if (executableName
&& CFGetTypeID(executableName
) == CFStringGetTypeID() && CFStringGetLength(executableName
) > 0) {
1918 CFRetain(executableName
);
1920 executableName
= NULL
;
1923 if (!executableName
&& url
) {
1924 // Third, take the name of the bundle itself (with path extension stripped)
1925 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1926 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1927 CFRelease(absoluteURL
);
1929 UniChar buff
[CFMaxPathSize
];
1930 CFIndex len
= CFStringGetLength(bundlePath
);
1931 CFIndex startOfBundleName
, endOfBundleName
;
1933 if (len
> CFMaxPathSize
) len
= CFMaxPathSize
;
1934 CFStringGetCharacters(bundlePath
, CFRangeMake(0, len
), buff
);
1935 startOfBundleName
= _CFStartOfLastPathComponent(buff
, len
);
1936 endOfBundleName
= _CFLengthAfterDeletingPathExtension(buff
, len
);
1938 if (startOfBundleName
<= len
&& endOfBundleName
<= len
&& startOfBundleName
< endOfBundleName
) executableName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfBundleName
]), endOfBundleName
- startOfBundleName
);
1939 CFRelease(bundlePath
);
1943 return executableName
;
1946 __private_extern__ CFURLRef
_CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle
, Boolean mayBeLocal
) {
1947 CFStringRef executableName
= _CFBundleCopyExecutableName(bundle
, NULL
, NULL
);
1948 CFURLRef resourceForkURL
= NULL
;
1949 if (executableName
) {
1951 resourceForkURL
= CFBundleCopyResourceURL(bundle
, executableName
, CFSTR("rsrc"), NULL
);
1953 resourceForkURL
= CFBundleCopyResourceURLForLocalization(bundle
, executableName
, CFSTR("rsrc"), NULL
, NULL
);
1955 CFRelease(executableName
);
1958 return resourceForkURL
;
1961 CFURLRef
_CFBundleCopyResourceForkURL(CFBundleRef bundle
) {
1962 return _CFBundleCopyResourceForkURLMayBeLocal(bundle
, true);
1965 static CFURLRef
_CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle
, CFURLRef url
, CFStringRef executableName
, Boolean ignoreCache
, Boolean useOtherPlatform
) {
1966 uint8_t version
= 0;
1967 CFDictionaryRef infoDict
= NULL
;
1968 CFStringRef executablePath
= NULL
;
1969 CFURLRef executableURL
= NULL
;
1970 Boolean foundIt
= false;
1971 Boolean lookupMainExe
= (executableName
? false : true);
1972 static CFSpinLock_t CFBundleExecutablePathLock
= CFSpinLockInit
;
1975 infoDict
= CFBundleGetInfoDictionary(bundle
);
1976 version
= bundle
->_version
;
1978 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, &version
);
1981 // If we have a bundle instance and an info dict, see if we have already cached the path
1982 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& bundle
&& infoDict
) {
1983 __CFSpinLock(&CFBundleExecutablePathLock
);
1984 executablePath
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleExecutablePathKey
);
1985 if (executablePath
) CFRetain(executablePath
);
1986 __CFSpinUnlock(&CFBundleExecutablePathLock
);
1987 if (executablePath
) {
1988 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1989 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, executablePath
, kCFURLPOSIXPathStyle
, false);
1990 #elif DEPLOYMENT_TARGET_WINDOWS
1991 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, executablePath
, kCFURLWindowsPathStyle
, false);
1993 #error Unknown or unspecified DEPLOYMENT_TARGET
1995 if (executableURL
) {
1998 __CFSpinLock(&CFBundleExecutablePathLock
);
1999 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
);
2000 __CFSpinUnlock(&CFBundleExecutablePathLock
);
2002 CFRelease(executablePath
);
2007 if (lookupMainExe
) executableName
= _CFBundleCopyExecutableName(bundle
, url
, infoDict
);
2008 if (executableName
) {
2009 #if DEPLOYMENT_TARGET_EMBEDDED
2010 Boolean doExecSearch
= false;
2012 Boolean doExecSearch
= true;
2014 // Now, look for the executable inside the bundle.
2015 if (doExecSearch
&& 0 != version
) {
2017 CFURLRef exeSubdirURL
;
2020 exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleExecutablesURLFromBase1
, url
);
2021 } else if (2 == version
) {
2022 exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleExecutablesURLFromBase2
, url
);
2024 #if DEPLOYMENT_TARGET_WINDOWS
2025 // On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory
2026 CFStringRef extension
= CFURLCopyPathExtension(url
);
2027 if (extension
&& CFEqual(extension
, _CFBundleWindowsResourceDirectoryExtension
)) {
2028 exeDirURL
= CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault
, url
);
2030 exeDirURL
= (CFURLRef
)CFRetain(url
);
2032 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2033 exeDirURL
= (CFURLRef
)CFRetain(url
);
2035 #error Unknown or unspecified DEPLOYMENT_TARGET
2038 CFStringRef platformSubDir
= useOtherPlatform
? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName();
2039 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
2040 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
2041 if (!executableURL
) {
2042 CFRelease(exeSubdirURL
);
2043 platformSubDir
= useOtherPlatform
? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName();
2044 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
2045 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
2047 if (!executableURL
) {
2048 CFRelease(exeSubdirURL
);
2049 platformSubDir
= useOtherPlatform
? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName();
2050 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
2051 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
2053 if (!executableURL
) {
2054 CFRelease(exeSubdirURL
);
2055 platformSubDir
= useOtherPlatform
? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName();
2056 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
2057 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
2059 if (!executableURL
) executableURL
= _CFBundleCopyExecutableURLRaw(exeDirURL
, executableName
);
2060 CFRelease(exeDirURL
);
2061 CFRelease(exeSubdirURL
);
2064 // If this was an old bundle, or we did not find the executable in the Executables subdirectory, look directly in the bundle wrapper.
2065 if (!executableURL
) executableURL
= _CFBundleCopyExecutableURLRaw(url
, executableName
);
2067 #if DEPLOYMENT_TARGET_WINDOWS
2068 // Windows only: If we still haven't found the exe, look in the Executables folder.
2069 // But only for the main bundle exe
2070 if (lookupMainExe
&& !executableURL
) {
2071 CFURLRef exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, CFSTR("../../Executables"), url
);
2072 executableURL
= _CFBundleCopyExecutableURLRaw(exeDirURL
, executableName
);
2073 CFRelease(exeDirURL
);
2075 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2077 #error Unknown or unspecified DEPLOYMENT_TARGET
2080 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& bundle
&& infoDict
&& executableURL
) {
2081 // We found it. Cache the path.
2082 CFURLRef absURL
= CFURLCopyAbsoluteURL(executableURL
);
2083 #if DEPLOYMENT_TARGET_WINDOWS
2084 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLWindowsPathStyle
);
2085 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2086 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLPOSIXPathStyle
);
2088 #error Unknown or unspecified DEPLOYMENT_TARGET
2091 __CFSpinLock(&CFBundleExecutablePathLock
);
2092 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
, executablePath
);
2093 __CFSpinUnlock(&CFBundleExecutablePathLock
);
2094 CFRelease(executablePath
);
2096 if (lookupMainExe
&& !useOtherPlatform
&& bundle
&& !executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
2097 if (lookupMainExe
) CFRelease(executableName
);
2100 if (!bundle
&& infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(infoDict
);
2101 return executableURL
;
2104 CFURLRef
_CFBundleCopyExecutableURLInDirectory(CFURLRef url
) {
2105 return _CFBundleCopyExecutableURLInDirectory2(NULL
, url
, NULL
, true, false);
2108 CFURLRef
_CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url
) {
2109 return _CFBundleCopyExecutableURLInDirectory2(NULL
, url
, NULL
, true, true);
2112 CFURLRef
CFBundleCopyExecutableURL(CFBundleRef bundle
) {
2113 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, NULL
, false, false);
2116 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
) {
2117 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, NULL
, true, false);
2120 CFURLRef
CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle
, CFStringRef executableName
) {
2121 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, executableName
, true, false);
2124 Boolean
CFBundleIsExecutableLoaded(CFBundleRef bundle
) {
2125 return bundle
->_isLoaded
;
2128 CFBundleExecutableType
CFBundleGetExecutableType(CFBundleRef bundle
) {
2129 CFBundleExecutableType result
= kCFBundleOtherExecutableType
;
2130 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2132 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
2133 #if defined(BINARY_SUPPORT_DYLD)
2134 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2135 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
2136 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
2138 #endif /* BINARY_SUPPORT_DYLD */
2139 if (executableURL
) CFRelease(executableURL
);
2141 if (bundle
->_binaryType
== __CFBundleCFMBinary
) {
2142 result
= kCFBundlePEFExecutableType
;
2143 } else if (bundle
->_binaryType
== __CFBundleDYLDExecutableBinary
|| bundle
->_binaryType
== __CFBundleDYLDBundleBinary
|| bundle
->_binaryType
== __CFBundleDYLDFrameworkBinary
) {
2144 result
= kCFBundleMachOExecutableType
;
2145 } else if (bundle
->_binaryType
== __CFBundleDLLBinary
) {
2146 result
= kCFBundleDLLExecutableType
;
2147 } else if (bundle
->_binaryType
== __CFBundleELFBinary
) {
2148 result
= kCFBundleELFExecutableType
;
2153 static SInt32
_CFBundleCurrentArchitecture(void) {
2155 #if defined(__ppc__)
2156 arch
= kCFBundleExecutableArchitecturePPC
;
2157 #elif defined(__ppc64__)
2158 arch
= kCFBundleExecutableArchitecturePPC64
;
2159 #elif defined(__i386__)
2160 arch
= kCFBundleExecutableArchitectureI386
;
2161 #elif defined(__x86_64__)
2162 arch
= kCFBundleExecutableArchitectureX86_64
;
2163 #elif defined(BINARY_SUPPORT_DYLD)
2164 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
2165 if (archInfo
) arch
= archInfo
->cputype
;
2170 #define UNKNOWN_FILETYPE 0x0
2171 #define PEF_FILETYPE 0x1000
2172 #define PEF_MAGIC 0x4a6f7921
2173 #define PEF_CIGAM 0x21796f4a
2174 #define TEXT_SEGMENT "__TEXT"
2175 #define PLIST_SECTION "__info_plist"
2176 #define OBJC_SEGMENT "__OBJC"
2177 #define IMAGE_INFO_SECTION "__image_info"
2178 #define OBJC_SEGMENT_64 "__DATA"
2179 #define IMAGE_INFO_SECTION_64 "__objc_imageinfo"
2180 #define LIB_X11 "/usr/X11R6/lib/libX"
2182 #define XLS_NAME "Book"
2183 #define XLS_NAME2 "Workbook"
2184 #define DOC_NAME "WordDocument"
2185 #define PPT_NAME "PowerPoint Document"
2187 #define ustrncmp(x, y, z) strncmp((char *)(x), (char *)(y), (z))
2188 #define ustrncasecmp(x, y, z) strncasecmp_l((char *)(x), (char *)(y), (z), NULL)
2190 static const uint32_t __CFBundleMagicNumbersArray
[] = {
2191 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0xfeedfacf, 0xcffaedfe, 0x4a6f7921, 0x21796f4a,
2192 0x7f454c46, 0xffd8ffe0, 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100,
2193 0x7b5c7274, 0x25504446, 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646,
2194 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435,
2195 0x53495444, 0x53747566, 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x3d796265,
2196 0x6b6f6c79, 0x3026b275, 0x0000000c, 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143,
2197 0x00010000, 0x74727565, 0x4f54544f, 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70,
2198 0x3c435058, 0x28445746, 0x424f4d53, 0x49544f4c, 0x72746664, 0x63616666, 0x802a5fd7, 0x762f3101
2201 // string, with groups of 5 characters being 1 element in the array
2202 static const char * __CFBundleExtensionsArray
=
2203 "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0"
2204 "elf\0\0" "jpeg\0" "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0"
2205 "rtf\0\0" "pdf\0\0" "ra\0\0\0""rm\0\0\0""au\0\0\0""au\0\0\0""iff\0\0" "riff\0"
2206 "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0"
2207 "sit\0\0" "sit\0\0" "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""ync\0\0"
2208 "dmg\0\0" "wmv\0\0" "jp2\0\0" "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0"
2209 "ttf\0\0" "ttf\0\0" "otf\0\0" "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0"
2210 "cpx\0\0" "dwf\0\0" "bom\0\0" "lit\0\0" "rtfd\0" "caf\0\0" "cin\0\0" "exr\0\0";
2212 static const char * __CFBundleOOExtensionsArray
= "sxc\0\0" "sxd\0\0" "sxg\0\0" "sxi\0\0" "sxm\0\0" "sxw\0\0";
2213 static const char * __CFBundleODExtensionsArray
= "odc\0\0" "odf\0\0" "odg\0\0" "oth\0\0" "odi\0\0" "odm\0\0" "odp\0\0" "ods\0\0" "odt\0\0";
2215 #define EXTENSION_LENGTH 5
2216 #define NUM_EXTENSIONS 64
2217 #define MAGIC_BYTES_TO_READ 512
2218 #define DMG_BYTES_TO_READ 512
2219 #define ZIP_BYTES_TO_READ 1024
2220 #define OLE_BYTES_TO_READ 512
2221 #define X11_BYTES_TO_READ 4096
2222 #define IMAGE_INFO_BYTES_TO_READ 4096
2224 #if defined(BINARY_SUPPORT_DYLD)
2226 CF_INLINE
uint32_t _CFBundleSwapInt32Conditional(uint32_t arg
, Boolean swap
) {return swap
? CFSwapInt32(arg
) : arg
;}
2227 CF_INLINE
uint32_t _CFBundleSwapInt64Conditional(uint64_t arg
, Boolean swap
) {return swap
? CFSwapInt64(arg
) : arg
;}
2229 // returns zero-ref dictionary under GC
2230 static CFMutableDictionaryRef
_CFBundleGrokInfoDictFromData(const char *bytes
, uint32_t length
) {
2231 CFMutableDictionaryRef result
= NULL
;
2232 CFDataRef infoData
= NULL
;
2233 if (bytes
&& 0 < length
) {
2234 infoData
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, (uint8_t *)bytes
, length
, kCFAllocatorNull
);
2236 result
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero
, infoData
, kCFPropertyListMutableContainers
, NULL
);
2237 if (result
&& CFDictionaryGetTypeID() != CFGetTypeID(result
)) {
2241 CFRelease(infoData
);
2243 if (!result
) result
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2245 if (result
) _processInfoDictionary((CFMutableDictionaryRef
)result
, _CFGetPlatformName(), _CFGetProductName());
2249 static char *_CFBundleGetSectData(const char *segname
, const char *sectname
, unsigned long *size
) {
2250 char *retval
= NULL
;
2251 unsigned long localSize
= 0;
2252 uint32_t i
, numImages
= _dyld_image_count();
2253 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
2255 for (i
= 0; i
< numImages
; i
++) {
2256 if (mhp
== (void *)_dyld_get_image_header(i
)) {
2258 const struct section_64
*sp
= getsectbynamefromheader_64((const struct mach_header_64
*)mhp
, segname
, sectname
);
2260 retval
= (char *)(sp
->addr
+ _dyld_get_image_vmaddr_slide(i
));
2261 localSize
= (unsigned long)sp
->size
;
2263 #else /* __LP64__ */
2264 const struct section
*sp
= getsectbynamefromheader((const struct mach_header
*)mhp
, segname
, sectname
);
2266 retval
= (char *)(sp
->addr
+ _dyld_get_image_vmaddr_slide(i
));
2267 localSize
= (unsigned long)sp
->size
;
2269 #endif /* __LP64__ */
2273 if (size
) *size
= localSize
;
2277 // returns zero-ref dictionary under GC
2278 static CFMutableDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable() {
2280 unsigned long length
= 0;
2281 if (getsegbyname(TEXT_SEGMENT
)) bytes
= _CFBundleGetSectData(TEXT_SEGMENT
, PLIST_SECTION
, &length
);
2282 return _CFBundleGrokInfoDictFromData(bytes
, length
);
2285 static Boolean
_CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion
, uint32_t *objcFlags
) {
2286 Boolean retval
= false;
2287 uint32_t localVersion
= 0, localFlags
= 0;
2289 unsigned long length
= 0;
2291 if (getsegbyname(OBJC_SEGMENT_64
)) bytes
= _CFBundleGetSectData(OBJC_SEGMENT_64
, IMAGE_INFO_SECTION_64
, &length
);
2292 #else /* __LP64__ */
2293 if (getsegbyname(OBJC_SEGMENT
)) bytes
= _CFBundleGetSectData(OBJC_SEGMENT
, IMAGE_INFO_SECTION
, &length
);
2294 #endif /* __LP64__ */
2295 if (bytes
&& length
>= 8) {
2296 localVersion
= *(uint32_t *)bytes
;
2297 localFlags
= *(uint32_t *)(bytes
+ 4);
2300 if (objcVersion
) *objcVersion
= localVersion
;
2301 if (objcFlags
) *objcFlags
= localFlags
;
2305 static Boolean
_CFBundleGrokX11FromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
2306 static const char libX11name
[] = LIB_X11
;
2307 char *buffer
= NULL
;
2308 const char *loc
= NULL
;
2310 Boolean result
= false;
2312 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2313 buffer
= malloc(X11_BYTES_TO_READ
);
2314 if (buffer
&& read(fd
, buffer
, X11_BYTES_TO_READ
) >= X11_BYTES_TO_READ
) loc
= buffer
;
2315 } else if (bytes
&& length
>= offset
+ X11_BYTES_TO_READ
) {
2316 loc
= bytes
+ offset
;
2320 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->ncmds
, swapped
);
2321 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->sizeofcmds
, swapped
);
2322 const char *startofcmds
= loc
+ sizeof(struct mach_header_64
);
2323 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2324 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
2325 if (endofcmds
> loc
+ X11_BYTES_TO_READ
) endofcmds
= loc
+ X11_BYTES_TO_READ
;
2326 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
2327 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
2328 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
2329 const char *name
= (const char *)dlp
+ nameoffset
;
2330 if (startofcmds
<= name
&& name
+ sizeof(libX11name
) <= endofcmds
&& 0 == strncmp(name
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
2332 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
2335 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->ncmds
, swapped
);
2336 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->sizeofcmds
, swapped
);
2337 const char *startofcmds
= loc
+ sizeof(struct mach_header
);
2338 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2339 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
2340 if (endofcmds
> loc
+ X11_BYTES_TO_READ
) endofcmds
= loc
+ X11_BYTES_TO_READ
;
2341 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
2342 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
2343 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
2344 const char *name
= (const char *)dlp
+ nameoffset
;
2345 if (startofcmds
<= name
&& name
+ sizeof(libX11name
) <= endofcmds
&& 0 == strncmp(name
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
2347 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
2351 if (buffer
) free(buffer
);
2355 // returns zero-ref dictionary under GC
2356 static CFDictionaryRef
_CFBundleGrokInfoDictFromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
2357 struct stat statBuf
;
2358 off_t fileLength
= 0;
2359 char *maploc
= NULL
;
2362 CFDictionaryRef result
= NULL
;
2363 Boolean foundit
= false;
2364 if (fd
>= 0 && fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
2366 fileLength
= statBuf
.st_size
;
2369 fileLength
= length
;
2371 if (fileLength
> offset
+ sizeof(struct mach_header_64
)) {
2373 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->ncmds
, swapped
);
2374 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->sizeofcmds
, swapped
);
2375 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header_64
);
2376 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2377 struct segment_command_64
*sgp
= (struct segment_command_64
*)startofcmds
;
2378 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
2379 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2380 if (LC_SEGMENT_64
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2381 struct section_64
*sp
= (struct section_64
*)((char *)sgp
+ sizeof(struct segment_command_64
));
2382 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2383 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2384 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, TEXT_SEGMENT
, sizeof(sp
->segname
))) {
2385 uint64_t sectlength64
= _CFBundleSwapInt64Conditional(sp
->size
, swapped
);
2386 uint32_t sectlength
= (uint32_t)(sectlength64
& 0xffffffff);
2387 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2388 const char *sectbytes
= loc
+ offset
+ sectoffset
;
2389 // we don't support huge-sized plists
2390 if (sectlength64
<= 0xffffffff && loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
2393 sp
= (struct section_64
*)((char *)sp
+ sizeof(struct section_64
));
2396 sgp
= (struct segment_command_64
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2399 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->ncmds
, swapped
);
2400 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->sizeofcmds
, swapped
);
2401 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header
);
2402 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2403 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
2404 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
2405 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2406 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2407 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
2408 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2409 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2410 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, TEXT_SEGMENT
, sizeof(sp
->segname
))) {
2411 uint32_t sectlength
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
2412 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2413 const char *sectbytes
= loc
+ offset
+ sectoffset
;
2414 if (loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
2417 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
2420 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2424 if (maploc
) munmap(maploc
, statBuf
.st_size
);
2428 static void _CFBundleGrokObjcImageInfoFromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
, Boolean
*hasObjc
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
2429 uint32_t sectlength
= 0, sectoffset
= 0, localVersion
= 0, localFlags
= 0;
2430 char *buffer
= NULL
;
2432 const char *loc
= NULL
;
2434 Boolean foundit
= false, localHasObjc
= false;
2436 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2437 buffer
= malloc(IMAGE_INFO_BYTES_TO_READ
);
2438 if (buffer
&& read(fd
, buffer
, IMAGE_INFO_BYTES_TO_READ
) >= IMAGE_INFO_BYTES_TO_READ
) loc
= buffer
;
2439 } else if (bytes
&& length
>= offset
+ IMAGE_INFO_BYTES_TO_READ
) {
2440 loc
= bytes
+ offset
;
2444 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->ncmds
, swapped
);
2445 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->sizeofcmds
, swapped
);
2446 const char *startofcmds
= loc
+ sizeof(struct mach_header_64
);
2447 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2448 struct segment_command_64
*sgp
= (struct segment_command_64
*)startofcmds
;
2449 if (endofcmds
> loc
+ IMAGE_INFO_BYTES_TO_READ
) endofcmds
= loc
+ IMAGE_INFO_BYTES_TO_READ
;
2450 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2451 if (LC_SEGMENT_64
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2452 struct section_64
*sp
= (struct section_64
*)((char *)sgp
+ sizeof(struct segment_command_64
));
2453 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2454 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2455 if (0 == strncmp(sp
->segname
, OBJC_SEGMENT_64
, sizeof(sp
->segname
))) localHasObjc
= true;
2456 if (0 == strncmp(sp
->sectname
, IMAGE_INFO_SECTION_64
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, OBJC_SEGMENT_64
, sizeof(sp
->segname
))) {
2457 uint64_t sectlength64
= _CFBundleSwapInt64Conditional(sp
->size
, swapped
);
2458 sectlength
= (uint32_t)(sectlength64
& 0xffffffff);
2459 sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2462 sp
= (struct section_64
*)((char *)sp
+ sizeof(struct section_64
));
2465 sgp
= (struct segment_command_64
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2468 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->ncmds
, swapped
);
2469 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->sizeofcmds
, swapped
);
2470 const char *startofcmds
= loc
+ sizeof(struct mach_header
);
2471 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2472 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
2473 if (endofcmds
> loc
+ IMAGE_INFO_BYTES_TO_READ
) endofcmds
= loc
+ IMAGE_INFO_BYTES_TO_READ
;
2474 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2475 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2476 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
2477 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2478 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2479 if (0 == strncmp(sp
->segname
, OBJC_SEGMENT
, sizeof(sp
->segname
))) localHasObjc
= true;
2480 if (0 == strncmp(sp
->sectname
, IMAGE_INFO_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, OBJC_SEGMENT
, sizeof(sp
->segname
))) {
2481 sectlength
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
2482 sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2485 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
2488 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2491 if (sectlength
>= 8) {
2492 if (fd
>= 0 && lseek(fd
, offset
+ sectoffset
, SEEK_SET
) == (off_t
)(offset
+ sectoffset
) && read(fd
, sectbuffer
, 8) >= 8) {
2493 localVersion
= _CFBundleSwapInt32Conditional(*(uint32_t *)sectbuffer
, swapped
);
2494 localFlags
= _CFBundleSwapInt32Conditional(*(uint32_t *)(sectbuffer
+ 4), swapped
);
2495 } else if (bytes
&& length
>= offset
+ sectoffset
+ 8) {
2496 localVersion
= _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes
+ offset
+ sectoffset
), swapped
);
2497 localFlags
= _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes
+ offset
+ sectoffset
+ 4), swapped
);
2501 if (buffer
) free(buffer
);
2502 if (hasObjc
) *hasObjc
= localHasObjc
;
2503 if (objcVersion
) *objcVersion
= localVersion
;
2504 if (objcFlags
) *objcFlags
= localFlags
;
2507 // returns zero-ref dictionary in *infodict under GC
2508 static UInt32
_CFBundleGrokMachTypeForFatFile(int fd
, const void *bytes
, CFIndex length
, Boolean swap
, Boolean
*isX11
, CFArrayRef
*architectures
, CFDictionaryRef
*infodict
, Boolean
*hasObjc
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
2509 CFIndex headerLength
= length
;
2510 unsigned char headerBuffer
[MAGIC_BYTES_TO_READ
];
2511 UInt32 machtype
= UNKNOWN_FILETYPE
, magic
, numFatHeaders
, maxFatHeaders
, i
;
2512 unsigned char buffer
[sizeof(struct mach_header_64
)];
2513 const unsigned char *moreBytes
= NULL
;
2514 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
2515 SInt32 curArch
= _CFBundleCurrentArchitecture();
2517 struct fat_arch
*fat
= NULL
;
2519 if (isX11
) *isX11
= false;
2520 if (architectures
) *architectures
= NULL
;
2521 if (infodict
) *infodict
= NULL
;
2522 if (hasObjc
) *hasObjc
= false;
2523 if (objcVersion
) *objcVersion
= 0;
2524 if (objcFlags
) *objcFlags
= 0;
2526 if (headerLength
> MAGIC_BYTES_TO_READ
) headerLength
= MAGIC_BYTES_TO_READ
;
2527 (void)memmove(headerBuffer
, bytes
, headerLength
);
2529 for (i
= 0; i
< headerLength
; i
+= 4) *(UInt32
*)(headerBuffer
+ i
) = CFSwapInt32(*(UInt32
*)(headerBuffer
+ i
));
2531 numFatHeaders
= ((struct fat_header
*)headerBuffer
)->nfat_arch
;
2532 maxFatHeaders
= (headerLength
- sizeof(struct fat_header
)) / sizeof(struct fat_arch
);
2533 if (numFatHeaders
> maxFatHeaders
) numFatHeaders
= maxFatHeaders
;
2534 if (numFatHeaders
> 0) {
2535 if (archInfo
) fat
= NXFindBestFatArch(archInfo
->cputype
, archInfo
->cpusubtype
, (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
)), numFatHeaders
);
2536 if (!fat
&& curArch
!= 0) fat
= NXFindBestFatArch((cpu_type_t
)curArch
, (cpu_subtype_t
)0, (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
)), numFatHeaders
);
2537 if (!fat
) fat
= (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
));
2538 if (architectures
) {
2539 CFMutableArrayRef mutableArchitectures
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2540 for (i
= 0; i
< numFatHeaders
; i
++) {
2541 CFNumberRef architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, headerBuffer
+ sizeof(struct fat_header
) + i
* sizeof(struct fat_arch
));
2542 if (CFArrayGetFirstIndexOfValue(mutableArchitectures
, CFRangeMake(0, CFArrayGetCount(mutableArchitectures
)), architecture
) < 0) CFArrayAppendValue(mutableArchitectures
, architecture
);
2543 CFRelease(architecture
);
2545 *architectures
= (CFArrayRef
)mutableArchitectures
;
2549 if (fd
>= 0 && lseek(fd
, fat
->offset
, SEEK_SET
) == (off_t
)fat
->offset
&& read(fd
, buffer
, sizeof(struct mach_header_64
)) >= (int)sizeof(struct mach_header_64
)) {
2551 } else if (bytes
&& (uint32_t)length
>= fat
->offset
+ sizeof(struct mach_header_64
)) {
2552 moreBytes
= bytes
+ fat
->offset
;
2555 magic
= *((UInt32
*)moreBytes
);
2556 if (MH_MAGIC
== magic
) {
2557 machtype
= ((struct mach_header
*)moreBytes
)->filetype
;
2558 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, false, false);
2559 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, false);
2560 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, false, false, hasObjc
, objcVersion
, objcFlags
);
2561 } else if (MH_CIGAM
== magic
) {
2562 machtype
= CFSwapInt32(((struct mach_header
*)moreBytes
)->filetype
);
2563 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, true, false);
2564 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, false);
2565 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, true, false, hasObjc
, objcVersion
, objcFlags
);
2566 } else if (MH_MAGIC_64
== magic
) {
2567 machtype
= ((struct mach_header_64
*)moreBytes
)->filetype
;
2568 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, false, true);
2569 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, true);
2570 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, false, true, hasObjc
, objcVersion
, objcFlags
);
2571 } else if (MH_CIGAM_64
== magic
) {
2572 machtype
= CFSwapInt32(((struct mach_header_64
*)moreBytes
)->filetype
);
2573 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, true, true);
2574 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, true);
2575 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, true, true, hasObjc
, objcVersion
, objcFlags
);
2582 // returns zero-ref dictionary in *infodict under GC
2583 static UInt32
_CFBundleGrokMachType(int fd
, const void *bytes
, CFIndex length
, Boolean
*isX11
, CFArrayRef
*architectures
, CFDictionaryRef
*infodict
, Boolean
*hasObjc
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
2584 unsigned int magic
= *((UInt32
*)bytes
), machtype
= UNKNOWN_FILETYPE
, cputype
;
2585 CFNumberRef architecture
= NULL
;
2587 if (isX11
) *isX11
= false;
2588 if (architectures
) *architectures
= NULL
;
2589 if (infodict
) *infodict
= NULL
;
2590 if (hasObjc
) *hasObjc
= false;
2591 if (objcVersion
) *objcVersion
= 0;
2592 if (objcFlags
) *objcFlags
= 0;
2593 if (MH_MAGIC
== magic
) {
2594 machtype
= ((struct mach_header
*)bytes
)->filetype
;
2595 cputype
= ((struct mach_header
*)bytes
)->cputype
;
2596 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2597 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, false, false);
2598 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, false);
2599 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, false, false, hasObjc
, objcVersion
, objcFlags
);
2600 } else if (MH_CIGAM
== magic
) {
2601 machtype
= CFSwapInt32(((struct mach_header
*)bytes
)->filetype
);
2602 cputype
= CFSwapInt32(((struct mach_header
*)bytes
)->cputype
);
2603 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2604 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, true, false);
2605 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, false);
2606 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, true, false, hasObjc
, objcVersion
, objcFlags
);
2607 } else if (MH_MAGIC_64
== magic
) {
2608 machtype
= ((struct mach_header_64
*)bytes
)->filetype
;
2609 cputype
= ((struct mach_header_64
*)bytes
)->cputype
;
2610 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2611 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, false, true);
2612 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, true);
2613 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, false, true, hasObjc
, objcVersion
, objcFlags
);
2614 } else if (MH_CIGAM_64
== magic
) {
2615 machtype
= CFSwapInt32(((struct mach_header_64
*)bytes
)->filetype
);
2616 cputype
= CFSwapInt32(((struct mach_header_64
*)bytes
)->cputype
);
2617 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2618 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, true, true);
2619 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, true);
2620 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, true, true, hasObjc
, objcVersion
, objcFlags
);
2621 } else if (FAT_MAGIC
== magic
) {
2622 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, false, isX11
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2623 } else if (FAT_CIGAM
== magic
) {
2624 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, true, isX11
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2625 } else if (PEF_MAGIC
== magic
|| PEF_CIGAM
== magic
) {
2626 machtype
= PEF_FILETYPE
;
2628 if (architectures
&& architecture
) *architectures
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&architecture
, 1, &kCFTypeArrayCallBacks
);
2629 if (architecture
) CFRelease(architecture
);
2633 #endif /* BINARY_SUPPORT_DYLD */
2635 static Boolean
_CFBundleGrokFileTypeForZipMimeType(const unsigned char *bytes
, CFIndex length
, const char **ext
) {
2636 unsigned namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 26))), extralength
= CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 28)));
2637 const unsigned char *data
= bytes
+ 30 + namelength
+ extralength
;
2639 if (bytes
< data
&& data
+ 56 <= bytes
+ length
&& 0 == CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 8))) && (0 == ustrncasecmp(data
, "application/vnd.", 16) || 0 == ustrncasecmp(data
, "application/x-vnd.", 18))) {
2640 data
+= ('.' == *(data
+ 15)) ? 16 : 18;
2641 if (0 == ustrncasecmp(data
, "sun.xml.", 8)) {
2643 if (0 == ustrncasecmp(data
, "calc", 4)) i
= 0;
2644 else if (0 == ustrncasecmp(data
, "draw", 4)) i
= 1;
2645 else if (0 == ustrncasecmp(data
, "writer.global", 13)) i
= 2;
2646 else if (0 == ustrncasecmp(data
, "impress", 7)) i
= 3;
2647 else if (0 == ustrncasecmp(data
, "math", 4)) i
= 4;
2648 else if (0 == ustrncasecmp(data
, "writer", 6)) i
= 5;
2649 if (i
>= 0 && ext
) *ext
= __CFBundleOOExtensionsArray
+ i
* EXTENSION_LENGTH
;
2650 } else if (0 == ustrncasecmp(data
, "oasis.opendocument.", 19)) {
2652 if (0 == ustrncasecmp(data
, "chart", 5)) i
= 0;
2653 else if (0 == ustrncasecmp(data
, "formula", 7)) i
= 1;
2654 else if (0 == ustrncasecmp(data
, "graphics", 8)) i
= 2;
2655 else if (0 == ustrncasecmp(data
, "text-web", 8)) i
= 3;
2656 else if (0 == ustrncasecmp(data
, "image", 5)) i
= 4;
2657 else if (0 == ustrncasecmp(data
, "text-master", 11)) i
= 5;
2658 else if (0 == ustrncasecmp(data
, "presentation", 12)) i
= 6;
2659 else if (0 == ustrncasecmp(data
, "spreadsheet", 11)) i
= 7;
2660 else if (0 == ustrncasecmp(data
, "text", 4)) i
= 8;
2661 if (i
>= 0 && ext
) *ext
= __CFBundleODExtensionsArray
+ i
* EXTENSION_LENGTH
;
2663 } else if (bytes
< data
&& data
+ 41 <= bytes
+ length
&& 8 == CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 8))) && 0x4b2c28c8 == CFSwapInt32HostToBig(*((UInt32
*)data
)) && 0xc94c4e2c == CFSwapInt32HostToBig(*((UInt32
*)(data
+ 4)))) {
2664 // AbiWord compressed mimetype odt
2665 if (ext
) *ext
= "odt";
2670 static const char *_CFBundleGrokFileTypeForZipFile(int fd
, const unsigned char *bytes
, CFIndex length
, off_t fileLength
) {
2671 const char *ext
= "zip";
2672 const unsigned char *moreBytes
= NULL
;
2673 unsigned char *buffer
= NULL
;
2675 Boolean foundMimetype
= false, hasMetaInf
= false, hasContentXML
= false, hasManifestMF
= false, hasManifestXML
= false, hasRels
= false, hasContentTypes
= false, hasWordDocument
= false, hasExcelDocument
= false, hasPowerPointDocument
= false, hasOPF
= false, hasSMIL
= false;
2678 for (i
= 0; !foundMimetype
&& i
+ 30 < length
; i
++) {
2679 if (0x50 == bytes
[i
] && 0x4b == bytes
[i
+ 1]) {
2680 unsigned namelength
= 0, offset
= 0;
2681 if (0x01 == bytes
[i
+ 2] && 0x02 == bytes
[i
+ 3]) {
2682 namelength
= (unsigned)CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ i
+ 28)));
2684 } else if (0x03 == bytes
[i
+ 2] && 0x04 == bytes
[i
+ 3]) {
2685 namelength
= (unsigned)CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ i
+ 26)));
2688 if (offset
> 0 && (CFIndex
)(i
+ offset
+ namelength
) <= length
) {
2689 //printf("%.*s\n", namelength, bytes + i + offset);
2690 if (8 == namelength
&& 30 == offset
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "mimetype", 8)) foundMimetype
= _CFBundleGrokFileTypeForZipMimeType(bytes
+ i
, length
- i
, &ext
);
2691 else if (9 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/", 9)) hasMetaInf
= true;
2692 else if (11 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "content.xml", 11)) hasContentXML
= true;
2693 else if (11 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "_rels/.rels", 11)) hasRels
= true;
2694 else if (19 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "[Content_Types].xml", 19)) hasContentTypes
= true;
2695 else if (20 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/MANIFEST.MF", 20)) hasManifestMF
= true;
2696 else if (21 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/manifest.xml", 21)) hasManifestXML
= true;
2697 else if (4 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".opf", 4)) hasOPF
= true;
2698 else if (4 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".sml", 4)) hasSMIL
= true;
2699 else if (5 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 5, ".smil", 5)) hasSMIL
= true;
2700 else if (7 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "xl/", 3) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2701 else if (8 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "ppt/", 4) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2702 else if (9 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "word/", 5) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasWordDocument
= true;
2703 else if (10 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "excel/", 6) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2704 else if (15 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "powerpoint/", 11) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2705 i
+= offset
+ namelength
- 1;
2710 if (!foundMimetype
) {
2711 if (fileLength
>= ZIP_BYTES_TO_READ
) {
2712 if (fd
>= 0 && lseek(fd
, fileLength
- ZIP_BYTES_TO_READ
, SEEK_SET
) == fileLength
- ZIP_BYTES_TO_READ
) {
2713 buffer
= (unsigned char *)malloc(ZIP_BYTES_TO_READ
);
2714 if (buffer
&& read(fd
, buffer
, ZIP_BYTES_TO_READ
) >= ZIP_BYTES_TO_READ
) moreBytes
= buffer
;
2715 } else if (bytes
&& length
>= ZIP_BYTES_TO_READ
) {
2716 moreBytes
= bytes
+ length
- ZIP_BYTES_TO_READ
;
2720 for (i
= 0; i
+ 30 < ZIP_BYTES_TO_READ
; i
++) {
2721 if (0x50 == moreBytes
[i
] && 0x4b == moreBytes
[i
+ 1]) {
2722 unsigned namelength
= 0, offset
= 0;
2723 if (0x01 == moreBytes
[i
+ 2] && 0x02 == moreBytes
[i
+ 3]) {
2724 namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(moreBytes
+ i
+ 28)));
2726 } else if (0x03 == moreBytes
[i
+ 2] && 0x04 == moreBytes
[i
+ 3]) {
2727 namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(moreBytes
+ i
+ 26)));
2730 if (offset
> 0 && i
+ offset
+ namelength
<= ZIP_BYTES_TO_READ
) {
2731 //printf("%.*s\n", namelength, moreBytes + i + offset);
2732 if (9 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/", 9)) hasMetaInf
= true;
2733 else if (11 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "content.xml", 11)) hasContentXML
= true;
2734 else if (11 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "_rels/.rels", 11)) hasRels
= true;
2735 else if (19 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "[Content_Types].xml", 19)) hasContentTypes
= true;
2736 else if (20 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/MANIFEST.MF", 20)) hasManifestMF
= true;
2737 else if (21 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/manifest.xml", 21)) hasManifestXML
= true;
2738 else if (4 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".opf", 4)) hasOPF
= true;
2739 else if (4 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".sml", 4)) hasSMIL
= true;
2740 else if (5 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 5, ".smil", 5)) hasSMIL
= true;
2741 else if (7 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "xl/", 3) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2742 else if (8 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "ppt/", 4) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2743 else if (9 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "word/", 5) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasWordDocument
= true;
2744 else if (10 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "excel/", 6) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2745 else if (15 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "powerpoint/", 11) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2746 i
+= offset
+ namelength
- 1;
2751 //printf("hasManifestMF %d hasManifestXML %d hasContentXML %d hasRels %d hasContentTypes %d hasWordDocument %d hasExcelDocument %d hasPowerPointDocument %d hasMetaInf %d hasOPF %d hasSMIL %d\n", hasManifestMF, hasManifestXML, hasContentXML, hasRels, hasContentTypes, hasWordDocument, hasExcelDocument, hasPowerPointDocument, hasMetaInf, hasOPF, hasSMIL);
2752 if (hasManifestMF
) ext
= "jar";
2753 else if ((hasRels
|| hasContentTypes
) && hasWordDocument
) ext
= "docx";
2754 else if ((hasRels
|| hasContentTypes
) && hasExcelDocument
) ext
= "xlsx";
2755 else if ((hasRels
|| hasContentTypes
) && hasPowerPointDocument
) ext
= "pptx";
2756 else if (hasManifestXML
|| hasContentXML
) ext
= "odt";
2757 else if (hasMetaInf
) ext
= "jar";
2758 else if (hasOPF
&& hasSMIL
) ext
= "dtb";
2759 else if (hasOPF
) ext
= "oeb";
2761 if (buffer
) free(buffer
);
2766 static Boolean
_CFBundleCheckOLEName(const char *name
, const char *bytes
, unsigned length
) {
2767 Boolean retval
= true;
2769 for (j
= 0; retval
&& j
< length
; j
++) if (bytes
[2 * j
] != name
[j
]) retval
= false;
2773 static const char *_CFBundleGrokFileTypeForOLEFile(int fd
, const void *bytes
, CFIndex length
, off_t offset
) {
2774 const char *ext
= "ole", *moreBytes
= NULL
;
2775 char *buffer
= NULL
;
2777 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2778 buffer
= (char *)malloc(OLE_BYTES_TO_READ
);
2779 if (buffer
&& read(fd
, buffer
, OLE_BYTES_TO_READ
) >= OLE_BYTES_TO_READ
) moreBytes
= buffer
;
2780 } else if (bytes
&& length
>= offset
+ OLE_BYTES_TO_READ
) {
2781 moreBytes
= (char *)bytes
+ offset
;
2784 Boolean foundit
= false;
2786 for (i
= 0; !foundit
&& i
< 4; i
++) {
2787 char namelength
= moreBytes
[128 * i
+ 64] / 2;
2789 if (sizeof(XLS_NAME
) == namelength
&& _CFBundleCheckOLEName(XLS_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "xls";
2790 else if (sizeof(XLS_NAME2
) == namelength
&& _CFBundleCheckOLEName(XLS_NAME2
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "xls";
2791 else if (sizeof(DOC_NAME
) == namelength
&& _CFBundleCheckOLEName(DOC_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "doc";
2792 else if (sizeof(PPT_NAME
) == namelength
&& _CFBundleCheckOLEName(PPT_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "ppt";
2793 else foundit
= false;
2796 if (buffer
) free(buffer
);
2800 #if DEPLOYMENT_TARGET_WINDOWS
2801 // Windows isspace implementation limits the input chars to < 256 in the ASCII range. It will
2802 // assert in debug builds. This is annoying. We merrily grok chars > 256.
2803 static inline BOOL
isspace(char c
) {
2804 return (c
== ' ' || c
== '\t' || c
== '\n' || c
== '\r'|| c
== '\v' || c
== '\f');
2808 // returns zero-ref dictionary in *infodict under GC
2809 static Boolean
_CFBundleGrokFileType(CFURLRef url
, CFDataRef data
, CFStringRef
*extension
, UInt32
*machtype
, CFArrayRef
*architectures
, CFDictionaryRef
*infodict
, Boolean
*hasObjc
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
2811 const unsigned char *bytes
= NULL
;
2812 unsigned char buffer
[MAGIC_BYTES_TO_READ
];
2813 CFIndex i
, length
= 0;
2814 off_t fileLength
= 0;
2815 const char *ext
= NULL
;
2816 UInt32 mt
= UNKNOWN_FILETYPE
;
2817 #if defined(BINARY_SUPPORT_DYLD)
2818 Boolean isX11
= false;
2819 #endif /* BINARY_SUPPORT_DYLD */
2820 Boolean isFile
= false, isPlain
= true, isZero
= true, isSpace
= true, hasBOM
= false;
2821 // extensions returned: o, tool, x11app, pef, core, dylib, bundle, elf, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, rtfd, pdf, ra, rm, au, aiff, aifc, caf, wav, avi, wmv, ogg, flac, psd, mpeg, mid, zip, jar, sit, cpio, html, ps, mov, qtif, ttf, otf, sfont, bmp, hqx, bin, class, tar, txt, gz, Z, uu, ync, bz, bz2, sh, pl, py, rb, dvi, sgi, tga, mp3, xml, plist, xls, doc, ppt, mp4, m4a, m4b, m4p, m4v, 3gp, 3g2, dmg, cwk, webarchive, dwg, dgn, pfa, pfb, afm, tfm, xcf, cpx, dwf, swf, swc, abw, bom, lit, svg, rdf, x3d, oeb, dtb, docx, xlsx, pptx, sxc, sxd, sxg, sxi, sxm, sxw, odc, odf, odg, oth, odi, odm, odp, ods, cin, exr
2822 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
2823 // ??? we do not distinguish between ordinary documents and template versions (often there is no difference in file contents)
2824 // ??? the distinctions between docx, xlsx, and pptx may not be entirely reliable
2825 if (architectures
) *architectures
= NULL
;
2826 if (infodict
) *infodict
= NULL
;
2827 if (hasObjc
) *hasObjc
= false;
2828 if (objcVersion
) *objcVersion
= 0;
2829 if (objcFlags
) *objcFlags
= 0;
2831 Boolean gotPath
= FALSE
;
2832 char path
[CFMaxPathSize
];
2833 gotPath
= CFURLGetFileSystemRepresentation(url
, true, (uint8_t *)path
, CFMaxPathSize
);
2834 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2835 struct stat statBuf
;
2836 #elif DEPLOYMENT_TARGET_WINDOWS
2837 struct _stat statBuf
;
2839 #error Unknown or unspecified DEPLOYMENT_TARGET
2841 if (gotPath
&& stat(path
, &statBuf
) == 0 && (statBuf
.st_mode
& S_IFMT
) == S_IFREG
&& (fd
= open(path
, O_RDONLY
| CF_OPENFLGS
, 0777)) >= 0) {
2842 length
= read(fd
, buffer
, MAGIC_BYTES_TO_READ
);
2843 fileLength
= statBuf
.st_size
;
2848 if (!isFile
&& data
) {
2849 length
= CFDataGetLength(data
);
2850 fileLength
= (off_t
)length
;
2851 bytes
= CFDataGetBytePtr(data
);
2852 if (length
== 0) ext
= "txt";
2856 UInt32 magic
= CFSwapInt32HostToBig(*((UInt32
*)bytes
));
2857 for (i
= 0; !ext
&& i
< NUM_EXTENSIONS
; i
++) {
2858 if (__CFBundleMagicNumbersArray
[i
] == magic
) ext
= __CFBundleExtensionsArray
+ i
* EXTENSION_LENGTH
;
2861 if (0xcafebabe == magic
&& 8 <= length
&& 0 != *((UInt16
*)(bytes
+ 4))) ext
= "class";
2862 #if defined(BINARY_SUPPORT_DYLD)
2863 else if ((int)sizeof(struct mach_header_64
) <= length
) mt
= _CFBundleGrokMachType(fd
, bytes
, length
, extension
? &isX11
: NULL
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2865 if (MH_OBJECT
== mt
) ext
= "o";
2866 else if (MH_EXECUTE
== mt
) ext
= isX11
? "x11app" : "tool";
2867 else if (PEF_FILETYPE
== mt
) ext
= "pef";
2868 else if (MH_CORE
== mt
) ext
= "core";
2869 else if (MH_DYLIB
== mt
) ext
= "dylib";
2870 else if (MH_BUNDLE
== mt
) ext
= "bundle";
2871 #endif /* BINARY_SUPPORT_DYLD */
2872 else if (0x7b5c7274 == magic
&& (6 > length
|| 'f' != bytes
[4])) ext
= NULL
;
2873 else if (0x25504446 == magic
&& (6 > length
|| '-' != bytes
[4])) ext
= NULL
;
2874 else if (0x00010000 == magic
&& (6 > length
|| 0 != bytes
[4])) ext
= NULL
;
2875 else if (0x47494638 == magic
&& (6 > length
|| (0x3761 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4)))))) ext
= NULL
;
2876 else if (0x0000000c == magic
&& (6 > length
|| 0x6a50 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2877 else if (0x2356524d == magic
&& (6 > length
|| 0x4c20 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2878 else if (0x28445746 == magic
&& (6 > length
|| 0x2056 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2879 else if (0x30373037 == magic
&& (6 > length
|| 0x30 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2880 else if (0x41433130 == magic
&& (6 > length
|| 0x31 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2881 else if (0x89504e47 == magic
&& (8 > length
|| 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2882 else if (0x53747566 == magic
&& (8 > length
|| 0x66497420 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2883 else if (0x3026b275 == magic
&& (8 > length
|| 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2884 else if (0x67696d70 == magic
&& (8 > length
|| 0x20786366 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2885 else if (0x424f4d53 == magic
&& (8 > length
|| 0x746f7265 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2886 else if (0x49544f4c == magic
&& (8 > length
|| 0x49544c53 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2887 else if (0x72746664 == magic
&& (8 > length
|| 0x00000000 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2888 else if (0x3d796265 == magic
&& (12 > length
|| 0x67696e20 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || (0x6c696e65 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8))) && 0x70617274 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))))) ext
= NULL
;
2889 else if (0x63616666 == magic
&& (12 > length
|| 0 != bytes
[4] || 0x64657363 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8))))) ext
= NULL
;
2890 else if (0x504b0304 == magic
) ext
= _CFBundleGrokFileTypeForZipFile(fd
, bytes
, length
, fileLength
);
2891 else if (0x25215053 == magic
) {
2892 if (11 <= length
&& 0 == ustrncmp(bytes
+ 4, "-Adobe-", 7)) ext
= "ps";
2893 else if (14 <= length
&& 0 == ustrncmp(bytes
+ 4, "-AdobeFont", 10)) ext
= "pfa";
2895 } else if (0x464f524d == magic
) {
2899 UInt32 iffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2900 if (0x41494646 == iffMagic
) ext
= "aiff";
2901 else if (0x414946 == iffMagic
) ext
= "aifc";
2903 } else if (0x52494646 == magic
) {
2907 UInt32 riffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2908 if (0x57415645 == riffMagic
) ext
= "wav";
2909 else if (0x41564920 == riffMagic
) ext
= "avi";
2911 } else if (0xd0cf11e0 == magic
) {
2913 if (52 <= length
) ext
= _CFBundleGrokFileTypeForOLEFile(fd
, bytes
, length
, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 48)))));
2914 } else if (0x62656769 == magic
) {
2917 if (76 <= length
&& 'n' == bytes
[4] && ' ' == bytes
[5] && isdigit(bytes
[6]) && isdigit(bytes
[7]) && isdigit(bytes
[8]) && ' ' == bytes
[9]) {
2918 CFIndex endOfLine
= 0;
2919 for (i
= 10; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2920 if (10 <= endOfLine
&& endOfLine
+ 62 < length
&& 'M' == bytes
[endOfLine
+ 1] && '\n' == bytes
[endOfLine
+ 62]) {
2922 for (i
= endOfLine
+ 1; ext
&& i
< endOfLine
+ 62; i
++) if (!isprint(bytes
[i
])) ext
= NULL
;
2927 if (extension
&& !ext
) {
2928 UInt16 shortMagic
= CFSwapInt16HostToBig(*((UInt16
*)bytes
));
2929 if (5 <= length
&& 0 == bytes
[3] && 0 == bytes
[4] && ((1 == bytes
[1] && 1 == (0xf7 & bytes
[2])) || (0 == bytes
[1] && (2 == (0xf7 & bytes
[2]) || (3 == (0xf7 & bytes
[2])))))) ext
= "tga";
2930 else if (8 <= length
&& (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "mov";
2931 else if (8 <= length
&& (0x69647363 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "qtif";
2932 else if (8 <= length
&& 0x424f424f == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) ext
= "cwk";
2933 else if (8 <= length
&& 0x62706c69 == magic
&& 0x7374 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && isdigit(bytes
[6]) && isdigit(bytes
[7])) {
2934 for (i
= 8; !ext
&& i
< 128 && i
+ 16 <= length
; i
++) {
2935 if (0 == ustrncmp(bytes
+ i
, "WebMainResource", 15)) ext
= "webarchive";
2937 if (!ext
) ext
= "plist";
2938 } else if (0 == shortMagic
&& 12 <= length
&& 0x66747970 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
2939 // ??? may want more ftyp values
2940 UInt32 ftyp
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2941 if (0x6d703431 == ftyp
|| 0x6d703432 == ftyp
|| 0x69736f6d == ftyp
|| 0x69736f32 == ftyp
) ext
= "mp4";
2942 else if (0x4d344120 == ftyp
) ext
= "m4a";
2943 else if (0x4d344220 == ftyp
) ext
= "m4b";
2944 else if (0x4d345020 == ftyp
) ext
= "m4p";
2945 else if (0x4d345620 == ftyp
|| 0x4d345648 == ftyp
|| 0x4d345650 == ftyp
) ext
= "m4v";
2946 else if (0x3367 == (ftyp
>> 16)) {
2947 UInt16 remainder
= (ftyp
& 0xffff);
2948 if (0x6536 == remainder
|| 0x6537 == remainder
|| 0x6736 == remainder
|| 0x7034 == remainder
|| 0x7035 == remainder
|| 0x7036 == remainder
|| 0x7236 == remainder
|| 0x7336 == remainder
|| 0x7337 == remainder
) ext
= "3gp";
2949 else if (0x3261 == remainder
) ext
= "3g2";
2951 } else if (0x424d == shortMagic
&& 18 <= length
) {
2952 UInt32 btyp
= CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 14)));
2953 if (40 == btyp
|| btyp
== 12 || btyp
== 64 || btyp
== 108 || btyp
== 124) ext
= "bmp";
2954 } else if (20 <= length
&& 0 == ustrncmp(bytes
+ 6, "%!PS-AdobeFont", 14)) ext
= "pfb";
2955 else if (40 <= length
&& 0x42696e48 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 38)))) ext
= "hqx";
2956 else if (128 <= length
&& 0x6d42494e == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 102)))) ext
= "bin";
2957 else if (128 <= length
&& 0 == bytes
[0] && 0 < bytes
[1] && bytes
[1] < 64 && 0 == bytes
[74] && 0 == bytes
[82] && 0 == (fileLength
% 128)) {
2958 UInt32 df
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 83))), rf
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 87))), blocks
= 1 + (df
+ 127) / 128 + (rf
+ 127) / 128;
2959 if (df
< 0x00800000 && rf
< 0x00800000 && 1 < blocks
&& (off_t
)(128 * blocks
) == fileLength
) ext
= "bin";
2960 } else if (265 <= length
&& 0x75737461 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 261))))) ext
= "tar";
2961 else if (0xfeff == shortMagic
|| 0xfffe == shortMagic
) {
2963 if (12 <= length
&& ((0x3cfeff == *((UInt32
*)bytes
) && 0x740068 == *((UInt32
*)(bytes
+ 4)) && 0x6c006d == *((UInt32
*)(bytes
+ 8))) || (0xfffe3c00 == *((UInt32
*)bytes
) && 0x68007400 == *((UInt32
*)(bytes
+ 4)) && 0x6d006c00 == *((UInt32
*)(bytes
+ 8))))) ext
= "html";
2964 } else if (0x1f9d == shortMagic
) ext
= "Z";
2965 else if (0x1f8b == shortMagic
) ext
= "gz";
2966 else if (0x71c7 == shortMagic
|| 0xc771 == shortMagic
) ext
= "cpio";
2967 else if (0xf702 == shortMagic
) ext
= "dvi";
2968 else if (0x01da == shortMagic
&& (0 == bytes
[2] || 1 == bytes
[2]) && (0 < bytes
[3] && 16 > bytes
[3])) ext
= "sgi";
2969 else if (0x2321 == shortMagic
) {
2970 CFIndex endOfLine
= 0, lastSlash
= 0;
2971 for (i
= 2; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2972 if (endOfLine
> 3) {
2973 for (i
= endOfLine
- 1; 0 == lastSlash
&& i
> 1; i
--) if ('/' == bytes
[i
]) lastSlash
= i
;
2974 if (lastSlash
> 0) {
2975 if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "perl", 4)) ext
= "pl";
2976 else if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "python", 6)) ext
= "py";
2977 else if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "ruby", 4)) ext
= "rb";
2981 } else if (0xffd8 == shortMagic
&& 0xff == bytes
[2]) ext
= "jpeg";
2982 else if (0x4657 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swf";
2983 else if (0x4357 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swc";
2984 else if (0x4944 == shortMagic
&& '3' == bytes
[2] && 0x20 > bytes
[3]) ext
= "mp3";
2985 else if (0x425a == shortMagic
&& isdigit(bytes
[2]) && isdigit(bytes
[3])) ext
= "bz";
2986 else if (0x425a == shortMagic
&& 'h' == bytes
[2] && isdigit(bytes
[3]) && 8 <= length
&& (0x31415926 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "bz2";
2987 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2)))) ext
= "tfm";
2990 if (extension
&& !ext
) {
2991 //??? what about MacOSRoman?
2992 if (0xef == bytes
[0] && 0xbb == bytes
[1] && 0xbf == bytes
[2]) { // UTF-8 BOM
2996 for (i
= (hasBOM
? 3 : 0); (isPlain
|| isZero
) && !ext
&& i
< length
&& i
< 512; i
++) {
2998 if (isPlain
&& '<' == c
&& i
+ 14 <= length
&& 0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) ext
= "html";
2999 if (isSpace
&& '<' == c
&& i
+ 14 <= length
) {
3000 if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype html", 13) || 0 == ustrncasecmp(bytes
+ i
+ 1, "head", 4) || 0 == ustrncasecmp(bytes
+ i
+ 1, "title", 5) || 0 == ustrncasecmp(bytes
+ i
+ 1, "script", 6) || 0 == ustrncasecmp(bytes
+ i
+ 1, "html", 4)) {
3002 } else if (0 == ustrncasecmp(bytes
+ i
+ 1, "?xml", 4)) {
3003 for (i
+= 4; !ext
&& i
< 128 && i
+ 20 <= length
; i
++) {
3004 if ('<' == bytes
[i
]) {
3005 if (0 == ustrncasecmp(bytes
+ i
+ 1, "abiword", 7)) ext
= "abw";
3006 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype svg", 12)) ext
= "svg";
3007 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype rdf", 12)) ext
= "rdf";
3008 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype x3d", 12)) ext
= "x3d";
3009 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) ext
= "html";
3010 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype posingfont", 19)) ext
= "sfont";
3011 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype plist", 14)) {
3012 for (i
+= 14; !ext
&& i
< 256 && i
+ 16 <= length
; i
++) {
3013 if (0 == ustrncmp(bytes
+ i
, "WebMainResource", 15)) ext
= "webarchive";
3015 if (!ext
) ext
= "plist";
3019 if (!ext
) ext
= "xml";
3022 if (0 != c
) isZero
= false;
3023 if (isZero
|| 0x7f <= c
|| (0x20 > c
&& !isspace(c
))) isPlain
= false;
3024 if (isZero
|| !isspace(c
)) isSpace
= false;
3028 if (16 <= length
&& 0 == ustrncmp(bytes
, "StartFontMetrics", 16)) ext
= "afm";
3030 } else if (isZero
&& length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= 526) {
3032 if (lseek(fd
, 512, SEEK_SET
) == 512 && read(fd
, buffer
, MAGIC_BYTES_TO_READ
) >= 14) {
3033 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 10)))) ext
= "pict";
3036 if (526 <= length
&& 0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 522)))) ext
= "pict";
3041 if (extension
&& (!ext
|| 0 == strcmp(ext
, "bz2")) && length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= DMG_BYTES_TO_READ
) {
3043 if (lseek(fd
, fileLength
- DMG_BYTES_TO_READ
, SEEK_SET
) == fileLength
- DMG_BYTES_TO_READ
&& read(fd
, buffer
, DMG_BYTES_TO_READ
) >= DMG_BYTES_TO_READ
) {
3044 if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32
*)buffer
)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ DMG_BYTES_TO_READ
- 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ DMG_BYTES_TO_READ
- 4))))) ext
= "dmg";
3047 if (DMG_BYTES_TO_READ
<= length
&& (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- DMG_BYTES_TO_READ
))) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ length
- 4)))))) ext
= "dmg";
3051 if (extension
) *extension
= ext
? CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, ext
, kCFStringEncodingUTF8
, kCFAllocatorNull
) : NULL
;
3052 if (machtype
) *machtype
= mt
;
3053 if (fd
>= 0) close(fd
);
3054 return (ext
? true : false);
3057 CFStringRef
_CFBundleCopyFileTypeForFileURL(CFURLRef url
) {
3058 CFStringRef extension
= NULL
;
3059 (void)_CFBundleGrokFileType(url
, NULL
, &extension
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
3063 CFStringRef
_CFBundleCopyFileTypeForFileData(CFDataRef data
) {
3064 CFStringRef extension
= NULL
;
3065 (void)_CFBundleGrokFileType(NULL
, data
, &extension
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
3069 // returns zero-ref dictionary under GC
3070 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInExecutable(CFURLRef url
) {
3071 CFDictionaryRef result
= NULL
;
3072 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, NULL
, &result
, NULL
, NULL
, NULL
);
3076 __private_extern__ CFArrayRef
_CFBundleCopyArchitecturesForExecutable(CFURLRef url
) {
3077 CFArrayRef result
= NULL
;
3078 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, &result
, NULL
, NULL
, NULL
, NULL
);
3082 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3083 static Boolean
_CFBundleGetObjCImageInfoForExecutable(CFURLRef url
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
3084 Boolean retval
= false;
3085 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, NULL
, NULL
, &retval
, objcVersion
, objcFlags
);
3090 #if defined(BINARY_SUPPORT_DYLD)
3092 __private_extern__ __CFPBinaryType
_CFBundleGrokBinaryType(CFURLRef executableURL
) {
3093 // Attempt to grok the type of the binary by looking for DYLD magic numbers. If one of the DYLD magic numbers is found, find out what type of Mach-o file it is. Otherwise, look for the PEF magic numbers to see if it is CFM.
3094 __CFPBinaryType result
= executableURL
? __CFBundleUnreadableBinary
: __CFBundleNoBinary
;
3095 UInt32 machtype
= UNKNOWN_FILETYPE
;
3096 if (_CFBundleGrokFileType(executableURL
, NULL
, NULL
, &machtype
, NULL
, NULL
, NULL
, NULL
, NULL
)) {
3099 result
= __CFBundleDYLDExecutableBinary
;
3102 result
= __CFBundleDYLDBundleBinary
;
3105 result
= __CFBundleDYLDFrameworkBinary
;
3108 result
= __CFBundleCFMBinary
;
3115 #endif /* BINARY_SUPPORT_DYLD */
3117 void _CFBundleSetCFMConnectionID(CFBundleRef bundle
, void *connectionID
) {
3118 bundle
->_connectionCookie
= connectionID
;
3119 bundle
->_isLoaded
= true;
3122 static CFStringRef
_CFBundleCopyLastPathComponent(CFBundleRef bundle
) {
3123 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
);
3124 CFStringRef str
= CFURLCopyFileSystemPath(bundleURL
, kCFURLPOSIXPathStyle
);
3125 UniChar buff
[CFMaxPathSize
];
3126 CFIndex buffLen
= CFStringGetLength(str
), startOfLastDir
= 0;
3128 CFRelease(bundleURL
);
3129 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
3130 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
3132 if (buffLen
> 0) startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
3133 return CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
3136 static CFErrorRef
_CFBundleCreateErrorDebug(CFAllocatorRef allocator
, CFBundleRef bundle
, CFIndex code
, CFStringRef debugString
) {
3137 const void *userInfoKeys
[6], *userInfoValues
[6];
3138 CFIndex numKeys
= 0;
3139 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
), absoluteURL
= CFURLCopyAbsoluteURL(bundleURL
), executableURL
= CFBundleCopyExecutableURL(bundle
);
3140 CFBundleRef bdl
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation"));
3141 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
), executablePath
= executableURL
? CFURLCopyFileSystemPath(executableURL
, PLATFORM_PATH_STYLE
) : NULL
, descFormat
= NULL
, desc
= NULL
, reason
= NULL
, suggestion
= NULL
;
3144 CFStringRef name
= (CFStringRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, kCFBundleNameKey
);
3145 name
= name
? (CFStringRef
)CFRetain(name
) : _CFBundleCopyLastPathComponent(bundle
);
3146 if (CFBundleExecutableNotFoundError
== code
) {
3147 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
3148 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl
, CFSTR("The bundle\\U2019s executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
3149 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError");
3150 } else if (CFBundleExecutableNotLoadableError
== code
) {
3151 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
3152 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl
, CFSTR("The bundle\\U2019s executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
3153 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError");
3154 } else if (CFBundleExecutableArchitectureMismatchError
== code
) {
3155 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");
3156 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl
, CFSTR("The bundle doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
3157 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl
, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError");
3158 } else if (CFBundleExecutableRuntimeMismatchError
== code
) {
3159 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");
3160 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl
, CFSTR("The bundle isn\\U2019t compatible with this application."), "NSExecutableRuntimeMismatchError");
3161 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl
, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError");
3162 } else if (CFBundleExecutableLoadError
== code
) {
3163 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");
3164 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl
, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError");
3165 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError");
3166 } else if (CFBundleExecutableLinkError
== code
) {
3167 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded."), "NSExecutableLinkError");
3168 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl
, CFSTR("The bundle couldn\\U2019t be loaded."), "NSExecutableLinkError");
3169 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError");
3172 desc
= CFStringCreateWithFormat(allocator
, NULL
, descFormat
, name
);
3173 CFRelease(descFormat
);
3178 userInfoKeys
[numKeys
] = CFSTR("NSBundlePath");
3179 userInfoValues
[numKeys
] = bundlePath
;
3182 if (executablePath
) {
3183 userInfoKeys
[numKeys
] = CFSTR("NSFilePath");
3184 userInfoValues
[numKeys
] = executablePath
;
3188 userInfoKeys
[numKeys
] = kCFErrorLocalizedDescriptionKey
;
3189 userInfoValues
[numKeys
] = desc
;
3193 userInfoKeys
[numKeys
] = kCFErrorLocalizedFailureReasonKey
;
3194 userInfoValues
[numKeys
] = reason
;
3198 userInfoKeys
[numKeys
] = kCFErrorLocalizedRecoverySuggestionKey
;
3199 userInfoValues
[numKeys
] = suggestion
;
3203 userInfoKeys
[numKeys
] = CFSTR("NSDebugDescription");
3204 userInfoValues
[numKeys
] = debugString
;
3207 error
= CFErrorCreateWithUserInfoKeysAndValues(allocator
, kCFErrorDomainCocoa
, code
, userInfoKeys
, userInfoValues
, numKeys
);
3208 if (bundleURL
) CFRelease(bundleURL
);
3209 if (absoluteURL
) CFRelease(absoluteURL
);
3210 if (executableURL
) CFRelease(executableURL
);
3211 if (bundlePath
) CFRelease(bundlePath
);
3212 if (executablePath
) CFRelease(executablePath
);
3213 if (desc
) CFRelease(desc
);
3214 if (reason
) CFRelease(reason
);
3215 if (suggestion
) CFRelease(suggestion
);
3219 CFErrorRef
_CFBundleCreateError(CFAllocatorRef allocator
, CFBundleRef bundle
, CFIndex code
) {
3220 allocator
= _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator
);
3221 return _CFBundleCreateErrorDebug(allocator
, bundle
, code
, NULL
);
3224 Boolean
_CFBundleLoadExecutableAndReturnError(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
3225 Boolean result
= false;
3226 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
3227 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3229 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3230 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
3231 // make sure we know whether bundle is already loaded or not
3232 #if defined(BINARY_SUPPORT_DLFCN)
3233 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3234 #elif defined(BINARY_SUPPORT_DYLD)
3235 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3236 #endif /* BINARY_SUPPORT_DLFCN */
3237 #if defined(BINARY_SUPPORT_DYLD)
3238 // We might need to figure out what it is
3239 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
3240 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
3241 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3243 #endif /* BINARY_SUPPORT_DYLD */
3244 if (executableURL
) CFRelease(executableURL
);
3246 if (bundle
->_isLoaded
) {
3247 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3248 // Remove from the scheduled unload set if we are there.
3249 __CFSpinLock(&CFBundleGlobalDataLock
);
3250 #if defined(AVOID_WEAK_COLLECTIONS)
3251 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3252 #else /* AVOID_WEAK_COLLECTIONS */
3253 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3254 #endif /* AVOID_WEAK_COLLECTIONS */
3255 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3259 // Unload bundles scheduled for unloading
3260 if (!_scheduledBundlesAreUnloading
) {
3261 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3262 _CFBundleUnloadScheduledBundles();
3263 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3266 if (bundle
->_isLoaded
) {
3267 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3268 // Remove from the scheduled unload set if we are there.
3269 __CFSpinLock(&CFBundleGlobalDataLock
);
3270 #if defined(AVOID_WEAK_COLLECTIONS)
3271 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3272 #else /* AVOID_WEAK_COLLECTIONS */
3273 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3274 #endif /* AVOID_WEAK_COLLECTIONS */
3275 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3278 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3280 switch (bundle
->_binaryType
) {
3281 #if defined(BINARY_SUPPORT_DLFCN)
3282 case __CFBundleUnreadableBinary
:
3283 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3285 #endif /* BINARY_SUPPORT_DLFCN */
3286 #if defined(BINARY_SUPPORT_DYLD)
3287 case __CFBundleDYLDBundleBinary
:
3288 #if defined(BINARY_SUPPORT_DLFCN)
3289 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3290 #else /* BINARY_SUPPORT_DLFCN */
3291 result
= _CFBundleDYLDLoadBundle(bundle
, forceGlobal
, subError
);
3292 #endif /* BINARY_SUPPORT_DLFCN */
3294 case __CFBundleDYLDFrameworkBinary
:
3295 #if defined(BINARY_SUPPORT_DLFCN)
3296 result
= _CFBundleDlfcnLoadFramework(bundle
, subError
);
3297 #else /* BINARY_SUPPORT_DLFCN */
3298 result
= _CFBundleDYLDLoadFramework(bundle
, subError
);
3299 #endif /* BINARY_SUPPORT_DLFCN */
3301 case __CFBundleDYLDExecutableBinary
:
3303 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3305 CFLog(__kCFLogBundle
, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle
);
3308 #endif /* BINARY_SUPPORT_DYLD */
3309 #if defined(BINARY_SUPPORT_DLFCN)
3310 case __CFBundleUnknownBinary
:
3311 case __CFBundleELFBinary
:
3312 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3314 #endif /* BINARY_SUPPORT_DLFCN */
3315 #if defined(BINARY_SUPPORT_DLL)
3316 case __CFBundleDLLBinary
:
3317 result
= _CFBundleDLLLoad(bundle
, subError
);
3319 #endif /* BINARY_SUPPORT_DLL */
3320 case __CFBundleNoBinary
:
3322 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
3324 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for %@"), bundle
);
3329 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3331 CFLog(__kCFLogBundle
, CFSTR("Cannot recognize type of executable for %@"), bundle
);
3335 if (result
&& bundle
->_plugInData
._isPlugIn
) _CFBundlePlugInLoaded(bundle
);
3336 if (!result
&& error
) *error
= localError
;
3340 Boolean
CFBundleLoadExecutableAndReturnError(CFBundleRef bundle
, CFErrorRef
*error
) {
3341 return _CFBundleLoadExecutableAndReturnError(bundle
, false, error
);
3344 Boolean
CFBundleLoadExecutable(CFBundleRef bundle
) {
3345 return _CFBundleLoadExecutableAndReturnError(bundle
, false, NULL
);
3348 Boolean
CFBundlePreflightExecutable(CFBundleRef bundle
, CFErrorRef
*error
) {
3349 Boolean result
= false;
3350 CFErrorRef localError
= NULL
;
3351 #if defined(BINARY_SUPPORT_DLFCN)
3352 CFErrorRef
*subError
= (error
? &localError
: NULL
);
3354 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3356 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3357 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
3358 // make sure we know whether bundle is already loaded or not
3359 #if defined(BINARY_SUPPORT_DLFCN)
3360 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3361 #elif defined(BINARY_SUPPORT_DYLD)
3362 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3363 #endif /* BINARY_SUPPORT_DLFCN */
3364 #if defined(BINARY_SUPPORT_DYLD)
3365 // We might need to figure out what it is
3366 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
3367 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
3368 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3370 #endif /* BINARY_SUPPORT_DYLD */
3371 if (executableURL
) CFRelease(executableURL
);
3373 if (bundle
->_isLoaded
) {
3374 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3377 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3379 switch (bundle
->_binaryType
) {
3380 #if defined(BINARY_SUPPORT_DLFCN)
3381 case __CFBundleUnreadableBinary
:
3382 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3384 #endif /* BINARY_SUPPORT_DLFCN */
3385 #if defined(BINARY_SUPPORT_DYLD)
3386 case __CFBundleDYLDBundleBinary
:
3388 #if defined(BINARY_SUPPORT_DLFCN)
3389 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3390 #endif /* BINARY_SUPPORT_DLFCN */
3392 case __CFBundleDYLDFrameworkBinary
:
3394 #if defined(BINARY_SUPPORT_DLFCN)
3395 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3396 #endif /* BINARY_SUPPORT_DLFCN */
3398 case __CFBundleDYLDExecutableBinary
:
3399 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3401 #endif /* BINARY_SUPPORT_DYLD */
3402 #if defined(BINARY_SUPPORT_DLFCN)
3403 case __CFBundleUnknownBinary
:
3404 case __CFBundleELFBinary
:
3405 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3407 #endif /* BINARY_SUPPORT_DLFCN */
3408 #if defined(BINARY_SUPPORT_DLL)
3409 case __CFBundleDLLBinary
:
3412 #endif /* BINARY_SUPPORT_DLL */
3413 case __CFBundleNoBinary
:
3414 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
3417 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3420 if (!result
&& error
) *error
= localError
;
3424 CFArrayRef
CFBundleCopyExecutableArchitectures(CFBundleRef bundle
) {
3425 CFArrayRef result
= NULL
;
3426 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3427 if (executableURL
) {
3428 result
= _CFBundleCopyArchitecturesForExecutable(executableURL
);
3429 CFRelease(executableURL
);
3434 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3435 static Boolean
_CFBundleGetObjCImageInfo(CFBundleRef bundle
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
3436 Boolean retval
= false;
3437 uint32_t localVersion
= 0, localFlags
= 0;
3438 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3439 if (executableURL
) {
3440 retval
= _CFBundleGetObjCImageInfoForExecutable(executableURL
, &localVersion
, &localFlags
);
3441 CFRelease(executableURL
);
3443 if (objcVersion
) *objcVersion
= localVersion
;
3444 if (objcFlags
) *objcFlags
= localFlags
;
3449 void CFBundleUnloadExecutable(CFBundleRef bundle
) {
3450 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
3451 if (!_scheduledBundlesAreUnloading
) _CFBundleUnloadScheduledBundles();
3453 if (!bundle
->_isLoaded
) return;
3455 // Remove from the scheduled unload set if we are there.
3456 if (!_scheduledBundlesAreUnloading
) __CFSpinLock(&CFBundleGlobalDataLock
);
3457 #if defined(AVOID_WEAK_COLLECTIONS)
3458 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3459 #else /* AVOID_WEAK_COLLECTIONS */
3460 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3461 #endif /* AVOID_WEAK_COLLECTIONS */
3462 if (!_scheduledBundlesAreUnloading
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
3464 // Give the plugIn code a chance to realize this...
3465 _CFPlugInWillUnload(bundle
);
3467 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3468 if (!bundle
->_isLoaded
) {
3469 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3472 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3474 switch (bundle
->_binaryType
) {
3475 #if defined(BINARY_SUPPORT_DYLD)
3476 case __CFBundleDYLDBundleBinary
:
3477 #if defined(BINARY_SUPPORT_DLFCN)
3478 if (bundle
->_handleCookie
) _CFBundleDlfcnUnload(bundle
);
3479 #else /* BINARY_SUPPORT_DLFCN */
3480 _CFBundleDYLDUnloadBundle(bundle
);
3481 #endif /* BINARY_SUPPORT_DLFCN */
3483 case __CFBundleDYLDFrameworkBinary
:
3484 #if defined(BINARY_SUPPORT_DLFCN)
3485 if (bundle
->_handleCookie
&& _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard
)) _CFBundleDlfcnUnload(bundle
);
3486 #endif /* BINARY_SUPPORT_DLFCN */
3488 #endif /* BINARY_SUPPORT_DYLD */
3489 #if defined(BINARY_SUPPORT_DLL)
3490 case __CFBundleDLLBinary
:
3491 _CFBundleDLLUnload(bundle
);
3493 #endif /* BINARY_SUPPORT_DLL */
3495 #if defined(BINARY_SUPPORT_DLFCN)
3496 if (bundle
->_handleCookie
) _CFBundleDlfcnUnload(bundle
);
3497 #endif /* BINARY_SUPPORT_DLFCN */
3500 if (!bundle
->_isLoaded
&& bundle
->_glueDict
) {
3501 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
3502 CFRelease(bundle
->_glueDict
);
3503 bundle
->_glueDict
= NULL
;
3507 #if defined(AVOID_WEAK_COLLECTIONS)
3509 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
3510 __CFSpinLock(&CFBundleGlobalDataLock
);
3511 if (!_bundlesToUnload
) {
3512 CFSetCallBacks nonRetainingCallbacks
= kCFTypeSetCallBacks
;
3513 nonRetainingCallbacks
.retain
= NULL
;
3514 nonRetainingCallbacks
.release
= NULL
;
3515 _bundlesToUnload
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingCallbacks
);
3517 CFSetAddValue(_bundlesToUnload
, bundle
);
3518 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3521 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
3522 __CFSpinLock(&CFBundleGlobalDataLock
);
3523 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3524 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3527 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
3528 __CFSpinLock(&CFBundleGlobalDataLock
);
3529 if (_bundlesToUnload
) {
3530 CFIndex i
, c
= CFSetGetCount(_bundlesToUnload
);
3532 CFBundleRef
*unloadThese
= (CFBundleRef
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(CFBundleRef
) * c
, 0);
3533 CFSetGetValues(_bundlesToUnload
, (const void **)unloadThese
);
3534 _scheduledBundlesAreUnloading
= true;
3535 for (i
= 0; i
< c
; i
++) {
3536 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
3537 CFBundleUnloadExecutable(unloadThese
[i
]);
3539 _scheduledBundlesAreUnloading
= false;
3540 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, unloadThese
);
3543 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3546 #else /* AVOID_WEAK_COLLECTIONS */
3548 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
3549 __CFSpinLock(&CFBundleGlobalDataLock
);
3550 if (!_bundlesToUnload
) _bundlesToUnload
= [[__CFHashTable alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
3551 [_bundlesToUnload addObject
:(id
)bundle
];
3552 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3555 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
3556 __CFSpinLock(&CFBundleGlobalDataLock
);
3557 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3558 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3561 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
3562 __CFSpinLock(&CFBundleGlobalDataLock
);
3563 if (_bundlesToUnload
&& [_bundlesToUnload count
] > 0) {
3565 CFMutableArrayRef unloadThese
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3566 for (id value in _bundlesToUnload
) CFArrayAppendValue(unloadThese
, value
);
3567 c
= CFArrayGetCount(unloadThese
);
3569 _scheduledBundlesAreUnloading
= true;
3570 for (i
= 0; i
< c
; i
++) {
3571 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
3572 CFBundleUnloadExecutable((CFBundleRef
)CFArrayGetValueAtIndex(unloadThese
, i
));
3574 _scheduledBundlesAreUnloading
= false;
3576 CFRelease(unloadThese
);
3578 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3581 #endif /* AVOID_WEAK_COLLECTIONS */
3583 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
3585 // Load if necessary
3586 if (!bundle
->_isLoaded
) {
3587 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
3590 switch (bundle
->_binaryType
) {
3591 #if defined(BINARY_SUPPORT_DYLD)
3592 case __CFBundleDYLDBundleBinary
:
3593 case __CFBundleDYLDFrameworkBinary
:
3594 case __CFBundleDYLDExecutableBinary
:
3595 #if defined(BINARY_SUPPORT_DLFCN)
3596 if (bundle
->_handleCookie
) return _CFBundleDlfcnGetSymbolByName(bundle
, funcName
);
3597 #else /* BINARY_SUPPORT_DLFCN */
3598 return _CFBundleDYLDGetSymbolByName(bundle
, funcName
);
3599 #endif /* BINARY_SUPPORT_DLFCN */
3601 #endif /* BINARY_SUPPORT_DYLD */
3602 #if defined(BINARY_SUPPORT_DLL)
3603 case __CFBundleDLLBinary
:
3604 tvp
= _CFBundleDLLGetSymbolByName(bundle
, funcName
);
3606 #endif /* BINARY_SUPPORT_DLL */
3608 #if defined(BINARY_SUPPORT_DLFCN)
3609 if (bundle
->_handleCookie
) return _CFBundleDlfcnGetSymbolByName(bundle
, funcName
);
3610 #endif /* BINARY_SUPPORT_DLFCN */
3616 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
3618 // Load if necessary
3619 if (!bundle
->_isLoaded
) {
3620 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
3622 #if defined (BINARY_SUPPORT_DYLD) || defined (BINARY_SUPPORT_DLFCN)
3623 switch (bundle
->_binaryType
) {
3624 #if defined(BINARY_SUPPORT_DYLD)
3625 case __CFBundleDYLDBundleBinary
:
3626 case __CFBundleDYLDFrameworkBinary
:
3627 case __CFBundleDYLDExecutableBinary
:
3628 #if defined(BINARY_SUPPORT_DLFCN)
3629 if (bundle
->_handleCookie
) fp
= _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, funcName
, true);
3630 #else /* BINARY_SUPPORT_DLFCN */
3631 fp
= _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, funcName
, true);
3632 #endif /* BINARY_SUPPORT_DLFCN */
3634 #endif /* BINARY_SUPPORT_DYLD */
3636 #if defined(BINARY_SUPPORT_DLFCN)
3637 if (bundle
->_handleCookie
) fp
= _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, funcName
, true);
3638 #endif /* BINARY_SUPPORT_DLFCN */
3641 #endif /* BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */
3645 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
3650 c
= CFArrayGetCount(functionNames
);
3651 for (i
= 0; i
< c
; i
++) ftbl
[i
] = CFBundleGetFunctionPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(functionNames
, i
));
3654 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
3659 c
= CFArrayGetCount(functionNames
);
3660 for (i
= 0; i
< c
; i
++) ftbl
[i
] = _CFBundleGetCFMFunctionPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(functionNames
, i
));
3663 void *CFBundleGetDataPointerForName(CFBundleRef bundle
, CFStringRef symbolName
) {
3665 // Load if necessary
3666 if (!bundle
->_isLoaded
&& !CFBundleLoadExecutable(bundle
)) return NULL
;
3668 switch (bundle
->_binaryType
) {
3669 #if defined(BINARY_SUPPORT_DYLD)
3670 case __CFBundleDYLDBundleBinary
:
3671 case __CFBundleDYLDFrameworkBinary
:
3672 case __CFBundleDYLDExecutableBinary
:
3673 #if defined(BINARY_SUPPORT_DLFCN)
3674 if (bundle
->_handleCookie
) dp
= _CFBundleDlfcnGetSymbolByName(bundle
, symbolName
);
3675 #else /* BINARY_SUPPORT_DLFCN */
3676 dp
= _CFBundleDYLDGetSymbolByName(bundle
, symbolName
);
3677 #endif /* BINARY_SUPPORT_DLFCN */
3679 #endif /* BINARY_SUPPORT_DYLD */
3680 #if defined(BINARY_SUPPORT_DLL)
3681 case __CFBundleDLLBinary
:
3682 /* MF:!!! Handle this someday */
3684 #endif /* BINARY_SUPPORT_DLL */
3686 #if defined(BINARY_SUPPORT_DLFCN)
3687 if (bundle
->_handleCookie
) dp
= _CFBundleDlfcnGetSymbolByName(bundle
, symbolName
);
3688 #endif /* BINARY_SUPPORT_DLFCN */
3694 void CFBundleGetDataPointersForNames(CFBundleRef bundle
, CFArrayRef symbolNames
, void *stbl
[]) {
3699 c
= CFArrayGetCount(symbolNames
);
3700 for (i
= 0; i
< c
; i
++) stbl
[i
] = CFBundleGetDataPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(symbolNames
, i
));
3703 __private_extern__ _CFResourceData
*__CFBundleGetResourceData(CFBundleRef bundle
) {
3704 return &(bundle
->_resourceData
);
3707 CFPlugInRef
CFBundleGetPlugIn(CFBundleRef bundle
) {
3708 return (bundle
->_plugInData
._isPlugIn
) ? (CFPlugInRef
)bundle
: NULL
;
3711 __private_extern__ _CFPlugInData
*__CFBundleGetPlugInData(CFBundleRef bundle
) {
3712 return &(bundle
->_plugInData
);
3715 __private_extern__ Boolean
_CFBundleCouldBeBundle(CFURLRef url
) {
3716 Boolean result
= false;
3719 if (_CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) result
= (exists
&& (mode
& S_IFMT
) == S_IFDIR
&& (mode
& 0444) != 0);
3723 #define LENGTH_OF(A) (sizeof(A) / sizeof(A[0]))
3725 //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/
3726 static CFURLRef
__CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath
, Boolean permissive
) {
3727 // 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.
3728 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3729 #elif 0 && DEPLOYMENT_TARGET_WINDOWS
3730 UniChar executablesToFrameworksPathBuff
[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3731 UniChar executablesToPrivateFrameworksPathBuff
[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3732 UniChar executablesToSystemFrameworksPathBuff
[MAX_PATH
+1] = { 0 };
3733 SHGetFolderPathAndSubDirW(NULL
, CSIDL_PROGRAM_FILES_COMMON
, NULL
, 0 /* SHGFP_TYPE_CURRENT */, L
"Apple\\Mobile Device Support\\Frameworks", executablesToSystemFrameworksPathBuff
);
3734 UniChar frameworksExtension
[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
3735 #elif DEPLOYMENT_TARGET_WINDOWS
3736 UniChar executablesToFrameworksPathBuff
[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3737 UniChar executablesToPrivateFrameworksPathBuff
[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3738 UniChar frameworksExtension
[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
3740 #error Unknown or unspecified DEPLOYMENT_TARGET
3742 UniChar pathBuff
[CFMaxPathSize
] = {0};
3743 UniChar nameBuff
[CFMaxPathSize
] = {0};
3744 CFIndex length
, nameStart
, nameLength
, savedLength
;
3745 CFMutableStringRef cheapStr
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, NULL
);
3746 CFURLRef bundleURL
= NULL
;
3748 length
= CFStringGetLength(executablePath
);
3749 if (length
> CFMaxPathSize
) length
= CFMaxPathSize
;
3750 CFStringGetCharacters(executablePath
, CFRangeMake(0, length
), pathBuff
);
3752 // Save the name in nameBuff
3753 length
= _CFLengthAfterDeletingPathExtension(pathBuff
, length
);
3754 nameStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3755 nameLength
= length
- nameStart
;
3756 memmove(nameBuff
, &(pathBuff
[nameStart
]), nameLength
* sizeof(UniChar
));
3758 // Strip the name from pathBuff
3759 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3760 savedLength
= length
;
3762 #if DEPLOYMENT_TARGET_WINDOWS
3763 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
3764 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToFrameworksPathBuff
, LENGTH_OF(executablesToFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3765 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3766 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3767 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3768 CFRelease(bundleURL
);
3772 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
3774 length
= savedLength
;
3775 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToPrivateFrameworksPathBuff
, LENGTH_OF(executablesToPrivateFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3776 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3777 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3778 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3779 CFRelease(bundleURL
);
3785 #elif 0 && DEPLOYMENT_TARGET_WINDOWS
3786 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
3787 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToFrameworksPathBuff
, LENGTH_OF(executablesToFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3788 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3789 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3790 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3791 CFRelease(bundleURL
);
3795 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
3797 length
= savedLength
;
3798 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToPrivateFrameworksPathBuff
, LENGTH_OF(executablesToPrivateFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3799 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3800 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3801 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3802 CFRelease(bundleURL
);
3807 // * (Windows-only) Next check the \Program Files\Apple\Mobile Device Support\Frameworks directory
3810 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToSystemFrameworksPathBuff
, wcslen(executablesToSystemFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3811 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3812 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3813 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3814 CFRelease(bundleURL
);
3819 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3821 #error Unknown or unspecified DEPLOYMENT_TARGET
3823 // * Finally check the executable inside the framework case.
3825 length
= savedLength
;
3826 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
3828 CFStringRef name
= permissive
? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, (const char *)nameBuff
);
3830 while (length
> 0) {
3831 CFIndex curStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3832 if (curStart
>= length
) break;
3833 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[curStart
]), length
- curStart
, CFMaxPathSize
- curStart
);
3834 if (!permissive
&& CFEqual(cheapStr
, _CFBundleResourcesDirectoryName
)) break;
3835 if (CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName1
) || CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName2
)) {
3837 CFIndex fmwkStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3838 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[fmwkStart
]), length
- fmwkStart
, CFMaxPathSize
- fmwkStart
);
3840 if (permissive
|| CFStringHasPrefix(cheapStr
, name
)) {
3841 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3842 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3844 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3845 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3846 CFRelease(bundleURL
);
3851 } else if (CFStringHasSuffix(cheapStr
, CFSTR(".framework")) && (permissive
|| CFStringHasPrefix(cheapStr
, name
))) {
3852 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3853 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3854 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3855 CFRelease(bundleURL
);
3860 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3862 if (!permissive
) CFRelease(name
);
3864 CFStringSetExternalCharactersNoCopy(cheapStr
, NULL
, 0, 0);
3865 CFRelease(cheapStr
);
3870 //SPI version; separated out to minimize linkage changes
3871 CFURLRef
_CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath
) {
3872 return __CFBundleCopyFrameworkURLForExecutablePath(executablePath
, false);
3875 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
) {
3876 // This finds the bundle for the given path.
3877 // 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.
3879 CFURLRef curURL
= __CFBundleCopyFrameworkURLForExecutablePath(imagePath
, true);
3880 Boolean createdBundle
= false;
3883 bundle
= _CFBundleCopyBundleForURL(curURL
, true);
3885 // Ensure bundle exists by creating it if necessary
3886 // NB doFinalProcessing must be false here, see below
3887 bundle
= _CFBundleCreate(kCFAllocatorSystemDefault
, curURL
, true, false);
3888 createdBundle
= true;
3891 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3892 if (!bundle
->_isLoaded
) {
3893 // 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)
3894 #if defined(BINARY_SUPPORT_DLFCN)
3895 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3896 #elif defined(BINARY_SUPPORT_DYLD)
3897 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3898 #endif /* BINARY_SUPPORT_DLFCN */
3899 #if defined(BINARY_SUPPORT_DYLD)
3900 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
3901 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3902 #endif /* BINARY_SUPPORT_DYLD */
3904 if (!bundle
->_isLoaded
) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle
, bundle
->_handleCookie
, bundle
->_imageCookie
, bundle
->_connectionCookie
);
3905 #endif /* LOG_BUNDLE_LOAD */
3906 bundle
->_isLoaded
= true;
3908 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3909 if (createdBundle
) {
3910 // Perform delayed final processing steps.
3911 // This must be done after _isLoaded has been set, for security reasons (3624341).
3912 _CFBundleCheckWorkarounds(bundle
);
3913 if (_CFBundleNeedsInitPlugIn(bundle
)) {
3914 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3915 _CFBundleInitPlugIn(bundle
);
3916 __CFSpinLock(&CFBundleGlobalDataLock
);
3919 // Release the bundle if we did not create it here
3927 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
) {
3928 // This finds the bundles for the given paths.
3929 // 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).
3930 CFIndex i
, imagePathCount
= CFArrayGetCount(imagePaths
);
3931 for (i
= 0; i
< imagePathCount
; i
++) _CFBundleEnsureBundleExistsForImagePath((CFStringRef
)CFArrayGetValueAtIndex(imagePaths
, i
));
3934 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
) {
3935 CFArrayRef imagePaths
= NULL
;
3936 // Tickle the main bundle into existence
3937 (void)_CFBundleGetMainBundleAlreadyLocked();
3938 #if defined(BINARY_SUPPORT_DYLD)
3939 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsForHint(hint
);
3940 #endif /* BINARY_SUPPORT_DYLD */
3942 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
3943 CFRelease(imagePaths
);
3947 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
3948 // 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.
3949 CFArrayRef imagePaths
= NULL
;
3950 // Tickle the main bundle into existence
3951 (void)_CFBundleGetMainBundleAlreadyLocked();
3953 #if defined(BINARY_SUPPORT_DLL)
3954 // Dont know how to find static bundles for DLLs
3955 #endif /* BINARY_SUPPORT_DLL */
3957 #if defined(BINARY_SUPPORT_DYLD)
3958 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsIfChanged();
3959 #endif /* BINARY_SUPPORT_DYLD */
3961 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
3962 CFRelease(imagePaths
);
3966 CFArrayRef
CFBundleGetAllBundles(void) {
3967 // To answer this properly, we have to have created the static bundles!
3968 #if !defined(AVOID_WEAK_COLLECTIONS)
3969 static CFMutableArrayRef externalAllBundles
= NULL
;
3970 #endif /* AVOID_WEAK_COLLECTIONS */
3972 __CFSpinLock(&CFBundleGlobalDataLock
);
3973 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
3974 #if defined(AVOID_WEAK_COLLECTIONS)
3975 bundles
= _allBundles
;
3976 #else /* AVOID_WEAK_COLLECTIONS */
3977 if (!externalAllBundles
) {
3978 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
3979 nonRetainingArrayCallbacks
.retain
= NULL
;
3980 nonRetainingArrayCallbacks
.release
= NULL
;
3981 externalAllBundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
3983 CFArrayRemoveAllValues(externalAllBundles
);
3984 for (id value in _allBundles
) CFArrayAppendValue(externalAllBundles
, value
);
3985 bundles
= externalAllBundles
;
3986 #endif /* AVOID_WEAK_COLLECTIONS */
3987 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3991 CF_EXPORT CFArrayRef
_CFBundleCopyAllBundles(void) {
3992 // To answer this properly, we have to have created the static bundles!
3993 __CFSpinLock(&CFBundleGlobalDataLock
);
3994 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
3995 #if defined(AVOID_WEAK_COLLECTIONS)
3996 CFArrayRef bundles
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, _allBundles
);
3997 #else /* AVOID_WEAK_COLLECTIONS */
3998 CFMutableArrayRef bundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
3999 for (id value in _allBundles
) CFArrayAppendValue(bundles
, value
);
4000 #endif /* AVOID_WEAK_COLLECTIONS */
4001 __CFSpinUnlock(&CFBundleGlobalDataLock
);
4005 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle
) {
4006 return bundle
->_version
;
4009 CF_EXPORT CFURLRef
_CFBundleCopyInfoPlistURL(CFBundleRef bundle
) {
4010 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
4011 CFURLRef url
= (CFURLRef
)CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
);
4012 if (!url
) url
= (CFURLRef
)CFDictionaryGetValue(infoDict
, _kCFBundleRawInfoPlistURLKey
);
4013 return (url
? (CFURLRef
)CFRetain(url
) : NULL
);
4016 CF_EXPORT CFURLRef
_CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
4017 return CFBundleCopyPrivateFrameworksURL(bundle
);
4020 CF_EXPORT CFURLRef
CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
4021 CFURLRef result
= NULL
;
4023 if (1 == bundle
->_version
) {
4024 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase1
, bundle
->_url
);
4025 } else if (2 == bundle
->_version
) {
4026 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase2
, bundle
->_url
);
4028 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase0
, bundle
->_url
);
4033 CF_EXPORT CFURLRef
_CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
4034 return CFBundleCopySharedFrameworksURL(bundle
);
4037 CF_EXPORT CFURLRef
CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
4038 CFURLRef result
= NULL
;
4040 if (1 == bundle
->_version
) {
4041 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase1
, bundle
->_url
);
4042 } else if (2 == bundle
->_version
) {
4043 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase2
, bundle
->_url
);
4045 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase0
, bundle
->_url
);
4050 CF_EXPORT CFURLRef
_CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
4051 return CFBundleCopySharedSupportURL(bundle
);
4054 CF_EXPORT CFURLRef
CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
4055 CFURLRef result
= NULL
;
4057 if (1 == bundle
->_version
) {
4058 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase1
, bundle
->_url
);
4059 } else if (2 == bundle
->_version
) {
4060 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase2
, bundle
->_url
);
4062 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase0
, bundle
->_url
);
4067 __private_extern__ CFURLRef
_CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
4068 return CFBundleCopyBuiltInPlugInsURL(bundle
);
4071 CF_EXPORT CFURLRef
CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
4072 CFURLRef result
= NULL
, alternateResult
= NULL
;
4074 CFAllocatorRef alloc
= CFGetAllocator(bundle
);
4075 if (1 == bundle
->_version
) {
4076 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase1
, bundle
->_url
);
4077 } else if (2 == bundle
->_version
) {
4078 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase2
, bundle
->_url
);
4080 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase0
, bundle
->_url
);
4082 if (!result
|| !_urlExists(result
)) {
4083 if (1 == bundle
->_version
) {
4084 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase1
, bundle
->_url
);
4085 } else if (2 == bundle
->_version
) {
4086 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase2
, bundle
->_url
);
4088 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase0
, bundle
->_url
);
4090 if (alternateResult
&& _urlExists(alternateResult
)) {
4091 if (result
) CFRelease(result
);
4092 result
= alternateResult
;
4094 if (alternateResult
) CFRelease(alternateResult
);
4100 #if defined(BINARY_SUPPORT_DYLD)
4102 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint
) {
4103 uint32_t i
, numImages
= _dyld_image_count();
4104 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
4105 CFRange range
= CFRangeMake(0, CFStringGetLength(hint
)), altRange
= CFRangeMake(0, 0), testRange
= CFRangeMake(0, 0);
4106 const char *processPath
= _CFProcessPath();
4107 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
4109 if (range
.length
> 14) {
4110 // handle some common variations on framework bundle identifiers
4111 if (CFStringFindWithOptions(hint
, CFSTR(".framework"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4112 // identifier has .framework appended
4113 altRange
.length
= testRange
.location
;
4114 } else if (CFStringFindWithOptions(hint
, CFSTR("framework"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4115 // identifier has Framework appended
4116 altRange
.length
= testRange
.location
;
4117 } else if (CFStringFindWithOptions(hint
, CFSTR("fw"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4118 // identifier has FW appended
4119 altRange
.length
= testRange
.location
;
4122 for (i
= 0; i
< numImages
; i
++) {
4123 const char *curName
= _dyld_get_image_name(i
), *lastComponent
= NULL
;
4124 if (curName
&& (!processPath
|| 0 != strcmp(curName
, processPath
)) && mhp
!= (void *)_dyld_get_image_header(i
)) lastComponent
= strrchr(curName
, '/');
4125 if (lastComponent
) {
4126 CFStringRef str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, lastComponent
+ 1);
4128 if (CFStringFindWithOptions(hint
, str
, range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
) || (altRange
.length
> 0 && CFStringFindWithOptions(hint
, str
, altRange
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
))) {
4129 CFStringRef curStr
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, curName
);
4131 CFArrayAppendValue(result
, curStr
);
4142 static char *_cleanedPathForPath(const char *curName
) {
4143 char *thePath
= strdup(curName
);
4145 // We are going to process the buffer replacing all "/./" and "//" with "/"
4146 CFIndex srcIndex
= 0, dstIndex
= 0;
4147 CFIndex len
= strlen(thePath
);
4148 for (srcIndex
=0; srcIndex
<len
; srcIndex
++) {
4149 thePath
[dstIndex
] = thePath
[srcIndex
];
4151 while (srcIndex
< len
-1 && thePath
[srcIndex
] == '/' && (thePath
[srcIndex
+1] == '/' || (thePath
[srcIndex
+1] == '.' && srcIndex
< len
-2 && thePath
[srcIndex
+2] == '/'))) srcIndex
+= (thePath
[srcIndex
+1] == '/' ? 1 : 2);
4153 thePath
[dstIndex
] = 0;
4158 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
4159 // This returns an array of the paths of all the dyld images in the process. These paths may not be absolute, they may point at things that are not bundles, they may be staticly linked bundles or dynamically loaded bundles, they may be NULL.
4160 uint32_t i
, numImages
= _dyld_image_count();
4161 CFMutableArrayRef result
= NULL
;
4162 static uint32_t _cachedDYLDImageCount
= -1;
4164 if (numImages
!= _cachedDYLDImageCount
) {
4165 const char *curName
;
4166 char *cleanedCurName
= NULL
;
4168 const char *processPath
= _CFProcessPath();
4169 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
4171 result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
4173 for (i
= 0; i
< numImages
; i
++) {
4174 curName
= _dyld_get_image_name(i
);
4175 if (curName
&& i
== 0) cleanedCurName
= _cleanedPathForPath(curName
);
4176 if (curName
&& (!processPath
|| 0 != strcmp(curName
, processPath
)) && (!processPath
|| !cleanedCurName
|| 0 != strcmp(cleanedCurName
, processPath
)) && mhp
!= (void *)_dyld_get_image_header(i
)) {
4177 curStr
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, curName
);
4179 CFArrayAppendValue(result
, curStr
);
4183 if (cleanedCurName
) {
4184 free(cleanedCurName
);
4185 cleanedCurName
= NULL
;
4188 _cachedDYLDImageCount
= numImages
;
4193 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
) {
4194 CFStringRef result
= NULL
;
4195 #if defined(USE_DYLD_PRIV)
4196 const char *name
= dyld_image_path_containing_address(p
);
4197 if (name
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, name
);
4198 #else /* USE_DYLD_PRIV */
4200 uint32_t i
, j
, n
= _dyld_image_count();
4201 Boolean foundit
= false;
4204 #define MACH_HEADER_TYPE struct mach_header_64
4205 #define MACH_SEGMENT_CMD_TYPE struct segment_command_64
4206 #define MACH_SEGMENT_FLAVOR LC_SEGMENT_64
4208 #define MACH_HEADER_TYPE struct mach_header
4209 #define MACH_SEGMENT_CMD_TYPE struct segment_command
4210 #define MACH_SEGMENT_FLAVOR LC_SEGMENT
4212 for (i
= 0; !foundit
&& i
< n
; i
++) {
4213 const MACH_HEADER_TYPE
*mh
= (const MACH_HEADER_TYPE
*)_dyld_get_image_header(i
);
4214 uintptr_t addr
= (uintptr_t)p
- _dyld_get_image_vmaddr_slide(i
);
4216 struct load_command
*lc
= (struct load_command
*)((char *)mh
+ sizeof(MACH_HEADER_TYPE
));
4217 for (j
= 0; !foundit
&& j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
)) {
4218 if (MACH_SEGMENT_FLAVOR
== lc
->cmd
&& ((MACH_SEGMENT_CMD_TYPE
*)lc
)->vmaddr
<= addr
&& addr
< ((MACH_SEGMENT_CMD_TYPE
*)lc
)->vmaddr
+ ((MACH_SEGMENT_CMD_TYPE
*)lc
)->vmsize
) {
4220 name
= _dyld_get_image_name(i
);
4221 if (name
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, name
);
4226 #undef MACH_HEADER_TYPE
4227 #undef MACH_SEGMENT_CMD_TYPE
4228 #undef MACH_SEGMENT_FLAVOR
4230 #endif /* USE_DYLD_PRIV */
4232 printf("dyld image path for pointer %p is %p\n", p
, result
);
4233 #endif /* LOG_BUNDLE_LOAD */
4237 #if !defined(BINARY_SUPPORT_DLFCN)
4239 static const void *__CFBundleDYLDFindImage(char *buff
) {
4240 const void *header
= NULL
;
4241 uint32_t i
, numImages
= _dyld_image_count(), numMatches
= 0;
4242 const char *curName
, *p
, *q
;
4244 for (i
= 0; !header
&& i
< numImages
; i
++) {
4245 curName
= _dyld_get_image_name(i
);
4246 if (curName
&& 0 == strncmp(curName
, buff
, CFMaxPathSize
)) {
4247 header
= _dyld_get_image_header(i
);
4252 for (i
= 0; i
< numImages
; i
++) {
4253 curName
= _dyld_get_image_name(i
);
4255 for (p
= buff
, q
= curName
; *p
&& *q
&& (q
- curName
< CFMaxPathSize
); p
++, q
++) {
4256 if (*p
!= *q
&& (q
- curName
> 11) && 0 == strncmp(q
- 11, ".framework/Versions/", 20) && *(q
+ 9) && '/' == *(q
+ 10)) q
+= 11;
4257 else if (*p
!= *q
&& (q
- curName
> 12) && 0 == strncmp(q
- 12, ".framework/Versions/", 20) && *(q
+ 8) && '/' == *(q
+ 9)) q
+= 10;
4258 if (*p
!= *q
) break;
4261 header
= _dyld_get_image_header(i
);
4267 return (numMatches
== 1) ? header
: NULL
;
4270 __private_extern__ Boolean
_CFBundleDYLDCheckLoaded(CFBundleRef bundle
) {
4271 if (!bundle
->_isLoaded
) {
4272 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4273 char buff
[CFMaxPathSize
];
4275 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4276 const void *header
= __CFBundleDYLDFindImage(buff
);
4278 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
4279 if (!bundle
->_imageCookie
) {
4280 bundle
->_imageCookie
= header
;
4282 printf("dyld check load bundle %p, find %s getting image %p\n", bundle
, buff
, bundle
->_imageCookie
);
4283 #endif /* LOG_BUNDLE_LOAD */
4285 bundle
->_isLoaded
= true;
4288 printf("dyld check load bundle %p, find %s no image\n", bundle
, buff
);
4289 #endif /* LOG_BUNDLE_LOAD */
4292 if (executableURL
) CFRelease(executableURL
);
4294 return bundle
->_isLoaded
;
4297 __private_extern__ Boolean
_CFBundleDYLDLoadBundle(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
4298 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4299 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
4300 int errorNumber
= 0;
4301 const char *fileName
= NULL
;
4302 const char *errorString
= NULL
;
4304 if (!bundle
->_isLoaded
) {
4305 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4306 char buff
[CFMaxPathSize
];
4308 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4309 NSObjectFileImage image
;
4310 NSObjectFileImageReturnCode retCode
= NSCreateObjectFileImageFromFile(buff
, &image
);
4312 printf("dyld load bundle %p, create image of %s returns image %p retcode %d\n", bundle
, buff
, image
, retCode
);
4313 #endif /* LOG_BUNDLE_LOAD */
4314 if (retCode
== NSObjectFileImageSuccess
) {
4315 uint32_t options
= forceGlobal
? NSLINKMODULE_OPTION_RETURN_ON_ERROR
: (NSLINKMODULE_OPTION_BINDNOW
| NSLINKMODULE_OPTION_PRIVATE
| NSLINKMODULE_OPTION_RETURN_ON_ERROR
);
4316 NSModule
module = NSLinkModule(image
, buff
, options
);
4318 printf("dyld load bundle %p, link module of %s options 0x%x returns module %p image %p\n", bundle
, buff
, options
, module, image
);
4319 #endif /* LOG_BUNDLE_LOAD */
4321 bundle
->_imageCookie
= image
;
4322 bundle
->_moduleCookie
= module;
4323 bundle
->_isLoaded
= true;
4325 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
4327 #if defined(BINARY_SUPPORT_DLFCN)
4328 _CFBundleDlfcnPreflight(bundle
, subError
);
4329 #endif /* BINARY_SUPPORT_DLFCN */
4331 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("error code %d, error number %d (%@)"), c
, errorNumber
, tempString
);
4332 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4333 if (tempString
) CFRelease(tempString
);
4334 if (debugString
) CFRelease(debugString
);
4337 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, fileName
);
4338 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString
, c
, errorNumber
, tempString
);
4339 if (tempString
) CFRelease(tempString
);
4340 if (executableString
) CFRelease(executableString
);
4342 (void)NSDestroyObjectFileImage(image
);
4346 if (retCode
== NSObjectFileImageArch
) {
4347 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableArchitectureMismatchError
);
4348 } else if (retCode
== NSObjectFileImageInappropriateFile
) {
4349 Boolean hasRuntimeMismatch
= false;
4350 uint32_t mainFlags
= 0, bundleFlags
= 0;
4351 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL
, &mainFlags
) && (mainFlags
& 0x2) != 0) {
4352 if (_CFBundleGetObjCImageInfo(bundle
, NULL
, &bundleFlags
) && (bundleFlags
& 0x2) == 0) hasRuntimeMismatch
= true;
4354 if (hasRuntimeMismatch
) {
4355 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableRuntimeMismatchError
);
4357 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
4360 #if defined(BINARY_SUPPORT_DLFCN)
4361 _CFBundleDlfcnPreflight(bundle
, subError
);
4362 #endif /* BINARY_SUPPORT_DLFCN */
4364 CFStringRef debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("dyld returns %d"), retCode
);
4365 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4366 CFRelease(debugString
);
4370 CFLog(__kCFLogBundle
, CFSTR("dyld returns %d when trying to load %@"), retCode
, executableURL
);
4375 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4377 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4380 if (executableURL
) CFRelease(executableURL
);
4382 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4383 return bundle
->_isLoaded
;
4386 __private_extern__ Boolean
_CFBundleDYLDLoadFramework(CFBundleRef bundle
, CFErrorRef
*error
) {
4387 // !!! Framework loading should be better. Can't unload frameworks.
4388 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4389 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
4390 int errorNumber
= 0;
4391 const char *fileName
= NULL
;
4392 const char *errorString
= NULL
;
4394 if (!bundle
->_isLoaded
) {
4395 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4396 char buff
[CFMaxPathSize
];
4398 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4399 void *image
= (void *)NSAddImage(buff
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
4401 printf("dyld load framework %p, add image of %s returns image %p\n", bundle
, buff
, image
);
4402 #endif /* LOG_BUNDLE_LOAD */
4404 bundle
->_imageCookie
= image
;
4405 bundle
->_isLoaded
= true;
4407 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
4409 #if defined(BINARY_SUPPORT_DLFCN)
4410 _CFBundleDlfcnPreflight(bundle
, subError
);
4411 #endif /* BINARY_SUPPORT_DLFCN */
4413 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("error code %d, error number %d (%@)"), c
, errorNumber
, tempString
);
4414 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4415 if (tempString
) CFRelease(tempString
);
4416 if (debugString
) CFRelease(debugString
);
4419 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, fileName
);
4420 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString
, c
, errorNumber
, tempString
);
4421 if (tempString
) CFRelease(tempString
);
4422 if (executableString
) CFRelease(executableString
);
4427 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4429 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4432 if (executableURL
) CFRelease(executableURL
);
4434 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4435 return bundle
->_isLoaded
;
4438 __private_extern__
void _CFBundleDYLDUnloadBundle(CFBundleRef bundle
) {
4439 if (bundle
->_isLoaded
) {
4441 printf("dyld unload bundle %p, handle %p module %p image %p\n", bundle
, bundle
->_handleCookie
, bundle
->_moduleCookie
, bundle
->_imageCookie
);
4442 #endif /* LOG_BUNDLE_LOAD */
4443 if (bundle
->_moduleCookie
&& !NSUnLinkModule((NSModule
)(bundle
->_moduleCookie
), NSUNLINKMODULE_OPTION_NONE
)) {
4444 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
4446 if (bundle
->_moduleCookie
&& bundle
->_imageCookie
) (void)NSDestroyObjectFileImage((NSObjectFileImage
)(bundle
->_imageCookie
));
4447 bundle
->_connectionCookie
= bundle
->_handleCookie
= NULL
;
4448 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
4449 bundle
->_isLoaded
= false;
4454 __private_extern__
void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4455 return _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, symbolName
, false);
4458 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
4459 void *result
= NULL
;
4461 NSSymbol symbol
= NULL
;
4464 if (CFStringGetCString(symbolName
, &(buff
[1]), 1024, kCFStringEncodingUTF8
)) {
4465 if (bundle
->_moduleCookie
) {
4466 symbol
= NSLookupSymbolInModule((NSModule
)(bundle
->_moduleCookie
), buff
);
4467 } else if (bundle
->_imageCookie
) {
4468 symbol
= NSLookupSymbolInImage(bundle
->_imageCookie
, buff
, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
4470 if (!symbol
&& !bundle
->_moduleCookie
&& (!bundle
->_imageCookie
|| globalSearch
)) {
4471 char hintBuff
[1026];
4472 CFStringRef executableName
= _CFBundleCopyExecutableName(bundle
, NULL
, NULL
);
4474 if (executableName
) {
4475 if (!CFStringGetCString(executableName
, hintBuff
, 1024, kCFStringEncodingUTF8
)) hintBuff
[0] = '\0';
4476 CFRelease(executableName
);
4478 // Nowdays, NSIsSymbolNameDefinedWithHint() and NSLookupAndBindSymbolWithHint()
4479 // are identical, except the first just returns a bool, so checking with the
4480 // Is function first just causes a redundant lookup.
4481 // This returns NULL on failure.
4482 symbol
= NSLookupAndBindSymbolWithHint(buff
, hintBuff
);
4484 if (symbol
) result
= NSAddressOfSymbol(symbol
);
4486 if (!result
) CFLog(__kCFLogBundle
, CFSTR("dyld cannot find symbol %@ in %@"), symbolName
, bundle
);
4489 printf("bundle %p handle %p module %p image %p dyld returns symbol %p for %s\n", bundle
, bundle
->_handleCookie
, bundle
->_moduleCookie
, bundle
->_imageCookie
, result
, buff
+ 1);
4490 #endif /* LOG_BUNDLE_LOAD */
4495 #endif /* !BINARY_SUPPORT_DLFCN */
4496 #endif /* BINARY_SUPPORT_DYLD */
4498 #if defined(BINARY_SUPPORT_DLFCN)
4500 __private_extern__ Boolean
_CFBundleDlfcnCheckLoaded(CFBundleRef bundle
) {
4501 if (!bundle
->_isLoaded
) {
4502 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4503 char buff
[CFMaxPathSize
];
4505 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4506 int mode
= RTLD_LAZY
| RTLD_LOCAL
| RTLD_NOLOAD
| RTLD_FIRST
;
4507 void *handle
= dlopen(buff
, mode
);
4509 if (!bundle
->_handleCookie
) {
4510 bundle
->_handleCookie
= handle
;
4512 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x getting handle %p\n", bundle
, buff
, mode
, bundle
->_handleCookie
);
4513 #endif /* LOG_BUNDLE_LOAD */
4515 bundle
->_isLoaded
= true;
4518 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x no handle\n", bundle
, buff
, mode
);
4519 #endif /* LOG_BUNDLE_LOAD */
4522 if (executableURL
) CFRelease(executableURL
);
4524 return bundle
->_isLoaded
;
4527 CF_EXPORT Boolean
_CFBundleDlfcnPreflight(CFBundleRef bundle
, CFErrorRef
*error
) {
4528 Boolean retval
= true;
4529 CFErrorRef localError
= NULL
;
4530 if (!bundle
->_isLoaded
) {
4531 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4532 char buff
[CFMaxPathSize
];
4535 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4536 retval
= dlopen_preflight(buff
);
4537 if (!retval
&& error
) {
4538 CFArrayRef archs
= CFBundleCopyExecutableArchitectures(bundle
);
4539 CFStringRef debugString
= NULL
;
4540 const char *errorString
= dlerror();
4541 if (errorString
&& strlen(errorString
) > 0) debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4543 Boolean hasSuitableArch
= false, hasRuntimeMismatch
= false;
4544 CFIndex i
, count
= CFArrayGetCount(archs
);
4545 SInt32 arch
, curArch
= _CFBundleCurrentArchitecture();
4546 for (i
= 0; !hasSuitableArch
&& i
< count
; i
++) {
4547 if (CFNumberGetValue((CFNumberRef
)CFArrayGetValueAtIndex(archs
, i
), kCFNumberSInt32Type
, (void *)&arch
) && arch
== curArch
) hasSuitableArch
= true;
4549 #if defined(BINARY_SUPPORT_DYLD)
4550 if (hasSuitableArch
) {
4551 uint32_t mainFlags
= 0, bundleFlags
= 0;
4552 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL
, &mainFlags
) && (mainFlags
& 0x2) != 0) {
4553 if (_CFBundleGetObjCImageInfo(bundle
, NULL
, &bundleFlags
) && (bundleFlags
& 0x2) == 0) hasRuntimeMismatch
= true;
4556 #endif /* BINARY_SUPPORT_DYLD */
4557 if (hasRuntimeMismatch
) {
4558 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableRuntimeMismatchError
, debugString
);
4559 } else if (!hasSuitableArch
) {
4560 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableArchitectureMismatchError
, debugString
);
4562 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLoadError
, debugString
);
4566 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLoadError
, debugString
);
4568 if (debugString
) CFRelease(debugString
);
4571 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4573 if (executableURL
) CFRelease(executableURL
);
4575 if (!retval
&& error
) *error
= localError
;
4579 __private_extern__ Boolean
_CFBundleDlfcnLoadBundle(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
4580 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4581 if (!bundle
->_isLoaded
) {
4582 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4583 char buff
[CFMaxPathSize
];
4584 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4585 int mode
= forceGlobal
? (RTLD_LAZY
| RTLD_GLOBAL
| RTLD_FIRST
) : (RTLD_NOW
| RTLD_LOCAL
| RTLD_FIRST
);
4586 void *cookie
= dlopen(buff
, mode
);
4588 printf("dlfcn load bundle %p, dlopen of %s mode 0x%x returns handle %p\n", bundle
, buff
, mode
, cookie
);
4589 #endif /* LOG_BUNDLE_LOAD */
4590 if (cookie
&& cookie
== bundle
->_handleCookie
) {
4591 // during the call to dlopen, arbitrary init routines may have run and caused bundle->_handleCookie to be set, in which case proper reference counting requires that reference to be released with dlclose
4593 printf("dlfcn load bundle %p closing existing reference to handle %p\n", bundle
, cookie
);
4594 #endif /* LOG_BUNDLE_LOAD */
4595 dlclose(bundle
->_handleCookie
);
4597 bundle
->_handleCookie
= cookie
;
4598 if (bundle
->_handleCookie
) {
4599 bundle
->_isLoaded
= true;
4601 const char *errorString
= dlerror();
4603 _CFBundleDlfcnPreflight(bundle
, subError
);
4605 CFStringRef debugString
= errorString
? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
) : NULL
;
4606 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4607 if (debugString
) CFRelease(debugString
);
4610 CFStringRef executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
4612 CFStringRef debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4613 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: %@"), executableString
, debugString
);
4614 if (debugString
) CFRelease(debugString
);
4616 CFLog(__kCFLogBundle
, CFSTR("Error loading %@"), executableString
);
4618 if (executableString
) CFRelease(executableString
);
4623 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4625 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4628 if (executableURL
) CFRelease(executableURL
);
4630 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4631 return bundle
->_isLoaded
;
4634 __private_extern__ Boolean
_CFBundleDlfcnLoadFramework(CFBundleRef bundle
, CFErrorRef
*error
) {
4635 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4636 if (!bundle
->_isLoaded
) {
4637 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4638 char buff
[CFMaxPathSize
];
4639 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4640 int mode
= RTLD_LAZY
| RTLD_GLOBAL
| RTLD_FIRST
;
4641 void *cookie
= dlopen(buff
, mode
);
4643 printf("dlfcn load framework %p, dlopen of %s mode 0x%x returns handle %p\n", bundle
, buff
, mode
, cookie
);
4644 #endif /* LOG_BUNDLE_LOAD */
4645 if (cookie
&& cookie
== bundle
->_handleCookie
) {
4646 // during the call to dlopen, arbitrary init routines may have run and caused bundle->_handleCookie to be set, in which case proper reference counting requires that reference to be released with dlclose
4648 printf("dlfcn load framework %p closing existing reference to handle %p\n", bundle
, cookie
);
4649 #endif /* LOG_BUNDLE_LOAD */
4650 dlclose(bundle
->_handleCookie
);
4652 bundle
->_handleCookie
= cookie
;
4653 if (bundle
->_handleCookie
) {
4654 bundle
->_isLoaded
= true;
4656 const char *errorString
= dlerror();
4658 _CFBundleDlfcnPreflight(bundle
, subError
);
4660 CFStringRef debugString
= errorString
? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
) : NULL
;
4661 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4662 if (debugString
) CFRelease(debugString
);
4665 CFStringRef executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
4667 CFStringRef debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4668 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: %@"), executableString
, debugString
);
4669 if (debugString
) CFRelease(debugString
);
4671 CFLog(__kCFLogBundle
, CFSTR("Error loading %@"), executableString
);
4673 if (executableString
) CFRelease(executableString
);
4678 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4680 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4683 if (executableURL
) CFRelease(executableURL
);
4685 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4686 return bundle
->_isLoaded
;
4689 __private_extern__
void _CFBundleDlfcnUnload(CFBundleRef bundle
) {
4690 if (bundle
->_isLoaded
) {
4692 printf("dlfcn unload bundle %p, handle %p module %p image %p\n", bundle
, bundle
->_handleCookie
, bundle
->_moduleCookie
, bundle
->_imageCookie
);
4693 #endif /* LOG_BUNDLE_LOAD */
4694 if (0 != dlclose(bundle
->_handleCookie
)) {
4695 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
4697 bundle
->_connectionCookie
= bundle
->_handleCookie
= NULL
;
4698 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
4699 bundle
->_isLoaded
= false;
4704 __private_extern__
void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4705 return _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, symbolName
, false);
4708 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
4709 void *result
= NULL
;
4712 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingUTF8
)) {
4713 result
= dlsym(bundle
->_handleCookie
, buff
);
4714 if (!result
&& globalSearch
) result
= dlsym(RTLD_DEFAULT
, buff
);
4716 if (!result
) CFLog(__kCFLogBundle
, CFSTR("dlsym cannot find symbol %@ in %@"), symbolName
, bundle
);
4719 printf("bundle %p handle %p module %p image %p dlsym returns symbol %p for %s\n", bundle
, bundle
->_handleCookie
, bundle
->_moduleCookie
, bundle
->_imageCookie
, result
, buff
);
4720 #endif /* LOG_BUNDLE_LOAD */
4725 #if !defined(BINARY_SUPPORT_DYLD)
4727 static CFStringRef
_CFBundleDlfcnCopyLoadedImagePathForPointer(void *p
) {
4728 CFStringRef result
= NULL
;
4730 if (0 != dladdr(p
, &info
) && info
.dli_fname
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, info
.dli_fname
);
4732 printf("dlfcn image path for pointer %p is %p\n", p
, result
);
4733 #endif /* LOG_BUNDLE_LOAD */
4737 #endif /* !BINARY_SUPPORT_DYLD */
4738 #endif /* BINARY_SUPPORT_DLFCN */
4740 #if defined(BINARY_SUPPORT_DLL)
4742 __private_extern__ Boolean
_CFBundleDLLLoad(CFBundleRef bundle
, CFErrorRef
*error
) {
4743 CFErrorRef localError
= NULL
;
4744 if (!bundle
->_isLoaded
) {
4745 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4746 wchar_t buff
[CFMaxPathSize
];
4748 if (executableURL
&& _CFURLGetWideFileSystemRepresentation(executableURL
, true, (wchar_t *)buff
, CFMaxPathSize
)) {
4749 bundle
->_hModule
= LoadLibraryW(buff
);
4750 if (bundle
->_hModule
) {
4751 bundle
->_isLoaded
= true;
4754 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
);
4756 CFLog(__kCFLogBundle
, CFSTR("Failed to load bundle %@"), bundle
);
4761 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4763 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4766 if (executableURL
) CFRelease(executableURL
);
4768 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4769 return bundle
->_isLoaded
;
4772 __private_extern__
void _CFBundleDLLUnload(CFBundleRef bundle
) {
4773 if (bundle
->_isLoaded
) {
4774 FreeLibrary(bundle
->_hModule
);
4775 bundle
->_hModule
= NULL
;
4776 bundle
->_isLoaded
= false;
4780 __private_extern__
void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4781 void *result
= NULL
;
4783 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingWindowsLatin1
)) result
= GetProcAddress(bundle
->_hModule
, buff
);
4787 #endif /* BINARY_SUPPORT_DLL */
4789 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
4792 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
) {