2 * Copyright (c) 2012 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 DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
531 #error Unknown or unspecified DEPLOYMENT_TARGET
534 static CFURLRef
_CFBundleCopyBundleURLForExecutablePath(CFStringRef str
) {
535 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
536 UniChar buff
[CFMaxPathSize
];
541 buffLen
= CFStringGetLength(str
);
542 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
543 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
545 #if DEPLOYMENT_TARGET_WINDOWS
546 // Is this a .dll or .exe?
547 if (buffLen
>= 5 && (_wcsnicmp((wchar_t *)&(buff
[buffLen
-4]), L
".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff
[buffLen
-4]), L
".exe", 4) == 0)) {
548 CFIndex extensionLength
= CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension
);
550 // If this is an _debug, we should strip that before looking for the bundle
551 if (buffLen
>= 7 && (_wcsnicmp((wchar_t *)&buff
[buffLen
-6], L
"_debug", 6) == 0)) buffLen
-= 6;
553 if (buffLen
+ 1 + extensionLength
< CFMaxPathSize
) {
556 CFStringGetCharacters(_CFBundleWindowsResourceDirectoryExtension
, CFRangeMake(0, extensionLength
), buff
+ buffLen
);
557 buffLen
+= extensionLength
;
558 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
559 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
563 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
565 #error Unknown or unspecified DEPLOYMENT_TARGET
569 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
); // Remove exe name
571 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
573 // See if this is a new bundle. If it is, we have to remove more path components.
574 CFIndex startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
575 if (startOfLastDir
> 0 && startOfLastDir
< buffLen
) {
576 CFStringRef lastDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
578 if (CFEqual(lastDirName
, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
579 // This is a new bundle. Back off a few more levels
581 // Remove platform folder
582 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
585 // Remove executables folder (if present)
586 CFIndex startOfNextDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
587 if (startOfNextDir
> 0 && startOfNextDir
< buffLen
) {
588 CFStringRef nextDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfNextDir
]), buffLen
- startOfNextDir
);
589 if (CFEqual(nextDirName
, _CFBundleExecutablesDirectoryName
)) buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
590 CFRelease(nextDirName
);
594 // Remove support files folder
595 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
597 #error Unknown or unspecified DEPLOYMENT_TARGET
601 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
602 CFRelease(lastDirName
);
606 #error Unknown or unspecified DEPLOYMENT_TARGET
610 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
611 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
618 static CFURLRef
_CFBundleCopyResolvedURLForExecutableURL(CFURLRef url
) {
619 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
620 CFURLRef absoluteURL
, url1
, url2
, outURL
= NULL
;
621 CFStringRef str
, str1
, str2
;
622 absoluteURL
= CFURLCopyAbsoluteURL(url
);
623 str
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
625 UniChar buff
[CFMaxPathSize
];
626 CFIndex buffLen
= CFStringGetLength(str
), len1
;
627 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
628 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
629 len1
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
630 if (len1
> 0 && len1
+ 1 < buffLen
) {
631 str1
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, buff
, len1
);
632 CFIndex skipSlashCount
= 1;
633 #if DEPLOYMENT_TARGET_WINDOWS
634 // 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
635 if (len1
== 3 && buff
[1] == ':' && buff
[2] == '\\') {
639 str2
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, buff
+ len1
+ skipSlashCount
, buffLen
- len1
- skipSlashCount
);
641 url1
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str1
, PLATFORM_PATH_STYLE
, true);
643 url2
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, str2
, PLATFORM_PATH_STYLE
, false, url1
);
645 outURL
= CFURLCopyAbsoluteURL(url2
);
651 if (str1
) CFRelease(str1
);
652 if (str2
) CFRelease(str2
);
657 outURL
= absoluteURL
;
659 CFRelease(absoluteURL
);
664 CFURLRef
_CFBundleCopyBundleURLForExecutableURL(CFURLRef url
) {
665 CFURLRef resolvedURL
, outurl
= NULL
;
667 resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
668 str
= CFURLCopyFileSystemPath(resolvedURL
, PLATFORM_PATH_STYLE
);
670 outurl
= _CFBundleCopyBundleURLForExecutablePath(str
);
673 CFRelease(resolvedURL
);
677 static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle
) {
678 uint8_t localVersion
= bundle
->_version
;
679 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
680 if (0 == localVersion
) {
681 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
682 if (!infoDict
|| 0 == CFDictionaryGetCount(infoDict
)) {
683 #if defined(BINARY_SUPPORT_DYLD)
684 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
686 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
687 if (bundle
->_binaryType
== __CFBundleCFMBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
690 bundle
->_resourceData
._executableLacksResourceFork
= true;
692 CFRelease(executableURL
);
697 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
699 CFRelease(executableURL
);
703 #endif /* BINARY_SUPPORT_DYLD */
709 CFBundleRef
_CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
710 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
712 uint8_t localVersion
= _CFBundleEffectiveLayoutVersion(bundle
);
713 if (3 == localVersion
|| 4 == localVersion
) {
721 CFBundleRef
_CFBundleGetMainBundleIfLooksLikeBundle(void) {
722 CFBundleRef mainBundle
= CFBundleGetMainBundle();
723 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
727 Boolean
_CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) {
728 CFBundleRef mainBundle
= CFBundleGetMainBundle();
729 return (mainBundle
&& mainBundle
->_resourceData
._infoDictionaryFromResourceFork
);
732 CFBundleRef
_CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
733 CFBundleRef bundle
= NULL
;
734 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
735 if (bundleURL
&& resolvedURL
) {
736 bundle
= _CFBundleCreateIfLooksLikeBundle(allocator
, bundleURL
);
738 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
739 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
740 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, (uint8_t *)buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
744 if (executableURL
) CFRelease(executableURL
);
747 if (bundleURL
) CFRelease(bundleURL
);
748 if (resolvedURL
) CFRelease(resolvedURL
);
752 CFBundleRef
_CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
753 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
755 Boolean mightBeBundle
= true, isDir
= false;
756 uint8_t localVersion
= _CFBundleEffectiveLayoutVersion(bundle
);
757 if (3 == localVersion
) {
758 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
759 CFURLRef executableURL
, supportFilesURL
, resourceSpecificationFileURL
;
760 CFArrayRef supportedPlatforms
;
761 CFStringRef resourceSpecificationFile
;
763 mightBeBundle
= false;
764 if (infoDict
&& CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
) && (executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
))) {
765 supportedPlatforms
= _CFBundleGetSupportedPlatforms(bundle
);
766 resourceSpecificationFile
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleResourceSpecificationKey
);
767 if (supportedPlatforms
&& CFArrayGetCount(supportedPlatforms
) > 0 && CFArrayGetFirstIndexOfValue(supportedPlatforms
, CFRangeMake(0, CFArrayGetCount(supportedPlatforms
)), CFSTR("iPhoneOS")) >= 0) {
768 mightBeBundle
= true;
769 } else if (resourceSpecificationFile
&& CFGetTypeID(resourceSpecificationFile
) == CFStringGetTypeID() && (supportFilesURL
= CFBundleCopySupportFilesDirectoryURL(bundle
))) {
770 resourceSpecificationFileURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, resourceSpecificationFile
, kCFURLPOSIXPathStyle
, false, supportFilesURL
);
771 if (resourceSpecificationFileURL
) {
772 if (_CFIsResourceAtURL(resourceSpecificationFileURL
, &isDir
) && !isDir
) mightBeBundle
= true;
773 CFRelease(resourceSpecificationFileURL
);
775 CFRelease(supportFilesURL
);
777 CFRelease(executableURL
);
779 } else if (4 == localVersion
) {
780 mightBeBundle
= false;
782 if (!mightBeBundle
) {
790 CFBundleRef
_CFBundleCreateWithExecutableURLIfMightBeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
791 CFBundleRef bundle
= NULL
;
792 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
793 if (bundleURL
&& resolvedURL
) {
794 bundle
= _CFBundleCreateIfMightBeBundle(allocator
, bundleURL
);
796 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
797 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
798 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, (uint8_t *)buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
802 if (executableURL
) CFRelease(executableURL
);
805 if (bundleURL
) CFRelease(bundleURL
);
806 if (resolvedURL
) CFRelease(resolvedURL
);
810 CFURLRef
_CFBundleCopyMainBundleExecutableURL(Boolean
*looksLikeBundle
) {
811 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
812 const char *processPath
;
813 CFStringRef str
= NULL
;
814 CFURLRef executableURL
= NULL
;
815 processPath
= _CFProcessPath();
817 str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, processPath
);
819 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, PLATFORM_PATH_STYLE
, false);
823 if (looksLikeBundle
) {
824 CFBundleRef mainBundle
= _mainBundle
;
825 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
826 *looksLikeBundle
= (mainBundle
? true : false);
828 return executableURL
;
831 static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef executablePath
) {
832 CFBundleGetInfoDictionary(_mainBundle
);
833 if (!_mainBundle
->_infoDict
|| CFDictionaryGetCount(_mainBundle
->_infoDict
) == 0) {
834 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
835 if (_mainBundle
->_version
== 3) _mainBundle
->_version
= 4;
836 if (_mainBundle
->_version
== 0) {
837 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
838 CFStringRef executableName
= _CFBundleCopyExecutableName(_mainBundle
, NULL
, NULL
);
839 if (!executableName
|| !executablePath
|| !CFStringHasSuffix(executablePath
, executableName
)) _mainBundle
->_version
= 4;
840 if (executableName
) CFRelease(executableName
);
842 #if defined(BINARY_SUPPORT_DYLD)
843 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
844 if (_mainBundle
->_infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(_mainBundle
->_infoDict
);
845 _mainBundle
->_infoDict
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromMainExecutable();
847 #endif /* BINARY_SUPPORT_DYLD */
849 #if defined(BINARY_SUPPORT_DYLD)
850 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
851 // if dyld and not main executable for bundle, prefer info dictionary from executable
852 CFStringRef executableName
= _CFBundleCopyExecutableName(_mainBundle
, NULL
, NULL
);
853 if (!executableName
|| !executablePath
|| !CFStringHasSuffix(executablePath
, executableName
)) {
854 CFDictionaryRef infoDictFromExecutable
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromMainExecutable();
855 if (infoDictFromExecutable
&& CFDictionaryGetCount(infoDictFromExecutable
) > 0) {
856 if (_mainBundle
->_infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(_mainBundle
->_infoDict
);
857 _mainBundle
->_infoDict
= infoDictFromExecutable
;
860 if (executableName
) CFRelease(executableName
);
862 #endif /* BINARY_SUPPORT_DYLD */
864 if (!_mainBundle
->_infoDict
) _mainBundle
->_infoDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
865 if (!CFDictionaryGetValue(_mainBundle
->_infoDict
, _kCFBundleExecutablePathKey
)) CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), _kCFBundleExecutablePathKey
, executablePath
);
866 CFStringRef bundleID
= (CFStringRef
)CFDictionaryGetValue(_mainBundle
->_infoDict
, kCFBundleIdentifierKey
);
868 if (!CFStringGetCString(bundleID
, __CFBundleMainID__
, sizeof(__CFBundleMainID__
) - 2, kCFStringEncodingUTF8
)) {
869 __CFBundleMainID__
[0] = '\0';
874 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle
, Boolean alreadyLocked
) {
875 CFDictionaryRef oldInfoDict
= bundle
->_infoDict
;
878 _CFBundleFlushCachesForURL(bundle
->_url
);
879 bundle
->_infoDict
= NULL
;
880 if (bundle
->_localInfoDict
) {
881 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(bundle
->_localInfoDict
);
882 bundle
->_localInfoDict
= NULL
;
884 if (bundle
->_searchLanguages
) {
885 CFRelease(bundle
->_searchLanguages
);
886 bundle
->_searchLanguages
= NULL
;
888 if (bundle
->_resourceData
._stringTableCache
) {
889 CFRelease(bundle
->_resourceData
._stringTableCache
);
890 bundle
->_resourceData
._stringTableCache
= NULL
;
892 if (bundle
== _mainBundle
) {
893 CFStringRef executablePath
= oldInfoDict
? (CFStringRef
)CFDictionaryGetValue(oldInfoDict
, _kCFBundleExecutablePathKey
) : NULL
;
894 if (!alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
895 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath
);
896 if (!alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
898 CFBundleGetInfoDictionary(bundle
);
901 if (!bundle
->_infoDict
) bundle
->_infoDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
902 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundleInitialPathKey
);
903 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundleInitialPathKey
, val
);
904 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundleResolvedPathKey
);
905 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundleResolvedPathKey
, val
);
906 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundlePrincipalClassKey
);
907 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundlePrincipalClassKey
, val
);
908 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(oldInfoDict
);
912 CF_EXPORT
void _CFBundleFlushBundleCaches(CFBundleRef bundle
) {
913 _CFBundleFlushBundleCachesAlreadyLocked(bundle
, false);
916 static CFBundleRef
_CFBundleGetMainBundleAlreadyLocked(void) {
917 if (!_initedMainBundle
) {
918 const char *processPath
;
919 CFStringRef str
= NULL
;
920 CFURLRef executableURL
= NULL
, bundleURL
= NULL
;
921 _initedMainBundle
= true;
922 processPath
= _CFProcessPath();
924 str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, processPath
);
925 if (!executableURL
) executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, PLATFORM_PATH_STYLE
, false);
927 if (executableURL
) bundleURL
= _CFBundleCopyBundleURLForExecutableURL(executableURL
);
929 // make sure that main bundle has executable path
930 //??? what if we are not the main executable in the bundle?
931 // NB doFinalProcessing must be false here, see below
932 _mainBundle
= _CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
, true, false);
934 // make sure that the main bundle is listed as loaded, and mark it as executable
935 _mainBundle
->_isLoaded
= true;
936 #if defined(BINARY_SUPPORT_DYLD)
937 if (_mainBundle
->_binaryType
== __CFBundleUnknownBinary
) {
938 if (!executableURL
) {
939 _mainBundle
->_binaryType
= __CFBundleNoBinary
;
941 _mainBundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
942 if (_mainBundle
->_binaryType
!= __CFBundleCFMBinary
&& _mainBundle
->_binaryType
!= __CFBundleUnreadableBinary
) _mainBundle
->_resourceData
._executableLacksResourceFork
= true;
945 #endif /* BINARY_SUPPORT_DYLD */
946 // get cookie for already-loaded main bundle
947 #if defined(BINARY_SUPPORT_DLFCN)
948 if (!_mainBundle
->_handleCookie
) {
949 _mainBundle
->_handleCookie
= dlopen(NULL
, RTLD_NOLOAD
| RTLD_FIRST
);
951 printf("main bundle %p getting handle %p\n", _mainBundle
, _mainBundle
->_handleCookie
);
952 #endif /* LOG_BUNDLE_LOAD */
954 #elif defined(BINARY_SUPPORT_DYLD)
955 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
&& !_mainBundle
->_imageCookie
) {
956 _mainBundle
->_imageCookie
= (void *)_dyld_get_image_header(0);
958 printf("main bundle %p getting image %p\n", _mainBundle
, _mainBundle
->_imageCookie
);
959 #endif /* LOG_BUNDLE_LOAD */
961 #endif /* BINARY_SUPPORT_DLFCN */
962 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str
);
963 // Perform delayed final processing steps.
964 // This must be done after _isLoaded has been set, for security reasons (3624341).
965 _CFBundleCheckWorkarounds(_mainBundle
);
966 if (_CFBundleNeedsInitPlugIn(_mainBundle
)) {
967 __CFSpinUnlock(&CFBundleGlobalDataLock
);
968 _CFBundleInitPlugIn(_mainBundle
);
969 __CFSpinLock(&CFBundleGlobalDataLock
);
973 if (bundleURL
) CFRelease(bundleURL
);
974 if (str
) CFRelease(str
);
975 if (executableURL
) CFRelease(executableURL
);
980 CFBundleRef
CFBundleGetMainBundle(void) {
981 CFBundleRef mainBundle
;
982 __CFSpinLock(&CFBundleGlobalDataLock
);
983 mainBundle
= _CFBundleGetMainBundleAlreadyLocked();
984 __CFSpinUnlock(&CFBundleGlobalDataLock
);
988 CFBundleRef
CFBundleGetBundleWithIdentifier(CFStringRef bundleID
) {
989 CFBundleRef result
= NULL
;
991 __CFSpinLock(&CFBundleGlobalDataLock
);
992 (void)_CFBundleGetMainBundleAlreadyLocked();
993 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
994 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
996 // Try to create the bundle for the caller and try again
997 void *p
= __builtin_return_address(0);
999 CFStringRef imagePath
= NULL
;
1000 #if defined(BINARY_SUPPORT_DYLD)
1001 if (!imagePath
) imagePath
= _CFBundleDYLDCopyLoadedImagePathForPointer(p
);
1002 #elif defined(BINARY_SUPPORT_DLFCN)
1003 if (!imagePath
) imagePath
= _CFBundleDlfcnCopyLoadedImagePathForPointer(p
);
1004 #endif /* BINARY_SUPPORT_DYLD */
1006 _CFBundleEnsureBundleExistsForImagePath(imagePath
);
1007 CFRelease(imagePath
);
1009 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
1012 #elif DEPLOYMENT_TARGET_WINDOWS
1014 #error Unknown or unspecified DEPLOYMENT_TARGET
1017 // Try to guess the bundle from the identifier and try again
1018 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID
);
1019 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
1022 // Make sure all bundles have been created and try again.
1023 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
1024 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
1026 __CFSpinUnlock(&CFBundleGlobalDataLock
);
1031 static CFStringRef
__CFBundleCopyDescription(CFTypeRef cf
) {
1032 char buff
[CFMaxPathSize
];
1033 CFStringRef path
= NULL
, binaryType
= NULL
, retval
= NULL
;
1034 if (((CFBundleRef
)cf
)->_url
&& CFURLGetFileSystemRepresentation(((CFBundleRef
)cf
)->_url
, true, (uint8_t *)buff
, CFMaxPathSize
)) path
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
1035 switch (((CFBundleRef
)cf
)->_binaryType
) {
1036 case __CFBundleCFMBinary
:
1037 binaryType
= CFSTR("");
1039 case __CFBundleDYLDExecutableBinary
:
1040 binaryType
= CFSTR("executable, ");
1042 case __CFBundleDYLDBundleBinary
:
1043 binaryType
= CFSTR("bundle, ");
1045 case __CFBundleDYLDFrameworkBinary
:
1046 binaryType
= CFSTR("framework, ");
1048 case __CFBundleDLLBinary
:
1049 binaryType
= CFSTR("DLL, ");
1051 case __CFBundleUnreadableBinary
:
1052 binaryType
= CFSTR("");
1055 binaryType
= CFSTR("");
1058 if (((CFBundleRef
)cf
)->_plugInData
._isPlugIn
) {
1059 retval
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("CFBundle/CFPlugIn %p <%@> (%@%@loaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? CFSTR("") : CFSTR("not "));
1061 retval
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("CFBundle %p <%@> (%@%@loaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? CFSTR("") : CFSTR("not "));
1063 if (path
) CFRelease(path
);
1067 static void _CFBundleDeallocateGlue(const void *key
, const void *value
, void *context
) {
1068 CFAllocatorRef allocator
= (CFAllocatorRef
)context
;
1069 if (value
) CFAllocatorDeallocate(allocator
, (void *)value
);
1072 static void __CFBundleDeallocate(CFTypeRef cf
) {
1073 CFBundleRef bundle
= (CFBundleRef
)cf
;
1075 CFStringRef bundleID
= NULL
;
1077 __CFGenericValidateType(cf
, __kCFBundleTypeID
);
1078 bundleURL
= bundle
->_url
;
1079 bundle
->_url
= NULL
;
1080 if (bundle
->_infoDict
) bundleID
= (CFStringRef
)CFDictionaryGetValue(bundle
->_infoDict
, kCFBundleIdentifierKey
);
1081 _CFBundleRemoveFromTables(bundle
, bundleURL
, bundleID
);
1082 CFBundleUnloadExecutable(bundle
);
1083 _CFBundleDeallocatePlugIn(bundle
);
1085 _CFBundleFlushCachesForURL(bundleURL
);
1086 CFRelease(bundleURL
);
1088 if (bundle
->_infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(bundle
->_infoDict
);
1089 if (bundle
->_modDate
) CFRelease(bundle
->_modDate
);
1090 if (bundle
->_localInfoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(bundle
->_localInfoDict
);
1091 if (bundle
->_searchLanguages
) CFRelease(bundle
->_searchLanguages
);
1092 if (bundle
->_glueDict
) {
1093 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
1094 CFRelease(bundle
->_glueDict
);
1096 if (bundle
->_resourceData
._stringTableCache
) CFRelease(bundle
->_resourceData
._stringTableCache
);
1099 static const CFRuntimeClass __CFBundleClass
= {
1100 _kCFRuntimeScannedObject
,
1104 __CFBundleDeallocate
,
1108 __CFBundleCopyDescription
1111 // From CFBundle_Resources.c
1112 void _CFBundleResourcesInitialize();
1114 __private_extern__
void __CFBundleInitialize(void) {
1115 __kCFBundleTypeID
= _CFRuntimeRegisterClass(&__CFBundleClass
);
1116 _CFBundleResourcesInitialize();
1119 CFTypeID
CFBundleGetTypeID(void) {
1120 return __kCFBundleTypeID
;
1123 CFBundleRef
_CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL
) {
1124 CFBundleRef bundle
= NULL
;
1125 char buff
[CFMaxPathSize
];
1126 CFURLRef newURL
= NULL
;
1128 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) return NULL
;
1130 newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)buff
, strlen(buff
), true);
1131 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1132 bundle
= _CFBundleCopyBundleForURL(newURL
, false);
1133 if (bundle
) CFRelease(bundle
);
1138 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
) {
1139 allocator
= _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator
);
1140 CFBundleRef bundle
= NULL
;
1141 char buff
[CFMaxPathSize
];
1142 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
1143 Boolean exists
= false;
1145 CFURLRef newURL
= NULL
;
1146 uint8_t localVersion
= 0;
1148 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) return NULL
;
1150 newURL
= CFURLCreateFromFileSystemRepresentation(allocator
, (uint8_t *)buff
, strlen(buff
), true);
1151 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1152 bundle
= _CFBundleCopyBundleForURL(newURL
, alreadyLocked
);
1158 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
1160 SInt32 res
= _CFGetPathProperties(allocator
, (char *)buff
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
);
1161 #if DEPLOYMENT_TARGET_WINDOWS
1162 if (!(res
== 0 && exists
&& ((mode
& S_IFMT
) == S_IFDIR
))) {
1163 // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again
1168 CFURLRef shorterPath
= CFURLCreateCopyDeletingLastPathComponent(allocator
, newURL
);
1170 newURL
= shorterPath
;
1171 res
= _CFGetFileProperties(allocator
, newURL
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
);
1175 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
1176 if (modDate
) CFRelease(modDate
);
1186 bundle
= (CFBundleRef
)_CFRuntimeCreateInstance(allocator
, __kCFBundleTypeID
, sizeof(struct __CFBundle
) - sizeof(CFRuntimeBase
), NULL
);
1192 bundle
->_url
= newURL
;
1194 bundle
->_modDate
= modDate
;
1195 bundle
->_version
= localVersion
;
1196 bundle
->_infoDict
= NULL
;
1197 bundle
->_localInfoDict
= NULL
;
1198 bundle
->_searchLanguages
= NULL
;
1200 #if defined(BINARY_SUPPORT_DYLD)
1201 /* We'll have to figure it out later */
1202 bundle
->_binaryType
= __CFBundleUnknownBinary
;
1203 #elif defined(BINARY_SUPPORT_DLL)
1204 /* We support DLL only */
1205 bundle
->_binaryType
= __CFBundleDLLBinary
;
1206 bundle
->_hModule
= NULL
;
1208 /* We'll have to figure it out later */
1209 bundle
->_binaryType
= __CFBundleUnknownBinary
;
1210 #endif /* BINARY_SUPPORT_DYLD */
1212 bundle
->_isLoaded
= false;
1213 bundle
->_sharesStringsFiles
= false;
1215 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1216 if (!__CFgetenv("CFBundleDisableStringsSharing") &&
1217 (strncmp(buff
, "/System/Library/Frameworks", 26) == 0) &&
1218 (strncmp(buff
+ strlen(buff
) - 10, ".framework", 10) == 0)) bundle
->_sharesStringsFiles
= true;
1219 #elif DEPLOYMENT_TARGET_WINDOWS
1221 #error Unknown or unspecified DEPLOYMENT_TARGET
1224 bundle
->_connectionCookie
= NULL
;
1225 bundle
->_handleCookie
= NULL
;
1226 bundle
->_imageCookie
= NULL
;
1227 bundle
->_moduleCookie
= NULL
;
1229 bundle
->_glueDict
= NULL
;
1231 bundle
->_resourceData
._executableLacksResourceFork
= false;
1232 bundle
->_resourceData
._infoDictionaryFromResourceFork
= false;
1233 bundle
->_resourceData
._stringTableCache
= NULL
;
1235 bundle
->_plugInData
._isPlugIn
= false;
1236 bundle
->_plugInData
._loadOnDemand
= false;
1237 bundle
->_plugInData
._isDoingDynamicRegistration
= false;
1238 bundle
->_plugInData
._instanceCount
= 0;
1239 bundle
->_plugInData
._factories
= NULL
;
1241 bundle
->_bundleLoadingLock
= CFSpinLockInit
;
1243 CFBundleGetInfoDictionary(bundle
);
1245 _CFBundleAddToTables(bundle
, alreadyLocked
);
1247 if (doFinalProcessing
) {
1248 _CFBundleCheckWorkarounds(bundle
);
1249 if (_CFBundleNeedsInitPlugIn(bundle
)) {
1250 if (alreadyLocked
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
1251 _CFBundleInitPlugIn(bundle
);
1252 if (alreadyLocked
) __CFSpinLock(&CFBundleGlobalDataLock
);
1259 CFBundleRef
CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
) {
1260 return _CFBundleCreate(allocator
, bundleURL
, false, true);
1263 CFArrayRef
CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc
, CFURLRef directoryURL
, CFStringRef bundleType
) {
1264 alloc
= _CFConvertAllocatorToNonGCRefZeroEquivalent(alloc
);
1265 CFMutableArrayRef bundles
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
1266 CFArrayRef URLs
= _CFContentsOfDirectory(alloc
, NULL
, NULL
, directoryURL
, bundleType
);
1268 CFIndex i
, c
= CFArrayGetCount(URLs
);
1270 CFBundleRef curBundle
;
1272 for (i
= 0; i
< c
; i
++) {
1273 curURL
= (CFURLRef
)CFArrayGetValueAtIndex(URLs
, i
);
1274 curBundle
= CFBundleCreate(alloc
, curURL
);
1275 if (curBundle
) CFArrayAppendValue(bundles
, curBundle
);
1283 CFURLRef
CFBundleCopyBundleURL(CFBundleRef bundle
) {
1284 if (bundle
->_url
) CFRetain(bundle
->_url
);
1285 return bundle
->_url
;
1288 void _CFBundleSetDefaultLocalization(CFStringRef localizationName
) {
1289 CFStringRef newLocalization
= localizationName
? (CFStringRef
)CFStringCreateCopy(kCFAllocatorSystemDefault
, localizationName
) : NULL
;
1290 if (_defaultLocalization
) CFRelease(_defaultLocalization
);
1291 _defaultLocalization
= newLocalization
;
1294 CFArrayRef
_CFBundleGetLanguageSearchList(CFBundleRef bundle
) {
1295 if (!bundle
->_searchLanguages
) {
1296 CFMutableArrayRef langs
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1297 CFStringRef devLang
= CFBundleGetDevelopmentRegion(bundle
);
1299 #if DEPLOYMENT_TARGET_WINDOWS
1300 if (_defaultLocalization
) CFArrayAppendValue(langs
, _defaultLocalization
);
1302 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, devLang
);
1304 if (CFArrayGetCount(langs
) == 0) {
1305 // If the user does not prefer any of our languages, and devLang is not present, try English
1306 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFSTR("en_US"));
1308 if (CFArrayGetCount(langs
) == 0) {
1309 // if none of the preferred localizations are present, fall back on a random localization that is present
1310 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
1311 if (localizations
) {
1312 if (CFArrayGetCount(localizations
) > 0) _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, (CFStringRef
)CFArrayGetValueAtIndex(localizations
, 0));
1313 CFRelease(localizations
);
1317 if (devLang
&& !CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
)) {
1318 // Make sure that devLang is on the list as a fallback for individual resources that are not present
1319 CFArrayAppendValue(langs
, devLang
);
1320 } else if (!devLang
) {
1321 // Or if there is no devLang, try some variation of English that is present
1322 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
1323 if (localizations
) {
1324 CFStringRef en_US
= CFSTR("en_US"), en
= CFSTR("en"), English
= CFSTR("English");
1325 CFRange range
= CFRangeMake(0, CFArrayGetCount(localizations
));
1326 if (CFArrayContainsValue(localizations
, range
, en
)) {
1327 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en
)) CFArrayAppendValue(langs
, en
);
1328 } else if (CFArrayContainsValue(localizations
, range
, English
)) {
1329 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), English
)) CFArrayAppendValue(langs
, English
);
1330 } else if (CFArrayContainsValue(localizations
, range
, en_US
)) {
1331 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en_US
)) CFArrayAppendValue(langs
, en_US
);
1333 CFRelease(localizations
);
1336 if (CFArrayGetCount(langs
) == 0) {
1337 // Total backstop behavior to avoid having an empty array.
1338 if (_defaultLocalization
) {
1339 CFArrayAppendValue(langs
, _defaultLocalization
);
1341 CFArrayAppendValue(langs
, CFSTR("en"));
1344 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, (void *)langs
, (void * volatile *)&(bundle
->_searchLanguages
))) CFRelease(langs
);
1346 return bundle
->_searchLanguages
;
1349 CFDictionaryRef
CFBundleCopyInfoDictionaryInDirectory(CFURLRef url
) {
1350 CFDictionaryRef dict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, NULL
);
1351 if (dict
&& _CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRetain(dict
); // conditionally put on a retain for a Copy function
1355 CFDictionaryRef
CFBundleGetInfoDictionary(CFBundleRef bundle
) {
1356 if (!bundle
->_infoDict
) bundle
->_infoDict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(kCFAllocatorSystemDefaultGCRefZero
, bundle
->_url
, bundle
->_version
);
1357 return bundle
->_infoDict
;
1360 CFDictionaryRef
_CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
1361 return CFBundleGetLocalInfoDictionary(bundle
);
1364 CFDictionaryRef
CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
1365 static CFSpinLock_t CFBundleLocalInfoLock
= CFSpinLockInit
;
1366 CFDictionaryRef localInfoDict
= bundle
->_localInfoDict
;
1367 if (!localInfoDict
) {
1368 CFURLRef url
= CFBundleCopyResourceURL(bundle
, _CFBundleLocalInfoName
, _CFBundleStringTableType
, NULL
);
1372 CFStringRef errStr
= NULL
;
1374 if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, url
, &data
, NULL
, NULL
, &errCode
)) {
1375 localInfoDict
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero
, data
, kCFPropertyListMutableContainers
, &errStr
);
1376 if (errStr
) CFRelease(errStr
);
1377 if (localInfoDict
&& CFDictionaryGetTypeID() != CFGetTypeID(localInfoDict
)) {
1378 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(localInfoDict
);
1379 localInfoDict
= NULL
;
1385 if (localInfoDict
) _processInfoDictionary((CFMutableDictionaryRef
)localInfoDict
, _CFGetPlatformName(), _CFGetProductName());
1386 __CFSpinLock(&CFBundleLocalInfoLock
);
1387 if (!bundle
->_localInfoDict
) {
1388 bundle
->_localInfoDict
= localInfoDict
;
1390 if (localInfoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(localInfoDict
);
1391 localInfoDict
= bundle
->_localInfoDict
;
1393 __CFSpinUnlock(&CFBundleLocalInfoLock
);
1395 return localInfoDict
;
1398 CFPropertyListRef
_CFBundleGetValueForInfoKey(CFBundleRef bundle
, CFStringRef key
) {
1399 return (CFPropertyListRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, key
);
1402 CFTypeRef
CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle
, CFStringRef key
) {
1403 // Look in InfoPlist.strings first. Then look in Info.plist
1404 CFTypeRef result
= NULL
;
1405 if (bundle
&& key
) {
1406 CFDictionaryRef dict
= CFBundleGetLocalInfoDictionary(bundle
);
1407 if (dict
) result
= CFDictionaryGetValue(dict
, key
);
1409 dict
= CFBundleGetInfoDictionary(bundle
);
1410 if (dict
) result
= CFDictionaryGetValue(dict
, key
);
1416 CFStringRef
CFBundleGetIdentifier(CFBundleRef bundle
) {
1417 CFStringRef bundleID
= NULL
;
1418 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1419 if (infoDict
) bundleID
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleIdentifierKey
);
1423 #define DEVELOPMENT_STAGE 0x20
1424 #define ALPHA_STAGE 0x40
1425 #define BETA_STAGE 0x60
1426 #define RELEASE_STAGE 0x80
1428 #define MAX_VERS_LEN 10
1430 CF_INLINE Boolean
_isDigit(UniChar aChar
) {return ((aChar
>= (UniChar
)'0' && aChar
<= (UniChar
)'9') ? true : false);}
1432 __private_extern__ CFStringRef
_CFCreateStringFromVersionNumber(CFAllocatorRef alloc
, UInt32 vers
) {
1433 CFStringRef result
= NULL
;
1434 uint8_t major1
, major2
, minor1
, minor2
, stage
, build
;
1436 major1
= (vers
& 0xF0000000) >> 28;
1437 major2
= (vers
& 0x0F000000) >> 24;
1438 minor1
= (vers
& 0x00F00000) >> 20;
1439 minor2
= (vers
& 0x000F0000) >> 16;
1440 stage
= (vers
& 0x0000FF00) >> 8;
1441 build
= (vers
& 0x000000FF);
1443 if (stage
== RELEASE_STAGE
) {
1445 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d"), major1
, major2
, minor1
, minor2
);
1447 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d"), major2
, minor1
, minor2
);
1451 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
);
1453 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d%C%d"), major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? 'd' : ((stage
== ALPHA_STAGE
) ? 'a' : 'b')), build
);
1459 __private_extern__ UInt32
_CFVersionNumberFromString(CFStringRef versStr
) {
1460 // Parse version number from string.
1461 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1462 UInt32 major1
= 0, major2
= 0, minor1
= 0, minor2
= 0, stage
= RELEASE_STAGE
, build
= 0;
1463 UniChar versChars
[MAX_VERS_LEN
];
1464 UniChar
*chars
= NULL
;
1467 Boolean digitsDone
= false;
1469 if (!versStr
) return 0;
1470 len
= CFStringGetLength(versStr
);
1471 if (len
<= 0 || len
> MAX_VERS_LEN
) return 0;
1473 CFStringGetCharacters(versStr
, CFRangeMake(0, len
), versChars
);
1476 // Get major version number.
1477 major1
= major2
= 0;
1478 if (_isDigit(*chars
)) {
1479 major2
= *chars
- (UniChar
)'0';
1483 if (_isDigit(*chars
)) {
1485 major2
= *chars
- (UniChar
)'0';
1489 if (*chars
== (UniChar
)'.') {
1496 } else if (*chars
== (UniChar
)'.') {
1503 } else if (*chars
== (UniChar
)'.') {
1510 // Now major1 and major2 contain first and second digit of the major version number as ints.
1511 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1513 // Get the first minor version number.
1514 if (len
> 0 && !digitsDone
) {
1515 if (_isDigit(*chars
)) {
1516 minor1
= *chars
- (UniChar
)'0';
1520 if (*chars
== (UniChar
)'.') {
1532 // Now minor1 contains the first minor version number as an int.
1533 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1535 // Get the second minor version number.
1536 if (len
> 0 && !digitsDone
) {
1537 if (_isDigit(*chars
)) {
1538 minor2
= *chars
- (UniChar
)'0';
1546 // Now minor2 contains the second minor version number as an int.
1547 // Now either len is 0 or chars points at the build stage letter.
1549 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1551 if (*chars
== (UniChar
)'d') {
1552 stage
= DEVELOPMENT_STAGE
;
1553 } else if (*chars
== (UniChar
)'a') {
1554 stage
= ALPHA_STAGE
;
1555 } else if (*chars
== (UniChar
)'b') {
1557 } else if (*chars
== (UniChar
)'f') {
1558 stage
= RELEASE_STAGE
;
1566 // Now stage contains the release stage.
1567 // Now either len is 0 or chars points at the build number.
1569 // Get the first digit of the build number.
1571 if (_isDigit(*chars
)) {
1572 build
= *chars
- (UniChar
)'0';
1579 // Get the second digit of the build number.
1581 if (_isDigit(*chars
)) {
1583 build
+= *chars
- (UniChar
)'0';
1590 // Get the third digit of the build number.
1592 if (_isDigit(*chars
)) {
1594 build
+= *chars
- (UniChar
)'0';
1602 // Range check the build number and make sure we exhausted the string.
1603 if (build
> 0xFF || len
> 0) return 0;
1606 theVers
= major1
<< 28;
1607 theVers
+= major2
<< 24;
1608 theVers
+= minor1
<< 20;
1609 theVers
+= minor2
<< 16;
1610 theVers
+= stage
<< 8;
1616 UInt32
CFBundleGetVersionNumber(CFBundleRef bundle
) {
1617 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1618 CFTypeRef unknownVersionValue
= CFDictionaryGetValue(infoDict
, _kCFBundleNumericVersionKey
);
1619 CFNumberRef versNum
;
1622 if (!unknownVersionValue
) unknownVersionValue
= CFDictionaryGetValue(infoDict
, kCFBundleVersionKey
);
1623 if (unknownVersionValue
) {
1624 if (CFGetTypeID(unknownVersionValue
) == CFStringGetTypeID()) {
1625 // Convert a string version number into a numeric one.
1626 vers
= _CFVersionNumberFromString((CFStringRef
)unknownVersionValue
);
1628 versNum
= CFNumberCreate(CFGetAllocator(bundle
), kCFNumberSInt32Type
, &vers
);
1629 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
, versNum
);
1631 } else if (CFGetTypeID(unknownVersionValue
) == CFNumberGetTypeID()) {
1632 CFNumberGetValue((CFNumberRef
)unknownVersionValue
, kCFNumberSInt32Type
, &vers
);
1634 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
);
1640 CFStringRef
CFBundleGetDevelopmentRegion(CFBundleRef bundle
) {
1641 CFStringRef devLang
= NULL
;
1642 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1644 devLang
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1645 if (devLang
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) {
1647 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleDevelopmentRegionKey
);
1654 Boolean
_CFBundleGetHasChanged(CFBundleRef bundle
) {
1656 Boolean result
= false;
1657 Boolean exists
= false;
1660 if (_CFGetFileProperties(CFGetAllocator(bundle
), bundle
->_url
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
1661 // If the bundle no longer exists or is not a folder, it must have "changed"
1662 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) result
= true;
1664 // Something is wrong. The stat failed.
1667 if (bundle
->_modDate
&& !CFEqual(bundle
->_modDate
, modDate
)) {
1668 // mod date is different from when we created.
1675 void _CFBundleSetStringsFilesShared(CFBundleRef bundle
, Boolean flag
) {
1676 bundle
->_sharesStringsFiles
= flag
;
1679 Boolean
_CFBundleGetStringsFilesShared(CFBundleRef bundle
) {
1680 return bundle
->_sharesStringsFiles
;
1683 static Boolean
_urlExists(CFURLRef url
) {
1685 return url
&& (0 == _CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, NULL
, NULL
, NULL
, NULL
, NULL
)) && exists
;
1688 // This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their
1689 // original locations on disk, so checking whether a binary's path exists is no longer sufficient.
1690 // For performance reasons, we only call dlopen_preflight() after we've verified that the binary
1691 // does not exist at its original path with _urlExists().
1692 // See <rdar://problem/6956670>
1693 static Boolean
_binaryLoadable(CFURLRef url
) {
1694 Boolean loadable
= _urlExists(url
);
1695 #if DEPLOYMENT_TARGET_EMBEDDED
1697 uint8_t path
[PATH_MAX
];
1698 if (url
&& CFURLGetFileSystemRepresentation(url
, true, path
, sizeof(path
))) {
1699 loadable
= dlopen_preflight((char *)path
);
1706 __private_extern__ CFURLRef
_CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1707 CFURLRef result
= NULL
;
1710 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase1
, bundleURL
);
1711 } else if (2 == version
) {
1712 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase2
, bundleURL
);
1714 result
= (CFURLRef
)CFRetain(bundleURL
);
1720 CF_EXPORT CFURLRef
CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle
) {
1721 return _CFBundleCopySupportFilesDirectoryURLInDirectory(bundle
->_url
, bundle
->_version
);
1724 __private_extern__ CFURLRef
_CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1725 CFURLRef result
= NULL
;
1728 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase0
, bundleURL
);
1729 } else if (1 == version
) {
1730 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase1
, bundleURL
);
1731 } else if (2 == version
) {
1732 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase2
, bundleURL
);
1734 result
= (CFURLRef
)CFRetain(bundleURL
);
1740 CFURLRef
CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle
) {
1741 return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle
->_url
, bundle
->_version
);
1744 __private_extern__ CFURLRef
_CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1745 CFURLRef result
= NULL
;
1748 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase0
, bundleURL
);
1749 } else if (1 == version
) {
1750 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase1
, bundleURL
);
1751 } else if (2 == version
) {
1752 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase2
, bundleURL
);
1758 CFURLRef
_CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle
) {
1759 return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle
->_url
, bundle
->_version
);
1762 static CFURLRef
_CFBundleCopyExecutableURLRaw(CFURLRef urlPath
, CFStringRef exeName
) {
1763 // 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.
1764 CFURLRef executableURL
= NULL
;
1765 if (!urlPath
|| !exeName
) return NULL
;
1767 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1768 const uint8_t *image_suffix
= (uint8_t *)__CFgetenv("DYLD_IMAGE_SUFFIX");
1770 CFStringRef newExeName
, imageSuffix
;
1771 imageSuffix
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, (char *)image_suffix
, kCFStringEncodingUTF8
);
1772 if (CFStringHasSuffix(exeName
, CFSTR(".dylib"))) {
1773 CFStringRef bareExeName
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, exeName
, CFRangeMake(0, CFStringGetLength(exeName
)-6));
1774 newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@.dylib"), exeName
, imageSuffix
);
1775 CFRelease(bareExeName
);
1777 newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, imageSuffix
);
1779 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, newExeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1780 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1781 CFRelease(executableURL
);
1782 executableURL
= NULL
;
1784 CFRelease(newExeName
);
1785 CFRelease(imageSuffix
);
1787 if (!executableURL
) {
1788 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, exeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1789 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1790 CFRelease(executableURL
);
1791 executableURL
= NULL
;
1794 #elif DEPLOYMENT_TARGET_WINDOWS
1795 if (!executableURL
) {
1796 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, exeName
, kCFURLWindowsPathStyle
, false, urlPath
);
1797 if (executableURL
&& !_urlExists(executableURL
)) {
1798 CFRelease(executableURL
);
1799 executableURL
= NULL
;
1802 if (!executableURL
) {
1803 if (!CFStringFindWithOptions(exeName
, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName
)), kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
1805 CFStringRef extension
= CFSTR("_debug.dll");
1807 CFStringRef extension
= CFSTR(".dll");
1809 CFStringRef newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, extension
);
1810 executableURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, newExeName
, urlPath
);
1811 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1812 CFRelease(executableURL
);
1813 executableURL
= NULL
;
1815 CFRelease(newExeName
);
1818 if (!executableURL
) {
1819 if (!CFStringFindWithOptions(exeName
, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName
)), kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
1821 CFStringRef extension
= CFSTR("_debug.exe");
1823 CFStringRef extension
= CFSTR(".exe");
1825 CFStringRef newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, extension
);
1826 executableURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, newExeName
, urlPath
);
1827 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1828 CFRelease(executableURL
);
1829 executableURL
= NULL
;
1831 CFRelease(newExeName
);
1835 #error Unknown or unspecified DEPLOYMENT_TARGET
1837 return executableURL
;
1840 static CFStringRef
_CFBundleCopyExecutableName(CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
) {
1841 CFStringRef executableName
= NULL
;
1843 if (!infoDict
&& bundle
) infoDict
= CFBundleGetInfoDictionary(bundle
);
1844 if (!url
&& bundle
) url
= bundle
->_url
;
1847 // Figure out the name of the executable.
1848 // First try for the new key in the plist.
1849 executableName
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
);
1850 // Second try for the old key in the plist.
1851 if (!executableName
) executableName
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleOldExecutableKey
);
1852 if (executableName
&& CFGetTypeID(executableName
) == CFStringGetTypeID() && CFStringGetLength(executableName
) > 0) {
1853 CFRetain(executableName
);
1855 executableName
= NULL
;
1858 if (!executableName
&& url
) {
1859 // Third, take the name of the bundle itself (with path extension stripped)
1860 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1861 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1862 CFRelease(absoluteURL
);
1864 UniChar buff
[CFMaxPathSize
];
1865 CFIndex len
= CFStringGetLength(bundlePath
);
1866 CFIndex startOfBundleName
, endOfBundleName
;
1868 if (len
> CFMaxPathSize
) len
= CFMaxPathSize
;
1869 CFStringGetCharacters(bundlePath
, CFRangeMake(0, len
), buff
);
1870 startOfBundleName
= _CFStartOfLastPathComponent(buff
, len
);
1871 endOfBundleName
= _CFLengthAfterDeletingPathExtension(buff
, len
);
1873 if (startOfBundleName
<= len
&& endOfBundleName
<= len
&& startOfBundleName
< endOfBundleName
) executableName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfBundleName
]), endOfBundleName
- startOfBundleName
);
1874 CFRelease(bundlePath
);
1878 return executableName
;
1881 __private_extern__ CFURLRef
_CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle
, Boolean mayBeLocal
) {
1882 CFStringRef executableName
= _CFBundleCopyExecutableName(bundle
, NULL
, NULL
);
1883 CFURLRef resourceForkURL
= NULL
;
1884 if (executableName
) {
1886 resourceForkURL
= CFBundleCopyResourceURL(bundle
, executableName
, CFSTR("rsrc"), NULL
);
1888 resourceForkURL
= CFBundleCopyResourceURLForLocalization(bundle
, executableName
, CFSTR("rsrc"), NULL
, NULL
);
1890 CFRelease(executableName
);
1893 return resourceForkURL
;
1896 CFURLRef
_CFBundleCopyResourceForkURL(CFBundleRef bundle
) {
1897 return _CFBundleCopyResourceForkURLMayBeLocal(bundle
, true);
1900 static CFURLRef
_CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle
, CFURLRef url
, CFStringRef executableName
, Boolean ignoreCache
, Boolean useOtherPlatform
) {
1901 uint8_t version
= 0;
1902 CFDictionaryRef infoDict
= NULL
;
1903 CFStringRef executablePath
= NULL
;
1904 CFURLRef executableURL
= NULL
;
1905 Boolean foundIt
= false;
1906 Boolean lookupMainExe
= (executableName
? false : true);
1907 static CFSpinLock_t CFBundleExecutablePathLock
= CFSpinLockInit
;
1910 infoDict
= CFBundleGetInfoDictionary(bundle
);
1911 version
= bundle
->_version
;
1913 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, &version
);
1916 // If we have a bundle instance and an info dict, see if we have already cached the path
1917 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& bundle
&& infoDict
) {
1918 __CFSpinLock(&CFBundleExecutablePathLock
);
1919 executablePath
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleExecutablePathKey
);
1920 if (executablePath
) CFRetain(executablePath
);
1921 __CFSpinUnlock(&CFBundleExecutablePathLock
);
1922 if (executablePath
) {
1923 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1924 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, executablePath
, kCFURLPOSIXPathStyle
, false);
1925 #elif DEPLOYMENT_TARGET_WINDOWS
1926 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, executablePath
, kCFURLWindowsPathStyle
, false);
1928 #error Unknown or unspecified DEPLOYMENT_TARGET
1930 if (executableURL
) {
1933 __CFSpinLock(&CFBundleExecutablePathLock
);
1934 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
);
1935 __CFSpinUnlock(&CFBundleExecutablePathLock
);
1937 CFRelease(executablePath
);
1942 if (lookupMainExe
) executableName
= _CFBundleCopyExecutableName(bundle
, url
, infoDict
);
1943 if (executableName
) {
1944 #if DEPLOYMENT_TARGET_EMBEDDED
1945 Boolean doExecSearch
= false;
1947 Boolean doExecSearch
= true;
1949 // Now, look for the executable inside the bundle.
1950 if (doExecSearch
&& 0 != version
) {
1952 CFURLRef exeSubdirURL
;
1955 exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleExecutablesURLFromBase1
, url
);
1956 } else if (2 == version
) {
1957 exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleExecutablesURLFromBase2
, url
);
1959 #if DEPLOYMENT_TARGET_WINDOWS
1960 // On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory
1961 CFStringRef extension
= CFURLCopyPathExtension(url
);
1962 if (extension
&& CFEqual(extension
, _CFBundleWindowsResourceDirectoryExtension
)) {
1963 exeDirURL
= CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault
, url
);
1965 exeDirURL
= (CFURLRef
)CFRetain(url
);
1967 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1968 exeDirURL
= (CFURLRef
)CFRetain(url
);
1970 #error Unknown or unspecified DEPLOYMENT_TARGET
1973 CFStringRef platformSubDir
= useOtherPlatform
? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName();
1974 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
1975 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
1976 if (!executableURL
) {
1977 CFRelease(exeSubdirURL
);
1978 platformSubDir
= useOtherPlatform
? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName();
1979 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
1980 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
1982 if (!executableURL
) {
1983 CFRelease(exeSubdirURL
);
1984 platformSubDir
= useOtherPlatform
? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName();
1985 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
1986 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
1988 if (!executableURL
) {
1989 CFRelease(exeSubdirURL
);
1990 platformSubDir
= useOtherPlatform
? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName();
1991 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
1992 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
1994 if (!executableURL
) executableURL
= _CFBundleCopyExecutableURLRaw(exeDirURL
, executableName
);
1995 CFRelease(exeDirURL
);
1996 CFRelease(exeSubdirURL
);
1999 // If this was an old bundle, or we did not find the executable in the Executables subdirectory, look directly in the bundle wrapper.
2000 if (!executableURL
) executableURL
= _CFBundleCopyExecutableURLRaw(url
, executableName
);
2002 #if DEPLOYMENT_TARGET_WINDOWS
2003 // Windows only: If we still haven't found the exe, look in the Executables folder.
2004 // But only for the main bundle exe
2005 if (lookupMainExe
&& !executableURL
) {
2006 CFURLRef exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, CFSTR("../../Executables"), url
);
2007 executableURL
= _CFBundleCopyExecutableURLRaw(exeDirURL
, executableName
);
2008 CFRelease(exeDirURL
);
2010 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2012 #error Unknown or unspecified DEPLOYMENT_TARGET
2015 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& bundle
&& infoDict
&& executableURL
) {
2016 // We found it. Cache the path.
2017 CFURLRef absURL
= CFURLCopyAbsoluteURL(executableURL
);
2018 #if DEPLOYMENT_TARGET_WINDOWS
2019 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLWindowsPathStyle
);
2020 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2021 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLPOSIXPathStyle
);
2023 #error Unknown or unspecified DEPLOYMENT_TARGET
2026 __CFSpinLock(&CFBundleExecutablePathLock
);
2027 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
, executablePath
);
2028 __CFSpinUnlock(&CFBundleExecutablePathLock
);
2029 CFRelease(executablePath
);
2031 if (lookupMainExe
&& !useOtherPlatform
&& bundle
&& !executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
2032 if (lookupMainExe
) CFRelease(executableName
);
2035 if (!bundle
&& infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(infoDict
);
2036 return executableURL
;
2039 CFURLRef
_CFBundleCopyExecutableURLInDirectory(CFURLRef url
) {
2040 return _CFBundleCopyExecutableURLInDirectory2(NULL
, url
, NULL
, true, false);
2043 CFURLRef
_CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url
) {
2044 return _CFBundleCopyExecutableURLInDirectory2(NULL
, url
, NULL
, true, true);
2047 CFURLRef
CFBundleCopyExecutableURL(CFBundleRef bundle
) {
2048 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, NULL
, false, false);
2051 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
) {
2052 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, NULL
, true, false);
2055 CFURLRef
CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle
, CFStringRef executableName
) {
2056 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, executableName
, true, false);
2059 Boolean
CFBundleIsExecutableLoaded(CFBundleRef bundle
) {
2060 return bundle
->_isLoaded
;
2063 CFBundleExecutableType
CFBundleGetExecutableType(CFBundleRef bundle
) {
2064 CFBundleExecutableType result
= kCFBundleOtherExecutableType
;
2065 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2067 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
2068 #if defined(BINARY_SUPPORT_DYLD)
2069 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2070 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
2071 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
2073 #endif /* BINARY_SUPPORT_DYLD */
2074 if (executableURL
) CFRelease(executableURL
);
2076 if (bundle
->_binaryType
== __CFBundleCFMBinary
) {
2077 result
= kCFBundlePEFExecutableType
;
2078 } else if (bundle
->_binaryType
== __CFBundleDYLDExecutableBinary
|| bundle
->_binaryType
== __CFBundleDYLDBundleBinary
|| bundle
->_binaryType
== __CFBundleDYLDFrameworkBinary
) {
2079 result
= kCFBundleMachOExecutableType
;
2080 } else if (bundle
->_binaryType
== __CFBundleDLLBinary
) {
2081 result
= kCFBundleDLLExecutableType
;
2082 } else if (bundle
->_binaryType
== __CFBundleELFBinary
) {
2083 result
= kCFBundleELFExecutableType
;
2088 static SInt32
_CFBundleCurrentArchitecture(void) {
2090 #if defined(__ppc__)
2091 arch
= kCFBundleExecutableArchitecturePPC
;
2092 #elif defined(__ppc64__)
2093 arch
= kCFBundleExecutableArchitecturePPC64
;
2094 #elif defined(__i386__)
2095 arch
= kCFBundleExecutableArchitectureI386
;
2096 #elif defined(__x86_64__)
2097 arch
= kCFBundleExecutableArchitectureX86_64
;
2098 #elif defined(BINARY_SUPPORT_DYLD)
2099 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
2100 if (archInfo
) arch
= archInfo
->cputype
;
2105 #define UNKNOWN_FILETYPE 0x0
2106 #define PEF_FILETYPE 0x1000
2107 #define PEF_MAGIC 0x4a6f7921
2108 #define PEF_CIGAM 0x21796f4a
2109 #define TEXT_SEGMENT "__TEXT"
2110 #define PLIST_SECTION "__info_plist"
2111 #define OBJC_SEGMENT "__OBJC"
2112 #define IMAGE_INFO_SECTION "__image_info"
2113 #define OBJC_SEGMENT_64 "__DATA"
2114 #define IMAGE_INFO_SECTION_64 "__objc_imageinfo"
2115 #define LIB_X11 "/usr/X11R6/lib/libX"
2117 #define XLS_NAME "Book"
2118 #define XLS_NAME2 "Workbook"
2119 #define DOC_NAME "WordDocument"
2120 #define PPT_NAME "PowerPoint Document"
2122 #define ustrncmp(x, y, z) strncmp((char *)(x), (char *)(y), (z))
2123 #define ustrncasecmp(x, y, z) strncasecmp_l((char *)(x), (char *)(y), (z), NULL)
2125 static const uint32_t __CFBundleMagicNumbersArray
[] = {
2126 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0xfeedfacf, 0xcffaedfe, 0x4a6f7921, 0x21796f4a,
2127 0x7f454c46, 0xffd8ffe0, 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100,
2128 0x7b5c7274, 0x25504446, 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646,
2129 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435,
2130 0x53495444, 0x53747566, 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x3d796265,
2131 0x6b6f6c79, 0x3026b275, 0x0000000c, 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143,
2132 0x00010000, 0x74727565, 0x4f54544f, 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70,
2133 0x3c435058, 0x28445746, 0x424f4d53, 0x49544f4c, 0x72746664, 0x63616666, 0x802a5fd7, 0x762f3101
2136 // string, with groups of 5 characters being 1 element in the array
2137 static const char * __CFBundleExtensionsArray
=
2138 "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0"
2139 "elf\0\0" "jpeg\0" "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0"
2140 "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"
2141 "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0"
2142 "sit\0\0" "sit\0\0" "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""ync\0\0"
2143 "dmg\0\0" "wmv\0\0" "jp2\0\0" "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0"
2144 "ttf\0\0" "ttf\0\0" "otf\0\0" "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0"
2145 "cpx\0\0" "dwf\0\0" "bom\0\0" "lit\0\0" "rtfd\0" "caf\0\0" "cin\0\0" "exr\0\0";
2147 static const char * __CFBundleOOExtensionsArray
= "sxc\0\0" "sxd\0\0" "sxg\0\0" "sxi\0\0" "sxm\0\0" "sxw\0\0";
2148 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";
2150 #define EXTENSION_LENGTH 5
2151 #define NUM_EXTENSIONS 64
2152 #define MAGIC_BYTES_TO_READ 512
2153 #define DMG_BYTES_TO_READ 512
2154 #define ZIP_BYTES_TO_READ 1024
2155 #define OLE_BYTES_TO_READ 512
2156 #define X11_BYTES_TO_READ 4096
2157 #define IMAGE_INFO_BYTES_TO_READ 4096
2159 #if defined(BINARY_SUPPORT_DYLD)
2161 CF_INLINE
uint32_t _CFBundleSwapInt32Conditional(uint32_t arg
, Boolean swap
) {return swap
? CFSwapInt32(arg
) : arg
;}
2162 CF_INLINE
uint32_t _CFBundleSwapInt64Conditional(uint64_t arg
, Boolean swap
) {return swap
? CFSwapInt64(arg
) : arg
;}
2164 // returns zero-ref dictionary under GC
2165 static CFMutableDictionaryRef
_CFBundleGrokInfoDictFromData(const char *bytes
, uint32_t length
) {
2166 CFMutableDictionaryRef result
= NULL
;
2167 CFDataRef infoData
= NULL
;
2168 if (bytes
&& 0 < length
) {
2169 infoData
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, (uint8_t *)bytes
, length
, kCFAllocatorNull
);
2171 result
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero
, infoData
, kCFPropertyListMutableContainers
, NULL
);
2172 if (result
&& CFDictionaryGetTypeID() != CFGetTypeID(result
)) {
2176 CFRelease(infoData
);
2178 if (!result
) result
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2180 if (result
) _processInfoDictionary((CFMutableDictionaryRef
)result
, _CFGetPlatformName(), _CFGetProductName());
2184 static char *_CFBundleGetSectData(const char *segname
, const char *sectname
, unsigned long *size
) {
2185 char *retval
= NULL
;
2186 unsigned long localSize
= 0;
2187 uint32_t i
, numImages
= _dyld_image_count();
2188 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
2190 for (i
= 0; i
< numImages
; i
++) {
2191 if (mhp
== (void *)_dyld_get_image_header(i
)) {
2193 const struct section_64
*sp
= getsectbynamefromheader_64((const struct mach_header_64
*)mhp
, segname
, sectname
);
2195 retval
= (char *)(sp
->addr
+ _dyld_get_image_vmaddr_slide(i
));
2196 localSize
= (unsigned long)sp
->size
;
2198 #else /* __LP64__ */
2199 const struct section
*sp
= getsectbynamefromheader((const struct mach_header
*)mhp
, segname
, sectname
);
2201 retval
= (char *)(sp
->addr
+ _dyld_get_image_vmaddr_slide(i
));
2202 localSize
= (unsigned long)sp
->size
;
2204 #endif /* __LP64__ */
2208 if (size
) *size
= localSize
;
2212 // returns zero-ref dictionary under GC
2213 static CFMutableDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable() {
2215 unsigned long length
= 0;
2216 if (getsegbyname(TEXT_SEGMENT
)) bytes
= _CFBundleGetSectData(TEXT_SEGMENT
, PLIST_SECTION
, &length
);
2217 return _CFBundleGrokInfoDictFromData(bytes
, length
);
2220 static Boolean
_CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion
, uint32_t *objcFlags
) {
2221 Boolean retval
= false;
2222 uint32_t localVersion
= 0, localFlags
= 0;
2224 unsigned long length
= 0;
2226 if (getsegbyname(OBJC_SEGMENT_64
)) bytes
= _CFBundleGetSectData(OBJC_SEGMENT_64
, IMAGE_INFO_SECTION_64
, &length
);
2227 #else /* __LP64__ */
2228 if (getsegbyname(OBJC_SEGMENT
)) bytes
= _CFBundleGetSectData(OBJC_SEGMENT
, IMAGE_INFO_SECTION
, &length
);
2229 #endif /* __LP64__ */
2230 if (bytes
&& length
>= 8) {
2231 localVersion
= *(uint32_t *)bytes
;
2232 localFlags
= *(uint32_t *)(bytes
+ 4);
2235 if (objcVersion
) *objcVersion
= localVersion
;
2236 if (objcFlags
) *objcFlags
= localFlags
;
2240 static Boolean
_CFBundleGrokX11FromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
2241 static const char libX11name
[] = LIB_X11
;
2242 char *buffer
= NULL
;
2243 const char *loc
= NULL
;
2245 Boolean result
= false;
2247 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2248 buffer
= malloc(X11_BYTES_TO_READ
);
2249 if (buffer
&& read(fd
, buffer
, X11_BYTES_TO_READ
) >= X11_BYTES_TO_READ
) loc
= buffer
;
2250 } else if (bytes
&& length
>= offset
+ X11_BYTES_TO_READ
) {
2251 loc
= bytes
+ offset
;
2255 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->ncmds
, swapped
);
2256 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->sizeofcmds
, swapped
);
2257 const char *startofcmds
= loc
+ sizeof(struct mach_header_64
);
2258 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2259 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
2260 if (endofcmds
> loc
+ X11_BYTES_TO_READ
) endofcmds
= loc
+ X11_BYTES_TO_READ
;
2261 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
2262 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
2263 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
2264 const char *name
= (const char *)dlp
+ nameoffset
;
2265 if (startofcmds
<= name
&& name
+ sizeof(libX11name
) <= endofcmds
&& 0 == strncmp(name
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
2267 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
2270 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->ncmds
, swapped
);
2271 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->sizeofcmds
, swapped
);
2272 const char *startofcmds
= loc
+ sizeof(struct mach_header
);
2273 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2274 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
2275 if (endofcmds
> loc
+ X11_BYTES_TO_READ
) endofcmds
= loc
+ X11_BYTES_TO_READ
;
2276 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
2277 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
2278 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
2279 const char *name
= (const char *)dlp
+ nameoffset
;
2280 if (startofcmds
<= name
&& name
+ sizeof(libX11name
) <= endofcmds
&& 0 == strncmp(name
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
2282 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
2286 if (buffer
) free(buffer
);
2290 // returns zero-ref dictionary under GC
2291 static CFDictionaryRef
_CFBundleGrokInfoDictFromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
2292 struct stat statBuf
;
2293 off_t fileLength
= 0;
2294 char *maploc
= NULL
;
2297 CFDictionaryRef result
= NULL
;
2298 Boolean foundit
= false;
2299 if (fd
>= 0 && fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
2301 fileLength
= statBuf
.st_size
;
2304 fileLength
= length
;
2306 if (fileLength
> offset
+ sizeof(struct mach_header_64
)) {
2308 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->ncmds
, swapped
);
2309 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->sizeofcmds
, swapped
);
2310 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header_64
);
2311 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2312 struct segment_command_64
*sgp
= (struct segment_command_64
*)startofcmds
;
2313 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
2314 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2315 if (LC_SEGMENT_64
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2316 struct section_64
*sp
= (struct section_64
*)((char *)sgp
+ sizeof(struct segment_command_64
));
2317 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2318 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2319 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, TEXT_SEGMENT
, sizeof(sp
->segname
))) {
2320 uint64_t sectlength64
= _CFBundleSwapInt64Conditional(sp
->size
, swapped
);
2321 uint32_t sectlength
= (uint32_t)(sectlength64
& 0xffffffff);
2322 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2323 const char *sectbytes
= loc
+ offset
+ sectoffset
;
2324 // we don't support huge-sized plists
2325 if (sectlength64
<= 0xffffffff && loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
2328 sp
= (struct section_64
*)((char *)sp
+ sizeof(struct section_64
));
2331 sgp
= (struct segment_command_64
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2334 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->ncmds
, swapped
);
2335 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->sizeofcmds
, swapped
);
2336 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header
);
2337 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2338 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
2339 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
2340 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2341 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2342 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
2343 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2344 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2345 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, TEXT_SEGMENT
, sizeof(sp
->segname
))) {
2346 uint32_t sectlength
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
2347 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2348 const char *sectbytes
= loc
+ offset
+ sectoffset
;
2349 if (loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
2352 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
2355 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2359 if (maploc
) munmap(maploc
, statBuf
.st_size
);
2363 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
) {
2364 uint32_t sectlength
= 0, sectoffset
= 0, localVersion
= 0, localFlags
= 0;
2365 char *buffer
= NULL
;
2367 const char *loc
= NULL
;
2369 Boolean foundit
= false, localHasObjc
= false;
2371 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2372 buffer
= malloc(IMAGE_INFO_BYTES_TO_READ
);
2373 if (buffer
&& read(fd
, buffer
, IMAGE_INFO_BYTES_TO_READ
) >= IMAGE_INFO_BYTES_TO_READ
) loc
= buffer
;
2374 } else if (bytes
&& length
>= offset
+ IMAGE_INFO_BYTES_TO_READ
) {
2375 loc
= bytes
+ offset
;
2379 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->ncmds
, swapped
);
2380 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->sizeofcmds
, swapped
);
2381 const char *startofcmds
= loc
+ sizeof(struct mach_header_64
);
2382 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2383 struct segment_command_64
*sgp
= (struct segment_command_64
*)startofcmds
;
2384 if (endofcmds
> loc
+ IMAGE_INFO_BYTES_TO_READ
) endofcmds
= loc
+ IMAGE_INFO_BYTES_TO_READ
;
2385 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2386 if (LC_SEGMENT_64
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2387 struct section_64
*sp
= (struct section_64
*)((char *)sgp
+ sizeof(struct segment_command_64
));
2388 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2389 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2390 if (0 == strncmp(sp
->segname
, OBJC_SEGMENT_64
, sizeof(sp
->segname
))) localHasObjc
= true;
2391 if (0 == strncmp(sp
->sectname
, IMAGE_INFO_SECTION_64
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, OBJC_SEGMENT_64
, sizeof(sp
->segname
))) {
2392 uint64_t sectlength64
= _CFBundleSwapInt64Conditional(sp
->size
, swapped
);
2393 sectlength
= (uint32_t)(sectlength64
& 0xffffffff);
2394 sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2397 sp
= (struct section_64
*)((char *)sp
+ sizeof(struct section_64
));
2400 sgp
= (struct segment_command_64
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2403 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->ncmds
, swapped
);
2404 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->sizeofcmds
, swapped
);
2405 const char *startofcmds
= loc
+ sizeof(struct mach_header
);
2406 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2407 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
2408 if (endofcmds
> loc
+ IMAGE_INFO_BYTES_TO_READ
) endofcmds
= loc
+ IMAGE_INFO_BYTES_TO_READ
;
2409 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2410 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2411 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
2412 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2413 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2414 if (0 == strncmp(sp
->segname
, OBJC_SEGMENT
, sizeof(sp
->segname
))) localHasObjc
= true;
2415 if (0 == strncmp(sp
->sectname
, IMAGE_INFO_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, OBJC_SEGMENT
, sizeof(sp
->segname
))) {
2416 sectlength
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
2417 sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2420 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
2423 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2426 if (sectlength
>= 8) {
2427 if (fd
>= 0 && lseek(fd
, offset
+ sectoffset
, SEEK_SET
) == (off_t
)(offset
+ sectoffset
) && read(fd
, sectbuffer
, 8) >= 8) {
2428 localVersion
= _CFBundleSwapInt32Conditional(*(uint32_t *)sectbuffer
, swapped
);
2429 localFlags
= _CFBundleSwapInt32Conditional(*(uint32_t *)(sectbuffer
+ 4), swapped
);
2430 } else if (bytes
&& length
>= offset
+ sectoffset
+ 8) {
2431 localVersion
= _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes
+ offset
+ sectoffset
), swapped
);
2432 localFlags
= _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes
+ offset
+ sectoffset
+ 4), swapped
);
2436 if (buffer
) free(buffer
);
2437 if (hasObjc
) *hasObjc
= localHasObjc
;
2438 if (objcVersion
) *objcVersion
= localVersion
;
2439 if (objcFlags
) *objcFlags
= localFlags
;
2442 // returns zero-ref dictionary in *infodict under GC
2443 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
) {
2444 CFIndex headerLength
= length
;
2445 unsigned char headerBuffer
[MAGIC_BYTES_TO_READ
];
2446 UInt32 machtype
= UNKNOWN_FILETYPE
, magic
, numFatHeaders
, maxFatHeaders
, i
;
2447 unsigned char buffer
[sizeof(struct mach_header_64
)];
2448 const unsigned char *moreBytes
= NULL
;
2449 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
2450 SInt32 curArch
= _CFBundleCurrentArchitecture();
2452 struct fat_arch
*fat
= NULL
;
2454 if (isX11
) *isX11
= false;
2455 if (architectures
) *architectures
= NULL
;
2456 if (infodict
) *infodict
= NULL
;
2457 if (hasObjc
) *hasObjc
= false;
2458 if (objcVersion
) *objcVersion
= 0;
2459 if (objcFlags
) *objcFlags
= 0;
2461 if (headerLength
> MAGIC_BYTES_TO_READ
) headerLength
= MAGIC_BYTES_TO_READ
;
2462 (void)memmove(headerBuffer
, bytes
, headerLength
);
2464 for (i
= 0; i
< headerLength
; i
+= 4) *(UInt32
*)(headerBuffer
+ i
) = CFSwapInt32(*(UInt32
*)(headerBuffer
+ i
));
2466 numFatHeaders
= ((struct fat_header
*)headerBuffer
)->nfat_arch
;
2467 maxFatHeaders
= (headerLength
- sizeof(struct fat_header
)) / sizeof(struct fat_arch
);
2468 if (numFatHeaders
> maxFatHeaders
) numFatHeaders
= maxFatHeaders
;
2469 if (numFatHeaders
> 0) {
2470 if (archInfo
) fat
= NXFindBestFatArch(archInfo
->cputype
, archInfo
->cpusubtype
, (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
)), numFatHeaders
);
2471 if (!fat
&& curArch
!= 0) fat
= NXFindBestFatArch((cpu_type_t
)curArch
, (cpu_subtype_t
)0, (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
)), numFatHeaders
);
2472 if (!fat
) fat
= (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
));
2473 if (architectures
) {
2474 CFMutableArrayRef mutableArchitectures
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2475 for (i
= 0; i
< numFatHeaders
; i
++) {
2476 CFNumberRef architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, headerBuffer
+ sizeof(struct fat_header
) + i
* sizeof(struct fat_arch
));
2477 if (CFArrayGetFirstIndexOfValue(mutableArchitectures
, CFRangeMake(0, CFArrayGetCount(mutableArchitectures
)), architecture
) < 0) CFArrayAppendValue(mutableArchitectures
, architecture
);
2478 CFRelease(architecture
);
2480 *architectures
= (CFArrayRef
)mutableArchitectures
;
2484 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
)) {
2486 } else if (bytes
&& (uint32_t)length
>= fat
->offset
+ sizeof(struct mach_header_64
)) {
2487 moreBytes
= bytes
+ fat
->offset
;
2490 magic
= *((UInt32
*)moreBytes
);
2491 if (MH_MAGIC
== magic
) {
2492 machtype
= ((struct mach_header
*)moreBytes
)->filetype
;
2493 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, false, false);
2494 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, false);
2495 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, false, false, hasObjc
, objcVersion
, objcFlags
);
2496 } else if (MH_CIGAM
== magic
) {
2497 machtype
= CFSwapInt32(((struct mach_header
*)moreBytes
)->filetype
);
2498 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, true, false);
2499 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, false);
2500 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, true, false, hasObjc
, objcVersion
, objcFlags
);
2501 } else if (MH_MAGIC_64
== magic
) {
2502 machtype
= ((struct mach_header_64
*)moreBytes
)->filetype
;
2503 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, false, true);
2504 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, true);
2505 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, false, true, hasObjc
, objcVersion
, objcFlags
);
2506 } else if (MH_CIGAM_64
== magic
) {
2507 machtype
= CFSwapInt32(((struct mach_header_64
*)moreBytes
)->filetype
);
2508 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, true, true);
2509 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, true);
2510 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, true, true, hasObjc
, objcVersion
, objcFlags
);
2517 // returns zero-ref dictionary in *infodict under GC
2518 static UInt32
_CFBundleGrokMachType(int fd
, const void *bytes
, CFIndex length
, Boolean
*isX11
, CFArrayRef
*architectures
, CFDictionaryRef
*infodict
, Boolean
*hasObjc
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
2519 unsigned int magic
= *((UInt32
*)bytes
), machtype
= UNKNOWN_FILETYPE
, cputype
;
2520 CFNumberRef architecture
= NULL
;
2522 if (isX11
) *isX11
= false;
2523 if (architectures
) *architectures
= NULL
;
2524 if (infodict
) *infodict
= NULL
;
2525 if (hasObjc
) *hasObjc
= false;
2526 if (objcVersion
) *objcVersion
= 0;
2527 if (objcFlags
) *objcFlags
= 0;
2528 if (MH_MAGIC
== magic
) {
2529 machtype
= ((struct mach_header
*)bytes
)->filetype
;
2530 cputype
= ((struct mach_header
*)bytes
)->cputype
;
2531 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2532 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, false, false);
2533 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, false);
2534 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, false, false, hasObjc
, objcVersion
, objcFlags
);
2535 } else if (MH_CIGAM
== magic
) {
2536 machtype
= CFSwapInt32(((struct mach_header
*)bytes
)->filetype
);
2537 cputype
= CFSwapInt32(((struct mach_header
*)bytes
)->cputype
);
2538 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2539 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, true, false);
2540 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, false);
2541 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, true, false, hasObjc
, objcVersion
, objcFlags
);
2542 } else if (MH_MAGIC_64
== magic
) {
2543 machtype
= ((struct mach_header_64
*)bytes
)->filetype
;
2544 cputype
= ((struct mach_header_64
*)bytes
)->cputype
;
2545 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2546 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, false, true);
2547 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, true);
2548 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, false, true, hasObjc
, objcVersion
, objcFlags
);
2549 } else if (MH_CIGAM_64
== magic
) {
2550 machtype
= CFSwapInt32(((struct mach_header_64
*)bytes
)->filetype
);
2551 cputype
= CFSwapInt32(((struct mach_header_64
*)bytes
)->cputype
);
2552 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2553 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, true, true);
2554 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, true);
2555 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, true, true, hasObjc
, objcVersion
, objcFlags
);
2556 } else if (FAT_MAGIC
== magic
) {
2557 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, false, isX11
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2558 } else if (FAT_CIGAM
== magic
) {
2559 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, true, isX11
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2560 } else if (PEF_MAGIC
== magic
|| PEF_CIGAM
== magic
) {
2561 machtype
= PEF_FILETYPE
;
2563 if (architectures
&& architecture
) *architectures
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&architecture
, 1, &kCFTypeArrayCallBacks
);
2564 if (architecture
) CFRelease(architecture
);
2568 #endif /* BINARY_SUPPORT_DYLD */
2570 static Boolean
_CFBundleGrokFileTypeForZipMimeType(const unsigned char *bytes
, CFIndex length
, const char **ext
) {
2571 unsigned namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 26))), extralength
= CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 28)));
2572 const unsigned char *data
= bytes
+ 30 + namelength
+ extralength
;
2574 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))) {
2575 data
+= ('.' == *(data
+ 15)) ? 16 : 18;
2576 if (0 == ustrncasecmp(data
, "sun.xml.", 8)) {
2578 if (0 == ustrncasecmp(data
, "calc", 4)) i
= 0;
2579 else if (0 == ustrncasecmp(data
, "draw", 4)) i
= 1;
2580 else if (0 == ustrncasecmp(data
, "writer.global", 13)) i
= 2;
2581 else if (0 == ustrncasecmp(data
, "impress", 7)) i
= 3;
2582 else if (0 == ustrncasecmp(data
, "math", 4)) i
= 4;
2583 else if (0 == ustrncasecmp(data
, "writer", 6)) i
= 5;
2584 if (i
>= 0 && ext
) *ext
= __CFBundleOOExtensionsArray
+ i
* EXTENSION_LENGTH
;
2585 } else if (0 == ustrncasecmp(data
, "oasis.opendocument.", 19)) {
2587 if (0 == ustrncasecmp(data
, "chart", 5)) i
= 0;
2588 else if (0 == ustrncasecmp(data
, "formula", 7)) i
= 1;
2589 else if (0 == ustrncasecmp(data
, "graphics", 8)) i
= 2;
2590 else if (0 == ustrncasecmp(data
, "text-web", 8)) i
= 3;
2591 else if (0 == ustrncasecmp(data
, "image", 5)) i
= 4;
2592 else if (0 == ustrncasecmp(data
, "text-master", 11)) i
= 5;
2593 else if (0 == ustrncasecmp(data
, "presentation", 12)) i
= 6;
2594 else if (0 == ustrncasecmp(data
, "spreadsheet", 11)) i
= 7;
2595 else if (0 == ustrncasecmp(data
, "text", 4)) i
= 8;
2596 if (i
>= 0 && ext
) *ext
= __CFBundleODExtensionsArray
+ i
* EXTENSION_LENGTH
;
2598 } else if (bytes
< data
&& data
+ 41 <= bytes
+ length
&& 8 == CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 8))) && 0x4b2c28c8 == CFSwapInt32HostToBig(*((UInt32
*)data
)) && 0xc94c4e2c == CFSwapInt32HostToBig(*((UInt32
*)(data
+ 4)))) {
2599 // AbiWord compressed mimetype odt
2600 if (ext
) *ext
= "odt";
2605 static const char *_CFBundleGrokFileTypeForZipFile(int fd
, const unsigned char *bytes
, CFIndex length
, off_t fileLength
) {
2606 const char *ext
= "zip";
2607 const unsigned char *moreBytes
= NULL
;
2608 unsigned char *buffer
= NULL
;
2610 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;
2613 for (i
= 0; !foundMimetype
&& i
+ 30 < length
; i
++) {
2614 if (0x50 == bytes
[i
] && 0x4b == bytes
[i
+ 1]) {
2615 unsigned namelength
= 0, offset
= 0;
2616 if (0x01 == bytes
[i
+ 2] && 0x02 == bytes
[i
+ 3]) {
2617 namelength
= (unsigned)CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ i
+ 28)));
2619 } else if (0x03 == bytes
[i
+ 2] && 0x04 == bytes
[i
+ 3]) {
2620 namelength
= (unsigned)CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ i
+ 26)));
2623 if (offset
> 0 && (CFIndex
)(i
+ offset
+ namelength
) <= length
) {
2624 //printf("%.*s\n", namelength, bytes + i + offset);
2625 if (8 == namelength
&& 30 == offset
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "mimetype", 8)) foundMimetype
= _CFBundleGrokFileTypeForZipMimeType(bytes
+ i
, length
- i
, &ext
);
2626 else if (9 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/", 9)) hasMetaInf
= true;
2627 else if (11 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "content.xml", 11)) hasContentXML
= true;
2628 else if (11 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "_rels/.rels", 11)) hasRels
= true;
2629 else if (19 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "[Content_Types].xml", 19)) hasContentTypes
= true;
2630 else if (20 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/MANIFEST.MF", 20)) hasManifestMF
= true;
2631 else if (21 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/manifest.xml", 21)) hasManifestXML
= true;
2632 else if (4 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".opf", 4)) hasOPF
= true;
2633 else if (4 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".sml", 4)) hasSMIL
= true;
2634 else if (5 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 5, ".smil", 5)) hasSMIL
= true;
2635 else if (7 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "xl/", 3) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2636 else if (8 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "ppt/", 4) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2637 else if (9 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "word/", 5) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasWordDocument
= true;
2638 else if (10 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "excel/", 6) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2639 else if (15 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "powerpoint/", 11) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2640 i
+= offset
+ namelength
- 1;
2645 if (!foundMimetype
) {
2646 if (fileLength
>= ZIP_BYTES_TO_READ
) {
2647 if (fd
>= 0 && lseek(fd
, fileLength
- ZIP_BYTES_TO_READ
, SEEK_SET
) == fileLength
- ZIP_BYTES_TO_READ
) {
2648 buffer
= (unsigned char *)malloc(ZIP_BYTES_TO_READ
);
2649 if (buffer
&& read(fd
, buffer
, ZIP_BYTES_TO_READ
) >= ZIP_BYTES_TO_READ
) moreBytes
= buffer
;
2650 } else if (bytes
&& length
>= ZIP_BYTES_TO_READ
) {
2651 moreBytes
= bytes
+ length
- ZIP_BYTES_TO_READ
;
2655 for (i
= 0; i
+ 30 < ZIP_BYTES_TO_READ
; i
++) {
2656 if (0x50 == moreBytes
[i
] && 0x4b == moreBytes
[i
+ 1]) {
2657 unsigned namelength
= 0, offset
= 0;
2658 if (0x01 == moreBytes
[i
+ 2] && 0x02 == moreBytes
[i
+ 3]) {
2659 namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(moreBytes
+ i
+ 28)));
2661 } else if (0x03 == moreBytes
[i
+ 2] && 0x04 == moreBytes
[i
+ 3]) {
2662 namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(moreBytes
+ i
+ 26)));
2665 if (offset
> 0 && i
+ offset
+ namelength
<= ZIP_BYTES_TO_READ
) {
2666 //printf("%.*s\n", namelength, moreBytes + i + offset);
2667 if (9 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/", 9)) hasMetaInf
= true;
2668 else if (11 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "content.xml", 11)) hasContentXML
= true;
2669 else if (11 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "_rels/.rels", 11)) hasRels
= true;
2670 else if (19 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "[Content_Types].xml", 19)) hasContentTypes
= true;
2671 else if (20 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/MANIFEST.MF", 20)) hasManifestMF
= true;
2672 else if (21 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/manifest.xml", 21)) hasManifestXML
= true;
2673 else if (4 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".opf", 4)) hasOPF
= true;
2674 else if (4 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".sml", 4)) hasSMIL
= true;
2675 else if (5 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 5, ".smil", 5)) hasSMIL
= true;
2676 else if (7 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "xl/", 3) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2677 else if (8 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "ppt/", 4) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2678 else if (9 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "word/", 5) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasWordDocument
= true;
2679 else if (10 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "excel/", 6) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2680 else if (15 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "powerpoint/", 11) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2681 i
+= offset
+ namelength
- 1;
2686 //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);
2687 if (hasManifestMF
) ext
= "jar";
2688 else if ((hasRels
|| hasContentTypes
) && hasWordDocument
) ext
= "docx";
2689 else if ((hasRels
|| hasContentTypes
) && hasExcelDocument
) ext
= "xlsx";
2690 else if ((hasRels
|| hasContentTypes
) && hasPowerPointDocument
) ext
= "pptx";
2691 else if (hasManifestXML
|| hasContentXML
) ext
= "odt";
2692 else if (hasMetaInf
) ext
= "jar";
2693 else if (hasOPF
&& hasSMIL
) ext
= "dtb";
2694 else if (hasOPF
) ext
= "oeb";
2696 if (buffer
) free(buffer
);
2701 static Boolean
_CFBundleCheckOLEName(const char *name
, const char *bytes
, unsigned length
) {
2702 Boolean retval
= true;
2704 for (j
= 0; retval
&& j
< length
; j
++) if (bytes
[2 * j
] != name
[j
]) retval
= false;
2708 static const char *_CFBundleGrokFileTypeForOLEFile(int fd
, const void *bytes
, CFIndex length
, off_t offset
) {
2709 const char *ext
= "ole", *moreBytes
= NULL
;
2710 char *buffer
= NULL
;
2712 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2713 buffer
= (char *)malloc(OLE_BYTES_TO_READ
);
2714 if (buffer
&& read(fd
, buffer
, OLE_BYTES_TO_READ
) >= OLE_BYTES_TO_READ
) moreBytes
= buffer
;
2715 } else if (bytes
&& length
>= offset
+ OLE_BYTES_TO_READ
) {
2716 moreBytes
= (char *)bytes
+ offset
;
2719 Boolean foundit
= false;
2721 for (i
= 0; !foundit
&& i
< 4; i
++) {
2722 char namelength
= moreBytes
[128 * i
+ 64] / 2;
2724 if (sizeof(XLS_NAME
) == namelength
&& _CFBundleCheckOLEName(XLS_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "xls";
2725 else if (sizeof(XLS_NAME2
) == namelength
&& _CFBundleCheckOLEName(XLS_NAME2
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "xls";
2726 else if (sizeof(DOC_NAME
) == namelength
&& _CFBundleCheckOLEName(DOC_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "doc";
2727 else if (sizeof(PPT_NAME
) == namelength
&& _CFBundleCheckOLEName(PPT_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "ppt";
2728 else foundit
= false;
2731 if (buffer
) free(buffer
);
2735 #if DEPLOYMENT_TARGET_WINDOWS
2736 // Windows isspace implementation limits the input chars to < 256 in the ASCII range. It will
2737 // assert in debug builds. This is annoying. We merrily grok chars > 256.
2738 static inline BOOL
isspace(char c
) {
2739 return (c
== ' ' || c
== '\t' || c
== '\n' || c
== '\r'|| c
== '\v' || c
== '\f');
2743 // returns zero-ref dictionary in *infodict under GC
2744 static Boolean
_CFBundleGrokFileType(CFURLRef url
, CFDataRef data
, CFStringRef
*extension
, UInt32
*machtype
, CFArrayRef
*architectures
, CFDictionaryRef
*infodict
, Boolean
*hasObjc
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
2746 const unsigned char *bytes
= NULL
;
2747 unsigned char buffer
[MAGIC_BYTES_TO_READ
];
2748 CFIndex i
, length
= 0;
2749 off_t fileLength
= 0;
2750 const char *ext
= NULL
;
2751 UInt32 mt
= UNKNOWN_FILETYPE
;
2752 #if defined(BINARY_SUPPORT_DYLD)
2753 Boolean isX11
= false;
2754 #endif /* BINARY_SUPPORT_DYLD */
2755 Boolean isFile
= false, isPlain
= true, isZero
= true, isSpace
= true, hasBOM
= false;
2756 // 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
2757 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
2758 // ??? we do not distinguish between ordinary documents and template versions (often there is no difference in file contents)
2759 // ??? the distinctions between docx, xlsx, and pptx may not be entirely reliable
2760 if (architectures
) *architectures
= NULL
;
2761 if (infodict
) *infodict
= NULL
;
2762 if (hasObjc
) *hasObjc
= false;
2763 if (objcVersion
) *objcVersion
= 0;
2764 if (objcFlags
) *objcFlags
= 0;
2766 Boolean gotPath
= FALSE
;
2767 char path
[CFMaxPathSize
];
2768 gotPath
= CFURLGetFileSystemRepresentation(url
, true, (uint8_t *)path
, CFMaxPathSize
);
2769 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2770 struct stat statBuf
;
2771 #elif DEPLOYMENT_TARGET_WINDOWS
2772 struct _stat statBuf
;
2774 #error Unknown or unspecified DEPLOYMENT_TARGET
2776 if (gotPath
&& stat(path
, &statBuf
) == 0 && (statBuf
.st_mode
& S_IFMT
) == S_IFREG
&& (fd
= open(path
, O_RDONLY
| CF_OPENFLGS
, 0777)) >= 0) {
2777 length
= read(fd
, buffer
, MAGIC_BYTES_TO_READ
);
2778 fileLength
= statBuf
.st_size
;
2783 if (!isFile
&& data
) {
2784 length
= CFDataGetLength(data
);
2785 fileLength
= (off_t
)length
;
2786 bytes
= CFDataGetBytePtr(data
);
2787 if (length
== 0) ext
= "txt";
2791 UInt32 magic
= CFSwapInt32HostToBig(*((UInt32
*)bytes
));
2792 for (i
= 0; !ext
&& i
< NUM_EXTENSIONS
; i
++) {
2793 if (__CFBundleMagicNumbersArray
[i
] == magic
) ext
= __CFBundleExtensionsArray
+ i
* EXTENSION_LENGTH
;
2796 if (0xcafebabe == magic
&& 8 <= length
&& 0 != *((UInt16
*)(bytes
+ 4))) ext
= "class";
2797 #if defined(BINARY_SUPPORT_DYLD)
2798 else if ((int)sizeof(struct mach_header_64
) <= length
) mt
= _CFBundleGrokMachType(fd
, bytes
, length
, extension
? &isX11
: NULL
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2800 if (MH_OBJECT
== mt
) ext
= "o";
2801 else if (MH_EXECUTE
== mt
) ext
= isX11
? "x11app" : "tool";
2802 else if (PEF_FILETYPE
== mt
) ext
= "pef";
2803 else if (MH_CORE
== mt
) ext
= "core";
2804 else if (MH_DYLIB
== mt
) ext
= "dylib";
2805 else if (MH_BUNDLE
== mt
) ext
= "bundle";
2806 #endif /* BINARY_SUPPORT_DYLD */
2807 else if (0x7b5c7274 == magic
&& (6 > length
|| 'f' != bytes
[4])) ext
= NULL
;
2808 else if (0x25504446 == magic
&& (6 > length
|| '-' != bytes
[4])) ext
= NULL
;
2809 else if (0x00010000 == magic
&& (6 > length
|| 0 != bytes
[4])) ext
= NULL
;
2810 else if (0x47494638 == magic
&& (6 > length
|| (0x3761 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4)))))) ext
= NULL
;
2811 else if (0x0000000c == magic
&& (6 > length
|| 0x6a50 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2812 else if (0x2356524d == magic
&& (6 > length
|| 0x4c20 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2813 else if (0x28445746 == magic
&& (6 > length
|| 0x2056 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2814 else if (0x30373037 == magic
&& (6 > length
|| 0x30 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2815 else if (0x41433130 == magic
&& (6 > length
|| 0x31 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2816 else if (0x89504e47 == magic
&& (8 > length
|| 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2817 else if (0x53747566 == magic
&& (8 > length
|| 0x66497420 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2818 else if (0x3026b275 == magic
&& (8 > length
|| 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2819 else if (0x67696d70 == magic
&& (8 > length
|| 0x20786366 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2820 else if (0x424f4d53 == magic
&& (8 > length
|| 0x746f7265 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2821 else if (0x49544f4c == magic
&& (8 > length
|| 0x49544c53 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2822 else if (0x72746664 == magic
&& (8 > length
|| 0x00000000 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2823 else if (0x3d796265 == magic
&& (12 > length
|| 0x67696e20 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || (0x6c696e65 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8))) && 0x70617274 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))))) ext
= NULL
;
2824 else if (0x63616666 == magic
&& (12 > length
|| 0 != bytes
[4] || 0x64657363 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8))))) ext
= NULL
;
2825 else if (0x504b0304 == magic
) ext
= _CFBundleGrokFileTypeForZipFile(fd
, bytes
, length
, fileLength
);
2826 else if (0x25215053 == magic
) {
2827 if (11 <= length
&& 0 == ustrncmp(bytes
+ 4, "-Adobe-", 7)) ext
= "ps";
2828 else if (14 <= length
&& 0 == ustrncmp(bytes
+ 4, "-AdobeFont", 10)) ext
= "pfa";
2830 } else if (0x464f524d == magic
) {
2834 UInt32 iffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2835 if (0x41494646 == iffMagic
) ext
= "aiff";
2836 else if (0x414946 == iffMagic
) ext
= "aifc";
2838 } else if (0x52494646 == magic
) {
2842 UInt32 riffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2843 if (0x57415645 == riffMagic
) ext
= "wav";
2844 else if (0x41564920 == riffMagic
) ext
= "avi";
2846 } else if (0xd0cf11e0 == magic
) {
2848 if (52 <= length
) ext
= _CFBundleGrokFileTypeForOLEFile(fd
, bytes
, length
, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 48)))));
2849 } else if (0x62656769 == magic
) {
2852 if (76 <= length
&& 'n' == bytes
[4] && ' ' == bytes
[5] && isdigit(bytes
[6]) && isdigit(bytes
[7]) && isdigit(bytes
[8]) && ' ' == bytes
[9]) {
2853 CFIndex endOfLine
= 0;
2854 for (i
= 10; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2855 if (10 <= endOfLine
&& endOfLine
+ 62 < length
&& 'M' == bytes
[endOfLine
+ 1] && '\n' == bytes
[endOfLine
+ 62]) {
2857 for (i
= endOfLine
+ 1; ext
&& i
< endOfLine
+ 62; i
++) if (!isprint(bytes
[i
])) ext
= NULL
;
2862 if (extension
&& !ext
) {
2863 UInt16 shortMagic
= CFSwapInt16HostToBig(*((UInt16
*)bytes
));
2864 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";
2865 else if (8 <= length
&& (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "mov";
2866 else if (8 <= length
&& (0x69647363 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "qtif";
2867 else if (8 <= length
&& 0x424f424f == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) ext
= "cwk";
2868 else if (8 <= length
&& 0x62706c69 == magic
&& 0x7374 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && isdigit(bytes
[6]) && isdigit(bytes
[7])) {
2869 for (i
= 8; !ext
&& i
< 128 && i
+ 16 <= length
; i
++) {
2870 if (0 == ustrncmp(bytes
+ i
, "WebMainResource", 15)) ext
= "webarchive";
2872 if (!ext
) ext
= "plist";
2873 } else if (0 == shortMagic
&& 12 <= length
&& 0x66747970 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
2874 // ??? may want more ftyp values
2875 UInt32 ftyp
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2876 if (0x6d703431 == ftyp
|| 0x6d703432 == ftyp
|| 0x69736f6d == ftyp
|| 0x69736f32 == ftyp
) ext
= "mp4";
2877 else if (0x4d344120 == ftyp
) ext
= "m4a";
2878 else if (0x4d344220 == ftyp
) ext
= "m4b";
2879 else if (0x4d345020 == ftyp
) ext
= "m4p";
2880 else if (0x4d345620 == ftyp
|| 0x4d345648 == ftyp
|| 0x4d345650 == ftyp
) ext
= "m4v";
2881 else if (0x3367 == (ftyp
>> 16)) {
2882 UInt16 remainder
= (ftyp
& 0xffff);
2883 if (0x6536 == remainder
|| 0x6537 == remainder
|| 0x6736 == remainder
|| 0x7034 == remainder
|| 0x7035 == remainder
|| 0x7036 == remainder
|| 0x7236 == remainder
|| 0x7336 == remainder
|| 0x7337 == remainder
) ext
= "3gp";
2884 else if (0x3261 == remainder
) ext
= "3g2";
2886 } else if (0x424d == shortMagic
&& 18 <= length
) {
2887 UInt32 btyp
= CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 14)));
2888 if (40 == btyp
|| btyp
== 12 || btyp
== 64 || btyp
== 108 || btyp
== 124) ext
= "bmp";
2889 } else if (20 <= length
&& 0 == ustrncmp(bytes
+ 6, "%!PS-AdobeFont", 14)) ext
= "pfb";
2890 else if (40 <= length
&& 0x42696e48 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 38)))) ext
= "hqx";
2891 else if (128 <= length
&& 0x6d42494e == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 102)))) ext
= "bin";
2892 else if (128 <= length
&& 0 == bytes
[0] && 0 < bytes
[1] && bytes
[1] < 64 && 0 == bytes
[74] && 0 == bytes
[82] && 0 == (fileLength
% 128)) {
2893 UInt32 df
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 83))), rf
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 87))), blocks
= 1 + (df
+ 127) / 128 + (rf
+ 127) / 128;
2894 if (df
< 0x00800000 && rf
< 0x00800000 && 1 < blocks
&& (off_t
)(128 * blocks
) == fileLength
) ext
= "bin";
2895 } else if (265 <= length
&& 0x75737461 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 261))))) ext
= "tar";
2896 else if (0xfeff == shortMagic
|| 0xfffe == shortMagic
) {
2898 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";
2899 } else if (0x1f9d == shortMagic
) ext
= "Z";
2900 else if (0x1f8b == shortMagic
) ext
= "gz";
2901 else if (0x71c7 == shortMagic
|| 0xc771 == shortMagic
) ext
= "cpio";
2902 else if (0xf702 == shortMagic
) ext
= "dvi";
2903 else if (0x01da == shortMagic
&& (0 == bytes
[2] || 1 == bytes
[2]) && (0 < bytes
[3] && 16 > bytes
[3])) ext
= "sgi";
2904 else if (0x2321 == shortMagic
) {
2905 CFIndex endOfLine
= 0, lastSlash
= 0;
2906 for (i
= 2; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2907 if (endOfLine
> 3) {
2908 for (i
= endOfLine
- 1; 0 == lastSlash
&& i
> 1; i
--) if ('/' == bytes
[i
]) lastSlash
= i
;
2909 if (lastSlash
> 0) {
2910 if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "perl", 4)) ext
= "pl";
2911 else if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "python", 6)) ext
= "py";
2912 else if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "ruby", 4)) ext
= "rb";
2916 } else if (0xffd8 == shortMagic
&& 0xff == bytes
[2]) ext
= "jpeg";
2917 else if (0x4657 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swf";
2918 else if (0x4357 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swc";
2919 else if (0x4944 == shortMagic
&& '3' == bytes
[2] && 0x20 > bytes
[3]) ext
= "mp3";
2920 else if (0x425a == shortMagic
&& isdigit(bytes
[2]) && isdigit(bytes
[3])) ext
= "bz";
2921 else if (0x425a == shortMagic
&& 'h' == bytes
[2] && isdigit(bytes
[3]) && 8 <= length
&& (0x31415926 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "bz2";
2922 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2)))) ext
= "tfm";
2925 if (extension
&& !ext
) {
2926 //??? what about MacOSRoman?
2927 if (0xef == bytes
[0] && 0xbb == bytes
[1] && 0xbf == bytes
[2]) { // UTF-8 BOM
2931 for (i
= (hasBOM
? 3 : 0); (isPlain
|| isZero
) && !ext
&& i
< length
&& i
< 512; i
++) {
2933 if (isPlain
&& '<' == c
&& i
+ 14 <= length
&& 0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) ext
= "html";
2934 if (isSpace
&& '<' == c
&& i
+ 14 <= length
) {
2935 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)) {
2937 } else if (0 == ustrncasecmp(bytes
+ i
+ 1, "?xml", 4)) {
2938 for (i
+= 4; !ext
&& i
< 128 && i
+ 20 <= length
; i
++) {
2939 if ('<' == bytes
[i
]) {
2940 if (0 == ustrncasecmp(bytes
+ i
+ 1, "abiword", 7)) ext
= "abw";
2941 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype svg", 12)) ext
= "svg";
2942 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype rdf", 12)) ext
= "rdf";
2943 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype x3d", 12)) ext
= "x3d";
2944 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) ext
= "html";
2945 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype posingfont", 19)) ext
= "sfont";
2946 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype plist", 14)) {
2947 for (i
+= 14; !ext
&& i
< 256 && i
+ 16 <= length
; i
++) {
2948 if (0 == ustrncmp(bytes
+ i
, "WebMainResource", 15)) ext
= "webarchive";
2950 if (!ext
) ext
= "plist";
2954 if (!ext
) ext
= "xml";
2957 if (0 != c
) isZero
= false;
2958 if (isZero
|| 0x7f <= c
|| (0x20 > c
&& !isspace(c
))) isPlain
= false;
2959 if (isZero
|| !isspace(c
)) isSpace
= false;
2963 if (16 <= length
&& 0 == ustrncmp(bytes
, "StartFontMetrics", 16)) ext
= "afm";
2965 } else if (isZero
&& length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= 526) {
2967 if (lseek(fd
, 512, SEEK_SET
) == 512 && read(fd
, buffer
, MAGIC_BYTES_TO_READ
) >= 14) {
2968 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 10)))) ext
= "pict";
2971 if (526 <= length
&& 0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 522)))) ext
= "pict";
2976 if (extension
&& (!ext
|| 0 == strcmp(ext
, "bz2")) && length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= DMG_BYTES_TO_READ
) {
2978 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
) {
2979 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";
2982 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";
2986 if (extension
) *extension
= ext
? CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, ext
, kCFStringEncodingUTF8
, kCFAllocatorNull
) : NULL
;
2987 if (machtype
) *machtype
= mt
;
2988 if (fd
>= 0) close(fd
);
2989 return (ext
? true : false);
2992 CFStringRef
_CFBundleCopyFileTypeForFileURL(CFURLRef url
) {
2993 CFStringRef extension
= NULL
;
2994 (void)_CFBundleGrokFileType(url
, NULL
, &extension
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
2998 CFStringRef
_CFBundleCopyFileTypeForFileData(CFDataRef data
) {
2999 CFStringRef extension
= NULL
;
3000 (void)_CFBundleGrokFileType(NULL
, data
, &extension
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
3004 // returns zero-ref dictionary under GC
3005 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInExecutable(CFURLRef url
) {
3006 CFDictionaryRef result
= NULL
;
3007 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, NULL
, &result
, NULL
, NULL
, NULL
);
3011 __private_extern__ CFArrayRef
_CFBundleCopyArchitecturesForExecutable(CFURLRef url
) {
3012 CFArrayRef result
= NULL
;
3013 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, &result
, NULL
, NULL
, NULL
, NULL
);
3017 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3018 static Boolean
_CFBundleGetObjCImageInfoForExecutable(CFURLRef url
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
3019 Boolean retval
= false;
3020 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, NULL
, NULL
, &retval
, objcVersion
, objcFlags
);
3025 #if defined(BINARY_SUPPORT_DYLD)
3027 __private_extern__ __CFPBinaryType
_CFBundleGrokBinaryType(CFURLRef executableURL
) {
3028 // 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.
3029 __CFPBinaryType result
= executableURL
? __CFBundleUnreadableBinary
: __CFBundleNoBinary
;
3030 UInt32 machtype
= UNKNOWN_FILETYPE
;
3031 if (_CFBundleGrokFileType(executableURL
, NULL
, NULL
, &machtype
, NULL
, NULL
, NULL
, NULL
, NULL
)) {
3034 result
= __CFBundleDYLDExecutableBinary
;
3037 result
= __CFBundleDYLDBundleBinary
;
3040 result
= __CFBundleDYLDFrameworkBinary
;
3043 result
= __CFBundleCFMBinary
;
3050 #endif /* BINARY_SUPPORT_DYLD */
3052 void _CFBundleSetCFMConnectionID(CFBundleRef bundle
, void *connectionID
) {
3053 bundle
->_connectionCookie
= connectionID
;
3054 bundle
->_isLoaded
= true;
3057 static CFStringRef
_CFBundleCopyLastPathComponent(CFBundleRef bundle
) {
3058 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
);
3059 CFStringRef str
= CFURLCopyFileSystemPath(bundleURL
, kCFURLPOSIXPathStyle
);
3060 UniChar buff
[CFMaxPathSize
];
3061 CFIndex buffLen
= CFStringGetLength(str
), startOfLastDir
= 0;
3063 CFRelease(bundleURL
);
3064 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
3065 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
3067 if (buffLen
> 0) startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
3068 return CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
3071 static CFErrorRef
_CFBundleCreateErrorDebug(CFAllocatorRef allocator
, CFBundleRef bundle
, CFIndex code
, CFStringRef debugString
) {
3072 const void *userInfoKeys
[6], *userInfoValues
[6];
3073 CFIndex numKeys
= 0;
3074 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
), absoluteURL
= CFURLCopyAbsoluteURL(bundleURL
), executableURL
= CFBundleCopyExecutableURL(bundle
);
3075 CFBundleRef bdl
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation"));
3076 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
), executablePath
= executableURL
? CFURLCopyFileSystemPath(executableURL
, PLATFORM_PATH_STYLE
) : NULL
, descFormat
= NULL
, desc
= NULL
, reason
= NULL
, suggestion
= NULL
;
3079 CFStringRef name
= (CFStringRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, kCFBundleNameKey
);
3080 name
= name
? (CFStringRef
)CFRetain(name
) : _CFBundleCopyLastPathComponent(bundle
);
3081 if (CFBundleExecutableNotFoundError
== code
) {
3082 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
3083 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl
, CFSTR("The bundle\\U2019s executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
3084 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError");
3085 } else if (CFBundleExecutableNotLoadableError
== code
) {
3086 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
3087 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl
, CFSTR("The bundle\\U2019s executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
3088 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError");
3089 } else if (CFBundleExecutableArchitectureMismatchError
== code
) {
3090 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");
3091 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl
, CFSTR("The bundle doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
3092 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl
, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError");
3093 } else if (CFBundleExecutableRuntimeMismatchError
== code
) {
3094 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");
3095 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl
, CFSTR("The bundle isn\\U2019t compatible with this application."), "NSExecutableRuntimeMismatchError");
3096 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl
, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError");
3097 } else if (CFBundleExecutableLoadError
== code
) {
3098 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");
3099 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl
, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError");
3100 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError");
3101 } else if (CFBundleExecutableLinkError
== code
) {
3102 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded."), "NSExecutableLinkError");
3103 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl
, CFSTR("The bundle couldn\\U2019t be loaded."), "NSExecutableLinkError");
3104 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError");
3107 desc
= CFStringCreateWithFormat(allocator
, NULL
, descFormat
, name
);
3108 CFRelease(descFormat
);
3113 userInfoKeys
[numKeys
] = CFSTR("NSBundlePath");
3114 userInfoValues
[numKeys
] = bundlePath
;
3117 if (executablePath
) {
3118 userInfoKeys
[numKeys
] = CFSTR("NSFilePath");
3119 userInfoValues
[numKeys
] = executablePath
;
3123 userInfoKeys
[numKeys
] = kCFErrorLocalizedDescriptionKey
;
3124 userInfoValues
[numKeys
] = desc
;
3128 userInfoKeys
[numKeys
] = kCFErrorLocalizedFailureReasonKey
;
3129 userInfoValues
[numKeys
] = reason
;
3133 userInfoKeys
[numKeys
] = kCFErrorLocalizedRecoverySuggestionKey
;
3134 userInfoValues
[numKeys
] = suggestion
;
3138 userInfoKeys
[numKeys
] = CFSTR("NSDebugDescription");
3139 userInfoValues
[numKeys
] = debugString
;
3142 error
= CFErrorCreateWithUserInfoKeysAndValues(allocator
, kCFErrorDomainCocoa
, code
, userInfoKeys
, userInfoValues
, numKeys
);
3143 if (bundleURL
) CFRelease(bundleURL
);
3144 if (absoluteURL
) CFRelease(absoluteURL
);
3145 if (executableURL
) CFRelease(executableURL
);
3146 if (bundlePath
) CFRelease(bundlePath
);
3147 if (executablePath
) CFRelease(executablePath
);
3148 if (desc
) CFRelease(desc
);
3149 if (reason
) CFRelease(reason
);
3150 if (suggestion
) CFRelease(suggestion
);
3154 CFErrorRef
_CFBundleCreateError(CFAllocatorRef allocator
, CFBundleRef bundle
, CFIndex code
) {
3155 allocator
= _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator
);
3156 return _CFBundleCreateErrorDebug(allocator
, bundle
, code
, NULL
);
3159 Boolean
_CFBundleLoadExecutableAndReturnError(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
3160 Boolean result
= false;
3161 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
3162 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3164 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3165 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
3166 // make sure we know whether bundle is already loaded or not
3167 #if defined(BINARY_SUPPORT_DLFCN)
3168 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3169 #elif defined(BINARY_SUPPORT_DYLD)
3170 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3171 #endif /* BINARY_SUPPORT_DLFCN */
3172 #if defined(BINARY_SUPPORT_DYLD)
3173 // We might need to figure out what it is
3174 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
3175 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
3176 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3178 #endif /* BINARY_SUPPORT_DYLD */
3179 if (executableURL
) CFRelease(executableURL
);
3181 if (bundle
->_isLoaded
) {
3182 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3183 // Remove from the scheduled unload set if we are there.
3184 __CFSpinLock(&CFBundleGlobalDataLock
);
3185 #if defined(AVOID_WEAK_COLLECTIONS)
3186 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3187 #else /* AVOID_WEAK_COLLECTIONS */
3188 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3189 #endif /* AVOID_WEAK_COLLECTIONS */
3190 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3194 // Unload bundles scheduled for unloading
3195 if (!_scheduledBundlesAreUnloading
) {
3196 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3197 _CFBundleUnloadScheduledBundles();
3198 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3201 if (bundle
->_isLoaded
) {
3202 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3203 // Remove from the scheduled unload set if we are there.
3204 __CFSpinLock(&CFBundleGlobalDataLock
);
3205 #if defined(AVOID_WEAK_COLLECTIONS)
3206 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3207 #else /* AVOID_WEAK_COLLECTIONS */
3208 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3209 #endif /* AVOID_WEAK_COLLECTIONS */
3210 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3213 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3215 switch (bundle
->_binaryType
) {
3216 #if defined(BINARY_SUPPORT_DLFCN)
3217 case __CFBundleUnreadableBinary
:
3218 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3220 #endif /* BINARY_SUPPORT_DLFCN */
3221 #if defined(BINARY_SUPPORT_DYLD)
3222 case __CFBundleDYLDBundleBinary
:
3223 #if defined(BINARY_SUPPORT_DLFCN)
3224 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3225 #else /* BINARY_SUPPORT_DLFCN */
3226 result
= _CFBundleDYLDLoadBundle(bundle
, forceGlobal
, subError
);
3227 #endif /* BINARY_SUPPORT_DLFCN */
3229 case __CFBundleDYLDFrameworkBinary
:
3230 #if defined(BINARY_SUPPORT_DLFCN)
3231 result
= _CFBundleDlfcnLoadFramework(bundle
, subError
);
3232 #else /* BINARY_SUPPORT_DLFCN */
3233 result
= _CFBundleDYLDLoadFramework(bundle
, subError
);
3234 #endif /* BINARY_SUPPORT_DLFCN */
3236 case __CFBundleDYLDExecutableBinary
:
3238 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3240 CFLog(__kCFLogBundle
, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle
);
3243 #endif /* BINARY_SUPPORT_DYLD */
3244 #if defined(BINARY_SUPPORT_DLFCN)
3245 case __CFBundleUnknownBinary
:
3246 case __CFBundleELFBinary
:
3247 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3249 #endif /* BINARY_SUPPORT_DLFCN */
3250 #if defined(BINARY_SUPPORT_DLL)
3251 case __CFBundleDLLBinary
:
3252 result
= _CFBundleDLLLoad(bundle
, subError
);
3254 #endif /* BINARY_SUPPORT_DLL */
3255 case __CFBundleNoBinary
:
3257 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
3259 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for %@"), bundle
);
3264 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3266 CFLog(__kCFLogBundle
, CFSTR("Cannot recognize type of executable for %@"), bundle
);
3270 if (result
&& bundle
->_plugInData
._isPlugIn
) _CFBundlePlugInLoaded(bundle
);
3271 if (!result
&& error
) *error
= localError
;
3275 Boolean
CFBundleLoadExecutableAndReturnError(CFBundleRef bundle
, CFErrorRef
*error
) {
3276 return _CFBundleLoadExecutableAndReturnError(bundle
, false, error
);
3279 Boolean
CFBundleLoadExecutable(CFBundleRef bundle
) {
3280 return _CFBundleLoadExecutableAndReturnError(bundle
, false, NULL
);
3283 Boolean
CFBundlePreflightExecutable(CFBundleRef bundle
, CFErrorRef
*error
) {
3284 Boolean result
= false;
3285 CFErrorRef localError
= NULL
;
3286 #if defined(BINARY_SUPPORT_DLFCN)
3287 CFErrorRef
*subError
= (error
? &localError
: NULL
);
3289 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3291 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3292 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
3293 // make sure we know whether bundle is already loaded or not
3294 #if defined(BINARY_SUPPORT_DLFCN)
3295 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3296 #elif defined(BINARY_SUPPORT_DYLD)
3297 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3298 #endif /* BINARY_SUPPORT_DLFCN */
3299 #if defined(BINARY_SUPPORT_DYLD)
3300 // We might need to figure out what it is
3301 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
3302 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
3303 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3305 #endif /* BINARY_SUPPORT_DYLD */
3306 if (executableURL
) CFRelease(executableURL
);
3308 if (bundle
->_isLoaded
) {
3309 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3312 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3314 switch (bundle
->_binaryType
) {
3315 #if defined(BINARY_SUPPORT_DLFCN)
3316 case __CFBundleUnreadableBinary
:
3317 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3319 #endif /* BINARY_SUPPORT_DLFCN */
3320 #if defined(BINARY_SUPPORT_DYLD)
3321 case __CFBundleDYLDBundleBinary
:
3323 #if defined(BINARY_SUPPORT_DLFCN)
3324 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3325 #endif /* BINARY_SUPPORT_DLFCN */
3327 case __CFBundleDYLDFrameworkBinary
:
3329 #if defined(BINARY_SUPPORT_DLFCN)
3330 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3331 #endif /* BINARY_SUPPORT_DLFCN */
3333 case __CFBundleDYLDExecutableBinary
:
3334 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3336 #endif /* BINARY_SUPPORT_DYLD */
3337 #if defined(BINARY_SUPPORT_DLFCN)
3338 case __CFBundleUnknownBinary
:
3339 case __CFBundleELFBinary
:
3340 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3342 #endif /* BINARY_SUPPORT_DLFCN */
3343 #if defined(BINARY_SUPPORT_DLL)
3344 case __CFBundleDLLBinary
:
3347 #endif /* BINARY_SUPPORT_DLL */
3348 case __CFBundleNoBinary
:
3349 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
3352 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3355 if (!result
&& error
) *error
= localError
;
3359 CFArrayRef
CFBundleCopyExecutableArchitectures(CFBundleRef bundle
) {
3360 CFArrayRef result
= NULL
;
3361 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3362 if (executableURL
) {
3363 result
= _CFBundleCopyArchitecturesForExecutable(executableURL
);
3364 CFRelease(executableURL
);
3369 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3370 static Boolean
_CFBundleGetObjCImageInfo(CFBundleRef bundle
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
3371 Boolean retval
= false;
3372 uint32_t localVersion
= 0, localFlags
= 0;
3373 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3374 if (executableURL
) {
3375 retval
= _CFBundleGetObjCImageInfoForExecutable(executableURL
, &localVersion
, &localFlags
);
3376 CFRelease(executableURL
);
3378 if (objcVersion
) *objcVersion
= localVersion
;
3379 if (objcFlags
) *objcFlags
= localFlags
;
3384 void CFBundleUnloadExecutable(CFBundleRef bundle
) {
3385 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
3386 if (!_scheduledBundlesAreUnloading
) _CFBundleUnloadScheduledBundles();
3388 if (!bundle
->_isLoaded
) return;
3390 // Remove from the scheduled unload set if we are there.
3391 if (!_scheduledBundlesAreUnloading
) __CFSpinLock(&CFBundleGlobalDataLock
);
3392 #if defined(AVOID_WEAK_COLLECTIONS)
3393 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3394 #else /* AVOID_WEAK_COLLECTIONS */
3395 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3396 #endif /* AVOID_WEAK_COLLECTIONS */
3397 if (!_scheduledBundlesAreUnloading
) __CFSpinUnlock(&CFBundleGlobalDataLock
);
3399 // Give the plugIn code a chance to realize this...
3400 _CFPlugInWillUnload(bundle
);
3402 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3403 if (!bundle
->_isLoaded
) {
3404 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3407 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3409 switch (bundle
->_binaryType
) {
3410 #if defined(BINARY_SUPPORT_DYLD)
3411 case __CFBundleDYLDBundleBinary
:
3412 #if defined(BINARY_SUPPORT_DLFCN)
3413 if (bundle
->_handleCookie
) _CFBundleDlfcnUnload(bundle
);
3414 #else /* BINARY_SUPPORT_DLFCN */
3415 _CFBundleDYLDUnloadBundle(bundle
);
3416 #endif /* BINARY_SUPPORT_DLFCN */
3418 case __CFBundleDYLDFrameworkBinary
:
3419 #if defined(BINARY_SUPPORT_DLFCN)
3420 if (bundle
->_handleCookie
&& _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard
)) _CFBundleDlfcnUnload(bundle
);
3421 #endif /* BINARY_SUPPORT_DLFCN */
3423 #endif /* BINARY_SUPPORT_DYLD */
3424 #if defined(BINARY_SUPPORT_DLL)
3425 case __CFBundleDLLBinary
:
3426 _CFBundleDLLUnload(bundle
);
3428 #endif /* BINARY_SUPPORT_DLL */
3430 #if defined(BINARY_SUPPORT_DLFCN)
3431 if (bundle
->_handleCookie
) _CFBundleDlfcnUnload(bundle
);
3432 #endif /* BINARY_SUPPORT_DLFCN */
3435 if (!bundle
->_isLoaded
&& bundle
->_glueDict
) {
3436 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
3437 CFRelease(bundle
->_glueDict
);
3438 bundle
->_glueDict
= NULL
;
3442 #if defined(AVOID_WEAK_COLLECTIONS)
3444 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
3445 __CFSpinLock(&CFBundleGlobalDataLock
);
3446 if (!_bundlesToUnload
) {
3447 CFSetCallBacks nonRetainingCallbacks
= kCFTypeSetCallBacks
;
3448 nonRetainingCallbacks
.retain
= NULL
;
3449 nonRetainingCallbacks
.release
= NULL
;
3450 _bundlesToUnload
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingCallbacks
);
3452 CFSetAddValue(_bundlesToUnload
, bundle
);
3453 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3456 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
3457 __CFSpinLock(&CFBundleGlobalDataLock
);
3458 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3459 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3462 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
3463 __CFSpinLock(&CFBundleGlobalDataLock
);
3464 if (_bundlesToUnload
) {
3465 CFIndex i
, c
= CFSetGetCount(_bundlesToUnload
);
3467 CFBundleRef
*unloadThese
= (CFBundleRef
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(CFBundleRef
) * c
, 0);
3468 CFSetGetValues(_bundlesToUnload
, (const void **)unloadThese
);
3469 _scheduledBundlesAreUnloading
= true;
3470 for (i
= 0; i
< c
; i
++) {
3471 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
3472 CFBundleUnloadExecutable(unloadThese
[i
]);
3474 _scheduledBundlesAreUnloading
= false;
3475 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, unloadThese
);
3478 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3481 #else /* AVOID_WEAK_COLLECTIONS */
3483 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
3484 __CFSpinLock(&CFBundleGlobalDataLock
);
3485 if (!_bundlesToUnload
) _bundlesToUnload
= [[__CFHashTable alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
3486 [_bundlesToUnload addObject
:(id
)bundle
];
3487 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3490 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
3491 __CFSpinLock(&CFBundleGlobalDataLock
);
3492 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3493 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3496 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
3497 __CFSpinLock(&CFBundleGlobalDataLock
);
3498 if (_bundlesToUnload
&& [_bundlesToUnload count
] > 0) {
3500 CFMutableArrayRef unloadThese
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3501 for (id value in _bundlesToUnload
) CFArrayAppendValue(unloadThese
, value
);
3502 c
= CFArrayGetCount(unloadThese
);
3504 _scheduledBundlesAreUnloading
= true;
3505 for (i
= 0; i
< c
; i
++) {
3506 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
3507 CFBundleUnloadExecutable((CFBundleRef
)CFArrayGetValueAtIndex(unloadThese
, i
));
3509 _scheduledBundlesAreUnloading
= false;
3511 CFRelease(unloadThese
);
3513 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3516 #endif /* AVOID_WEAK_COLLECTIONS */
3518 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
3520 // Load if necessary
3521 if (!bundle
->_isLoaded
) {
3522 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
3525 switch (bundle
->_binaryType
) {
3526 #if defined(BINARY_SUPPORT_DYLD)
3527 case __CFBundleDYLDBundleBinary
:
3528 case __CFBundleDYLDFrameworkBinary
:
3529 case __CFBundleDYLDExecutableBinary
:
3530 #if defined(BINARY_SUPPORT_DLFCN)
3531 if (bundle
->_handleCookie
) return _CFBundleDlfcnGetSymbolByName(bundle
, funcName
);
3532 #else /* BINARY_SUPPORT_DLFCN */
3533 return _CFBundleDYLDGetSymbolByName(bundle
, funcName
);
3534 #endif /* BINARY_SUPPORT_DLFCN */
3536 #endif /* BINARY_SUPPORT_DYLD */
3537 #if defined(BINARY_SUPPORT_DLL)
3538 case __CFBundleDLLBinary
:
3539 tvp
= _CFBundleDLLGetSymbolByName(bundle
, funcName
);
3541 #endif /* BINARY_SUPPORT_DLL */
3543 #if defined(BINARY_SUPPORT_DLFCN)
3544 if (bundle
->_handleCookie
) return _CFBundleDlfcnGetSymbolByName(bundle
, funcName
);
3545 #endif /* BINARY_SUPPORT_DLFCN */
3551 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
3553 // Load if necessary
3554 if (!bundle
->_isLoaded
) {
3555 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
3557 #if defined (BINARY_SUPPORT_DYLD) || defined (BINARY_SUPPORT_DLFCN)
3558 switch (bundle
->_binaryType
) {
3559 #if defined(BINARY_SUPPORT_DYLD)
3560 case __CFBundleDYLDBundleBinary
:
3561 case __CFBundleDYLDFrameworkBinary
:
3562 case __CFBundleDYLDExecutableBinary
:
3563 #if defined(BINARY_SUPPORT_DLFCN)
3564 if (bundle
->_handleCookie
) fp
= _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, funcName
, true);
3565 #else /* BINARY_SUPPORT_DLFCN */
3566 fp
= _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, funcName
, true);
3567 #endif /* BINARY_SUPPORT_DLFCN */
3569 #endif /* BINARY_SUPPORT_DYLD */
3571 #if defined(BINARY_SUPPORT_DLFCN)
3572 if (bundle
->_handleCookie
) fp
= _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, funcName
, true);
3573 #endif /* BINARY_SUPPORT_DLFCN */
3576 #endif /* BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */
3580 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
3585 c
= CFArrayGetCount(functionNames
);
3586 for (i
= 0; i
< c
; i
++) ftbl
[i
] = CFBundleGetFunctionPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(functionNames
, i
));
3589 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
3594 c
= CFArrayGetCount(functionNames
);
3595 for (i
= 0; i
< c
; i
++) ftbl
[i
] = _CFBundleGetCFMFunctionPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(functionNames
, i
));
3598 void *CFBundleGetDataPointerForName(CFBundleRef bundle
, CFStringRef symbolName
) {
3600 // Load if necessary
3601 if (!bundle
->_isLoaded
&& !CFBundleLoadExecutable(bundle
)) return NULL
;
3603 switch (bundle
->_binaryType
) {
3604 #if defined(BINARY_SUPPORT_DYLD)
3605 case __CFBundleDYLDBundleBinary
:
3606 case __CFBundleDYLDFrameworkBinary
:
3607 case __CFBundleDYLDExecutableBinary
:
3608 #if defined(BINARY_SUPPORT_DLFCN)
3609 if (bundle
->_handleCookie
) dp
= _CFBundleDlfcnGetSymbolByName(bundle
, symbolName
);
3610 #else /* BINARY_SUPPORT_DLFCN */
3611 dp
= _CFBundleDYLDGetSymbolByName(bundle
, symbolName
);
3612 #endif /* BINARY_SUPPORT_DLFCN */
3614 #endif /* BINARY_SUPPORT_DYLD */
3615 #if defined(BINARY_SUPPORT_DLL)
3616 case __CFBundleDLLBinary
:
3617 /* MF:!!! Handle this someday */
3619 #endif /* BINARY_SUPPORT_DLL */
3621 #if defined(BINARY_SUPPORT_DLFCN)
3622 if (bundle
->_handleCookie
) dp
= _CFBundleDlfcnGetSymbolByName(bundle
, symbolName
);
3623 #endif /* BINARY_SUPPORT_DLFCN */
3629 void CFBundleGetDataPointersForNames(CFBundleRef bundle
, CFArrayRef symbolNames
, void *stbl
[]) {
3634 c
= CFArrayGetCount(symbolNames
);
3635 for (i
= 0; i
< c
; i
++) stbl
[i
] = CFBundleGetDataPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(symbolNames
, i
));
3638 __private_extern__ _CFResourceData
*__CFBundleGetResourceData(CFBundleRef bundle
) {
3639 return &(bundle
->_resourceData
);
3642 CFPlugInRef
CFBundleGetPlugIn(CFBundleRef bundle
) {
3643 return (bundle
->_plugInData
._isPlugIn
) ? (CFPlugInRef
)bundle
: NULL
;
3646 __private_extern__ _CFPlugInData
*__CFBundleGetPlugInData(CFBundleRef bundle
) {
3647 return &(bundle
->_plugInData
);
3650 __private_extern__ Boolean
_CFBundleCouldBeBundle(CFURLRef url
) {
3651 Boolean result
= false;
3654 if (_CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) result
= (exists
&& (mode
& S_IFMT
) == S_IFDIR
&& (mode
& 0444) != 0);
3658 #define LENGTH_OF(A) (sizeof(A) / sizeof(A[0]))
3660 //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/
3661 static CFURLRef
__CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath
, Boolean permissive
) {
3662 // 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.
3663 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3664 #elif DEPLOYMENT_TARGET_WINDOWS
3665 UniChar executablesToFrameworksPathBuff
[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3666 UniChar executablesToPrivateFrameworksPathBuff
[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3667 UniChar frameworksExtension
[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
3669 #error Unknown or unspecified DEPLOYMENT_TARGET
3671 UniChar pathBuff
[CFMaxPathSize
] = {0};
3672 UniChar nameBuff
[CFMaxPathSize
] = {0};
3673 CFIndex length
, nameStart
, nameLength
, savedLength
;
3674 CFMutableStringRef cheapStr
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, NULL
);
3675 CFURLRef bundleURL
= NULL
;
3677 length
= CFStringGetLength(executablePath
);
3678 if (length
> CFMaxPathSize
) length
= CFMaxPathSize
;
3679 CFStringGetCharacters(executablePath
, CFRangeMake(0, length
), pathBuff
);
3681 // Save the name in nameBuff
3682 length
= _CFLengthAfterDeletingPathExtension(pathBuff
, length
);
3683 nameStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3684 nameLength
= length
- nameStart
;
3685 memmove(nameBuff
, &(pathBuff
[nameStart
]), nameLength
* sizeof(UniChar
));
3687 // Strip the name from pathBuff
3688 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3689 savedLength
= length
;
3691 #if DEPLOYMENT_TARGET_WINDOWS
3692 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
3693 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToFrameworksPathBuff
, LENGTH_OF(executablesToFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3694 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3695 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3696 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3697 CFRelease(bundleURL
);
3701 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
3703 length
= savedLength
;
3704 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToPrivateFrameworksPathBuff
, LENGTH_OF(executablesToPrivateFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3705 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3706 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3707 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3708 CFRelease(bundleURL
);
3714 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3716 #error Unknown or unspecified DEPLOYMENT_TARGET
3718 // * Finally check the executable inside the framework case.
3720 length
= savedLength
;
3721 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
3723 CFStringRef name
= permissive
? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, (const char *)nameBuff
);
3725 while (length
> 0) {
3726 CFIndex curStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3727 if (curStart
>= length
) break;
3728 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[curStart
]), length
- curStart
, CFMaxPathSize
- curStart
);
3729 if (!permissive
&& CFEqual(cheapStr
, _CFBundleResourcesDirectoryName
)) break;
3730 if (CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName1
) || CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName2
)) {
3732 CFIndex fmwkStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3733 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[fmwkStart
]), length
- fmwkStart
, CFMaxPathSize
- fmwkStart
);
3735 if (permissive
|| CFStringHasPrefix(cheapStr
, name
)) {
3736 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3737 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3739 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3740 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3741 CFRelease(bundleURL
);
3746 } else if (CFStringHasSuffix(cheapStr
, CFSTR(".framework")) && (permissive
|| CFStringHasPrefix(cheapStr
, name
))) {
3747 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3748 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3749 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3750 CFRelease(bundleURL
);
3755 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3757 if (!permissive
) CFRelease(name
);
3759 CFStringSetExternalCharactersNoCopy(cheapStr
, NULL
, 0, 0);
3760 CFRelease(cheapStr
);
3765 //SPI version; separated out to minimize linkage changes
3766 CFURLRef
_CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath
) {
3767 return __CFBundleCopyFrameworkURLForExecutablePath(executablePath
, false);
3770 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
) {
3771 // This finds the bundle for the given path.
3772 // 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.
3774 CFURLRef curURL
= __CFBundleCopyFrameworkURLForExecutablePath(imagePath
, true);
3775 Boolean createdBundle
= false;
3778 bundle
= _CFBundleCopyBundleForURL(curURL
, true);
3780 // Ensure bundle exists by creating it if necessary
3781 // NB doFinalProcessing must be false here, see below
3782 bundle
= _CFBundleCreate(kCFAllocatorSystemDefault
, curURL
, true, false);
3783 createdBundle
= true;
3786 __CFSpinLock(&(bundle
->_bundleLoadingLock
));
3787 if (!bundle
->_isLoaded
) {
3788 // 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)
3789 #if defined(BINARY_SUPPORT_DLFCN)
3790 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3791 #elif defined(BINARY_SUPPORT_DYLD)
3792 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3793 #endif /* BINARY_SUPPORT_DLFCN */
3794 #if defined(BINARY_SUPPORT_DYLD)
3795 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
3796 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3797 #endif /* BINARY_SUPPORT_DYLD */
3799 if (!bundle
->_isLoaded
) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle
, bundle
->_handleCookie
, bundle
->_imageCookie
, bundle
->_connectionCookie
);
3800 #endif /* LOG_BUNDLE_LOAD */
3801 bundle
->_isLoaded
= true;
3803 __CFSpinUnlock(&(bundle
->_bundleLoadingLock
));
3804 if (createdBundle
) {
3805 // Perform delayed final processing steps.
3806 // This must be done after _isLoaded has been set, for security reasons (3624341).
3807 _CFBundleCheckWorkarounds(bundle
);
3808 if (_CFBundleNeedsInitPlugIn(bundle
)) {
3809 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3810 _CFBundleInitPlugIn(bundle
);
3811 __CFSpinLock(&CFBundleGlobalDataLock
);
3814 // Release the bundle if we did not create it here
3822 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
) {
3823 // This finds the bundles for the given paths.
3824 // 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).
3825 CFIndex i
, imagePathCount
= CFArrayGetCount(imagePaths
);
3826 for (i
= 0; i
< imagePathCount
; i
++) _CFBundleEnsureBundleExistsForImagePath((CFStringRef
)CFArrayGetValueAtIndex(imagePaths
, i
));
3829 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
) {
3830 CFArrayRef imagePaths
= NULL
;
3831 // Tickle the main bundle into existence
3832 (void)_CFBundleGetMainBundleAlreadyLocked();
3833 #if defined(BINARY_SUPPORT_DYLD)
3834 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsForHint(hint
);
3835 #endif /* BINARY_SUPPORT_DYLD */
3837 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
3838 CFRelease(imagePaths
);
3842 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
3843 // 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.
3844 CFArrayRef imagePaths
= NULL
;
3845 // Tickle the main bundle into existence
3846 (void)_CFBundleGetMainBundleAlreadyLocked();
3848 #if defined(BINARY_SUPPORT_DLL)
3849 // Dont know how to find static bundles for DLLs
3850 #endif /* BINARY_SUPPORT_DLL */
3852 #if defined(BINARY_SUPPORT_DYLD)
3853 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsIfChanged();
3854 #endif /* BINARY_SUPPORT_DYLD */
3856 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
3857 CFRelease(imagePaths
);
3861 CFArrayRef
CFBundleGetAllBundles(void) {
3862 // To answer this properly, we have to have created the static bundles!
3863 #if !defined(AVOID_WEAK_COLLECTIONS)
3864 static CFMutableArrayRef externalAllBundles
= NULL
;
3865 #endif /* AVOID_WEAK_COLLECTIONS */
3867 __CFSpinLock(&CFBundleGlobalDataLock
);
3868 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
3869 #if defined(AVOID_WEAK_COLLECTIONS)
3870 bundles
= _allBundles
;
3871 #else /* AVOID_WEAK_COLLECTIONS */
3872 if (!externalAllBundles
) {
3873 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
3874 nonRetainingArrayCallbacks
.retain
= NULL
;
3875 nonRetainingArrayCallbacks
.release
= NULL
;
3876 externalAllBundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
3878 CFArrayRemoveAllValues(externalAllBundles
);
3879 for (id value in _allBundles
) CFArrayAppendValue(externalAllBundles
, value
);
3880 bundles
= externalAllBundles
;
3881 #endif /* AVOID_WEAK_COLLECTIONS */
3882 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3886 CF_EXPORT CFArrayRef
_CFBundleCopyAllBundles(void) {
3887 // To answer this properly, we have to have created the static bundles!
3888 __CFSpinLock(&CFBundleGlobalDataLock
);
3889 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
3890 #if defined(AVOID_WEAK_COLLECTIONS)
3891 CFArrayRef bundles
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, _allBundles
);
3892 #else /* AVOID_WEAK_COLLECTIONS */
3893 CFMutableArrayRef bundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
3894 for (id value in _allBundles
) CFArrayAppendValue(bundles
, value
);
3895 #endif /* AVOID_WEAK_COLLECTIONS */
3896 __CFSpinUnlock(&CFBundleGlobalDataLock
);
3900 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle
) {
3901 return bundle
->_version
;
3904 CF_EXPORT CFURLRef
_CFBundleCopyInfoPlistURL(CFBundleRef bundle
) {
3905 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
3906 CFURLRef url
= (CFURLRef
)CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
);
3907 if (!url
) url
= (CFURLRef
)CFDictionaryGetValue(infoDict
, _kCFBundleRawInfoPlistURLKey
);
3908 return (url
? (CFURLRef
)CFRetain(url
) : NULL
);
3911 CF_EXPORT CFURLRef
_CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
3912 return CFBundleCopyPrivateFrameworksURL(bundle
);
3915 CF_EXPORT CFURLRef
CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
3916 CFURLRef result
= NULL
;
3918 if (1 == bundle
->_version
) {
3919 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase1
, bundle
->_url
);
3920 } else if (2 == bundle
->_version
) {
3921 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase2
, bundle
->_url
);
3923 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase0
, bundle
->_url
);
3928 CF_EXPORT CFURLRef
_CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
3929 return CFBundleCopySharedFrameworksURL(bundle
);
3932 CF_EXPORT CFURLRef
CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
3933 CFURLRef result
= NULL
;
3935 if (1 == bundle
->_version
) {
3936 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase1
, bundle
->_url
);
3937 } else if (2 == bundle
->_version
) {
3938 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase2
, bundle
->_url
);
3940 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase0
, bundle
->_url
);
3945 CF_EXPORT CFURLRef
_CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
3946 return CFBundleCopySharedSupportURL(bundle
);
3949 CF_EXPORT CFURLRef
CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
3950 CFURLRef result
= NULL
;
3952 if (1 == bundle
->_version
) {
3953 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase1
, bundle
->_url
);
3954 } else if (2 == bundle
->_version
) {
3955 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase2
, bundle
->_url
);
3957 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase0
, bundle
->_url
);
3962 __private_extern__ CFURLRef
_CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
3963 return CFBundleCopyBuiltInPlugInsURL(bundle
);
3966 CF_EXPORT CFURLRef
CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
3967 CFURLRef result
= NULL
, alternateResult
= NULL
;
3969 CFAllocatorRef alloc
= CFGetAllocator(bundle
);
3970 if (1 == bundle
->_version
) {
3971 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase1
, bundle
->_url
);
3972 } else if (2 == bundle
->_version
) {
3973 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase2
, bundle
->_url
);
3975 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase0
, bundle
->_url
);
3977 if (!result
|| !_urlExists(result
)) {
3978 if (1 == bundle
->_version
) {
3979 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase1
, bundle
->_url
);
3980 } else if (2 == bundle
->_version
) {
3981 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase2
, bundle
->_url
);
3983 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase0
, bundle
->_url
);
3985 if (alternateResult
&& _urlExists(alternateResult
)) {
3986 if (result
) CFRelease(result
);
3987 result
= alternateResult
;
3989 if (alternateResult
) CFRelease(alternateResult
);
3995 #if defined(BINARY_SUPPORT_DYLD)
3997 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint
) {
3998 uint32_t i
, numImages
= _dyld_image_count();
3999 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
4000 CFRange range
= CFRangeMake(0, CFStringGetLength(hint
)), altRange
= CFRangeMake(0, 0), testRange
= CFRangeMake(0, 0);
4001 const char *processPath
= _CFProcessPath();
4002 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
4004 if (range
.length
> 14) {
4005 // handle some common variations on framework bundle identifiers
4006 if (CFStringFindWithOptions(hint
, CFSTR(".framework"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4007 // identifier has .framework appended
4008 altRange
.length
= testRange
.location
;
4009 } else if (CFStringFindWithOptions(hint
, CFSTR("framework"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4010 // identifier has Framework appended
4011 altRange
.length
= testRange
.location
;
4012 } else if (CFStringFindWithOptions(hint
, CFSTR("fw"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4013 // identifier has FW appended
4014 altRange
.length
= testRange
.location
;
4017 for (i
= 0; i
< numImages
; i
++) {
4018 const char *curName
= _dyld_get_image_name(i
), *lastComponent
= NULL
;
4019 if (curName
&& (!processPath
|| 0 != strcmp(curName
, processPath
)) && mhp
!= (void *)_dyld_get_image_header(i
)) lastComponent
= strrchr(curName
, '/');
4020 if (lastComponent
) {
4021 CFStringRef str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, lastComponent
+ 1);
4023 if (CFStringFindWithOptions(hint
, str
, range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
) || (altRange
.length
> 0 && CFStringFindWithOptions(hint
, str
, altRange
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
))) {
4024 CFStringRef curStr
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, curName
);
4026 CFArrayAppendValue(result
, curStr
);
4037 static char *_cleanedPathForPath(const char *curName
) {
4038 char *thePath
= strdup(curName
);
4040 // We are going to process the buffer replacing all "/./" and "//" with "/"
4041 CFIndex srcIndex
= 0, dstIndex
= 0;
4042 CFIndex len
= strlen(thePath
);
4043 for (srcIndex
=0; srcIndex
<len
; srcIndex
++) {
4044 thePath
[dstIndex
] = thePath
[srcIndex
];
4046 while (srcIndex
< len
-1 && thePath
[srcIndex
] == '/' && (thePath
[srcIndex
+1] == '/' || (thePath
[srcIndex
+1] == '.' && srcIndex
< len
-2 && thePath
[srcIndex
+2] == '/'))) srcIndex
+= (thePath
[srcIndex
+1] == '/' ? 1 : 2);
4048 thePath
[dstIndex
] = 0;
4053 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
4054 // 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.
4055 uint32_t i
, numImages
= _dyld_image_count();
4056 CFMutableArrayRef result
= NULL
;
4057 static uint32_t _cachedDYLDImageCount
= -1;
4059 if (numImages
!= _cachedDYLDImageCount
) {
4060 const char *curName
;
4061 char *cleanedCurName
= NULL
;
4063 const char *processPath
= _CFProcessPath();
4064 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
4066 result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
4068 for (i
= 0; i
< numImages
; i
++) {
4069 curName
= _dyld_get_image_name(i
);
4070 if (curName
&& i
== 0) cleanedCurName
= _cleanedPathForPath(curName
);
4071 if (curName
&& (!processPath
|| 0 != strcmp(curName
, processPath
)) && (!processPath
|| !cleanedCurName
|| 0 != strcmp(cleanedCurName
, processPath
)) && mhp
!= (void *)_dyld_get_image_header(i
)) {
4072 curStr
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, curName
);
4074 CFArrayAppendValue(result
, curStr
);
4078 if (cleanedCurName
) {
4079 free(cleanedCurName
);
4080 cleanedCurName
= NULL
;
4083 _cachedDYLDImageCount
= numImages
;
4088 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
) {
4089 CFStringRef result
= NULL
;
4090 #if defined(USE_DYLD_PRIV)
4091 const char *name
= dyld_image_path_containing_address(p
);
4092 if (name
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, name
);
4093 #else /* USE_DYLD_PRIV */
4095 uint32_t i
, j
, n
= _dyld_image_count();
4096 Boolean foundit
= false;
4099 #define MACH_HEADER_TYPE struct mach_header_64
4100 #define MACH_SEGMENT_CMD_TYPE struct segment_command_64
4101 #define MACH_SEGMENT_FLAVOR LC_SEGMENT_64
4103 #define MACH_HEADER_TYPE struct mach_header
4104 #define MACH_SEGMENT_CMD_TYPE struct segment_command
4105 #define MACH_SEGMENT_FLAVOR LC_SEGMENT
4107 for (i
= 0; !foundit
&& i
< n
; i
++) {
4108 const MACH_HEADER_TYPE
*mh
= (const MACH_HEADER_TYPE
*)_dyld_get_image_header(i
);
4109 uintptr_t addr
= (uintptr_t)p
- _dyld_get_image_vmaddr_slide(i
);
4111 struct load_command
*lc
= (struct load_command
*)((char *)mh
+ sizeof(MACH_HEADER_TYPE
));
4112 for (j
= 0; !foundit
&& j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
)) {
4113 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
) {
4115 name
= _dyld_get_image_name(i
);
4116 if (name
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, name
);
4121 #undef MACH_HEADER_TYPE
4122 #undef MACH_SEGMENT_CMD_TYPE
4123 #undef MACH_SEGMENT_FLAVOR
4125 #endif /* USE_DYLD_PRIV */
4127 printf("dyld image path for pointer %p is %p\n", p
, result
);
4128 #endif /* LOG_BUNDLE_LOAD */
4132 #if !defined(BINARY_SUPPORT_DLFCN)
4134 static const void *__CFBundleDYLDFindImage(char *buff
) {
4135 const void *header
= NULL
;
4136 uint32_t i
, numImages
= _dyld_image_count(), numMatches
= 0;
4137 const char *curName
, *p
, *q
;
4139 for (i
= 0; !header
&& i
< numImages
; i
++) {
4140 curName
= _dyld_get_image_name(i
);
4141 if (curName
&& 0 == strncmp(curName
, buff
, CFMaxPathSize
)) {
4142 header
= _dyld_get_image_header(i
);
4147 for (i
= 0; i
< numImages
; i
++) {
4148 curName
= _dyld_get_image_name(i
);
4150 for (p
= buff
, q
= curName
; *p
&& *q
&& (q
- curName
< CFMaxPathSize
); p
++, q
++) {
4151 if (*p
!= *q
&& (q
- curName
> 11) && 0 == strncmp(q
- 11, ".framework/Versions/", 20) && *(q
+ 9) && '/' == *(q
+ 10)) q
+= 11;
4152 else if (*p
!= *q
&& (q
- curName
> 12) && 0 == strncmp(q
- 12, ".framework/Versions/", 20) && *(q
+ 8) && '/' == *(q
+ 9)) q
+= 10;
4153 if (*p
!= *q
) break;
4156 header
= _dyld_get_image_header(i
);
4162 return (numMatches
== 1) ? header
: NULL
;
4165 __private_extern__ Boolean
_CFBundleDYLDCheckLoaded(CFBundleRef bundle
) {
4166 if (!bundle
->_isLoaded
) {
4167 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4168 char buff
[CFMaxPathSize
];
4170 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4171 const void *header
= __CFBundleDYLDFindImage(buff
);
4173 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
4174 if (!bundle
->_imageCookie
) {
4175 bundle
->_imageCookie
= header
;
4177 printf("dyld check load bundle %p, find %s getting image %p\n", bundle
, buff
, bundle
->_imageCookie
);
4178 #endif /* LOG_BUNDLE_LOAD */
4180 bundle
->_isLoaded
= true;
4183 printf("dyld check load bundle %p, find %s no image\n", bundle
, buff
);
4184 #endif /* LOG_BUNDLE_LOAD */
4187 if (executableURL
) CFRelease(executableURL
);
4189 return bundle
->_isLoaded
;
4192 __private_extern__ Boolean
_CFBundleDYLDLoadBundle(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
4193 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4194 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
4195 int errorNumber
= 0;
4196 const char *fileName
= NULL
;
4197 const char *errorString
= NULL
;
4199 if (!bundle
->_isLoaded
) {
4200 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4201 char buff
[CFMaxPathSize
];
4203 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4204 NSObjectFileImage image
;
4205 NSObjectFileImageReturnCode retCode
= NSCreateObjectFileImageFromFile(buff
, &image
);
4207 printf("dyld load bundle %p, create image of %s returns image %p retcode %d\n", bundle
, buff
, image
, retCode
);
4208 #endif /* LOG_BUNDLE_LOAD */
4209 if (retCode
== NSObjectFileImageSuccess
) {
4210 uint32_t options
= forceGlobal
? NSLINKMODULE_OPTION_RETURN_ON_ERROR
: (NSLINKMODULE_OPTION_BINDNOW
| NSLINKMODULE_OPTION_PRIVATE
| NSLINKMODULE_OPTION_RETURN_ON_ERROR
);
4211 NSModule
module = NSLinkModule(image
, buff
, options
);
4213 printf("dyld load bundle %p, link module of %s options 0x%x returns module %p image %p\n", bundle
, buff
, options
, module, image
);
4214 #endif /* LOG_BUNDLE_LOAD */
4216 bundle
->_imageCookie
= image
;
4217 bundle
->_moduleCookie
= module;
4218 bundle
->_isLoaded
= true;
4220 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
4222 #if defined(BINARY_SUPPORT_DLFCN)
4223 _CFBundleDlfcnPreflight(bundle
, subError
);
4224 #endif /* BINARY_SUPPORT_DLFCN */
4226 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("error code %d, error number %d (%@)"), c
, errorNumber
, tempString
);
4227 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4228 if (tempString
) CFRelease(tempString
);
4229 if (debugString
) CFRelease(debugString
);
4232 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, fileName
);
4233 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString
, c
, errorNumber
, tempString
);
4234 if (tempString
) CFRelease(tempString
);
4235 if (executableString
) CFRelease(executableString
);
4237 (void)NSDestroyObjectFileImage(image
);
4241 if (retCode
== NSObjectFileImageArch
) {
4242 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableArchitectureMismatchError
);
4243 } else if (retCode
== NSObjectFileImageInappropriateFile
) {
4244 Boolean hasRuntimeMismatch
= false;
4245 uint32_t mainFlags
= 0, bundleFlags
= 0;
4246 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL
, &mainFlags
) && (mainFlags
& 0x2) != 0) {
4247 if (_CFBundleGetObjCImageInfo(bundle
, NULL
, &bundleFlags
) && (bundleFlags
& 0x2) == 0) hasRuntimeMismatch
= true;
4249 if (hasRuntimeMismatch
) {
4250 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableRuntimeMismatchError
);
4252 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
4255 #if defined(BINARY_SUPPORT_DLFCN)
4256 _CFBundleDlfcnPreflight(bundle
, subError
);
4257 #endif /* BINARY_SUPPORT_DLFCN */
4259 CFStringRef debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("dyld returns %d"), retCode
);
4260 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4261 CFRelease(debugString
);
4265 CFLog(__kCFLogBundle
, CFSTR("dyld returns %d when trying to load %@"), retCode
, executableURL
);
4270 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4272 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4275 if (executableURL
) CFRelease(executableURL
);
4277 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4278 return bundle
->_isLoaded
;
4281 __private_extern__ Boolean
_CFBundleDYLDLoadFramework(CFBundleRef bundle
, CFErrorRef
*error
) {
4282 // !!! Framework loading should be better. Can't unload frameworks.
4283 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4284 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
4285 int errorNumber
= 0;
4286 const char *fileName
= NULL
;
4287 const char *errorString
= NULL
;
4289 if (!bundle
->_isLoaded
) {
4290 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4291 char buff
[CFMaxPathSize
];
4293 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4294 void *image
= (void *)NSAddImage(buff
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
4296 printf("dyld load framework %p, add image of %s returns image %p\n", bundle
, buff
, image
);
4297 #endif /* LOG_BUNDLE_LOAD */
4299 bundle
->_imageCookie
= image
;
4300 bundle
->_isLoaded
= true;
4302 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
4304 #if defined(BINARY_SUPPORT_DLFCN)
4305 _CFBundleDlfcnPreflight(bundle
, subError
);
4306 #endif /* BINARY_SUPPORT_DLFCN */
4308 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("error code %d, error number %d (%@)"), c
, errorNumber
, tempString
);
4309 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4310 if (tempString
) CFRelease(tempString
);
4311 if (debugString
) CFRelease(debugString
);
4314 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, fileName
);
4315 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString
, c
, errorNumber
, tempString
);
4316 if (tempString
) CFRelease(tempString
);
4317 if (executableString
) CFRelease(executableString
);
4322 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4324 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4327 if (executableURL
) CFRelease(executableURL
);
4329 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4330 return bundle
->_isLoaded
;
4333 __private_extern__
void _CFBundleDYLDUnloadBundle(CFBundleRef bundle
) {
4334 if (bundle
->_isLoaded
) {
4336 printf("dyld unload bundle %p, handle %p module %p image %p\n", bundle
, bundle
->_handleCookie
, bundle
->_moduleCookie
, bundle
->_imageCookie
);
4337 #endif /* LOG_BUNDLE_LOAD */
4338 if (bundle
->_moduleCookie
&& !NSUnLinkModule((NSModule
)(bundle
->_moduleCookie
), NSUNLINKMODULE_OPTION_NONE
)) {
4339 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
4341 if (bundle
->_moduleCookie
&& bundle
->_imageCookie
) (void)NSDestroyObjectFileImage((NSObjectFileImage
)(bundle
->_imageCookie
));
4342 bundle
->_connectionCookie
= bundle
->_handleCookie
= NULL
;
4343 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
4344 bundle
->_isLoaded
= false;
4349 __private_extern__
void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4350 return _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, symbolName
, false);
4353 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
4354 void *result
= NULL
;
4356 NSSymbol symbol
= NULL
;
4359 if (CFStringGetCString(symbolName
, &(buff
[1]), 1024, kCFStringEncodingUTF8
)) {
4360 if (bundle
->_moduleCookie
) {
4361 symbol
= NSLookupSymbolInModule((NSModule
)(bundle
->_moduleCookie
), buff
);
4362 } else if (bundle
->_imageCookie
) {
4363 symbol
= NSLookupSymbolInImage(bundle
->_imageCookie
, buff
, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
4365 if (!symbol
&& !bundle
->_moduleCookie
&& (!bundle
->_imageCookie
|| globalSearch
)) {
4366 char hintBuff
[1026];
4367 CFStringRef executableName
= _CFBundleCopyExecutableName(bundle
, NULL
, NULL
);
4369 if (executableName
) {
4370 if (!CFStringGetCString(executableName
, hintBuff
, 1024, kCFStringEncodingUTF8
)) hintBuff
[0] = '\0';
4371 CFRelease(executableName
);
4373 // Nowdays, NSIsSymbolNameDefinedWithHint() and NSLookupAndBindSymbolWithHint()
4374 // are identical, except the first just returns a bool, so checking with the
4375 // Is function first just causes a redundant lookup.
4376 // This returns NULL on failure.
4377 symbol
= NSLookupAndBindSymbolWithHint(buff
, hintBuff
);
4379 if (symbol
) result
= NSAddressOfSymbol(symbol
);
4381 if (!result
) CFLog(__kCFLogBundle
, CFSTR("dyld cannot find symbol %@ in %@"), symbolName
, bundle
);
4384 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);
4385 #endif /* LOG_BUNDLE_LOAD */
4390 #endif /* !BINARY_SUPPORT_DLFCN */
4391 #endif /* BINARY_SUPPORT_DYLD */
4393 #if defined(BINARY_SUPPORT_DLFCN)
4395 __private_extern__ Boolean
_CFBundleDlfcnCheckLoaded(CFBundleRef bundle
) {
4396 if (!bundle
->_isLoaded
) {
4397 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4398 char buff
[CFMaxPathSize
];
4400 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4401 int mode
= RTLD_LAZY
| RTLD_LOCAL
| RTLD_NOLOAD
| RTLD_FIRST
;
4402 void *handle
= dlopen(buff
, mode
);
4404 if (!bundle
->_handleCookie
) {
4405 bundle
->_handleCookie
= handle
;
4407 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x getting handle %p\n", bundle
, buff
, mode
, bundle
->_handleCookie
);
4408 #endif /* LOG_BUNDLE_LOAD */
4410 bundle
->_isLoaded
= true;
4413 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x no handle\n", bundle
, buff
, mode
);
4414 #endif /* LOG_BUNDLE_LOAD */
4417 if (executableURL
) CFRelease(executableURL
);
4419 return bundle
->_isLoaded
;
4422 CF_EXPORT Boolean
_CFBundleDlfcnPreflight(CFBundleRef bundle
, CFErrorRef
*error
) {
4423 Boolean retval
= true;
4424 CFErrorRef localError
= NULL
;
4425 if (!bundle
->_isLoaded
) {
4426 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4427 char buff
[CFMaxPathSize
];
4430 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4431 retval
= dlopen_preflight(buff
);
4432 if (!retval
&& error
) {
4433 CFArrayRef archs
= CFBundleCopyExecutableArchitectures(bundle
);
4434 CFStringRef debugString
= NULL
;
4435 const char *errorString
= dlerror();
4436 if (errorString
&& strlen(errorString
) > 0) debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4438 Boolean hasSuitableArch
= false, hasRuntimeMismatch
= false;
4439 CFIndex i
, count
= CFArrayGetCount(archs
);
4440 SInt32 arch
, curArch
= _CFBundleCurrentArchitecture();
4441 for (i
= 0; !hasSuitableArch
&& i
< count
; i
++) {
4442 if (CFNumberGetValue((CFNumberRef
)CFArrayGetValueAtIndex(archs
, i
), kCFNumberSInt32Type
, (void *)&arch
) && arch
== curArch
) hasSuitableArch
= true;
4444 #if defined(BINARY_SUPPORT_DYLD)
4445 if (hasSuitableArch
) {
4446 uint32_t mainFlags
= 0, bundleFlags
= 0;
4447 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL
, &mainFlags
) && (mainFlags
& 0x2) != 0) {
4448 if (_CFBundleGetObjCImageInfo(bundle
, NULL
, &bundleFlags
) && (bundleFlags
& 0x2) == 0) hasRuntimeMismatch
= true;
4451 #endif /* BINARY_SUPPORT_DYLD */
4452 if (hasRuntimeMismatch
) {
4453 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableRuntimeMismatchError
, debugString
);
4454 } else if (!hasSuitableArch
) {
4455 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableArchitectureMismatchError
, debugString
);
4457 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLoadError
, debugString
);
4461 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLoadError
, debugString
);
4463 if (debugString
) CFRelease(debugString
);
4466 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4468 if (executableURL
) CFRelease(executableURL
);
4470 if (!retval
&& error
) *error
= localError
;
4474 __private_extern__ Boolean
_CFBundleDlfcnLoadBundle(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
4475 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4476 if (!bundle
->_isLoaded
) {
4477 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4478 char buff
[CFMaxPathSize
];
4479 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4480 int mode
= forceGlobal
? (RTLD_LAZY
| RTLD_GLOBAL
| RTLD_FIRST
) : (RTLD_NOW
| RTLD_LOCAL
| RTLD_FIRST
);
4481 void *cookie
= dlopen(buff
, mode
);
4483 printf("dlfcn load bundle %p, dlopen of %s mode 0x%x returns handle %p\n", bundle
, buff
, mode
, cookie
);
4484 #endif /* LOG_BUNDLE_LOAD */
4485 if (cookie
&& cookie
== bundle
->_handleCookie
) {
4486 // 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
4488 printf("dlfcn load bundle %p closing existing reference to handle %p\n", bundle
, cookie
);
4489 #endif /* LOG_BUNDLE_LOAD */
4490 dlclose(bundle
->_handleCookie
);
4492 bundle
->_handleCookie
= cookie
;
4493 if (bundle
->_handleCookie
) {
4494 bundle
->_isLoaded
= true;
4496 const char *errorString
= dlerror();
4498 _CFBundleDlfcnPreflight(bundle
, subError
);
4500 CFStringRef debugString
= errorString
? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
) : NULL
;
4501 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4502 if (debugString
) CFRelease(debugString
);
4505 CFStringRef executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
4507 CFStringRef debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4508 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: %@"), executableString
, debugString
);
4509 if (debugString
) CFRelease(debugString
);
4511 CFLog(__kCFLogBundle
, CFSTR("Error loading %@"), executableString
);
4513 if (executableString
) CFRelease(executableString
);
4518 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4520 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4523 if (executableURL
) CFRelease(executableURL
);
4525 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4526 return bundle
->_isLoaded
;
4529 __private_extern__ Boolean
_CFBundleDlfcnLoadFramework(CFBundleRef bundle
, CFErrorRef
*error
) {
4530 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4531 if (!bundle
->_isLoaded
) {
4532 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4533 char buff
[CFMaxPathSize
];
4534 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4535 int mode
= RTLD_LAZY
| RTLD_GLOBAL
| RTLD_FIRST
;
4536 void *cookie
= dlopen(buff
, mode
);
4538 printf("dlfcn load framework %p, dlopen of %s mode 0x%x returns handle %p\n", bundle
, buff
, mode
, cookie
);
4539 #endif /* LOG_BUNDLE_LOAD */
4540 if (cookie
&& cookie
== bundle
->_handleCookie
) {
4541 // 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
4543 printf("dlfcn load framework %p closing existing reference to handle %p\n", bundle
, cookie
);
4544 #endif /* LOG_BUNDLE_LOAD */
4545 dlclose(bundle
->_handleCookie
);
4547 bundle
->_handleCookie
= cookie
;
4548 if (bundle
->_handleCookie
) {
4549 bundle
->_isLoaded
= true;
4551 const char *errorString
= dlerror();
4553 _CFBundleDlfcnPreflight(bundle
, subError
);
4555 CFStringRef debugString
= errorString
? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
) : NULL
;
4556 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4557 if (debugString
) CFRelease(debugString
);
4560 CFStringRef executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
4562 CFStringRef debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4563 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: %@"), executableString
, debugString
);
4564 if (debugString
) CFRelease(debugString
);
4566 CFLog(__kCFLogBundle
, CFSTR("Error loading %@"), executableString
);
4568 if (executableString
) CFRelease(executableString
);
4573 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4575 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4578 if (executableURL
) CFRelease(executableURL
);
4580 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4581 return bundle
->_isLoaded
;
4584 __private_extern__
void _CFBundleDlfcnUnload(CFBundleRef bundle
) {
4585 if (bundle
->_isLoaded
) {
4587 printf("dlfcn unload bundle %p, handle %p module %p image %p\n", bundle
, bundle
->_handleCookie
, bundle
->_moduleCookie
, bundle
->_imageCookie
);
4588 #endif /* LOG_BUNDLE_LOAD */
4589 if (0 != dlclose(bundle
->_handleCookie
)) {
4590 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
4592 bundle
->_connectionCookie
= bundle
->_handleCookie
= NULL
;
4593 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
4594 bundle
->_isLoaded
= false;
4599 __private_extern__
void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4600 return _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, symbolName
, false);
4603 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
4604 void *result
= NULL
;
4607 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingUTF8
)) {
4608 result
= dlsym(bundle
->_handleCookie
, buff
);
4609 if (!result
&& globalSearch
) result
= dlsym(RTLD_DEFAULT
, buff
);
4611 if (!result
) CFLog(__kCFLogBundle
, CFSTR("dlsym cannot find symbol %@ in %@"), symbolName
, bundle
);
4614 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
);
4615 #endif /* LOG_BUNDLE_LOAD */
4620 #if !defined(BINARY_SUPPORT_DYLD)
4622 static CFStringRef
_CFBundleDlfcnCopyLoadedImagePathForPointer(void *p
) {
4623 CFStringRef result
= NULL
;
4625 if (0 != dladdr(p
, &info
) && info
.dli_fname
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, info
.dli_fname
);
4627 printf("dlfcn image path for pointer %p is %p\n", p
, result
);
4628 #endif /* LOG_BUNDLE_LOAD */
4632 #endif /* !BINARY_SUPPORT_DYLD */
4633 #endif /* BINARY_SUPPORT_DLFCN */
4635 #if defined(BINARY_SUPPORT_DLL)
4637 __private_extern__ Boolean
_CFBundleDLLLoad(CFBundleRef bundle
, CFErrorRef
*error
) {
4638 CFErrorRef localError
= NULL
;
4639 if (!bundle
->_isLoaded
) {
4640 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4641 wchar_t buff
[CFMaxPathSize
];
4643 if (executableURL
&& _CFURLGetWideFileSystemRepresentation(executableURL
, true, (wchar_t *)buff
, CFMaxPathSize
)) {
4644 bundle
->_hModule
= LoadLibraryW(buff
);
4645 if (bundle
->_hModule
) {
4646 bundle
->_isLoaded
= true;
4649 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
);
4651 CFLog(__kCFLogBundle
, CFSTR("Failed to load bundle %@"), bundle
);
4656 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4658 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4661 if (executableURL
) CFRelease(executableURL
);
4663 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4664 return bundle
->_isLoaded
;
4667 __private_extern__
void _CFBundleDLLUnload(CFBundleRef bundle
) {
4668 if (bundle
->_isLoaded
) {
4669 FreeLibrary(bundle
->_hModule
);
4670 bundle
->_hModule
= NULL
;
4671 bundle
->_isLoaded
= false;
4675 __private_extern__
void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4676 void *result
= NULL
;
4678 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingWindowsLatin1
)) result
= GetProcAddress(bundle
->_hModule
, buff
);
4682 #endif /* BINARY_SUPPORT_DLL */
4684 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
4687 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
) {