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-2012, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
29 #include "CFBundle_Internal.h"
30 #include <CoreFoundation/CFPropertyList.h>
31 #include <CoreFoundation/CFNumber.h>
32 #include <CoreFoundation/CFSet.h>
33 #include <CoreFoundation/CFURLAccess.h>
34 #include <CoreFoundation/CFError.h>
36 #include <CoreFoundation/CFPriv.h>
37 #include "CFInternal.h"
38 #include <CoreFoundation/CFByteOrder.h>
39 #include "CFBundle_BinaryTypes.h"
44 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS
46 #error Unknown deployment target
49 #define AVOID_WEAK_COLLECTIONS 1
51 #if !AVOID_WEAK_COLLECTIONS
52 #include "CFHashTable.h"
53 #include "CFMapTable.h"
54 #include "CFPointerArray.h"
55 #endif /* !AVOID_WEAK_COLLECTIONS */
57 #if defined(BINARY_SUPPORT_DYLD)
58 // Import the mach-o headers that define the macho magic numbers
59 #include <mach-o/loader.h>
60 #include <mach-o/fat.h>
61 #include <mach-o/arch.h>
62 #include <mach-o/dyld.h>
63 #include <mach-o/getsect.h>
67 #include <crt_externs.h>
68 #if defined(USE_DYLD_PRIV)
69 #include <mach-o/dyld_priv.h>
70 #endif /* USE_DYLD_PRIV */
71 #endif /* BINARY_SUPPORT_DYLD */
73 #if defined(BINARY_SUPPORT_DLFCN)
75 #endif /* BINARY_SUPPORT_DLFCN */
77 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
79 #elif DEPLOYMENT_TARGET_WINDOWS
84 #define stat(x,y) _NS_stat(x,y)
87 #if DEPLOYMENT_TARGET_WINDOWS
88 #define statinfo _stat
90 // Windows isspace implementation limits the input chars to < 256 in the ASCII range. It will
91 // assert in debug builds. This is annoying. We merrily grok chars > 256.
92 static inline BOOL
isspace(char c
) {
93 return (c
== ' ' || c
== '\t' || c
== '\n' || c
== '\r'|| c
== '\v' || c
== '\f');
100 __private_extern__
void _processInfoDictionary(CFMutableDictionaryRef dict
, CFStringRef platformSuffix
, CFStringRef productSuffix
);
101 CF_EXPORT CFStringRef
_CFGetProductName(void);
102 CF_EXPORT CFStringRef
_CFGetPlatformName(void);
103 CF_EXPORT CFStringRef
_CFGetAlternatePlatformName(void);
105 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle
, Boolean alreadyLocked
);
107 #define LOG_BUNDLE_LOAD 0
109 // Public CFBundle Info plist keys
110 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey
, "CFBundleInfoDictionaryVersion")
111 CONST_STRING_DECL(kCFBundleExecutableKey
, "CFBundleExecutable")
112 CONST_STRING_DECL(kCFBundleIdentifierKey
, "CFBundleIdentifier")
113 CONST_STRING_DECL(kCFBundleVersionKey
, "CFBundleVersion")
114 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey
, "CFBundleDevelopmentRegion")
115 CONST_STRING_DECL(kCFBundleLocalizationsKey
, "CFBundleLocalizations")
117 // Private CFBundle Info plist keys, possible candidates for public constants
118 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey
, "CFBundleAllowMixedLocalizations")
119 CONST_STRING_DECL(_kCFBundleSupportedPlatformsKey
, "CFBundleSupportedPlatforms")
120 CONST_STRING_DECL(_kCFBundleResourceSpecificationKey
, "CFBundleResourceSpecification")
123 CONST_STRING_DECL(_kCFBundlePackageTypeKey
, "CFBundlePackageType")
124 CONST_STRING_DECL(_kCFBundleSignatureKey
, "CFBundleSignature")
125 CONST_STRING_DECL(_kCFBundleIconFileKey
, "CFBundleIconFile")
126 CONST_STRING_DECL(_kCFBundleDocumentTypesKey
, "CFBundleDocumentTypes")
127 CONST_STRING_DECL(_kCFBundleURLTypesKey
, "CFBundleURLTypes")
129 // Keys that are usually localized in InfoPlist.strings
130 CONST_STRING_DECL(kCFBundleNameKey
, "CFBundleName")
131 CONST_STRING_DECL(_kCFBundleDisplayNameKey
, "CFBundleDisplayName")
132 CONST_STRING_DECL(_kCFBundleShortVersionStringKey
, "CFBundleShortVersionString")
133 CONST_STRING_DECL(_kCFBundleGetInfoStringKey
, "CFBundleGetInfoString")
134 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey
, "CFBundleGetInfoHTML")
136 // Sub-keys for CFBundleDocumentTypes dictionaries
137 CONST_STRING_DECL(_kCFBundleTypeNameKey
, "CFBundleTypeName")
138 CONST_STRING_DECL(_kCFBundleTypeRoleKey
, "CFBundleTypeRole")
139 CONST_STRING_DECL(_kCFBundleTypeIconFileKey
, "CFBundleTypeIconFile")
140 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey
, "CFBundleTypeOSTypes")
141 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey
, "CFBundleTypeExtensions")
142 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey
, "CFBundleTypeMIMETypes")
144 // Sub-keys for CFBundleURLTypes dictionaries
145 CONST_STRING_DECL(_kCFBundleURLNameKey
, "CFBundleURLName")
146 CONST_STRING_DECL(_kCFBundleURLIconFileKey
, "CFBundleURLIconFile")
147 CONST_STRING_DECL(_kCFBundleURLSchemesKey
, "CFBundleURLSchemes")
149 // Compatibility key names
150 CONST_STRING_DECL(_kCFBundleOldExecutableKey
, "NSExecutable")
151 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey
, "NSInfoPlistVersion")
152 CONST_STRING_DECL(_kCFBundleOldNameKey
, "NSHumanReadableName")
153 CONST_STRING_DECL(_kCFBundleOldIconFileKey
, "NSIcon")
154 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey
, "NSTypes")
155 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey
, "NSAppVersion")
157 // Compatibility CFBundleDocumentTypes key names
158 CONST_STRING_DECL(_kCFBundleOldTypeNameKey
, "NSName")
159 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey
, "NSRole")
160 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey
, "NSIcon")
161 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key
, "NSUnixExtensions")
162 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key
, "NSDOSExtensions")
163 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey
, "NSMacOSType")
165 // Internally used keys for loaded Info plists.
166 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey
, "CFBundleInfoPlistURL")
167 CONST_STRING_DECL(_kCFBundleRawInfoPlistURLKey
, "CFBundleRawInfoPlistURL")
168 CONST_STRING_DECL(_kCFBundleNumericVersionKey
, "CFBundleNumericVersion")
169 CONST_STRING_DECL(_kCFBundleExecutablePathKey
, "CFBundleExecutablePath")
170 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey
, "CSResourcesFileMapped")
171 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey
, "CFBundleCFMLoadAsBundle")
173 // Keys used by NSBundle for loaded Info plists.
174 CONST_STRING_DECL(_kCFBundleInitialPathKey
, "NSBundleInitialPath")
175 CONST_STRING_DECL(_kCFBundleResolvedPathKey
, "NSBundleResolvedPath")
176 CONST_STRING_DECL(_kCFBundlePrincipalClassKey
, "NSPrincipalClass")
178 static char __CFBundleMainID__
[1026] = {0};
179 __private_extern__
char *__CFBundleMainID
= __CFBundleMainID__
;
181 static CFTypeID __kCFBundleTypeID
= _kCFRuntimeNotATypeID
;
189 __strong CFDictionaryRef _infoDict
; // the ref stored in here must always be allocated with kCFAllocatorSystemDefaultGCRefZero
190 __strong CFDictionaryRef _localInfoDict
; // the ref stored in here must always be allocated with kCFAllocatorSystemDefaultGCRefZero
191 CFArrayRef _searchLanguages
;
193 __CFPBinaryType _binaryType
;
196 Boolean _sharesStringsFiles
;
200 void *_connectionCookie
;
203 const void *_imageCookie
;
204 const void *_moduleCookie
;
209 /* CFM<->DYLD glue */
210 CFMutableDictionaryRef _glueDict
;
212 /* Resource fork goop */
213 _CFResourceData _resourceData
;
215 _CFPlugInData _plugInData
;
217 pthread_mutex_t _bundleLoadingLock
;
220 /* resouce fast lookup*/
221 CFSpinLock_t _queryLock
;
222 CFMutableDictionaryRef _queryTable
;
223 CFStringRef _bundleBasePath
;
225 #if defined(BINARY_SUPPORT_DLL)
227 #endif /* BINARY_SUPPORT_DLL */
231 static pthread_mutex_t CFBundleGlobalDataLock
= PTHREAD_MUTEX_INITIALIZER
;
233 static CFMutableDictionaryRef _bundlesByIdentifier
= NULL
;
234 #if AVOID_WEAK_COLLECTIONS
235 static CFMutableDictionaryRef _bundlesByURL
= NULL
;
236 static CFMutableArrayRef _allBundles
= NULL
;
237 static CFMutableSetRef _bundlesToUnload
= NULL
;
238 #else /* AVOID_WEAK_COLLECTIONS */
239 static __CFHashTable
*_allBundles
= nil
;
240 static __CFHashTable
*_bundlesToUnload
= nil
;
241 #endif /* AVOID_WEAK_COLLECTIONS */
242 static Boolean _scheduledBundlesAreUnloading
= false;
244 static Boolean _initedMainBundle
= false;
245 static CFBundleRef _mainBundle
= NULL
;
246 static CFStringRef _defaultLocalization
= NULL
;
248 // Forward declares functions.
249 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
);
250 static CFStringRef
_CFBundleCopyExecutableName(CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
);
251 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
);
252 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
);
253 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
254 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
);
255 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
);
256 #if defined(BINARY_SUPPORT_DYLD)
257 static CFMutableDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable(void);
258 static Boolean
_CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion
, uint32_t *objcFlags
);
259 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
);
260 #if !defined(BINARY_SUPPORT_DLFCN)
261 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
);
262 #endif /* !BINARY_SUPPORT_DLFCN */
263 #endif /* BINARY_SUPPORT_DYLD */
264 #if defined(BINARY_SUPPORT_DLFCN)
265 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
);
266 #if !defined(BINARY_SUPPORT_DYLD)
267 static CFStringRef
_CFBundleDlfcnCopyLoadedImagePathForPointer(void *p
);
268 #endif /* !BINARY_SUPPORT_DYLD */
269 #endif /* BINARY_SUPPORT_DLFCN */
272 #if AVOID_WEAK_COLLECTIONS
274 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
275 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
277 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
279 // Add to the _allBundles list
281 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
282 nonRetainingArrayCallbacks
.retain
= NULL
;
283 nonRetainingArrayCallbacks
.release
= NULL
;
284 _allBundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
286 CFArrayAppendValue(_allBundles
, bundle
);
288 // Add to the table that maps urls to bundles
289 if (!_bundlesByURL
) {
290 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
291 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
292 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
293 _bundlesByURL
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
295 CFDictionarySetValue(_bundlesByURL
, bundle
->_url
, bundle
);
297 // Add to the table that maps identifiers to bundles
299 CFMutableArrayRef bundlesWithThisID
= NULL
;
300 CFBundleRef existingBundle
= NULL
;
301 if (!_bundlesByIdentifier
) {
302 _bundlesByIdentifier
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
304 bundlesWithThisID
= (CFMutableArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
305 if (bundlesWithThisID
) {
306 CFIndex i
, count
= CFArrayGetCount(bundlesWithThisID
);
307 UInt32 existingVersion
, newVersion
= CFBundleGetVersionNumber(bundle
);
308 for (i
= 0; i
< count
; i
++) {
309 existingBundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, i
);
310 existingVersion
= CFBundleGetVersionNumber(existingBundle
);
311 // If you load two bundles with the same identifier and the same version, the last one wins.
312 if (newVersion
>= existingVersion
) break;
314 CFArrayInsertValueAtIndex(bundlesWithThisID
, i
, bundle
);
316 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
317 nonRetainingArrayCallbacks
.retain
= NULL
;
318 nonRetainingArrayCallbacks
.release
= NULL
;
319 bundlesWithThisID
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
320 CFArrayAppendValue(bundlesWithThisID
, bundle
);
321 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundlesWithThisID
);
322 CFRelease(bundlesWithThisID
);
325 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
328 static void _CFBundleRemoveFromTables(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef bundleID
) {
329 pthread_mutex_lock(&CFBundleGlobalDataLock
);
330 // Remove from the various lists
332 CFIndex i
= CFArrayGetFirstIndexOfValue(_allBundles
, CFRangeMake(0, CFArrayGetCount(_allBundles
)), bundle
);
333 if (i
>= 0) CFArrayRemoveValueAtIndex(_allBundles
, i
);
336 // Remove from the table that maps urls to bundles
337 if (bundleURL
&& _bundlesByURL
) {
338 CFBundleRef bundleForURL
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, bundleURL
);
339 if (bundleForURL
== bundle
) CFDictionaryRemoveValue(_bundlesByURL
, bundleURL
);
342 // Remove from the table that maps identifiers to bundles
343 if (bundleID
&& _bundlesByIdentifier
) {
344 CFMutableArrayRef bundlesWithThisID
= (CFMutableArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
345 if (bundlesWithThisID
) {
346 CFIndex count
= CFArrayGetCount(bundlesWithThisID
);
347 while (count
-- > 0) if (bundle
== (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, count
)) CFArrayRemoveValueAtIndex(bundlesWithThisID
, count
);
348 if (0 == CFArrayGetCount(bundlesWithThisID
)) CFDictionaryRemoveValue(_bundlesByIdentifier
, bundleID
);
351 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
354 static CFBundleRef
_CFBundleCopyBundleForURL(CFURLRef url
, Boolean alreadyLocked
) {
355 CFBundleRef result
= NULL
;
356 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
357 if (_bundlesByURL
) result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, url
);
358 if (result
&& !result
->_url
) {
360 CFDictionaryRemoveValue(_bundlesByURL
, url
);
362 if (result
) CFRetain(result
);
363 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
367 static CFBundleRef
_CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID
) {
368 CFBundleRef result
= NULL
, bundle
;
369 if (_bundlesByIdentifier
&& bundleID
) {
370 // Note that this array is maintained in descending order by version number
371 CFArrayRef bundlesWithThisID
= (CFArrayRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
372 if (bundlesWithThisID
) {
373 CFIndex i
, count
= CFArrayGetCount(bundlesWithThisID
);
375 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
376 for (i
= 0; !result
&& i
< count
; i
++) {
377 bundle
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, i
);
378 if (CFBundleIsExecutableLoaded(bundle
)) result
= bundle
;
380 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
381 if (!result
) result
= (CFBundleRef
)CFArrayGetValueAtIndex(bundlesWithThisID
, 0);
388 #else /* AVOID_WEAK_COLLECTIONS */
391 An explanation of what I'm doing here is probably in order.
392 8029300 has cast suspicion on the correctness of __CFMapTable with strong keys and weak values, at least under non-GC.
393 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
394 This indicates that it's not an overrelease in securityd, since AVOID_WEAK_COLLECTIONS wouldn't help in that case.
395 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.
397 static inline id
_getBundlesByURL() {
398 static id _bundles
= nil
;
399 static dispatch_once_t onceToken
;
400 dispatch_once(&onceToken
, ^{
401 if (CF_USING_COLLECTABLE_MEMORY
) {
402 _bundles
= [[__CFMapTable alloc
] initWithKeyOptions
:CFPointerFunctionsStrongMemory valueOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
404 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks
= kCFTypeDictionaryValueCallBacks
;
405 nonRetainingDictionaryValueCallbacks
.retain
= NULL
;
406 nonRetainingDictionaryValueCallbacks
.release
= NULL
;
407 _bundles
= (id
)CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &nonRetainingDictionaryValueCallbacks
);
413 #define _bundlesByURL _getBundlesByURL()
415 static void _setInBundlesByURL(CFURLRef key
, CFBundleRef bundle
) {
416 if (CF_USING_COLLECTABLE_MEMORY
) {
417 [(__CFMapTable
*)_bundlesByURL setObject
:(id
)bundle forKey
:(id
)key
];
419 CFDictionarySetValue((CFMutableDictionaryRef
)_bundlesByURL
, key
, bundle
);
423 static void _removeFromBundlesByURL(CFURLRef key
) {
424 if (CF_USING_COLLECTABLE_MEMORY
) {
425 [(__CFMapTable
*)_bundlesByURL removeObjectForKey
:(id
)key
];
427 CFDictionaryRemoveValue((CFMutableDictionaryRef
)_bundlesByURL
, key
);
431 static CFBundleRef
_getFromBundlesByURL(CFURLRef key
) {
432 if (CF_USING_COLLECTABLE_MEMORY
) {
433 return (CFBundleRef
)[(__CFMapTable
*)_bundlesByURL objectForKey
:(id
)key
];
435 return (CFBundleRef
)CFDictionaryGetValue((CFMutableDictionaryRef
)_bundlesByURL
, key
);
439 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
440 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
442 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
444 // Add to the _allBundles list
445 if (!_allBundles
) _allBundles
= [[__CFHashTable alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
446 [_allBundles addObject
:(id
)bundle
];
448 // Add to the table that maps urls to bundles
449 _setInBundlesByURL(bundle
->_url
, bundle
);
451 // Add to the table that maps identifiers to bundles
453 __CFPointerArray
*bundlesWithThisID
= nil
;
454 CFBundleRef existingBundle
= NULL
;
455 if (!_bundlesByIdentifier
) {
456 _bundlesByIdentifier
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
458 bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
459 if (bundlesWithThisID
) {
460 CFIndex i
, count
= (CFIndex
)[bundlesWithThisID count
];
461 UInt32 existingVersion
, newVersion
= CFBundleGetVersionNumber(bundle
);
462 for (i
= 0; i
< count
; i
++) {
463 existingBundle
= (CFBundleRef
)[bundlesWithThisID pointerAtIndex
:i
];
464 if (!existingBundle
) continue;
465 existingVersion
= CFBundleGetVersionNumber(existingBundle
);
466 // If you load two bundles with the same identifier and the same version, the last one wins.
467 if (newVersion
>= existingVersion
) break;
470 [bundlesWithThisID insertPointer
:bundle atIndex
:i
];
472 [bundlesWithThisID addPointer
:bundle
];
475 bundlesWithThisID
= [[__CFPointerArray alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory
];
476 [bundlesWithThisID addPointer
:bundle
];
477 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundlesWithThisID
);
478 [bundlesWithThisID release
];
481 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
484 static void _CFBundleRemoveFromTables(CFBundleRef bundle
, CFURLRef bundleURL
, CFStringRef bundleID
) {
485 pthread_mutex_lock(&CFBundleGlobalDataLock
);
486 // Remove from the various lists
487 if (_allBundles
&& [_allBundles member
:(id
)bundle
]) [_allBundles removeObject
:(id
)bundle
];
489 // Remove from the table that maps urls to bundles
491 _removeFromBundlesByURL(bundleURL
);
494 // Remove from the table that maps identifiers to bundles
495 if (bundleID
&& _bundlesByIdentifier
) {
496 __CFPointerArray
*bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
497 if (bundlesWithThisID
) {
498 CFIndex count
= (CFIndex
)[bundlesWithThisID count
];
499 while (count
-- > 0) if (bundle
== (CFBundleRef
)[bundlesWithThisID pointerAtIndex
:count
]) [bundlesWithThisID removePointerAtIndex
:count
];
500 [bundlesWithThisID compact
];
501 if (0 == [bundlesWithThisID count
]) CFDictionaryRemoveValue(_bundlesByIdentifier
, bundleID
);
504 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
507 static CFBundleRef
_CFBundleCopyBundleForURL(CFURLRef url
, Boolean alreadyLocked
) {
508 CFBundleRef result
= NULL
;
509 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
510 result
= _getFromBundlesByURL(url
);
511 if (result
&& !result
->_url
) {
513 _removeFromBundlesByURL(url
);
515 if (result
) CFRetain(result
);
516 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
520 static CFBundleRef
_CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID
) {
521 CFBundleRef result
= NULL
;
522 if (_bundlesByIdentifier
&& bundleID
) {
523 // Note that this array is maintained in descending order by version number
524 __CFPointerArray
*bundlesWithThisID
= (__CFPointerArray
*)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
525 if (bundlesWithThisID
&& [bundlesWithThisID count
] > 0) {
526 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
527 for (id bundle in bundlesWithThisID
) {
528 if (bundle
&& CFBundleIsExecutableLoaded((CFBundleRef
)bundle
)) {
529 result
= (CFBundleRef
)bundle
;
533 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
535 for (id bundle in bundlesWithThisID
) {
537 result
= (CFBundleRef
)bundle
;
547 #endif /* AVOID_WEAK_COLLECTIONS */
549 static CFURLRef
_CFBundleCopyBundleURLForExecutablePath(CFStringRef str
) {
550 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
551 UniChar buff
[CFMaxPathSize
];
556 buffLen
= CFStringGetLength(str
);
557 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
558 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
560 #if DEPLOYMENT_TARGET_WINDOWS
561 // Is this a .dll or .exe?
562 if (buffLen
>= 5 && (_wcsnicmp((wchar_t *)&(buff
[buffLen
-4]), L
".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff
[buffLen
-4]), L
".exe", 4) == 0)) {
563 CFIndex extensionLength
= CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension
);
565 // If this is an _debug, we should strip that before looking for the bundle
566 if (buffLen
>= 7 && (_wcsnicmp((wchar_t *)&buff
[buffLen
-6], L
"_debug", 6) == 0)) buffLen
-= 6;
568 if (buffLen
+ 1 + extensionLength
< CFMaxPathSize
) {
571 CFStringGetCharacters(_CFBundleWindowsResourceDirectoryExtension
, CFRangeMake(0, extensionLength
), buff
+ buffLen
);
572 buffLen
+= extensionLength
;
573 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
574 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
581 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
); // Remove exe name
584 // See if this is a new bundle. If it is, we have to remove more path components.
585 CFIndex startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
586 if (startOfLastDir
> 0 && startOfLastDir
< buffLen
) {
587 CFStringRef lastDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
589 if (CFEqual(lastDirName
, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName
, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
590 // This is a new bundle. Back off a few more levels
592 // Remove platform folder
593 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
596 // Remove executables folder (if present)
597 CFIndex startOfNextDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
598 if (startOfNextDir
> 0 && startOfNextDir
< buffLen
) {
599 CFStringRef nextDirName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfNextDir
]), buffLen
- startOfNextDir
);
600 if (CFEqual(nextDirName
, _CFBundleExecutablesDirectoryName
)) buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
601 CFRelease(nextDirName
);
605 // Remove support files folder
606 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
609 CFRelease(lastDirName
);
614 outstr
= CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault
, buff
, buffLen
, kCFAllocatorNull
);
615 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, outstr
, PLATFORM_PATH_STYLE
, true);
622 static CFURLRef
_CFBundleCopyResolvedURLForExecutableURL(CFURLRef url
) {
623 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
624 CFURLRef absoluteURL
, url1
, url2
, outURL
= NULL
;
625 CFStringRef str
, str1
, str2
;
626 absoluteURL
= CFURLCopyAbsoluteURL(url
);
627 str
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
629 UniChar buff
[CFMaxPathSize
];
630 CFIndex buffLen
= CFStringGetLength(str
), len1
;
631 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
632 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
633 len1
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
634 if (len1
> 0 && len1
+ 1 < buffLen
) {
635 str1
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, buff
, len1
);
636 CFIndex skipSlashCount
= 1;
637 #if DEPLOYMENT_TARGET_WINDOWS
638 // 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
639 if (len1
== 3 && buff
[1] == ':' && buff
[2] == '\\') {
643 str2
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, buff
+ len1
+ skipSlashCount
, buffLen
- len1
- skipSlashCount
);
645 url1
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str1
, PLATFORM_PATH_STYLE
, true);
647 url2
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, str2
, PLATFORM_PATH_STYLE
, false, url1
);
649 outURL
= CFURLCopyAbsoluteURL(url2
);
655 if (str1
) CFRelease(str1
);
656 if (str2
) CFRelease(str2
);
661 outURL
= absoluteURL
;
663 CFRelease(absoluteURL
);
668 CFURLRef
_CFBundleCopyBundleURLForExecutableURL(CFURLRef url
) {
669 CFURLRef resolvedURL
, outurl
= NULL
;
671 resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
672 str
= CFURLCopyFileSystemPath(resolvedURL
, PLATFORM_PATH_STYLE
);
674 outurl
= _CFBundleCopyBundleURLForExecutablePath(str
);
677 CFRelease(resolvedURL
);
681 static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle
) {
682 uint8_t localVersion
= bundle
->_version
;
683 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
684 if (0 == localVersion
) {
685 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
686 if (!infoDict
|| 0 == CFDictionaryGetCount(infoDict
)) {
687 #if defined(BINARY_SUPPORT_DYLD)
688 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
690 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
691 if (bundle
->_binaryType
== __CFBundleCFMBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
694 bundle
->_resourceData
._executableLacksResourceFork
= true;
696 CFRelease(executableURL
);
701 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
703 CFRelease(executableURL
);
707 #endif /* BINARY_SUPPORT_DYLD */
713 CFBundleRef
_CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
714 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
716 uint8_t localVersion
= _CFBundleEffectiveLayoutVersion(bundle
);
717 if (3 == localVersion
|| 4 == localVersion
) {
725 CFBundleRef
_CFBundleGetMainBundleIfLooksLikeBundle(void) {
726 CFBundleRef mainBundle
= CFBundleGetMainBundle();
727 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
731 Boolean
_CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) {
732 CFBundleRef mainBundle
= CFBundleGetMainBundle();
733 return (mainBundle
&& mainBundle
->_resourceData
._infoDictionaryFromResourceFork
);
736 CFBundleRef
_CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
737 CFBundleRef bundle
= NULL
;
738 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
739 if (bundleURL
&& resolvedURL
) {
740 bundle
= _CFBundleCreateIfLooksLikeBundle(allocator
, bundleURL
);
742 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
743 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
744 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, (uint8_t *)buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
748 if (executableURL
) CFRelease(executableURL
);
751 if (bundleURL
) CFRelease(bundleURL
);
752 if (resolvedURL
) CFRelease(resolvedURL
);
756 CFBundleRef
_CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
757 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
759 Boolean mightBeBundle
= true, isDir
= false;
760 uint8_t localVersion
= _CFBundleEffectiveLayoutVersion(bundle
);
761 if (3 == localVersion
) {
762 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
763 CFURLRef executableURL
, supportFilesURL
, resourceSpecificationFileURL
;
764 CFArrayRef supportedPlatforms
;
765 CFStringRef resourceSpecificationFile
;
767 mightBeBundle
= false;
768 if (infoDict
&& CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
) && (executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
))) {
769 supportedPlatforms
= _CFBundleGetSupportedPlatforms(bundle
);
770 resourceSpecificationFile
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleResourceSpecificationKey
);
771 if (supportedPlatforms
&& CFArrayGetCount(supportedPlatforms
) > 0 && CFArrayGetFirstIndexOfValue(supportedPlatforms
, CFRangeMake(0, CFArrayGetCount(supportedPlatforms
)), CFSTR("iPhoneOS")) >= 0) {
772 mightBeBundle
= true;
773 } else if (resourceSpecificationFile
&& CFGetTypeID(resourceSpecificationFile
) == CFStringGetTypeID() && (supportFilesURL
= CFBundleCopySupportFilesDirectoryURL(bundle
))) {
774 resourceSpecificationFileURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, resourceSpecificationFile
, kCFURLPOSIXPathStyle
, false, supportFilesURL
);
775 if (resourceSpecificationFileURL
) {
776 if (_CFIsResourceAtURL(resourceSpecificationFileURL
, &isDir
) && !isDir
) mightBeBundle
= true;
777 CFRelease(resourceSpecificationFileURL
);
779 CFRelease(supportFilesURL
);
781 CFRelease(executableURL
);
783 } else if (4 == localVersion
) {
784 mightBeBundle
= false;
786 if (!mightBeBundle
) {
794 CFBundleRef
_CFBundleCreateWithExecutableURLIfMightBeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
795 CFBundleRef bundle
= NULL
;
796 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
797 if (bundleURL
&& resolvedURL
) {
798 bundle
= _CFBundleCreateIfMightBeBundle(allocator
, bundleURL
);
800 CFURLRef executableURL
= _CFBundleCopyExecutableURLIgnoringCache(bundle
);
801 char buff1
[CFMaxPathSize
], buff2
[CFMaxPathSize
];
802 if (!executableURL
|| !CFURLGetFileSystemRepresentation(resolvedURL
, true, (uint8_t *)buff1
, CFMaxPathSize
) || !CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff2
, CFMaxPathSize
) || 0 != strcmp(buff1
, buff2
)) {
806 if (executableURL
) CFRelease(executableURL
);
809 if (bundleURL
) CFRelease(bundleURL
);
810 if (resolvedURL
) CFRelease(resolvedURL
);
814 CFURLRef
_CFBundleCopyMainBundleExecutableURL(Boolean
*looksLikeBundle
) {
815 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
816 const char *processPath
;
817 CFStringRef str
= NULL
;
818 CFURLRef executableURL
= NULL
;
819 processPath
= _CFProcessPath();
821 str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, processPath
);
823 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, PLATFORM_PATH_STYLE
, false);
827 if (looksLikeBundle
) {
828 CFBundleRef mainBundle
= _mainBundle
;
829 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) mainBundle
= NULL
;
830 *looksLikeBundle
= (mainBundle
? true : false);
832 return executableURL
;
835 static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef executablePath
) {
836 CFBundleGetInfoDictionary(_mainBundle
);
837 if (!_mainBundle
->_infoDict
|| CFDictionaryGetCount(_mainBundle
->_infoDict
) == 0) {
838 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
839 if (_mainBundle
->_version
== 3) _mainBundle
->_version
= 4;
840 if (_mainBundle
->_version
== 0) {
841 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
842 CFStringRef executableName
= _CFBundleCopyExecutableName(_mainBundle
, NULL
, NULL
);
843 if (!executableName
|| !executablePath
|| !CFStringHasSuffix(executablePath
, executableName
)) _mainBundle
->_version
= 4;
844 if (executableName
) CFRelease(executableName
);
846 #if defined(BINARY_SUPPORT_DYLD)
847 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
848 if (_mainBundle
->_infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(_mainBundle
->_infoDict
);
849 _mainBundle
->_infoDict
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromMainExecutable();
851 #endif /* BINARY_SUPPORT_DYLD */
853 #if defined(BINARY_SUPPORT_DYLD)
854 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
855 // if dyld and not main executable for bundle, prefer info dictionary from executable
856 CFStringRef executableName
= _CFBundleCopyExecutableName(_mainBundle
, NULL
, NULL
);
857 if (!executableName
|| !executablePath
|| !CFStringHasSuffix(executablePath
, executableName
)) {
858 CFDictionaryRef infoDictFromExecutable
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromMainExecutable();
859 if (infoDictFromExecutable
&& CFDictionaryGetCount(infoDictFromExecutable
) > 0) {
860 if (_mainBundle
->_infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(_mainBundle
->_infoDict
);
861 _mainBundle
->_infoDict
= infoDictFromExecutable
;
864 if (executableName
) CFRelease(executableName
);
866 #endif /* BINARY_SUPPORT_DYLD */
868 if (!_mainBundle
->_infoDict
) _mainBundle
->_infoDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
869 if (!CFDictionaryGetValue(_mainBundle
->_infoDict
, _kCFBundleExecutablePathKey
)) CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), _kCFBundleExecutablePathKey
, executablePath
);
870 CFStringRef bundleID
= (CFStringRef
)CFDictionaryGetValue(_mainBundle
->_infoDict
, kCFBundleIdentifierKey
);
872 if (!CFStringGetCString(bundleID
, __CFBundleMainID__
, sizeof(__CFBundleMainID__
) - 2, kCFStringEncodingUTF8
)) {
873 __CFBundleMainID__
[0] = '\0';
878 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle
, Boolean alreadyLocked
) {
879 CFDictionaryRef oldInfoDict
= bundle
->_infoDict
;
882 _CFBundleFlushCachesForURL(bundle
->_url
);
883 bundle
->_infoDict
= NULL
;
884 if (bundle
->_localInfoDict
) {
885 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(bundle
->_localInfoDict
);
886 bundle
->_localInfoDict
= NULL
;
888 if (bundle
->_searchLanguages
) {
889 CFRelease(bundle
->_searchLanguages
);
890 bundle
->_searchLanguages
= NULL
;
892 if (bundle
->_resourceData
._stringTableCache
) {
893 CFRelease(bundle
->_resourceData
._stringTableCache
);
894 bundle
->_resourceData
._stringTableCache
= NULL
;
896 if (bundle
== _mainBundle
) {
897 CFStringRef executablePath
= oldInfoDict
? (CFStringRef
)CFDictionaryGetValue(oldInfoDict
, _kCFBundleExecutablePathKey
) : NULL
;
898 if (!alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
899 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath
);
900 if (!alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
902 CFBundleGetInfoDictionary(bundle
);
905 if (!bundle
->_infoDict
) bundle
->_infoDict
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
906 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundleInitialPathKey
);
907 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundleInitialPathKey
, val
);
908 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundleResolvedPathKey
);
909 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundleResolvedPathKey
, val
);
910 val
= CFDictionaryGetValue(oldInfoDict
, _kCFBundlePrincipalClassKey
);
911 if (val
) CFDictionarySetValue((CFMutableDictionaryRef
)bundle
->_infoDict
, _kCFBundlePrincipalClassKey
, val
);
912 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(oldInfoDict
);
916 CF_EXPORT
void _CFBundleFlushBundleCaches(CFBundleRef bundle
) {
917 _CFBundleFlushBundleCachesAlreadyLocked(bundle
, false);
920 static CFBundleRef
_CFBundleGetMainBundleAlreadyLocked(void) {
921 if (!_initedMainBundle
) {
922 const char *processPath
;
923 CFStringRef str
= NULL
;
924 CFURLRef executableURL
= NULL
, bundleURL
= NULL
;
925 _initedMainBundle
= true;
926 processPath
= _CFProcessPath();
928 str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, processPath
);
929 if (!executableURL
) executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, str
, PLATFORM_PATH_STYLE
, false);
931 if (executableURL
) bundleURL
= _CFBundleCopyBundleURLForExecutableURL(executableURL
);
933 // make sure that main bundle has executable path
934 //??? what if we are not the main executable in the bundle?
935 // NB doFinalProcessing must be false here, see below
936 _mainBundle
= _CFBundleCreate(kCFAllocatorSystemDefault
, bundleURL
, true, false);
938 // make sure that the main bundle is listed as loaded, and mark it as executable
939 _mainBundle
->_isLoaded
= true;
940 #if defined(BINARY_SUPPORT_DYLD)
941 if (_mainBundle
->_binaryType
== __CFBundleUnknownBinary
) {
942 if (!executableURL
) {
943 _mainBundle
->_binaryType
= __CFBundleNoBinary
;
945 _mainBundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
946 if (_mainBundle
->_binaryType
!= __CFBundleCFMBinary
&& _mainBundle
->_binaryType
!= __CFBundleUnreadableBinary
) _mainBundle
->_resourceData
._executableLacksResourceFork
= true;
949 #endif /* BINARY_SUPPORT_DYLD */
950 // get cookie for already-loaded main bundle
951 #if defined(BINARY_SUPPORT_DLFCN)
952 if (!_mainBundle
->_handleCookie
) {
953 _mainBundle
->_handleCookie
= dlopen(NULL
, RTLD_NOLOAD
| RTLD_FIRST
);
955 printf("main bundle %p getting handle %p\n", _mainBundle
, _mainBundle
->_handleCookie
);
956 #endif /* LOG_BUNDLE_LOAD */
958 #elif defined(BINARY_SUPPORT_DYLD)
959 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
&& !_mainBundle
->_imageCookie
) {
960 _mainBundle
->_imageCookie
= (void *)_dyld_get_image_header(0);
962 printf("main bundle %p getting image %p\n", _mainBundle
, _mainBundle
->_imageCookie
);
963 #endif /* LOG_BUNDLE_LOAD */
965 #endif /* BINARY_SUPPORT_DLFCN */
966 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str
);
967 // Perform delayed final processing steps.
968 // This must be done after _isLoaded has been set, for security reasons (3624341).
969 if (_CFBundleNeedsInitPlugIn(_mainBundle
)) {
970 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
971 _CFBundleInitPlugIn(_mainBundle
);
972 pthread_mutex_lock(&CFBundleGlobalDataLock
);
976 if (bundleURL
) CFRelease(bundleURL
);
977 if (str
) CFRelease(str
);
978 if (executableURL
) CFRelease(executableURL
);
983 CFBundleRef
CFBundleGetMainBundle(void) {
984 CFBundleRef mainBundle
;
985 pthread_mutex_lock(&CFBundleGlobalDataLock
);
986 mainBundle
= _CFBundleGetMainBundleAlreadyLocked();
987 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
991 CFBundleRef
CFBundleGetBundleWithIdentifier(CFStringRef bundleID
) {
992 CFBundleRef result
= NULL
;
994 pthread_mutex_lock(&CFBundleGlobalDataLock
);
995 (void)_CFBundleGetMainBundleAlreadyLocked();
996 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
997 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
999 // Try to create the bundle for the caller and try again
1000 void *p
= __builtin_return_address(0);
1002 CFStringRef imagePath
= NULL
;
1003 #if defined(BINARY_SUPPORT_DYLD)
1004 if (!imagePath
) imagePath
= _CFBundleDYLDCopyLoadedImagePathForPointer(p
);
1005 #elif defined(BINARY_SUPPORT_DLFCN)
1006 if (!imagePath
) imagePath
= _CFBundleDlfcnCopyLoadedImagePathForPointer(p
);
1007 #endif /* BINARY_SUPPORT_DYLD */
1009 _CFBundleEnsureBundleExistsForImagePath(imagePath
);
1010 CFRelease(imagePath
);
1012 result
= _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID
);
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 pthread_mutex_unlock(&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 if (bundle
->_bundleBasePath
) CFRelease(bundle
->_bundleBasePath
);
1100 if (bundle
->_queryTable
) CFRelease(bundle
->_queryTable
);
1102 pthread_mutex_destroy(&(bundle
->_bundleLoadingLock
));
1105 static const CFRuntimeClass __CFBundleClass
= {
1106 _kCFRuntimeScannedObject
,
1110 __CFBundleDeallocate
,
1114 __CFBundleCopyDescription
1117 // From CFBundle_Resources.c
1118 __private_extern__
void _CFBundleResourcesInitialize();
1120 __private_extern__
void __CFBundleInitialize(void) {
1121 __kCFBundleTypeID
= _CFRuntimeRegisterClass(&__CFBundleClass
);
1122 _CFBundleResourcesInitialize();
1125 CFTypeID
CFBundleGetTypeID(void) {
1126 return __kCFBundleTypeID
;
1129 CFBundleRef
_CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL
) {
1130 CFBundleRef bundle
= NULL
;
1131 char buff
[CFMaxPathSize
];
1132 CFURLRef newURL
= NULL
;
1134 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) return NULL
;
1136 newURL
= CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault
, (uint8_t *)buff
, strlen(buff
), true);
1137 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1138 bundle
= _CFBundleCopyBundleForURL(newURL
, false);
1139 if (bundle
) CFRelease(bundle
);
1144 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
) {
1145 allocator
= _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator
);
1146 CFBundleRef bundle
= NULL
;
1147 char buff
[CFMaxPathSize
];
1148 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
1149 Boolean exists
= false;
1151 CFURLRef newURL
= NULL
;
1152 uint8_t localVersion
= 0;
1154 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) return NULL
;
1156 newURL
= CFURLCreateFromFileSystemRepresentation(allocator
, (uint8_t *)buff
, strlen(buff
), true);
1157 if (!newURL
) newURL
= (CFURLRef
)CFRetain(bundleURL
);
1158 bundle
= _CFBundleCopyBundleForURL(newURL
, alreadyLocked
);
1164 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
1166 SInt32 res
= _CFGetPathProperties(allocator
, (char *)buff
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
);
1167 #if DEPLOYMENT_TARGET_WINDOWS
1168 if (!(res
== 0 && exists
&& ((mode
& S_IFMT
) == S_IFDIR
))) {
1169 // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again
1174 CFURLRef shorterPath
= CFURLCreateCopyDeletingLastPathComponent(allocator
, newURL
);
1176 newURL
= shorterPath
;
1177 res
= _CFGetFileProperties(allocator
, newURL
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
);
1181 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
1182 if (modDate
) CFRelease(modDate
);
1192 bundle
= (CFBundleRef
)_CFRuntimeCreateInstance(allocator
, __kCFBundleTypeID
, sizeof(struct __CFBundle
) - sizeof(CFRuntimeBase
), NULL
);
1198 bundle
->_url
= newURL
;
1200 bundle
->_modDate
= modDate
;
1201 bundle
->_version
= localVersion
;
1202 bundle
->_infoDict
= NULL
;
1203 bundle
->_localInfoDict
= NULL
;
1204 bundle
->_searchLanguages
= NULL
;
1206 #if defined(BINARY_SUPPORT_DYLD)
1207 /* We'll have to figure it out later */
1208 bundle
->_binaryType
= __CFBundleUnknownBinary
;
1209 #elif defined(BINARY_SUPPORT_DLL)
1210 /* We support DLL only */
1211 bundle
->_binaryType
= __CFBundleDLLBinary
;
1212 bundle
->_hModule
= NULL
;
1214 /* We'll have to figure it out later */
1215 bundle
->_binaryType
= __CFBundleUnknownBinary
;
1216 #endif /* BINARY_SUPPORT_DYLD */
1218 bundle
->_isLoaded
= false;
1219 bundle
->_sharesStringsFiles
= false;
1221 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1222 if (!__CFgetenv("CFBundleDisableStringsSharing") &&
1223 (strncmp(buff
, "/System/Library/Frameworks", 26) == 0) &&
1224 (strncmp(buff
+ strlen(buff
) - 10, ".framework", 10) == 0)) bundle
->_sharesStringsFiles
= true;
1227 bundle
->_connectionCookie
= NULL
;
1228 bundle
->_handleCookie
= NULL
;
1229 bundle
->_imageCookie
= NULL
;
1230 bundle
->_moduleCookie
= NULL
;
1232 bundle
->_glueDict
= NULL
;
1234 bundle
->_resourceData
._executableLacksResourceFork
= false;
1235 bundle
->_resourceData
._infoDictionaryFromResourceFork
= false;
1236 bundle
->_resourceData
._stringTableCache
= NULL
;
1238 bundle
->_plugInData
._isPlugIn
= false;
1239 bundle
->_plugInData
._loadOnDemand
= false;
1240 bundle
->_plugInData
._isDoingDynamicRegistration
= false;
1241 bundle
->_plugInData
._instanceCount
= 0;
1242 bundle
->_plugInData
._factories
= NULL
;
1244 pthread_mutexattr_t mattr
;
1245 pthread_mutexattr_init(&mattr
);
1246 pthread_mutexattr_settype(&mattr
, PTHREAD_MUTEX_DEFAULT
);
1247 int32_t mret
= pthread_mutex_init(&(bundle
->_bundleLoadingLock
), &mattr
);
1248 pthread_mutexattr_destroy(&mattr
);
1250 CFLog(4, CFSTR("%s: failed to initialize bundle loading lock for bundle %@."), __PRETTY_FUNCTION__
, bundle
);
1254 /* resource fast look up */
1255 bundle
->_queryLock
= CFSpinLockInit
;
1256 bundle
->_queryTable
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1257 CFURLRef absoURL
= CFURLCopyAbsoluteURL(bundle
->_url
);
1258 bundle
->_bundleBasePath
= CFURLCopyFileSystemPath(absoURL
, PLATFORM_PATH_STYLE
);
1261 CFBundleGetInfoDictionary(bundle
);
1263 _CFBundleAddToTables(bundle
, alreadyLocked
);
1265 if (doFinalProcessing
) {
1266 if (_CFBundleNeedsInitPlugIn(bundle
)) {
1267 if (alreadyLocked
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
1268 _CFBundleInitPlugIn(bundle
);
1269 if (alreadyLocked
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
1276 CFBundleRef
CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
) {
1277 return _CFBundleCreate(allocator
, bundleURL
, false, true);
1280 CFArrayRef
CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc
, CFURLRef directoryURL
, CFStringRef bundleType
) {
1281 alloc
= _CFConvertAllocatorToNonGCRefZeroEquivalent(alloc
);
1282 CFMutableArrayRef bundles
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
1283 CFArrayRef URLs
= _CFContentsOfDirectory(alloc
, NULL
, NULL
, directoryURL
, bundleType
);
1285 CFIndex i
, c
= CFArrayGetCount(URLs
);
1287 CFBundleRef curBundle
;
1289 for (i
= 0; i
< c
; i
++) {
1290 curURL
= (CFURLRef
)CFArrayGetValueAtIndex(URLs
, i
);
1291 curBundle
= CFBundleCreate(alloc
, curURL
);
1292 if (curBundle
) CFArrayAppendValue(bundles
, curBundle
);
1300 CFURLRef
CFBundleCopyBundleURL(CFBundleRef bundle
) {
1301 if (bundle
->_url
) CFRetain(bundle
->_url
);
1302 return bundle
->_url
;
1305 void _CFBundleSetDefaultLocalization(CFStringRef localizationName
) {
1306 CFStringRef newLocalization
= localizationName
? (CFStringRef
)CFStringCreateCopy(kCFAllocatorSystemDefault
, localizationName
) : NULL
;
1307 if (_defaultLocalization
) CFRelease(_defaultLocalization
);
1308 _defaultLocalization
= newLocalization
;
1311 CFArrayRef
_CFBundleGetLanguageSearchList(CFBundleRef bundle
) {
1312 if (!bundle
->_searchLanguages
) {
1313 CFMutableArrayRef langs
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
1314 CFStringRef devLang
= CFBundleGetDevelopmentRegion(bundle
);
1316 #if DEPLOYMENT_TARGET_WINDOWS
1317 if (_defaultLocalization
) CFArrayAppendValue(langs
, _defaultLocalization
);
1319 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, devLang
);
1321 if (CFArrayGetCount(langs
) == 0) {
1322 // If the user does not prefer any of our languages, and devLang is not present, try English
1323 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFSTR("en_US"));
1325 if (CFArrayGetCount(langs
) == 0) {
1326 // if none of the preferred localizations are present, fall back on a random localization that is present
1327 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
1328 if (localizations
) {
1329 if (CFArrayGetCount(localizations
) > 0) _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, (CFStringRef
)CFArrayGetValueAtIndex(localizations
, 0));
1330 CFRelease(localizations
);
1334 if (devLang
&& !CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
)) {
1335 // Make sure that devLang is on the list as a fallback for individual resources that are not present
1336 CFArrayAppendValue(langs
, devLang
);
1337 } else if (!devLang
) {
1338 // Or if there is no devLang, try some variation of English that is present
1339 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
1340 if (localizations
) {
1341 CFStringRef en_US
= CFSTR("en_US"), en
= CFSTR("en"), English
= CFSTR("English");
1342 CFRange range
= CFRangeMake(0, CFArrayGetCount(localizations
));
1343 if (CFArrayContainsValue(localizations
, range
, en
)) {
1344 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en
)) CFArrayAppendValue(langs
, en
);
1345 } else if (CFArrayContainsValue(localizations
, range
, English
)) {
1346 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), English
)) CFArrayAppendValue(langs
, English
);
1347 } else if (CFArrayContainsValue(localizations
, range
, en_US
)) {
1348 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en_US
)) CFArrayAppendValue(langs
, en_US
);
1350 CFRelease(localizations
);
1353 if (CFArrayGetCount(langs
) == 0) {
1354 // Total backstop behavior to avoid having an empty array.
1355 if (_defaultLocalization
) {
1356 CFArrayAppendValue(langs
, _defaultLocalization
);
1358 CFArrayAppendValue(langs
, CFSTR("en"));
1361 if (!OSAtomicCompareAndSwapPtrBarrier(NULL
, (void *)langs
, (void * volatile *)&(bundle
->_searchLanguages
))) CFRelease(langs
);
1363 return bundle
->_searchLanguages
;
1366 CFDictionaryRef
CFBundleCopyInfoDictionaryInDirectory(CFURLRef url
) {
1367 CFDictionaryRef dict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, NULL
);
1368 if (dict
&& _CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRetain(dict
); // conditionally put on a retain for a Copy function
1372 CFDictionaryRef
CFBundleGetInfoDictionary(CFBundleRef bundle
) {
1373 if (!bundle
->_infoDict
) bundle
->_infoDict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(kCFAllocatorSystemDefaultGCRefZero
, bundle
->_url
, bundle
->_version
);
1374 return bundle
->_infoDict
;
1377 CFDictionaryRef
_CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
1378 return CFBundleGetLocalInfoDictionary(bundle
);
1381 CFDictionaryRef
CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
1382 static pthread_mutex_t CFBundleLocalInfoLock
= PTHREAD_MUTEX_INITIALIZER
;
1383 CFDictionaryRef localInfoDict
= bundle
->_localInfoDict
;
1384 if (!localInfoDict
) {
1385 CFURLRef url
= CFBundleCopyResourceURL(bundle
, _CFBundleLocalInfoName
, _CFBundleStringTableType
, NULL
);
1389 CFStringRef errStr
= NULL
;
1391 if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, url
, &data
, NULL
, NULL
, &errCode
)) {
1392 localInfoDict
= (CFDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero
, data
, kCFPropertyListMutableContainers
, &errStr
);
1393 if (errStr
) CFRelease(errStr
);
1394 if (localInfoDict
&& CFDictionaryGetTypeID() != CFGetTypeID(localInfoDict
)) {
1395 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(localInfoDict
);
1396 localInfoDict
= NULL
;
1402 if (localInfoDict
) _processInfoDictionary((CFMutableDictionaryRef
)localInfoDict
, _CFGetPlatformName(), _CFGetProductName());
1403 pthread_mutex_lock(&CFBundleLocalInfoLock
);
1404 if (!bundle
->_localInfoDict
) {
1405 bundle
->_localInfoDict
= localInfoDict
;
1407 if (localInfoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(localInfoDict
);
1408 localInfoDict
= bundle
->_localInfoDict
;
1410 pthread_mutex_unlock(&CFBundleLocalInfoLock
);
1412 return localInfoDict
;
1415 CFPropertyListRef
_CFBundleGetValueForInfoKey(CFBundleRef bundle
, CFStringRef key
) {
1416 return (CFPropertyListRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, key
);
1419 CFTypeRef
CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle
, CFStringRef key
) {
1420 // Look in InfoPlist.strings first. Then look in Info.plist
1421 CFTypeRef result
= NULL
;
1422 if (bundle
&& key
) {
1423 CFDictionaryRef dict
= CFBundleGetLocalInfoDictionary(bundle
);
1424 if (dict
) result
= CFDictionaryGetValue(dict
, key
);
1426 dict
= CFBundleGetInfoDictionary(bundle
);
1427 if (dict
) result
= CFDictionaryGetValue(dict
, key
);
1433 CFStringRef
CFBundleGetIdentifier(CFBundleRef bundle
) {
1434 CFStringRef bundleID
= NULL
;
1435 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1436 if (infoDict
) bundleID
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleIdentifierKey
);
1440 #define DEVELOPMENT_STAGE 0x20
1441 #define ALPHA_STAGE 0x40
1442 #define BETA_STAGE 0x60
1443 #define RELEASE_STAGE 0x80
1445 #define MAX_VERS_LEN 10
1447 CF_INLINE Boolean
_isDigit(UniChar aChar
) {return ((aChar
>= (UniChar
)'0' && aChar
<= (UniChar
)'9') ? true : false);}
1449 __private_extern__ CFStringRef
_CFCreateStringFromVersionNumber(CFAllocatorRef alloc
, UInt32 vers
) {
1450 CFStringRef result
= NULL
;
1451 uint8_t major1
, major2
, minor1
, minor2
, stage
, build
;
1453 major1
= (vers
& 0xF0000000) >> 28;
1454 major2
= (vers
& 0x0F000000) >> 24;
1455 minor1
= (vers
& 0x00F00000) >> 20;
1456 minor2
= (vers
& 0x000F0000) >> 16;
1457 stage
= (vers
& 0x0000FF00) >> 8;
1458 build
= (vers
& 0x000000FF);
1460 if (stage
== RELEASE_STAGE
) {
1462 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d"), major1
, major2
, minor1
, minor2
);
1464 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d"), major2
, minor1
, minor2
);
1468 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
);
1470 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d%C%d"), major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? 'd' : ((stage
== ALPHA_STAGE
) ? 'a' : 'b')), build
);
1476 __private_extern__ UInt32
_CFVersionNumberFromString(CFStringRef versStr
) {
1477 // Parse version number from string.
1478 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1479 UInt32 major1
= 0, major2
= 0, minor1
= 0, minor2
= 0, stage
= RELEASE_STAGE
, build
= 0;
1480 UniChar versChars
[MAX_VERS_LEN
];
1481 UniChar
*chars
= NULL
;
1484 Boolean digitsDone
= false;
1486 if (!versStr
) return 0;
1487 len
= CFStringGetLength(versStr
);
1488 if (len
<= 0 || len
> MAX_VERS_LEN
) return 0;
1490 CFStringGetCharacters(versStr
, CFRangeMake(0, len
), versChars
);
1493 // Get major version number.
1494 major1
= major2
= 0;
1495 if (_isDigit(*chars
)) {
1496 major2
= *chars
- (UniChar
)'0';
1500 if (_isDigit(*chars
)) {
1502 major2
= *chars
- (UniChar
)'0';
1506 if (*chars
== (UniChar
)'.') {
1513 } else if (*chars
== (UniChar
)'.') {
1520 } else if (*chars
== (UniChar
)'.') {
1527 // Now major1 and major2 contain first and second digit of the major version number as ints.
1528 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1530 // Get the first minor version number.
1531 if (len
> 0 && !digitsDone
) {
1532 if (_isDigit(*chars
)) {
1533 minor1
= *chars
- (UniChar
)'0';
1537 if (*chars
== (UniChar
)'.') {
1549 // Now minor1 contains the first minor version number as an int.
1550 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1552 // Get the second minor version number.
1553 if (len
> 0 && !digitsDone
) {
1554 if (_isDigit(*chars
)) {
1555 minor2
= *chars
- (UniChar
)'0';
1563 // Now minor2 contains the second minor version number as an int.
1564 // Now either len is 0 or chars points at the build stage letter.
1566 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1568 if (*chars
== (UniChar
)'d') {
1569 stage
= DEVELOPMENT_STAGE
;
1570 } else if (*chars
== (UniChar
)'a') {
1571 stage
= ALPHA_STAGE
;
1572 } else if (*chars
== (UniChar
)'b') {
1574 } else if (*chars
== (UniChar
)'f') {
1575 stage
= RELEASE_STAGE
;
1583 // Now stage contains the release stage.
1584 // Now either len is 0 or chars points at the build number.
1586 // Get the first digit of the build number.
1588 if (_isDigit(*chars
)) {
1589 build
= *chars
- (UniChar
)'0';
1596 // Get the second digit of the build number.
1598 if (_isDigit(*chars
)) {
1600 build
+= *chars
- (UniChar
)'0';
1607 // Get the third digit of the build number.
1609 if (_isDigit(*chars
)) {
1611 build
+= *chars
- (UniChar
)'0';
1619 // Range check the build number and make sure we exhausted the string.
1620 if (build
> 0xFF || len
> 0) return 0;
1623 theVers
= major1
<< 28;
1624 theVers
+= major2
<< 24;
1625 theVers
+= minor1
<< 20;
1626 theVers
+= minor2
<< 16;
1627 theVers
+= stage
<< 8;
1633 UInt32
CFBundleGetVersionNumber(CFBundleRef bundle
) {
1634 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1635 CFTypeRef unknownVersionValue
= CFDictionaryGetValue(infoDict
, _kCFBundleNumericVersionKey
);
1636 CFNumberRef versNum
;
1639 if (!unknownVersionValue
) unknownVersionValue
= CFDictionaryGetValue(infoDict
, kCFBundleVersionKey
);
1640 if (unknownVersionValue
) {
1641 if (CFGetTypeID(unknownVersionValue
) == CFStringGetTypeID()) {
1642 // Convert a string version number into a numeric one.
1643 vers
= _CFVersionNumberFromString((CFStringRef
)unknownVersionValue
);
1645 versNum
= CFNumberCreate(CFGetAllocator(bundle
), kCFNumberSInt32Type
, &vers
);
1646 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
, versNum
);
1648 } else if (CFGetTypeID(unknownVersionValue
) == CFNumberGetTypeID()) {
1649 CFNumberGetValue((CFNumberRef
)unknownVersionValue
, kCFNumberSInt32Type
, &vers
);
1651 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
);
1657 CFStringRef
CFBundleGetDevelopmentRegion(CFBundleRef bundle
) {
1658 CFStringRef devLang
= NULL
;
1659 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1661 devLang
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1662 if (devLang
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) {
1664 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleDevelopmentRegionKey
);
1671 Boolean
_CFBundleGetHasChanged(CFBundleRef bundle
) {
1673 Boolean result
= false;
1674 Boolean exists
= false;
1677 if (_CFGetFileProperties(CFGetAllocator(bundle
), bundle
->_url
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
1678 // If the bundle no longer exists or is not a folder, it must have "changed"
1679 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) result
= true;
1681 // Something is wrong. The stat failed.
1684 if (bundle
->_modDate
&& !CFEqual(bundle
->_modDate
, modDate
)) {
1685 // mod date is different from when we created.
1692 void _CFBundleSetStringsFilesShared(CFBundleRef bundle
, Boolean flag
) {
1693 bundle
->_sharesStringsFiles
= flag
;
1696 Boolean
_CFBundleGetStringsFilesShared(CFBundleRef bundle
) {
1697 return bundle
->_sharesStringsFiles
;
1700 static Boolean
_urlExists(CFURLRef url
) {
1702 return url
&& (0 == _CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, NULL
, NULL
, NULL
, NULL
, NULL
)) && exists
;
1705 // This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their
1706 // original locations on disk, so checking whether a binary's path exists is no longer sufficient.
1707 // For performance reasons, we only call dlopen_preflight() after we've verified that the binary
1708 // does not exist at its original path with _urlExists().
1709 // See <rdar://problem/6956670>
1710 static Boolean
_binaryLoadable(CFURLRef url
) {
1711 Boolean loadable
= _urlExists(url
);
1712 #if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1714 uint8_t path
[PATH_MAX
];
1715 if (url
&& CFURLGetFileSystemRepresentation(url
, true, path
, sizeof(path
))) {
1716 loadable
= dlopen_preflight((char *)path
);
1723 __private_extern__ CFURLRef
_CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1724 CFURLRef result
= NULL
;
1727 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase1
, bundleURL
);
1728 } else if (2 == version
) {
1729 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleSupportFilesURLFromBase2
, bundleURL
);
1731 result
= (CFURLRef
)CFRetain(bundleURL
);
1737 CF_EXPORT CFURLRef
CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle
) {
1738 return _CFBundleCopySupportFilesDirectoryURLInDirectory(bundle
->_url
, bundle
->_version
);
1741 __private_extern__ CFURLRef
_CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1742 CFURLRef result
= NULL
;
1745 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase0
, bundleURL
);
1746 } else if (1 == version
) {
1747 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase1
, bundleURL
);
1748 } else if (2 == version
) {
1749 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleResourcesURLFromBase2
, bundleURL
);
1751 result
= (CFURLRef
)CFRetain(bundleURL
);
1757 CFURLRef
CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle
) {
1758 return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle
->_url
, bundle
->_version
);
1761 __private_extern__ CFURLRef
_CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL
, uint8_t version
) {
1762 CFURLRef result
= NULL
;
1765 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase0
, bundleURL
);
1766 } else if (1 == version
) {
1767 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase1
, bundleURL
);
1768 } else if (2 == version
) {
1769 result
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleAppStoreReceiptURLFromBase2
, bundleURL
);
1775 CFURLRef
_CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle
) {
1776 return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle
->_url
, bundle
->_version
);
1779 static CFURLRef
_CFBundleCopyExecutableURLRaw(CFURLRef urlPath
, CFStringRef exeName
) {
1780 // 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.
1781 CFURLRef executableURL
= NULL
;
1782 if (!urlPath
|| !exeName
) return NULL
;
1784 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1785 const uint8_t *image_suffix
= (uint8_t *)__CFgetenv("DYLD_IMAGE_SUFFIX");
1787 CFStringRef newExeName
, imageSuffix
;
1788 imageSuffix
= CFStringCreateWithCString(kCFAllocatorSystemDefault
, (char *)image_suffix
, kCFStringEncodingUTF8
);
1789 if (CFStringHasSuffix(exeName
, CFSTR(".dylib"))) {
1790 CFStringRef bareExeName
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, exeName
, CFRangeMake(0, CFStringGetLength(exeName
)-6));
1791 newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@.dylib"), exeName
, imageSuffix
);
1792 CFRelease(bareExeName
);
1794 newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, imageSuffix
);
1796 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, newExeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1797 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1798 CFRelease(executableURL
);
1799 executableURL
= NULL
;
1801 CFRelease(newExeName
);
1802 CFRelease(imageSuffix
);
1804 if (!executableURL
) {
1805 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, exeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1806 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1807 CFRelease(executableURL
);
1808 executableURL
= NULL
;
1811 #elif DEPLOYMENT_TARGET_WINDOWS
1812 if (!executableURL
) {
1813 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, exeName
, kCFURLWindowsPathStyle
, false, urlPath
);
1814 if (executableURL
&& !_urlExists(executableURL
)) {
1815 CFRelease(executableURL
);
1816 executableURL
= NULL
;
1819 if (!executableURL
) {
1820 if (!CFStringFindWithOptions(exeName
, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName
)), kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
1822 CFStringRef extension
= CFSTR("_debug.dll");
1824 CFStringRef extension
= CFSTR(".dll");
1826 CFStringRef newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, extension
);
1827 executableURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, newExeName
, urlPath
);
1828 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1829 CFRelease(executableURL
);
1830 executableURL
= NULL
;
1832 CFRelease(newExeName
);
1835 if (!executableURL
) {
1836 if (!CFStringFindWithOptions(exeName
, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName
)), kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
1838 CFStringRef extension
= CFSTR("_debug.exe");
1840 CFStringRef extension
= CFSTR(".exe");
1842 CFStringRef newExeName
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@%@"), exeName
, extension
);
1843 executableURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, newExeName
, urlPath
);
1844 if (executableURL
&& !_binaryLoadable(executableURL
)) {
1845 CFRelease(executableURL
);
1846 executableURL
= NULL
;
1848 CFRelease(newExeName
);
1852 return executableURL
;
1855 static CFStringRef
_CFBundleCopyExecutableName(CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
) {
1856 CFStringRef executableName
= NULL
;
1858 if (!infoDict
&& bundle
) infoDict
= CFBundleGetInfoDictionary(bundle
);
1859 if (!url
&& bundle
) url
= bundle
->_url
;
1862 // Figure out the name of the executable.
1863 // First try for the new key in the plist.
1864 executableName
= (CFStringRef
)CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
);
1865 // Second try for the old key in the plist.
1866 if (!executableName
) executableName
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleOldExecutableKey
);
1867 if (executableName
&& CFGetTypeID(executableName
) == CFStringGetTypeID() && CFStringGetLength(executableName
) > 0) {
1868 CFRetain(executableName
);
1870 executableName
= NULL
;
1873 if (!executableName
&& url
) {
1874 // Third, take the name of the bundle itself (with path extension stripped)
1875 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1876 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1877 CFRelease(absoluteURL
);
1879 UniChar buff
[CFMaxPathSize
];
1880 CFIndex len
= CFStringGetLength(bundlePath
);
1881 CFIndex startOfBundleName
, endOfBundleName
;
1883 if (len
> CFMaxPathSize
) len
= CFMaxPathSize
;
1884 CFStringGetCharacters(bundlePath
, CFRangeMake(0, len
), buff
);
1885 startOfBundleName
= _CFStartOfLastPathComponent(buff
, len
);
1886 endOfBundleName
= _CFLengthAfterDeletingPathExtension(buff
, len
);
1888 if (startOfBundleName
<= len
&& endOfBundleName
<= len
&& startOfBundleName
< endOfBundleName
) executableName
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfBundleName
]), endOfBundleName
- startOfBundleName
);
1889 CFRelease(bundlePath
);
1893 return executableName
;
1896 __private_extern__ CFURLRef
_CFBundleCopyResourceForkURLWithoutLocal(CFBundleRef bundle
) {
1897 CFStringRef executableName
= _CFBundleCopyExecutableName(bundle
, NULL
, NULL
);
1898 CFURLRef resourceForkURL
= NULL
;
1899 if (executableName
) {
1900 UniChar
*path
= (UniChar
*) CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(UniChar
) * CFMaxPathSize
, 0);
1901 CFIndex pathLen
= CFStringGetLength(bundle
->_bundleBasePath
);
1902 CFStringGetCharacters(bundle
->_bundleBasePath
, CFRangeMake(0, CFStringGetLength(bundle
->_bundleBasePath
)), path
);
1903 _CFBundleSetResourceDir(path
, &pathLen
, CFMaxPathSize
, bundle
->_version
);
1904 _CFAppendTrailingPathSlash(path
, &pathLen
, CFMaxPathSize
);
1905 CFStringGetCharacters(executableName
, CFRangeMake(0, CFStringGetLength(executableName
)), path
+pathLen
);
1906 pathLen
+= CFStringGetLength(executableName
);
1907 path
[pathLen
++] = '.';
1908 CFStringGetCharacters(CFSTR("rsrc"), CFRangeMake(0, 4), path
+pathLen
);
1910 CFStringRef pathStr
= CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, path
, pathLen
);
1911 Boolean found
= false;
1912 found
= _CFIsResourceAtPath(pathStr
, NULL
);
1914 resourceForkURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, pathStr
, PLATFORM_PATH_STYLE
, false);
1917 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, path
);
1918 CFRelease(executableName
);
1921 return resourceForkURL
;
1924 __private_extern__ CFURLRef
_CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle
, Boolean mayBeLocal
) {
1925 CFStringRef executableName
= _CFBundleCopyExecutableName(bundle
, NULL
, NULL
);
1926 CFURLRef resourceForkURL
= NULL
;
1927 if (executableName
) {
1928 CFStringRef type
= CFSTR("rsrc");
1929 #ifdef CFBUNDLE_NEWLOOKUP
1931 resourceForkURL
= (CFURLRef
) _CFBundleCopyFindResourcesWithNoBlock(bundle
, NULL
, NULL
, executableName
, type
, NULL
, NULL
, NO
, NO
);
1933 CFArrayRef languages
= CFArrayCreate(kCFAllocatorSystemDefault
, NULL
, 0, &kCFTypeArrayCallBacks
);
1934 resourceForkURL
= (CFURLRef
) _CFBundleCopyFindResourcesWithNoBlock(bundle
, NULL
, languages
, executableName
, type
, NULL
, NULL
, NO
, NO
);
1935 CFRelease(languages
);
1938 CFArrayRef types
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&type
, 1, &kCFTypeArrayCallBacks
);
1939 CFArrayRef array
= NULL
;
1941 CFArrayRef languages
= _CFBundleGetLanguageSearchList(bundle
);
1942 array
= _CFFindBundleResourcesNoBlock(bundle
, NULL
, NULL
, languages
, executableName
, types
, 1, _CFBundleLayoutVersion(bundle
));
1944 if (CFArrayGetCount(array
) > 0) resourceForkURL
= (CFURLRef
)CFRetain(CFArrayGetValueAtIndex(array
, 0));
1948 array
= _CFFindBundleResourcesNoBlock(bundle
, NULL
, NULL
, NULL
, executableName
, types
, 1, _CFBundleLayoutVersion(bundle
));
1950 if (CFArrayGetCount(array
) > 0) resourceForkURL
= (CFURLRef
)CFRetain(CFArrayGetValueAtIndex(array
, 0));
1956 CFRelease(executableName
);
1959 return resourceForkURL
;
1962 CFURLRef
_CFBundleCopyResourceForkURL(CFBundleRef bundle
) {
1963 return _CFBundleCopyResourceForkURLMayBeLocal(bundle
, true);
1966 static CFURLRef
_CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle
, CFURLRef url
, CFStringRef executableName
, Boolean ignoreCache
, Boolean useOtherPlatform
) {
1967 uint8_t version
= 0;
1968 CFDictionaryRef infoDict
= NULL
;
1969 CFStringRef executablePath
= NULL
;
1970 CFURLRef executableURL
= NULL
;
1971 Boolean foundIt
= false;
1972 Boolean lookupMainExe
= (executableName
? false : true);
1973 static CFSpinLock_t CFBundleExecutablePathLock
= CFSpinLockInit
;
1976 infoDict
= CFBundleGetInfoDictionary(bundle
);
1977 version
= bundle
->_version
;
1979 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero
, url
, &version
);
1982 // If we have a bundle instance and an info dict, see if we have already cached the path
1983 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& bundle
&& infoDict
) {
1984 __CFSpinLock(&CFBundleExecutablePathLock
);
1985 executablePath
= (CFStringRef
)CFDictionaryGetValue(infoDict
, _kCFBundleExecutablePathKey
);
1986 if (executablePath
) CFRetain(executablePath
);
1987 __CFSpinUnlock(&CFBundleExecutablePathLock
);
1988 if (executablePath
) {
1989 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
1990 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, executablePath
, kCFURLPOSIXPathStyle
, false);
1991 #elif DEPLOYMENT_TARGET_WINDOWS
1992 executableURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, executablePath
, kCFURLWindowsPathStyle
, false);
1994 if (executableURL
) {
1997 __CFSpinLock(&CFBundleExecutablePathLock
);
1998 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
);
1999 __CFSpinUnlock(&CFBundleExecutablePathLock
);
2001 CFRelease(executablePath
);
2006 if (lookupMainExe
) executableName
= _CFBundleCopyExecutableName(bundle
, url
, infoDict
);
2007 if (executableName
) {
2008 #if (DEPLOYMENT_TARGET_EMBEDDED && !TARGET_IPHONE_SIMULATOR)
2009 Boolean doExecSearch
= false;
2011 Boolean doExecSearch
= true;
2013 // Now, look for the executable inside the bundle.
2014 if (doExecSearch
&& 0 != version
) {
2015 CFURLRef exeDirURL
= NULL
;
2016 CFURLRef exeSubdirURL
;
2019 exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleExecutablesURLFromBase1
, url
);
2020 } else if (2 == version
) {
2021 exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, _CFBundleExecutablesURLFromBase2
, url
);
2023 #if DEPLOYMENT_TARGET_WINDOWS
2024 // On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory
2025 CFStringRef extension
= CFURLCopyPathExtension(url
);
2026 if (extension
&& CFEqual(extension
, _CFBundleWindowsResourceDirectoryExtension
)) {
2027 exeDirURL
= CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault
, url
);
2029 exeDirURL
= (CFURLRef
)CFRetain(url
);
2031 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2032 exeDirURL
= (CFURLRef
)CFRetain(url
);
2035 CFStringRef platformSubDir
= useOtherPlatform
? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName();
2036 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
2037 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
2038 if (!executableURL
) {
2039 CFRelease(exeSubdirURL
);
2040 platformSubDir
= useOtherPlatform
? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName();
2041 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
2042 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
2044 if (!executableURL
) {
2045 CFRelease(exeSubdirURL
);
2046 platformSubDir
= useOtherPlatform
? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName();
2047 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
2048 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
2050 if (!executableURL
) {
2051 CFRelease(exeSubdirURL
);
2052 platformSubDir
= useOtherPlatform
? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName();
2053 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault
, platformSubDir
, kCFURLPOSIXPathStyle
, true, exeDirURL
);
2054 executableURL
= _CFBundleCopyExecutableURLRaw(exeSubdirURL
, executableName
);
2056 if (!executableURL
) executableURL
= _CFBundleCopyExecutableURLRaw(exeDirURL
, executableName
);
2057 CFRelease(exeDirURL
);
2058 CFRelease(exeSubdirURL
);
2061 // If this was an old bundle, or we did not find the executable in the Executables subdirectory, look directly in the bundle wrapper.
2062 if (!executableURL
) executableURL
= _CFBundleCopyExecutableURLRaw(url
, executableName
);
2064 #if DEPLOYMENT_TARGET_WINDOWS
2065 // Windows only: If we still haven't found the exe, look in the Executables folder.
2066 // But only for the main bundle exe
2067 if (lookupMainExe
&& !executableURL
) {
2068 CFURLRef exeDirURL
= CFURLCreateWithString(kCFAllocatorSystemDefault
, CFSTR("../../Executables"), url
);
2069 executableURL
= _CFBundleCopyExecutableURLRaw(exeDirURL
, executableName
);
2070 CFRelease(exeDirURL
);
2074 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& bundle
&& infoDict
&& executableURL
) {
2075 // We found it. Cache the path.
2076 CFURLRef absURL
= CFURLCopyAbsoluteURL(executableURL
);
2077 #if DEPLOYMENT_TARGET_WINDOWS
2078 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLWindowsPathStyle
);
2079 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
2080 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLPOSIXPathStyle
);
2083 __CFSpinLock(&CFBundleExecutablePathLock
);
2084 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
, executablePath
);
2085 __CFSpinUnlock(&CFBundleExecutablePathLock
);
2086 CFRelease(executablePath
);
2088 if (lookupMainExe
&& !useOtherPlatform
&& bundle
&& !executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
2089 if (lookupMainExe
) CFRelease(executableName
);
2092 if (!bundle
&& infoDict
&& !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero
)) CFRelease(infoDict
);
2093 return executableURL
;
2096 CFURLRef
_CFBundleCopyExecutableURLInDirectory(CFURLRef url
) {
2097 return _CFBundleCopyExecutableURLInDirectory2(NULL
, url
, NULL
, true, false);
2100 CFURLRef
_CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url
) {
2101 return _CFBundleCopyExecutableURLInDirectory2(NULL
, url
, NULL
, true, true);
2104 CFURLRef
CFBundleCopyExecutableURL(CFBundleRef bundle
) {
2105 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, NULL
, false, false);
2108 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
) {
2109 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, NULL
, true, false);
2112 CFURLRef
CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle
, CFStringRef executableName
) {
2113 return _CFBundleCopyExecutableURLInDirectory2(bundle
, bundle
->_url
, executableName
, true, false);
2116 Boolean
CFBundleIsExecutableLoaded(CFBundleRef bundle
) {
2117 return bundle
->_isLoaded
;
2120 CFBundleExecutableType
CFBundleGetExecutableType(CFBundleRef bundle
) {
2121 CFBundleExecutableType result
= kCFBundleOtherExecutableType
;
2122 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2124 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
2125 #if defined(BINARY_SUPPORT_DYLD)
2126 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2127 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
2128 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
2130 #endif /* BINARY_SUPPORT_DYLD */
2131 if (executableURL
) CFRelease(executableURL
);
2133 if (bundle
->_binaryType
== __CFBundleCFMBinary
) {
2134 result
= kCFBundlePEFExecutableType
;
2135 } else if (bundle
->_binaryType
== __CFBundleDYLDExecutableBinary
|| bundle
->_binaryType
== __CFBundleDYLDBundleBinary
|| bundle
->_binaryType
== __CFBundleDYLDFrameworkBinary
) {
2136 result
= kCFBundleMachOExecutableType
;
2137 } else if (bundle
->_binaryType
== __CFBundleDLLBinary
) {
2138 result
= kCFBundleDLLExecutableType
;
2139 } else if (bundle
->_binaryType
== __CFBundleELFBinary
) {
2140 result
= kCFBundleELFExecutableType
;
2145 static SInt32
_CFBundleCurrentArchitecture(void) {
2147 #if defined(__ppc__)
2148 arch
= kCFBundleExecutableArchitecturePPC
;
2149 #elif defined(__ppc64__)
2150 arch
= kCFBundleExecutableArchitecturePPC64
;
2151 #elif defined(__i386__)
2152 arch
= kCFBundleExecutableArchitectureI386
;
2153 #elif defined(__x86_64__)
2154 arch
= kCFBundleExecutableArchitectureX86_64
;
2155 #elif defined(BINARY_SUPPORT_DYLD)
2156 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
2157 if (archInfo
) arch
= archInfo
->cputype
;
2162 #define UNKNOWN_FILETYPE 0x0
2163 #define PEF_FILETYPE 0x1000
2164 #define PEF_MAGIC 0x4a6f7921
2165 #define PEF_CIGAM 0x21796f4a
2166 #define TEXT_SEGMENT "__TEXT"
2167 #define PLIST_SECTION "__info_plist"
2168 #define OBJC_SEGMENT "__OBJC"
2169 #define IMAGE_INFO_SECTION "__image_info"
2170 #define OBJC_SEGMENT_64 "__DATA"
2171 #define IMAGE_INFO_SECTION_64 "__objc_imageinfo"
2172 #define LIB_X11 "/usr/X11R6/lib/libX"
2174 #define XLS_NAME "Book"
2175 #define XLS_NAME2 "Workbook"
2176 #define DOC_NAME "WordDocument"
2177 #define PPT_NAME "PowerPoint Document"
2179 #define ustrncmp(x, y, z) strncmp((char *)(x), (char *)(y), (z))
2180 #define ustrncasecmp(x, y, z) strncasecmp_l((char *)(x), (char *)(y), (z), NULL)
2182 static const uint32_t __CFBundleMagicNumbersArray
[] = {
2183 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0xfeedfacf, 0xcffaedfe, 0x4a6f7921, 0x21796f4a,
2184 0x7f454c46, 0xffd8ffe0, 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100,
2185 0x7b5c7274, 0x25504446, 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646,
2186 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435,
2187 0x53495444, 0x53747566, 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x3d796265,
2188 0x6b6f6c79, 0x3026b275, 0x0000000c, 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143,
2189 0x00010000, 0x74727565, 0x4f54544f, 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70,
2190 0x3c435058, 0x28445746, 0x424f4d53, 0x49544f4c, 0x72746664, 0x63616666, 0x802a5fd7, 0x762f3101
2193 // string, with groups of 5 characters being 1 element in the array
2194 static const char * __CFBundleExtensionsArray
=
2195 "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0"
2196 "elf\0\0" "jpeg\0" "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0"
2197 "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"
2198 "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0"
2199 "sit\0\0" "sit\0\0" "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""ync\0\0"
2200 "dmg\0\0" "wmv\0\0" "jp2\0\0" "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0"
2201 "ttf\0\0" "ttf\0\0" "otf\0\0" "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0"
2202 "cpx\0\0" "dwf\0\0" "bom\0\0" "lit\0\0" "rtfd\0" "caf\0\0" "cin\0\0" "exr\0\0";
2204 static const char * __CFBundleOOExtensionsArray
= "sxc\0\0" "sxd\0\0" "sxg\0\0" "sxi\0\0" "sxm\0\0" "sxw\0\0";
2205 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";
2207 #define EXTENSION_LENGTH 5
2208 #define NUM_EXTENSIONS 64
2209 #define MAGIC_BYTES_TO_READ 512
2210 #define DMG_BYTES_TO_READ 512
2211 #define ZIP_BYTES_TO_READ 1024
2212 #define OLE_BYTES_TO_READ 512
2213 #define X11_BYTES_TO_READ 4096
2214 #define IMAGE_INFO_BYTES_TO_READ 4096
2216 #if defined(BINARY_SUPPORT_DYLD)
2218 CF_INLINE
uint32_t _CFBundleSwapInt32Conditional(uint32_t arg
, Boolean swap
) {return swap
? CFSwapInt32(arg
) : arg
;}
2219 CF_INLINE
uint32_t _CFBundleSwapInt64Conditional(uint64_t arg
, Boolean swap
) {return swap
? CFSwapInt64(arg
) : arg
;}
2221 // returns zero-ref dictionary under GC
2222 static CFMutableDictionaryRef
_CFBundleGrokInfoDictFromData(const char *bytes
, uint32_t length
) {
2223 CFMutableDictionaryRef result
= NULL
;
2224 CFDataRef infoData
= NULL
;
2225 if (bytes
&& 0 < length
) {
2226 infoData
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, (uint8_t *)bytes
, length
, kCFAllocatorNull
);
2228 result
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero
, infoData
, kCFPropertyListMutableContainers
, NULL
);
2229 if (result
&& CFDictionaryGetTypeID() != CFGetTypeID(result
)) {
2233 CFRelease(infoData
);
2235 if (!result
) result
= CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
2237 if (result
) _processInfoDictionary((CFMutableDictionaryRef
)result
, _CFGetPlatformName(), _CFGetProductName());
2241 static char *_CFBundleGetSectData(const char *segname
, const char *sectname
, unsigned long *size
) {
2242 char *retval
= NULL
;
2243 unsigned long localSize
= 0;
2244 uint32_t i
, numImages
= _dyld_image_count();
2245 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
2247 for (i
= 0; i
< numImages
; i
++) {
2248 if (mhp
== (void *)_dyld_get_image_header(i
)) {
2250 const struct section_64
*sp
= getsectbynamefromheader_64((const struct mach_header_64
*)mhp
, segname
, sectname
);
2252 retval
= (char *)(sp
->addr
+ _dyld_get_image_vmaddr_slide(i
));
2253 localSize
= (unsigned long)sp
->size
;
2255 #else /* __LP64__ */
2256 const struct section
*sp
= getsectbynamefromheader((const struct mach_header
*)mhp
, segname
, sectname
);
2258 retval
= (char *)(sp
->addr
+ _dyld_get_image_vmaddr_slide(i
));
2259 localSize
= (unsigned long)sp
->size
;
2261 #endif /* __LP64__ */
2265 if (size
) *size
= localSize
;
2269 // returns zero-ref dictionary under GC
2270 static CFMutableDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable() {
2272 unsigned long length
= 0;
2273 if (getsegbyname(TEXT_SEGMENT
)) bytes
= _CFBundleGetSectData(TEXT_SEGMENT
, PLIST_SECTION
, &length
);
2274 return _CFBundleGrokInfoDictFromData(bytes
, length
);
2277 static Boolean
_CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion
, uint32_t *objcFlags
) {
2278 Boolean retval
= false;
2279 uint32_t localVersion
= 0, localFlags
= 0;
2281 unsigned long length
= 0;
2283 if (getsegbyname(OBJC_SEGMENT_64
)) bytes
= _CFBundleGetSectData(OBJC_SEGMENT_64
, IMAGE_INFO_SECTION_64
, &length
);
2284 #else /* __LP64__ */
2285 if (getsegbyname(OBJC_SEGMENT
)) bytes
= _CFBundleGetSectData(OBJC_SEGMENT
, IMAGE_INFO_SECTION
, &length
);
2286 #endif /* __LP64__ */
2287 if (bytes
&& length
>= 8) {
2288 localVersion
= *(uint32_t *)bytes
;
2289 localFlags
= *(uint32_t *)(bytes
+ 4);
2292 if (objcVersion
) *objcVersion
= localVersion
;
2293 if (objcFlags
) *objcFlags
= localFlags
;
2297 static Boolean
_CFBundleGrokX11FromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
2298 static const char libX11name
[] = LIB_X11
;
2299 char *buffer
= NULL
;
2300 const char *loc
= NULL
;
2302 Boolean result
= false;
2304 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2305 buffer
= malloc(X11_BYTES_TO_READ
);
2306 if (buffer
&& read(fd
, buffer
, X11_BYTES_TO_READ
) >= X11_BYTES_TO_READ
) loc
= buffer
;
2307 } else if (bytes
&& length
>= offset
+ X11_BYTES_TO_READ
) {
2308 loc
= bytes
+ offset
;
2312 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->ncmds
, swapped
);
2313 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->sizeofcmds
, swapped
);
2314 const char *startofcmds
= loc
+ sizeof(struct mach_header_64
);
2315 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2316 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
2317 if (endofcmds
> loc
+ X11_BYTES_TO_READ
) endofcmds
= loc
+ X11_BYTES_TO_READ
;
2318 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
2319 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
2320 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
2321 const char *name
= (const char *)dlp
+ nameoffset
;
2322 if (startofcmds
<= name
&& name
+ sizeof(libX11name
) <= endofcmds
&& 0 == strncmp(name
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
2324 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
2327 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->ncmds
, swapped
);
2328 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->sizeofcmds
, swapped
);
2329 const char *startofcmds
= loc
+ sizeof(struct mach_header
);
2330 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2331 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
2332 if (endofcmds
> loc
+ X11_BYTES_TO_READ
) endofcmds
= loc
+ X11_BYTES_TO_READ
;
2333 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
2334 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
2335 uint32_t nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
2336 const char *name
= (const char *)dlp
+ nameoffset
;
2337 if (startofcmds
<= name
&& name
+ sizeof(libX11name
) <= endofcmds
&& 0 == strncmp(name
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
2339 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
2343 if (buffer
) free(buffer
);
2347 // returns zero-ref dictionary under GC
2348 static CFDictionaryRef
_CFBundleGrokInfoDictFromFile(int fd
, const void *bytes
, CFIndex length
, uint32_t offset
, Boolean swapped
, Boolean sixtyFour
) {
2349 struct statinfo statBuf
;
2350 off_t fileLength
= 0;
2351 char *maploc
= NULL
;
2354 CFDictionaryRef result
= NULL
;
2355 Boolean foundit
= false;
2356 if (fd
>= 0 && fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
2358 fileLength
= statBuf
.st_size
;
2361 fileLength
= length
;
2363 if (fileLength
> offset
+ sizeof(struct mach_header_64
)) {
2365 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->ncmds
, swapped
);
2366 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)(loc
+ offset
))->sizeofcmds
, swapped
);
2367 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header_64
);
2368 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2369 struct segment_command_64
*sgp
= (struct segment_command_64
*)startofcmds
;
2370 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
2371 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2372 if (LC_SEGMENT_64
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2373 struct section_64
*sp
= (struct section_64
*)((char *)sgp
+ sizeof(struct segment_command_64
));
2374 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2375 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2376 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, TEXT_SEGMENT
, sizeof(sp
->segname
))) {
2377 uint64_t sectlength64
= _CFBundleSwapInt64Conditional(sp
->size
, swapped
);
2378 uint32_t sectlength
= (uint32_t)(sectlength64
& 0xffffffff);
2379 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2380 const char *sectbytes
= loc
+ offset
+ sectoffset
;
2381 // we don't support huge-sized plists
2382 if (sectlength64
<= 0xffffffff && loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
2385 sp
= (struct section_64
*)((char *)sp
+ sizeof(struct section_64
));
2388 sgp
= (struct segment_command_64
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2391 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->ncmds
, swapped
);
2392 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(loc
+ offset
))->sizeofcmds
, swapped
);
2393 const char *startofcmds
= loc
+ offset
+ sizeof(struct mach_header
);
2394 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2395 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
2396 if (endofcmds
> loc
+ fileLength
) endofcmds
= loc
+ fileLength
;
2397 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2398 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2399 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
2400 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2401 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2402 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, TEXT_SEGMENT
, sizeof(sp
->segname
))) {
2403 uint32_t sectlength
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
2404 uint32_t sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2405 const char *sectbytes
= loc
+ offset
+ sectoffset
;
2406 if (loc
<= sectbytes
&& sectbytes
+ sectlength
<= loc
+ fileLength
) result
= (CFDictionaryRef
)_CFBundleGrokInfoDictFromData(sectbytes
, sectlength
);
2409 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
2412 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2416 if (maploc
) munmap(maploc
, statBuf
.st_size
);
2420 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
) {
2421 uint32_t sectlength
= 0, sectoffset
= 0, localVersion
= 0, localFlags
= 0;
2422 char *buffer
= NULL
;
2424 const char *loc
= NULL
;
2426 Boolean foundit
= false, localHasObjc
= false;
2428 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2429 buffer
= malloc(IMAGE_INFO_BYTES_TO_READ
);
2430 if (buffer
&& read(fd
, buffer
, IMAGE_INFO_BYTES_TO_READ
) >= IMAGE_INFO_BYTES_TO_READ
) loc
= buffer
;
2431 } else if (bytes
&& length
>= offset
+ IMAGE_INFO_BYTES_TO_READ
) {
2432 loc
= bytes
+ offset
;
2436 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->ncmds
, swapped
);
2437 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header_64
*)loc
)->sizeofcmds
, swapped
);
2438 const char *startofcmds
= loc
+ sizeof(struct mach_header_64
);
2439 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2440 struct segment_command_64
*sgp
= (struct segment_command_64
*)startofcmds
;
2441 if (endofcmds
> loc
+ IMAGE_INFO_BYTES_TO_READ
) endofcmds
= loc
+ IMAGE_INFO_BYTES_TO_READ
;
2442 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2443 if (LC_SEGMENT_64
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2444 struct section_64
*sp
= (struct section_64
*)((char *)sgp
+ sizeof(struct segment_command_64
));
2445 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2446 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2447 if (0 == strncmp(sp
->segname
, OBJC_SEGMENT_64
, sizeof(sp
->segname
))) localHasObjc
= true;
2448 if (0 == strncmp(sp
->sectname
, IMAGE_INFO_SECTION_64
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, OBJC_SEGMENT_64
, sizeof(sp
->segname
))) {
2449 uint64_t sectlength64
= _CFBundleSwapInt64Conditional(sp
->size
, swapped
);
2450 sectlength
= (uint32_t)(sectlength64
& 0xffffffff);
2451 sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2454 sp
= (struct section_64
*)((char *)sp
+ sizeof(struct section_64
));
2457 sgp
= (struct segment_command_64
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2460 uint32_t ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->ncmds
, swapped
);
2461 uint32_t sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)loc
)->sizeofcmds
, swapped
);
2462 const char *startofcmds
= loc
+ sizeof(struct mach_header
);
2463 const char *endofcmds
= startofcmds
+ sizeofcmds
;
2464 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
2465 if (endofcmds
> loc
+ IMAGE_INFO_BYTES_TO_READ
) endofcmds
= loc
+ IMAGE_INFO_BYTES_TO_READ
;
2466 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
2467 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
2468 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
2469 uint32_t nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
2470 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
2471 if (0 == strncmp(sp
->segname
, OBJC_SEGMENT
, sizeof(sp
->segname
))) localHasObjc
= true;
2472 if (0 == strncmp(sp
->sectname
, IMAGE_INFO_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, OBJC_SEGMENT
, sizeof(sp
->segname
))) {
2473 sectlength
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
2474 sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
2477 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
2480 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
2483 if (sectlength
>= 8) {
2484 if (fd
>= 0 && lseek(fd
, offset
+ sectoffset
, SEEK_SET
) == (off_t
)(offset
+ sectoffset
) && read(fd
, sectbuffer
, 8) >= 8) {
2485 localVersion
= _CFBundleSwapInt32Conditional(*(uint32_t *)sectbuffer
, swapped
);
2486 localFlags
= _CFBundleSwapInt32Conditional(*(uint32_t *)(sectbuffer
+ 4), swapped
);
2487 } else if (bytes
&& length
>= offset
+ sectoffset
+ 8) {
2488 localVersion
= _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes
+ offset
+ sectoffset
), swapped
);
2489 localFlags
= _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes
+ offset
+ sectoffset
+ 4), swapped
);
2493 if (buffer
) free(buffer
);
2494 if (hasObjc
) *hasObjc
= localHasObjc
;
2495 if (objcVersion
) *objcVersion
= localVersion
;
2496 if (objcFlags
) *objcFlags
= localFlags
;
2499 // returns zero-ref dictionary in *infodict under GC
2500 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
) {
2501 CFIndex headerLength
= length
;
2502 unsigned char headerBuffer
[MAGIC_BYTES_TO_READ
];
2503 UInt32 machtype
= UNKNOWN_FILETYPE
, magic
, numFatHeaders
, maxFatHeaders
, i
;
2504 unsigned char buffer
[sizeof(struct mach_header_64
)];
2505 const unsigned char *moreBytes
= NULL
;
2506 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
2507 SInt32 curArch
= _CFBundleCurrentArchitecture();
2509 struct fat_arch
*fat
= NULL
;
2511 if (isX11
) *isX11
= false;
2512 if (architectures
) *architectures
= NULL
;
2513 if (infodict
) *infodict
= NULL
;
2514 if (hasObjc
) *hasObjc
= false;
2515 if (objcVersion
) *objcVersion
= 0;
2516 if (objcFlags
) *objcFlags
= 0;
2518 if (headerLength
> MAGIC_BYTES_TO_READ
) headerLength
= MAGIC_BYTES_TO_READ
;
2519 (void)memmove(headerBuffer
, bytes
, headerLength
);
2521 for (i
= 0; i
< headerLength
; i
+= 4) *(UInt32
*)(headerBuffer
+ i
) = CFSwapInt32(*(UInt32
*)(headerBuffer
+ i
));
2523 numFatHeaders
= ((struct fat_header
*)headerBuffer
)->nfat_arch
;
2524 maxFatHeaders
= (headerLength
- sizeof(struct fat_header
)) / sizeof(struct fat_arch
);
2525 if (numFatHeaders
> maxFatHeaders
) numFatHeaders
= maxFatHeaders
;
2526 if (numFatHeaders
> 0) {
2527 if (archInfo
) fat
= NXFindBestFatArch(archInfo
->cputype
, archInfo
->cpusubtype
, (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
)), numFatHeaders
);
2528 if (!fat
&& curArch
!= 0) fat
= NXFindBestFatArch((cpu_type_t
)curArch
, (cpu_subtype_t
)0, (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
)), numFatHeaders
);
2529 if (!fat
) fat
= (struct fat_arch
*)(headerBuffer
+ sizeof(struct fat_header
));
2530 if (architectures
) {
2531 CFMutableArrayRef mutableArchitectures
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
2532 for (i
= 0; i
< numFatHeaders
; i
++) {
2533 CFNumberRef architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, headerBuffer
+ sizeof(struct fat_header
) + i
* sizeof(struct fat_arch
));
2534 if (CFArrayGetFirstIndexOfValue(mutableArchitectures
, CFRangeMake(0, CFArrayGetCount(mutableArchitectures
)), architecture
) < 0) CFArrayAppendValue(mutableArchitectures
, architecture
);
2535 CFRelease(architecture
);
2537 *architectures
= (CFArrayRef
)mutableArchitectures
;
2541 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
)) {
2543 } else if (bytes
&& (uint32_t)length
>= fat
->offset
+ sizeof(struct mach_header_64
)) {
2544 moreBytes
= bytes
+ fat
->offset
;
2547 magic
= *((UInt32
*)moreBytes
);
2548 if (MH_MAGIC
== magic
) {
2549 machtype
= ((struct mach_header
*)moreBytes
)->filetype
;
2550 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, false, false);
2551 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, false);
2552 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, false, false, hasObjc
, objcVersion
, objcFlags
);
2553 } else if (MH_CIGAM
== magic
) {
2554 machtype
= CFSwapInt32(((struct mach_header
*)moreBytes
)->filetype
);
2555 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, true, false);
2556 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, false);
2557 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, true, false, hasObjc
, objcVersion
, objcFlags
);
2558 } else if (MH_MAGIC_64
== magic
) {
2559 machtype
= ((struct mach_header_64
*)moreBytes
)->filetype
;
2560 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, false, true);
2561 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, false, true);
2562 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, false, true, hasObjc
, objcVersion
, objcFlags
);
2563 } else if (MH_CIGAM_64
== magic
) {
2564 machtype
= CFSwapInt32(((struct mach_header_64
*)moreBytes
)->filetype
);
2565 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, fat
->offset
, true, true);
2566 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, fat
->offset
, true, true);
2567 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, fat
->offset
, true, true, hasObjc
, objcVersion
, objcFlags
);
2574 // returns zero-ref dictionary in *infodict under GC
2575 static UInt32
_CFBundleGrokMachType(int fd
, const void *bytes
, CFIndex length
, Boolean
*isX11
, CFArrayRef
*architectures
, CFDictionaryRef
*infodict
, Boolean
*hasObjc
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
2576 unsigned int magic
= *((UInt32
*)bytes
), machtype
= UNKNOWN_FILETYPE
, cputype
;
2577 CFNumberRef architecture
= NULL
;
2579 if (isX11
) *isX11
= false;
2580 if (architectures
) *architectures
= NULL
;
2581 if (infodict
) *infodict
= NULL
;
2582 if (hasObjc
) *hasObjc
= false;
2583 if (objcVersion
) *objcVersion
= 0;
2584 if (objcFlags
) *objcFlags
= 0;
2585 if (MH_MAGIC
== magic
) {
2586 machtype
= ((struct mach_header
*)bytes
)->filetype
;
2587 cputype
= ((struct mach_header
*)bytes
)->cputype
;
2588 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2589 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, false, false);
2590 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, false);
2591 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, false, false, hasObjc
, objcVersion
, objcFlags
);
2592 } else if (MH_CIGAM
== magic
) {
2593 machtype
= CFSwapInt32(((struct mach_header
*)bytes
)->filetype
);
2594 cputype
= CFSwapInt32(((struct mach_header
*)bytes
)->cputype
);
2595 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2596 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, true, false);
2597 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, false);
2598 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, true, false, hasObjc
, objcVersion
, objcFlags
);
2599 } else if (MH_MAGIC_64
== magic
) {
2600 machtype
= ((struct mach_header_64
*)bytes
)->filetype
;
2601 cputype
= ((struct mach_header_64
*)bytes
)->cputype
;
2602 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2603 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, false, true);
2604 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, false, true);
2605 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, false, true, hasObjc
, objcVersion
, objcFlags
);
2606 } else if (MH_CIGAM_64
== magic
) {
2607 machtype
= CFSwapInt32(((struct mach_header_64
*)bytes
)->filetype
);
2608 cputype
= CFSwapInt32(((struct mach_header_64
*)bytes
)->cputype
);
2609 if (architectures
) architecture
= CFNumberCreate(kCFAllocatorSystemDefault
, kCFNumberSInt32Type
, &cputype
);
2610 if (isX11
&& MH_EXECUTE
== machtype
) *isX11
= _CFBundleGrokX11FromFile(fd
, bytes
, length
, 0, true, true);
2611 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, bytes
, length
, 0, true, true);
2612 if (hasObjc
|| objcVersion
|| objcFlags
) _CFBundleGrokObjcImageInfoFromFile(fd
, bytes
, length
, 0, true, true, hasObjc
, objcVersion
, objcFlags
);
2613 } else if (FAT_MAGIC
== magic
) {
2614 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, false, isX11
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2615 } else if (FAT_CIGAM
== magic
) {
2616 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, true, isX11
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2617 } else if (PEF_MAGIC
== magic
|| PEF_CIGAM
== magic
) {
2618 machtype
= PEF_FILETYPE
;
2620 if (architectures
&& architecture
) *architectures
= CFArrayCreate(kCFAllocatorSystemDefault
, (const void **)&architecture
, 1, &kCFTypeArrayCallBacks
);
2621 if (architecture
) CFRelease(architecture
);
2625 #endif /* BINARY_SUPPORT_DYLD */
2627 static Boolean
_CFBundleGrokFileTypeForZipMimeType(const unsigned char *bytes
, CFIndex length
, const char **ext
) {
2628 unsigned namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 26))), extralength
= CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 28)));
2629 const unsigned char *data
= bytes
+ 30 + namelength
+ extralength
;
2631 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))) {
2632 data
+= ('.' == *(data
+ 15)) ? 16 : 18;
2633 if (0 == ustrncasecmp(data
, "sun.xml.", 8)) {
2635 if (0 == ustrncasecmp(data
, "calc", 4)) i
= 0;
2636 else if (0 == ustrncasecmp(data
, "draw", 4)) i
= 1;
2637 else if (0 == ustrncasecmp(data
, "writer.global", 13)) i
= 2;
2638 else if (0 == ustrncasecmp(data
, "impress", 7)) i
= 3;
2639 else if (0 == ustrncasecmp(data
, "math", 4)) i
= 4;
2640 else if (0 == ustrncasecmp(data
, "writer", 6)) i
= 5;
2641 if (i
>= 0 && ext
) *ext
= __CFBundleOOExtensionsArray
+ i
* EXTENSION_LENGTH
;
2642 } else if (0 == ustrncasecmp(data
, "oasis.opendocument.", 19)) {
2644 if (0 == ustrncasecmp(data
, "chart", 5)) i
= 0;
2645 else if (0 == ustrncasecmp(data
, "formula", 7)) i
= 1;
2646 else if (0 == ustrncasecmp(data
, "graphics", 8)) i
= 2;
2647 else if (0 == ustrncasecmp(data
, "text-web", 8)) i
= 3;
2648 else if (0 == ustrncasecmp(data
, "image", 5)) i
= 4;
2649 else if (0 == ustrncasecmp(data
, "text-master", 11)) i
= 5;
2650 else if (0 == ustrncasecmp(data
, "presentation", 12)) i
= 6;
2651 else if (0 == ustrncasecmp(data
, "spreadsheet", 11)) i
= 7;
2652 else if (0 == ustrncasecmp(data
, "text", 4)) i
= 8;
2653 if (i
>= 0 && ext
) *ext
= __CFBundleODExtensionsArray
+ i
* EXTENSION_LENGTH
;
2655 } else if (bytes
< data
&& data
+ 41 <= bytes
+ length
&& 8 == CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ 8))) && 0x4b2c28c8 == CFSwapInt32HostToBig(*((UInt32
*)data
)) && 0xc94c4e2c == CFSwapInt32HostToBig(*((UInt32
*)(data
+ 4)))) {
2656 // AbiWord compressed mimetype odt
2657 if (ext
) *ext
= "odt";
2658 // almost certainly this should set i to 0 but I don't want to upset the apple cart now
2659 } else if (bytes
< data
&& data
+ 29 <= bytes
+ length
&& (0 == ustrncasecmp(data
, "application/oebps-package+xml", 29))) {
2660 // epub, official epub 3 mime type
2661 if (ext
) *ext
= "epub";
2663 } else if (bytes
< data
&& data
+ 20 <= bytes
+ length
&& (0 == ustrncasecmp(data
, "application/epub+zip", 20))) {
2664 // epub, unofficial epub 2 mime type
2665 if (ext
) *ext
= "epub";
2671 static const char *_CFBundleGrokFileTypeForZipFile(int fd
, const unsigned char *bytes
, CFIndex length
, off_t fileLength
) {
2672 const char *ext
= "zip";
2673 const unsigned char *moreBytes
= NULL
;
2674 unsigned char *buffer
= NULL
;
2676 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;
2679 for (i
= 0; !foundMimetype
&& i
+ 30 < length
; i
++) {
2680 if (0x50 == bytes
[i
] && 0x4b == bytes
[i
+ 1]) {
2681 unsigned namelength
= 0, offset
= 0;
2682 if (0x01 == bytes
[i
+ 2] && 0x02 == bytes
[i
+ 3]) {
2683 namelength
= (unsigned)CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ i
+ 28)));
2685 } else if (0x03 == bytes
[i
+ 2] && 0x04 == bytes
[i
+ 3]) {
2686 namelength
= (unsigned)CFSwapInt16HostToLittle(*((UInt16
*)(bytes
+ i
+ 26)));
2689 if (offset
> 0 && (CFIndex
)(i
+ offset
+ namelength
) <= length
) {
2690 //printf("%.*s\n", namelength, bytes + i + offset);
2691 if (8 == namelength
&& 30 == offset
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "mimetype", 8)) foundMimetype
= _CFBundleGrokFileTypeForZipMimeType(bytes
+ i
, length
- i
, &ext
);
2692 else if (9 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/", 9)) hasMetaInf
= true;
2693 else if (11 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "content.xml", 11)) hasContentXML
= true;
2694 else if (11 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "_rels/.rels", 11)) hasRels
= true;
2695 else if (19 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "[Content_Types].xml", 19)) hasContentTypes
= true;
2696 else if (20 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/MANIFEST.MF", 20)) hasManifestMF
= true;
2697 else if (21 == namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "META-INF/manifest.xml", 21)) hasManifestXML
= true;
2698 else if (4 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".opf", 4)) hasOPF
= true;
2699 else if (4 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".sml", 4)) hasSMIL
= true;
2700 else if (5 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 5, ".smil", 5)) hasSMIL
= true;
2701 else if (7 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "xl/", 3) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2702 else if (8 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "ppt/", 4) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2703 else if (9 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "word/", 5) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasWordDocument
= true;
2704 else if (10 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "excel/", 6) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2705 else if (15 < namelength
&& 0 == ustrncasecmp(bytes
+ i
+ offset
, "powerpoint/", 11) && 0 == ustrncasecmp(bytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2706 i
+= offset
+ namelength
- 1;
2711 if (!foundMimetype
) {
2712 if (fileLength
>= ZIP_BYTES_TO_READ
) {
2713 if (fd
>= 0 && lseek(fd
, fileLength
- ZIP_BYTES_TO_READ
, SEEK_SET
) == fileLength
- ZIP_BYTES_TO_READ
) {
2714 buffer
= (unsigned char *)malloc(ZIP_BYTES_TO_READ
);
2715 if (buffer
&& read(fd
, buffer
, ZIP_BYTES_TO_READ
) >= ZIP_BYTES_TO_READ
) moreBytes
= buffer
;
2716 } else if (bytes
&& length
>= ZIP_BYTES_TO_READ
) {
2717 moreBytes
= bytes
+ length
- ZIP_BYTES_TO_READ
;
2721 for (i
= 0; i
+ 30 < ZIP_BYTES_TO_READ
; i
++) {
2722 if (0x50 == moreBytes
[i
] && 0x4b == moreBytes
[i
+ 1]) {
2723 unsigned namelength
= 0, offset
= 0;
2724 if (0x01 == moreBytes
[i
+ 2] && 0x02 == moreBytes
[i
+ 3]) {
2725 namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(moreBytes
+ i
+ 28)));
2727 } else if (0x03 == moreBytes
[i
+ 2] && 0x04 == moreBytes
[i
+ 3]) {
2728 namelength
= CFSwapInt16HostToLittle(*((UInt16
*)(moreBytes
+ i
+ 26)));
2731 if (offset
> 0 && i
+ offset
+ namelength
<= ZIP_BYTES_TO_READ
) {
2732 //printf("%.*s\n", namelength, moreBytes + i + offset);
2733 if (9 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/", 9)) hasMetaInf
= true;
2734 else if (11 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "content.xml", 11)) hasContentXML
= true;
2735 else if (11 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "_rels/.rels", 11)) hasRels
= true;
2736 else if (19 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "[Content_Types].xml", 19)) hasContentTypes
= true;
2737 else if (20 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/MANIFEST.MF", 20)) hasManifestMF
= true;
2738 else if (21 == namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "META-INF/manifest.xml", 21)) hasManifestXML
= true;
2739 else if (4 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".opf", 4)) hasOPF
= true;
2740 else if (4 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".sml", 4)) hasSMIL
= true;
2741 else if (5 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 5, ".smil", 5)) hasSMIL
= true;
2742 else if (7 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "xl/", 3) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2743 else if (8 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "ppt/", 4) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2744 else if (9 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "word/", 5) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasWordDocument
= true;
2745 else if (10 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "excel/", 6) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasExcelDocument
= true;
2746 else if (15 < namelength
&& 0 == ustrncasecmp(moreBytes
+ i
+ offset
, "powerpoint/", 11) && 0 == ustrncasecmp(moreBytes
+ i
+ offset
+ namelength
- 4, ".xml", 4)) hasPowerPointDocument
= true;
2747 i
+= offset
+ namelength
- 1;
2752 //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);
2753 if (hasManifestMF
) ext
= "jar";
2754 else if ((hasRels
|| hasContentTypes
) && hasWordDocument
) ext
= "docx";
2755 else if ((hasRels
|| hasContentTypes
) && hasExcelDocument
) ext
= "xlsx";
2756 else if ((hasRels
|| hasContentTypes
) && hasPowerPointDocument
) ext
= "pptx";
2757 else if (hasManifestXML
|| hasContentXML
) ext
= "odt";
2758 else if (hasMetaInf
) ext
= "jar";
2759 else if (hasOPF
&& hasSMIL
) ext
= "dtb";
2760 else if (hasOPF
) ext
= "oeb";
2762 if (buffer
) free(buffer
);
2767 static Boolean
_CFBundleCheckOLEName(const char *name
, const char *bytes
, unsigned length
) {
2768 Boolean retval
= true;
2770 for (j
= 0; retval
&& j
< length
; j
++) if (bytes
[2 * j
] != name
[j
]) retval
= false;
2774 static const char *_CFBundleGrokFileTypeForOLEFile(int fd
, const void *bytes
, CFIndex length
, off_t offset
) {
2775 const char *ext
= "ole", *moreBytes
= NULL
;
2776 char *buffer
= NULL
;
2778 if (fd
>= 0 && lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
) {
2779 buffer
= (char *)malloc(OLE_BYTES_TO_READ
);
2780 if (buffer
&& read(fd
, buffer
, OLE_BYTES_TO_READ
) >= OLE_BYTES_TO_READ
) moreBytes
= buffer
;
2781 } else if (bytes
&& length
>= offset
+ OLE_BYTES_TO_READ
) {
2782 moreBytes
= (char *)bytes
+ offset
;
2785 Boolean foundit
= false;
2787 for (i
= 0; !foundit
&& i
< 4; i
++) {
2788 char namelength
= moreBytes
[128 * i
+ 64] / 2;
2790 if (sizeof(XLS_NAME
) == namelength
&& _CFBundleCheckOLEName(XLS_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "xls";
2791 else if (sizeof(XLS_NAME2
) == namelength
&& _CFBundleCheckOLEName(XLS_NAME2
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "xls";
2792 else if (sizeof(DOC_NAME
) == namelength
&& _CFBundleCheckOLEName(DOC_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "doc";
2793 else if (sizeof(PPT_NAME
) == namelength
&& _CFBundleCheckOLEName(PPT_NAME
, moreBytes
+ 128 * i
, namelength
- 1)) ext
= "ppt";
2794 else foundit
= false;
2797 if (buffer
) free(buffer
);
2801 // returns zero-ref dictionary in *infodict under GC
2802 static Boolean
_CFBundleGrokFileType(CFURLRef url
, CFDataRef data
, CFStringRef
*extension
, UInt32
*machtype
, CFArrayRef
*architectures
, CFDictionaryRef
*infodict
, Boolean
*hasObjc
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
2804 const unsigned char *bytes
= NULL
;
2805 unsigned char buffer
[MAGIC_BYTES_TO_READ
];
2806 CFIndex i
, length
= 0;
2807 off_t fileLength
= 0;
2808 const char *ext
= NULL
;
2809 UInt32 mt
= UNKNOWN_FILETYPE
;
2810 #if defined(BINARY_SUPPORT_DYLD)
2811 Boolean isX11
= false;
2812 #endif /* BINARY_SUPPORT_DYLD */
2813 Boolean isFile
= false, isPlain
= true, isZero
= true, isSpace
= true, hasBOM
= false;
2814 // 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
2815 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
2816 // ??? we do not distinguish between ordinary documents and template versions (often there is no difference in file contents)
2817 // ??? the distinctions between docx, xlsx, and pptx may not be entirely reliable
2818 if (architectures
) *architectures
= NULL
;
2819 if (infodict
) *infodict
= NULL
;
2820 if (hasObjc
) *hasObjc
= false;
2821 if (objcVersion
) *objcVersion
= 0;
2822 if (objcFlags
) *objcFlags
= 0;
2824 Boolean gotPath
= FALSE
;
2825 char path
[CFMaxPathSize
];
2826 gotPath
= CFURLGetFileSystemRepresentation(url
, true, (uint8_t *)path
, CFMaxPathSize
);
2827 struct statinfo statBuf
;
2828 if (gotPath
&& stat(path
, &statBuf
) == 0 && (statBuf
.st_mode
& S_IFMT
) == S_IFREG
&& (fd
= open(path
, O_RDONLY
| CF_OPENFLGS
, 0777)) >= 0) {
2829 length
= read(fd
, buffer
, MAGIC_BYTES_TO_READ
);
2830 fileLength
= statBuf
.st_size
;
2835 if (!isFile
&& data
) {
2836 length
= CFDataGetLength(data
);
2837 fileLength
= (off_t
)length
;
2838 bytes
= CFDataGetBytePtr(data
);
2839 if (length
== 0) ext
= "txt";
2843 UInt32 magic
= CFSwapInt32HostToBig(*((UInt32
*)bytes
));
2844 for (i
= 0; !ext
&& i
< NUM_EXTENSIONS
; i
++) {
2845 if (__CFBundleMagicNumbersArray
[i
] == magic
) ext
= __CFBundleExtensionsArray
+ i
* EXTENSION_LENGTH
;
2848 if (0xcafebabe == magic
&& 8 <= length
&& 0 != *((UInt16
*)(bytes
+ 4))) ext
= "class";
2849 #if defined(BINARY_SUPPORT_DYLD)
2850 else if ((int)sizeof(struct mach_header_64
) <= length
) mt
= _CFBundleGrokMachType(fd
, bytes
, length
, extension
? &isX11
: NULL
, architectures
, infodict
, hasObjc
, objcVersion
, objcFlags
);
2852 if (MH_OBJECT
== mt
) ext
= "o";
2853 else if (MH_EXECUTE
== mt
) ext
= isX11
? "x11app" : "tool";
2854 else if (PEF_FILETYPE
== mt
) ext
= "pef";
2855 else if (MH_CORE
== mt
) ext
= "core";
2856 else if (MH_DYLIB
== mt
) ext
= "dylib";
2857 else if (MH_BUNDLE
== mt
) ext
= "bundle";
2858 #endif /* BINARY_SUPPORT_DYLD */
2859 else if (0x7b5c7274 == magic
&& (6 > length
|| 'f' != bytes
[4])) ext
= NULL
;
2860 else if (0x25504446 == magic
&& (6 > length
|| '-' != bytes
[4])) ext
= NULL
;
2861 else if (0x00010000 == magic
&& (6 > length
|| 0 != bytes
[4])) ext
= NULL
;
2862 else if (0x47494638 == magic
&& (6 > length
|| (0x3761 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4)))))) ext
= NULL
;
2863 else if (0x0000000c == magic
&& (6 > length
|| 0x6a50 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2864 else if (0x2356524d == magic
&& (6 > length
|| 0x4c20 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2865 else if (0x28445746 == magic
&& (6 > length
|| 0x2056 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) ext
= NULL
;
2866 else if (0x30373037 == magic
&& (6 > length
|| 0x30 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2867 else if (0x41433130 == magic
&& (6 > length
|| 0x31 != bytes
[4] || !isdigit(bytes
[5]))) ext
= NULL
;
2868 else if (0x89504e47 == magic
&& (8 > length
|| 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2869 else if (0x53747566 == magic
&& (8 > length
|| 0x66497420 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2870 else if (0x3026b275 == magic
&& (8 > length
|| 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2871 else if (0x67696d70 == magic
&& (8 > length
|| 0x20786366 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2872 else if (0x424f4d53 == magic
&& (8 > length
|| 0x746f7265 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2873 else if (0x49544f4c == magic
&& (8 > length
|| 0x49544c53 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2874 else if (0x72746664 == magic
&& (8 > length
|| 0x00000000 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= NULL
;
2875 else if (0x3d796265 == magic
&& (12 > length
|| 0x67696e20 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || (0x6c696e65 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8))) && 0x70617274 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))))) ext
= NULL
;
2876 else if (0x63616666 == magic
&& (12 > length
|| 0 != bytes
[4] || 0x64657363 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8))))) ext
= NULL
;
2877 else if (0x504b0304 == magic
) ext
= _CFBundleGrokFileTypeForZipFile(fd
, bytes
, length
, fileLength
);
2878 else if (0x25215053 == magic
) {
2879 if (11 <= length
&& 0 == ustrncmp(bytes
+ 4, "-Adobe-", 7)) ext
= "ps";
2880 else if (14 <= length
&& 0 == ustrncmp(bytes
+ 4, "-AdobeFont", 10)) ext
= "pfa";
2882 } else if (0x464f524d == magic
) {
2886 UInt32 iffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2887 if (0x41494646 == iffMagic
) ext
= "aiff";
2888 else if (0x414946 == iffMagic
) ext
= "aifc";
2890 } else if (0x52494646 == magic
) {
2894 UInt32 riffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2895 if (0x57415645 == riffMagic
) ext
= "wav";
2896 else if (0x41564920 == riffMagic
) ext
= "avi";
2898 } else if (0xd0cf11e0 == magic
) {
2900 if (52 <= length
) ext
= _CFBundleGrokFileTypeForOLEFile(fd
, bytes
, length
, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 48)))));
2901 } else if (0x62656769 == magic
) {
2904 if (76 <= length
&& 'n' == bytes
[4] && ' ' == bytes
[5] && isdigit(bytes
[6]) && isdigit(bytes
[7]) && isdigit(bytes
[8]) && ' ' == bytes
[9]) {
2905 CFIndex endOfLine
= 0;
2906 for (i
= 10; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2907 if (10 <= endOfLine
&& endOfLine
+ 62 < length
&& 'M' == bytes
[endOfLine
+ 1] && '\n' == bytes
[endOfLine
+ 62]) {
2909 for (i
= endOfLine
+ 1; ext
&& i
< endOfLine
+ 62; i
++) if (!isprint(bytes
[i
])) ext
= NULL
;
2914 if (extension
&& !ext
) {
2915 UInt16 shortMagic
= CFSwapInt16HostToBig(*((UInt16
*)bytes
));
2916 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";
2917 else if (8 <= length
&& (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "mov";
2918 else if (8 <= length
&& (0x69647363 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "qtif";
2919 else if (8 <= length
&& 0x424f424f == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) ext
= "cwk";
2920 else if (8 <= length
&& 0x62706c69 == magic
&& 0x7374 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && isdigit(bytes
[6]) && isdigit(bytes
[7])) {
2921 for (i
= 8; !ext
&& i
< 128 && i
+ 16 <= length
; i
++) {
2922 if (0 == ustrncmp(bytes
+ i
, "WebMainResource", 15)) ext
= "webarchive";
2924 if (!ext
) ext
= "plist";
2925 } else if (0 == shortMagic
&& 12 <= length
&& 0x66747970 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
2926 // ??? may want more ftyp values
2927 UInt32 ftyp
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
2928 if (0x6d703431 == ftyp
|| 0x6d703432 == ftyp
|| 0x69736f6d == ftyp
|| 0x69736f32 == ftyp
) ext
= "mp4";
2929 else if (0x4d344120 == ftyp
) ext
= "m4a";
2930 else if (0x4d344220 == ftyp
) ext
= "m4b";
2931 else if (0x4d345020 == ftyp
) ext
= "m4p";
2932 else if (0x4d345620 == ftyp
|| 0x4d345648 == ftyp
|| 0x4d345650 == ftyp
) ext
= "m4v";
2933 else if (0x3367 == (ftyp
>> 16)) {
2934 UInt16 remainder
= (ftyp
& 0xffff);
2935 if (0x6536 == remainder
|| 0x6537 == remainder
|| 0x6736 == remainder
|| 0x7034 == remainder
|| 0x7035 == remainder
|| 0x7036 == remainder
|| 0x7236 == remainder
|| 0x7336 == remainder
|| 0x7337 == remainder
) ext
= "3gp";
2936 else if (0x3261 == remainder
) ext
= "3g2";
2938 } else if (0x424d == shortMagic
&& 18 <= length
) {
2939 UInt32 btyp
= CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 14)));
2940 if (40 == btyp
|| btyp
== 12 || btyp
== 64 || btyp
== 108 || btyp
== 124) ext
= "bmp";
2941 } else if (20 <= length
&& 0 == ustrncmp(bytes
+ 6, "%!PS-AdobeFont", 14)) ext
= "pfb";
2942 else if (40 <= length
&& 0x42696e48 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 38)))) ext
= "hqx";
2943 else if (128 <= length
&& 0x6d42494e == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 102)))) ext
= "bin";
2944 else if (128 <= length
&& 0 == bytes
[0] && 0 < bytes
[1] && bytes
[1] < 64 && 0 == bytes
[74] && 0 == bytes
[82] && 0 == (fileLength
% 128)) {
2945 UInt32 df
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 83))), rf
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 87))), blocks
= 1 + (df
+ 127) / 128 + (rf
+ 127) / 128;
2946 if (df
< 0x00800000 && rf
< 0x00800000 && 1 < blocks
&& (off_t
)(128 * blocks
) == fileLength
) ext
= "bin";
2947 } else if (265 <= length
&& 0x75737461 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 261))))) ext
= "tar";
2948 else if (0xfeff == shortMagic
|| 0xfffe == shortMagic
) {
2950 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";
2951 } else if (0x1f9d == shortMagic
) ext
= "Z";
2952 else if (0x1f8b == shortMagic
) ext
= "gz";
2953 else if (0x71c7 == shortMagic
|| 0xc771 == shortMagic
) ext
= "cpio";
2954 else if (0xf702 == shortMagic
) ext
= "dvi";
2955 else if (0x01da == shortMagic
&& (0 == bytes
[2] || 1 == bytes
[2]) && (0 < bytes
[3] && 16 > bytes
[3])) ext
= "sgi";
2956 else if (0x2321 == shortMagic
) {
2957 CFIndex endOfLine
= 0, lastSlash
= 0;
2958 for (i
= 2; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
2959 if (endOfLine
> 3) {
2960 for (i
= endOfLine
- 1; 0 == lastSlash
&& i
> 1; i
--) if ('/' == bytes
[i
]) lastSlash
= i
;
2961 if (lastSlash
> 0) {
2962 if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "perl", 4)) ext
= "pl";
2963 else if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "python", 6)) ext
= "py";
2964 else if (0 == ustrncmp(bytes
+ lastSlash
+ 1, "ruby", 4)) ext
= "rb";
2968 } else if (0xffd8 == shortMagic
&& 0xff == bytes
[2]) ext
= "jpeg";
2969 else if (0x4657 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swf";
2970 else if (0x4357 == shortMagic
&& 0x53 == bytes
[2]) ext
= "swc";
2971 else if (0x4944 == shortMagic
&& '3' == bytes
[2] && 0x20 > bytes
[3]) ext
= "mp3";
2972 else if (0x425a == shortMagic
&& isdigit(bytes
[2]) && isdigit(bytes
[3])) ext
= "bz";
2973 else if (0x425a == shortMagic
&& 'h' == bytes
[2] && isdigit(bytes
[3]) && 8 <= length
&& (0x31415926 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) ext
= "bz2";
2974 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 2)))) ext
= "tfm";
2977 if (extension
&& !ext
) {
2978 //??? what about MacOSRoman?
2979 if (0xef == bytes
[0] && 0xbb == bytes
[1] && 0xbf == bytes
[2]) { // UTF-8 BOM
2983 for (i
= (hasBOM
? 3 : 0); (isPlain
|| isZero
) && !ext
&& i
< length
&& i
< 512; i
++) {
2985 if (isPlain
&& '<' == c
&& i
+ 14 <= length
&& 0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) ext
= "html";
2986 if (isSpace
&& '<' == c
&& i
+ 14 <= length
) {
2987 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)) {
2989 } else if (0 == ustrncasecmp(bytes
+ i
+ 1, "?xml", 4)) {
2990 for (i
+= 4; !ext
&& i
< 128 && i
+ 20 <= length
; i
++) {
2991 if ('<' == bytes
[i
]) {
2992 if (0 == ustrncasecmp(bytes
+ i
+ 1, "abiword", 7)) ext
= "abw";
2993 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype svg", 12)) ext
= "svg";
2994 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype rdf", 12)) ext
= "rdf";
2995 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype x3d", 12)) ext
= "x3d";
2996 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype html", 13)) ext
= "html";
2997 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype posingfont", 19)) ext
= "sfont";
2998 else if (0 == ustrncasecmp(bytes
+ i
+ 1, "!doctype plist", 14)) {
2999 for (i
+= 14; !ext
&& i
< 256 && i
+ 16 <= length
; i
++) {
3000 if (0 == ustrncmp(bytes
+ i
, "WebMainResource", 15)) ext
= "webarchive";
3002 if (!ext
) ext
= "plist";
3006 if (!ext
) ext
= "xml";
3009 if (0 != c
) isZero
= false;
3010 if (isZero
|| 0x7f <= c
|| (0x20 > c
&& !isspace(c
))) isPlain
= false;
3011 if (isZero
|| !isspace(c
)) isSpace
= false;
3015 if (16 <= length
&& 0 == ustrncmp(bytes
, "StartFontMetrics", 16)) ext
= "afm";
3017 } else if (isZero
&& length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= 526) {
3019 if (lseek(fd
, 512, SEEK_SET
) == 512 && read(fd
, buffer
, MAGIC_BYTES_TO_READ
) >= 14) {
3020 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(buffer
+ 10)))) ext
= "pict";
3023 if (526 <= length
&& 0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 522)))) ext
= "pict";
3028 if (extension
&& (!ext
|| 0 == strcmp(ext
, "bz2")) && length
>= MAGIC_BYTES_TO_READ
&& fileLength
>= DMG_BYTES_TO_READ
) {
3030 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
) {
3031 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";
3034 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";
3038 if (extension
) *extension
= ext
? CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault
, ext
, kCFStringEncodingUTF8
, kCFAllocatorNull
) : NULL
;
3039 if (machtype
) *machtype
= mt
;
3040 if (fd
>= 0) close(fd
);
3041 return (ext
? true : false);
3044 CFStringRef
_CFBundleCopyFileTypeForFileURL(CFURLRef url
) {
3045 CFStringRef extension
= NULL
;
3046 (void)_CFBundleGrokFileType(url
, NULL
, &extension
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
3050 CFStringRef
_CFBundleCopyFileTypeForFileData(CFDataRef data
) {
3051 CFStringRef extension
= NULL
;
3052 (void)_CFBundleGrokFileType(NULL
, data
, &extension
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
3056 // returns zero-ref dictionary under GC
3057 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInExecutable(CFURLRef url
) {
3058 CFDictionaryRef result
= NULL
;
3059 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, NULL
, &result
, NULL
, NULL
, NULL
);
3063 __private_extern__ CFArrayRef
_CFBundleCopyArchitecturesForExecutable(CFURLRef url
) {
3064 CFArrayRef result
= NULL
;
3065 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, &result
, NULL
, NULL
, NULL
, NULL
);
3069 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3070 static Boolean
_CFBundleGetObjCImageInfoForExecutable(CFURLRef url
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
3071 Boolean retval
= false;
3072 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, NULL
, NULL
, NULL
, &retval
, objcVersion
, objcFlags
);
3077 #if defined(BINARY_SUPPORT_DYLD)
3079 __private_extern__ __CFPBinaryType
_CFBundleGrokBinaryType(CFURLRef executableURL
) {
3080 // 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.
3081 __CFPBinaryType result
= executableURL
? __CFBundleUnreadableBinary
: __CFBundleNoBinary
;
3082 UInt32 machtype
= UNKNOWN_FILETYPE
;
3083 if (_CFBundleGrokFileType(executableURL
, NULL
, NULL
, &machtype
, NULL
, NULL
, NULL
, NULL
, NULL
)) {
3086 result
= __CFBundleDYLDExecutableBinary
;
3089 result
= __CFBundleDYLDBundleBinary
;
3092 result
= __CFBundleDYLDFrameworkBinary
;
3095 result
= __CFBundleCFMBinary
;
3102 #endif /* BINARY_SUPPORT_DYLD */
3104 void _CFBundleSetCFMConnectionID(CFBundleRef bundle
, void *connectionID
) {
3105 bundle
->_connectionCookie
= connectionID
;
3106 bundle
->_isLoaded
= true;
3109 static CFStringRef
_CFBundleCopyLastPathComponent(CFBundleRef bundle
) {
3110 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
);
3111 CFStringRef str
= CFURLCopyFileSystemPath(bundleURL
, kCFURLPOSIXPathStyle
);
3112 UniChar buff
[CFMaxPathSize
];
3113 CFIndex buffLen
= CFStringGetLength(str
), startOfLastDir
= 0;
3115 CFRelease(bundleURL
);
3116 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
3117 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
3119 if (buffLen
> 0) startOfLastDir
= _CFStartOfLastPathComponent(buff
, buffLen
);
3120 return CFStringCreateWithCharacters(kCFAllocatorSystemDefault
, &(buff
[startOfLastDir
]), buffLen
- startOfLastDir
);
3123 static CFErrorRef
_CFBundleCreateErrorDebug(CFAllocatorRef allocator
, CFBundleRef bundle
, CFIndex code
, CFStringRef debugString
) {
3124 const void *userInfoKeys
[6], *userInfoValues
[6];
3125 CFIndex numKeys
= 0;
3126 CFURLRef bundleURL
= CFBundleCopyBundleURL(bundle
), absoluteURL
= CFURLCopyAbsoluteURL(bundleURL
), executableURL
= CFBundleCopyExecutableURL(bundle
);
3127 CFBundleRef bdl
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation"));
3128 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
), executablePath
= executableURL
? CFURLCopyFileSystemPath(executableURL
, PLATFORM_PATH_STYLE
) : NULL
, descFormat
= NULL
, desc
= NULL
, reason
= NULL
, suggestion
= NULL
;
3131 CFStringRef name
= (CFStringRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, kCFBundleNameKey
);
3132 name
= name
? (CFStringRef
)CFRetain(name
) : _CFBundleCopyLastPathComponent(bundle
);
3133 if (CFBundleExecutableNotFoundError
== code
) {
3134 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
3135 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl
, CFSTR("The bundle\\U2019s executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
3136 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError");
3137 } else if (CFBundleExecutableNotLoadableError
== code
) {
3138 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
3139 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl
, CFSTR("The bundle\\U2019s executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
3140 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError");
3141 } else if (CFBundleExecutableArchitectureMismatchError
== code
) {
3142 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");
3143 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl
, CFSTR("The bundle doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
3144 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl
, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError");
3145 } else if (CFBundleExecutableRuntimeMismatchError
== code
) {
3146 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");
3147 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl
, CFSTR("The bundle isn\\U2019t compatible with this application."), "NSExecutableRuntimeMismatchError");
3148 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl
, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError");
3149 } else if (CFBundleExecutableLoadError
== code
) {
3150 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");
3151 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl
, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError");
3152 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError");
3153 } else if (CFBundleExecutableLinkError
== code
) {
3154 descFormat
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl
, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded."), "NSExecutableLinkError");
3155 reason
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl
, CFSTR("The bundle couldn\\U2019t be loaded."), "NSExecutableLinkError");
3156 suggestion
= CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl
, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError");
3159 desc
= CFStringCreateWithFormat(allocator
, NULL
, descFormat
, name
);
3160 CFRelease(descFormat
);
3165 userInfoKeys
[numKeys
] = CFSTR("NSBundlePath");
3166 userInfoValues
[numKeys
] = bundlePath
;
3169 if (executablePath
) {
3170 userInfoKeys
[numKeys
] = CFSTR("NSFilePath");
3171 userInfoValues
[numKeys
] = executablePath
;
3175 userInfoKeys
[numKeys
] = kCFErrorLocalizedDescriptionKey
;
3176 userInfoValues
[numKeys
] = desc
;
3180 userInfoKeys
[numKeys
] = kCFErrorLocalizedFailureReasonKey
;
3181 userInfoValues
[numKeys
] = reason
;
3185 userInfoKeys
[numKeys
] = kCFErrorLocalizedRecoverySuggestionKey
;
3186 userInfoValues
[numKeys
] = suggestion
;
3190 userInfoKeys
[numKeys
] = CFSTR("NSDebugDescription");
3191 userInfoValues
[numKeys
] = debugString
;
3194 error
= CFErrorCreateWithUserInfoKeysAndValues(allocator
, kCFErrorDomainCocoa
, code
, userInfoKeys
, userInfoValues
, numKeys
);
3195 if (bundleURL
) CFRelease(bundleURL
);
3196 if (absoluteURL
) CFRelease(absoluteURL
);
3197 if (executableURL
) CFRelease(executableURL
);
3198 if (bundlePath
) CFRelease(bundlePath
);
3199 if (executablePath
) CFRelease(executablePath
);
3200 if (desc
) CFRelease(desc
);
3201 if (reason
) CFRelease(reason
);
3202 if (suggestion
) CFRelease(suggestion
);
3206 CFErrorRef
_CFBundleCreateError(CFAllocatorRef allocator
, CFBundleRef bundle
, CFIndex code
) {
3207 allocator
= _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator
);
3208 return _CFBundleCreateErrorDebug(allocator
, bundle
, code
, NULL
);
3211 Boolean
_CFBundleLoadExecutableAndReturnError(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
3212 Boolean result
= false;
3213 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
3214 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3216 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
3217 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
3218 // make sure we know whether bundle is already loaded or not
3219 #if defined(BINARY_SUPPORT_DLFCN)
3220 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3221 #elif defined(BINARY_SUPPORT_DYLD)
3222 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3223 #endif /* BINARY_SUPPORT_DLFCN */
3224 #if defined(BINARY_SUPPORT_DYLD)
3225 // We might need to figure out what it is
3226 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
3227 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
3228 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3230 #endif /* BINARY_SUPPORT_DYLD */
3231 if (executableURL
) CFRelease(executableURL
);
3233 if (bundle
->_isLoaded
) {
3234 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3235 // Remove from the scheduled unload set if we are there.
3236 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3237 #if AVOID_WEAK_COLLECTIONS
3238 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3239 #else /* AVOID_WEAK_COLLECTIONS */
3240 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3241 #endif /* AVOID_WEAK_COLLECTIONS */
3242 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3246 // Unload bundles scheduled for unloading
3247 if (!_scheduledBundlesAreUnloading
) {
3248 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3249 _CFBundleUnloadScheduledBundles();
3250 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
3253 if (bundle
->_isLoaded
) {
3254 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3255 // Remove from the scheduled unload set if we are there.
3256 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3257 #if AVOID_WEAK_COLLECTIONS
3258 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3259 #else /* AVOID_WEAK_COLLECTIONS */
3260 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3261 #endif /* AVOID_WEAK_COLLECTIONS */
3262 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3265 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3267 switch (bundle
->_binaryType
) {
3268 #if defined(BINARY_SUPPORT_DLFCN)
3269 case __CFBundleUnreadableBinary
:
3270 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3272 #endif /* BINARY_SUPPORT_DLFCN */
3273 #if defined(BINARY_SUPPORT_DYLD)
3274 case __CFBundleDYLDBundleBinary
:
3275 #if defined(BINARY_SUPPORT_DLFCN)
3276 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3277 #else /* BINARY_SUPPORT_DLFCN */
3278 result
= _CFBundleDYLDLoadBundle(bundle
, forceGlobal
, subError
);
3279 #endif /* BINARY_SUPPORT_DLFCN */
3281 case __CFBundleDYLDFrameworkBinary
:
3282 #if defined(BINARY_SUPPORT_DLFCN)
3283 result
= _CFBundleDlfcnLoadFramework(bundle
, subError
);
3284 #else /* BINARY_SUPPORT_DLFCN */
3285 result
= _CFBundleDYLDLoadFramework(bundle
, subError
);
3286 #endif /* BINARY_SUPPORT_DLFCN */
3288 case __CFBundleDYLDExecutableBinary
:
3290 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3292 CFLog(__kCFLogBundle
, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle
);
3295 #endif /* BINARY_SUPPORT_DYLD */
3296 #if defined(BINARY_SUPPORT_DLFCN)
3297 case __CFBundleUnknownBinary
:
3298 case __CFBundleELFBinary
:
3299 result
= _CFBundleDlfcnLoadBundle(bundle
, forceGlobal
, subError
);
3301 #endif /* BINARY_SUPPORT_DLFCN */
3302 #if defined(BINARY_SUPPORT_DLL)
3303 case __CFBundleDLLBinary
:
3304 result
= _CFBundleDLLLoad(bundle
, subError
);
3306 #endif /* BINARY_SUPPORT_DLL */
3307 case __CFBundleNoBinary
:
3309 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
3311 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for %@"), bundle
);
3316 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3318 CFLog(__kCFLogBundle
, CFSTR("Cannot recognize type of executable for %@"), bundle
);
3322 if (result
&& bundle
->_plugInData
._isPlugIn
) _CFBundlePlugInLoaded(bundle
);
3323 if (!result
&& error
) *error
= localError
;
3327 Boolean
CFBundleLoadExecutableAndReturnError(CFBundleRef bundle
, CFErrorRef
*error
) {
3328 return _CFBundleLoadExecutableAndReturnError(bundle
, false, error
);
3331 Boolean
CFBundleLoadExecutable(CFBundleRef bundle
) {
3332 return _CFBundleLoadExecutableAndReturnError(bundle
, false, NULL
);
3335 Boolean
CFBundlePreflightExecutable(CFBundleRef bundle
, CFErrorRef
*error
) {
3336 Boolean result
= false;
3337 CFErrorRef localError
= NULL
;
3338 #if defined(BINARY_SUPPORT_DLFCN)
3339 CFErrorRef
*subError
= (error
? &localError
: NULL
);
3341 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3343 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
3344 if (!executableURL
) bundle
->_binaryType
= __CFBundleNoBinary
;
3345 // make sure we know whether bundle is already loaded or not
3346 #if defined(BINARY_SUPPORT_DLFCN)
3347 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3348 #elif defined(BINARY_SUPPORT_DYLD)
3349 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3350 #endif /* BINARY_SUPPORT_DLFCN */
3351 #if defined(BINARY_SUPPORT_DYLD)
3352 // We might need to figure out what it is
3353 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
3354 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
3355 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3357 #endif /* BINARY_SUPPORT_DYLD */
3358 if (executableURL
) CFRelease(executableURL
);
3360 if (bundle
->_isLoaded
) {
3361 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3364 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3366 switch (bundle
->_binaryType
) {
3367 #if defined(BINARY_SUPPORT_DLFCN)
3368 case __CFBundleUnreadableBinary
:
3369 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3371 #endif /* BINARY_SUPPORT_DLFCN */
3372 #if defined(BINARY_SUPPORT_DYLD)
3373 case __CFBundleDYLDBundleBinary
:
3375 #if defined(BINARY_SUPPORT_DLFCN)
3376 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3377 #endif /* BINARY_SUPPORT_DLFCN */
3379 case __CFBundleDYLDFrameworkBinary
:
3381 #if defined(BINARY_SUPPORT_DLFCN)
3382 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3383 #endif /* BINARY_SUPPORT_DLFCN */
3385 case __CFBundleDYLDExecutableBinary
:
3386 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3388 #endif /* BINARY_SUPPORT_DYLD */
3389 #if defined(BINARY_SUPPORT_DLFCN)
3390 case __CFBundleUnknownBinary
:
3391 case __CFBundleELFBinary
:
3392 result
= _CFBundleDlfcnPreflight(bundle
, subError
);
3394 #endif /* BINARY_SUPPORT_DLFCN */
3395 #if defined(BINARY_SUPPORT_DLL)
3396 case __CFBundleDLLBinary
:
3399 #endif /* BINARY_SUPPORT_DLL */
3400 case __CFBundleNoBinary
:
3401 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
3404 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
3407 if (!result
&& error
) *error
= localError
;
3411 CFArrayRef
CFBundleCopyExecutableArchitectures(CFBundleRef bundle
) {
3412 CFArrayRef result
= NULL
;
3413 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3414 if (executableURL
) {
3415 result
= _CFBundleCopyArchitecturesForExecutable(executableURL
);
3416 CFRelease(executableURL
);
3421 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3422 static Boolean
_CFBundleGetObjCImageInfo(CFBundleRef bundle
, uint32_t *objcVersion
, uint32_t *objcFlags
) {
3423 Boolean retval
= false;
3424 uint32_t localVersion
= 0, localFlags
= 0;
3425 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
3426 if (executableURL
) {
3427 retval
= _CFBundleGetObjCImageInfoForExecutable(executableURL
, &localVersion
, &localFlags
);
3428 CFRelease(executableURL
);
3430 if (objcVersion
) *objcVersion
= localVersion
;
3431 if (objcFlags
) *objcFlags
= localFlags
;
3436 void CFBundleUnloadExecutable(CFBundleRef bundle
) {
3437 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
3438 if (!_scheduledBundlesAreUnloading
) _CFBundleUnloadScheduledBundles();
3440 if (!bundle
->_isLoaded
) return;
3442 // Remove from the scheduled unload set if we are there.
3443 if (!_scheduledBundlesAreUnloading
) pthread_mutex_lock(&CFBundleGlobalDataLock
);
3444 #if AVOID_WEAK_COLLECTIONS
3445 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3446 #else /* AVOID_WEAK_COLLECTIONS */
3447 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3448 #endif /* AVOID_WEAK_COLLECTIONS */
3449 if (!_scheduledBundlesAreUnloading
) pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3451 // Give the plugIn code a chance to realize this...
3452 _CFPlugInWillUnload(bundle
);
3454 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
3455 if (!bundle
->_isLoaded
) {
3456 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3459 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3461 switch (bundle
->_binaryType
) {
3462 #if defined(BINARY_SUPPORT_DYLD)
3463 case __CFBundleDYLDBundleBinary
:
3464 #if defined(BINARY_SUPPORT_DLFCN)
3465 if (bundle
->_handleCookie
) _CFBundleDlfcnUnload(bundle
);
3466 #else /* BINARY_SUPPORT_DLFCN */
3467 _CFBundleDYLDUnloadBundle(bundle
);
3468 #endif /* BINARY_SUPPORT_DLFCN */
3470 case __CFBundleDYLDFrameworkBinary
:
3471 #if defined(BINARY_SUPPORT_DLFCN)
3472 if (bundle
->_handleCookie
&& _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard
)) _CFBundleDlfcnUnload(bundle
);
3473 #endif /* BINARY_SUPPORT_DLFCN */
3475 #endif /* BINARY_SUPPORT_DYLD */
3476 #if defined(BINARY_SUPPORT_DLL)
3477 case __CFBundleDLLBinary
:
3478 _CFBundleDLLUnload(bundle
);
3480 #endif /* BINARY_SUPPORT_DLL */
3482 #if defined(BINARY_SUPPORT_DLFCN)
3483 if (bundle
->_handleCookie
) _CFBundleDlfcnUnload(bundle
);
3484 #endif /* BINARY_SUPPORT_DLFCN */
3487 if (!bundle
->_isLoaded
&& bundle
->_glueDict
) {
3488 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
3489 CFRelease(bundle
->_glueDict
);
3490 bundle
->_glueDict
= NULL
;
3494 #if AVOID_WEAK_COLLECTIONS
3496 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
3497 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3498 if (!_bundlesToUnload
) {
3499 CFSetCallBacks nonRetainingCallbacks
= kCFTypeSetCallBacks
;
3500 nonRetainingCallbacks
.retain
= NULL
;
3501 nonRetainingCallbacks
.release
= NULL
;
3502 _bundlesToUnload
= CFSetCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingCallbacks
);
3504 CFSetAddValue(_bundlesToUnload
, bundle
);
3505 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3508 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
3509 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3510 if (_bundlesToUnload
) CFSetRemoveValue(_bundlesToUnload
, bundle
);
3511 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3514 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
3515 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3516 if (_bundlesToUnload
) {
3517 CFIndex i
, c
= CFSetGetCount(_bundlesToUnload
);
3519 CFBundleRef
*unloadThese
= (CFBundleRef
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(CFBundleRef
) * c
, 0);
3520 CFSetGetValues(_bundlesToUnload
, (const void **)unloadThese
);
3521 _scheduledBundlesAreUnloading
= true;
3522 for (i
= 0; i
< c
; i
++) {
3523 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
3524 CFBundleUnloadExecutable(unloadThese
[i
]);
3526 _scheduledBundlesAreUnloading
= false;
3527 CFAllocatorDeallocate(kCFAllocatorSystemDefault
, unloadThese
);
3530 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3533 #else /* AVOID_WEAK_COLLECTIONS */
3535 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
3536 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3537 if (!_bundlesToUnload
) _bundlesToUnload
= [[__CFHashTable alloc
] initWithOptions
:CFPointerFunctionsZeroingWeakMemory capacity
:0];
3538 [_bundlesToUnload addObject
:(id
)bundle
];
3539 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3542 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
3543 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3544 if (_bundlesToUnload
) [_bundlesToUnload removeObject
:(id
)bundle
];
3545 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3548 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
3549 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3550 if (_bundlesToUnload
&& [_bundlesToUnload count
] > 0) {
3552 CFMutableArrayRef unloadThese
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
3553 for (id value in _bundlesToUnload
) CFArrayAppendValue(unloadThese
, value
);
3554 c
= CFArrayGetCount(unloadThese
);
3556 _scheduledBundlesAreUnloading
= true;
3557 for (i
= 0; i
< c
; i
++) {
3558 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
3559 CFBundleUnloadExecutable((CFBundleRef
)CFArrayGetValueAtIndex(unloadThese
, i
));
3561 _scheduledBundlesAreUnloading
= false;
3563 CFRelease(unloadThese
);
3565 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3568 #endif /* AVOID_WEAK_COLLECTIONS */
3570 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
3572 // Load if necessary
3573 if (!bundle
->_isLoaded
) {
3574 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
3577 switch (bundle
->_binaryType
) {
3578 #if defined(BINARY_SUPPORT_DYLD)
3579 case __CFBundleDYLDBundleBinary
:
3580 case __CFBundleDYLDFrameworkBinary
:
3581 case __CFBundleDYLDExecutableBinary
:
3582 #if defined(BINARY_SUPPORT_DLFCN)
3583 if (bundle
->_handleCookie
) return _CFBundleDlfcnGetSymbolByName(bundle
, funcName
);
3584 #else /* BINARY_SUPPORT_DLFCN */
3585 return _CFBundleDYLDGetSymbolByName(bundle
, funcName
);
3586 #endif /* BINARY_SUPPORT_DLFCN */
3588 #endif /* BINARY_SUPPORT_DYLD */
3589 #if defined(BINARY_SUPPORT_DLL)
3590 case __CFBundleDLLBinary
:
3591 tvp
= _CFBundleDLLGetSymbolByName(bundle
, funcName
);
3593 #endif /* BINARY_SUPPORT_DLL */
3595 #if defined(BINARY_SUPPORT_DLFCN)
3596 if (bundle
->_handleCookie
) return _CFBundleDlfcnGetSymbolByName(bundle
, funcName
);
3597 #endif /* BINARY_SUPPORT_DLFCN */
3603 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
3605 // Load if necessary
3606 if (!bundle
->_isLoaded
) {
3607 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
3609 #if defined (BINARY_SUPPORT_DYLD) || defined (BINARY_SUPPORT_DLFCN)
3610 switch (bundle
->_binaryType
) {
3611 #if defined(BINARY_SUPPORT_DYLD)
3612 case __CFBundleDYLDBundleBinary
:
3613 case __CFBundleDYLDFrameworkBinary
:
3614 case __CFBundleDYLDExecutableBinary
:
3615 #if defined(BINARY_SUPPORT_DLFCN)
3616 if (bundle
->_handleCookie
) fp
= _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, funcName
, true);
3617 #else /* BINARY_SUPPORT_DLFCN */
3618 fp
= _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, funcName
, true);
3619 #endif /* BINARY_SUPPORT_DLFCN */
3621 #endif /* BINARY_SUPPORT_DYLD */
3623 #if defined(BINARY_SUPPORT_DLFCN)
3624 if (bundle
->_handleCookie
) fp
= _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, funcName
, true);
3625 #endif /* BINARY_SUPPORT_DLFCN */
3628 #endif /* BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */
3632 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
3637 c
= CFArrayGetCount(functionNames
);
3638 for (i
= 0; i
< c
; i
++) ftbl
[i
] = CFBundleGetFunctionPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(functionNames
, i
));
3641 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
3646 c
= CFArrayGetCount(functionNames
);
3647 for (i
= 0; i
< c
; i
++) ftbl
[i
] = _CFBundleGetCFMFunctionPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(functionNames
, i
));
3650 void *CFBundleGetDataPointerForName(CFBundleRef bundle
, CFStringRef symbolName
) {
3652 // Load if necessary
3653 if (!bundle
->_isLoaded
&& !CFBundleLoadExecutable(bundle
)) return NULL
;
3655 switch (bundle
->_binaryType
) {
3656 #if defined(BINARY_SUPPORT_DYLD)
3657 case __CFBundleDYLDBundleBinary
:
3658 case __CFBundleDYLDFrameworkBinary
:
3659 case __CFBundleDYLDExecutableBinary
:
3660 #if defined(BINARY_SUPPORT_DLFCN)
3661 if (bundle
->_handleCookie
) dp
= _CFBundleDlfcnGetSymbolByName(bundle
, symbolName
);
3662 #else /* BINARY_SUPPORT_DLFCN */
3663 dp
= _CFBundleDYLDGetSymbolByName(bundle
, symbolName
);
3664 #endif /* BINARY_SUPPORT_DLFCN */
3666 #endif /* BINARY_SUPPORT_DYLD */
3667 #if defined(BINARY_SUPPORT_DLL)
3668 case __CFBundleDLLBinary
:
3669 /* MF:!!! Handle this someday */
3671 #endif /* BINARY_SUPPORT_DLL */
3673 #if defined(BINARY_SUPPORT_DLFCN)
3674 if (bundle
->_handleCookie
) dp
= _CFBundleDlfcnGetSymbolByName(bundle
, symbolName
);
3675 #endif /* BINARY_SUPPORT_DLFCN */
3681 void CFBundleGetDataPointersForNames(CFBundleRef bundle
, CFArrayRef symbolNames
, void *stbl
[]) {
3686 c
= CFArrayGetCount(symbolNames
);
3687 for (i
= 0; i
< c
; i
++) stbl
[i
] = CFBundleGetDataPointerForName(bundle
, (CFStringRef
)CFArrayGetValueAtIndex(symbolNames
, i
));
3690 __private_extern__ _CFResourceData
*__CFBundleGetResourceData(CFBundleRef bundle
) {
3691 return &(bundle
->_resourceData
);
3694 CFPlugInRef
CFBundleGetPlugIn(CFBundleRef bundle
) {
3695 return (bundle
->_plugInData
._isPlugIn
) ? (CFPlugInRef
)bundle
: NULL
;
3698 __private_extern__ _CFPlugInData
*__CFBundleGetPlugInData(CFBundleRef bundle
) {
3699 return &(bundle
->_plugInData
);
3702 __private_extern__ Boolean
_CFBundleCouldBeBundle(CFURLRef url
) {
3703 Boolean result
= false;
3706 if (_CFGetFileProperties(kCFAllocatorSystemDefault
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) result
= (exists
&& (mode
& S_IFMT
) == S_IFDIR
&& (mode
& 0444) != 0);
3710 #define LENGTH_OF(A) (sizeof(A) / sizeof(A[0]))
3712 //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/
3713 static CFURLRef
__CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath
, Boolean permissive
) {
3714 // 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.
3715 #if DEPLOYMENT_TARGET_WINDOWS
3716 UniChar executablesToFrameworksPathBuff
[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3717 UniChar executablesToPrivateFrameworksPathBuff
[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3718 UniChar frameworksExtension
[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
3720 UniChar pathBuff
[CFMaxPathSize
] = {0};
3721 UniChar nameBuff
[CFMaxPathSize
] = {0};
3722 CFIndex length
, nameStart
, nameLength
, savedLength
;
3723 CFMutableStringRef cheapStr
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, NULL
, 0, 0, NULL
);
3724 CFURLRef bundleURL
= NULL
;
3726 length
= CFStringGetLength(executablePath
);
3727 if (length
> CFMaxPathSize
) length
= CFMaxPathSize
;
3728 CFStringGetCharacters(executablePath
, CFRangeMake(0, length
), pathBuff
);
3730 // Save the name in nameBuff
3731 length
= _CFLengthAfterDeletingPathExtension(pathBuff
, length
);
3732 nameStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3733 nameLength
= length
- nameStart
;
3734 memmove(nameBuff
, &(pathBuff
[nameStart
]), nameLength
* sizeof(UniChar
));
3736 // Strip the name from pathBuff
3737 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3738 savedLength
= length
;
3740 #if DEPLOYMENT_TARGET_WINDOWS
3741 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
3742 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToFrameworksPathBuff
, LENGTH_OF(executablesToFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3743 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3744 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3745 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3746 CFRelease(bundleURL
);
3750 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
3752 length
= savedLength
;
3753 if (_CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToPrivateFrameworksPathBuff
, LENGTH_OF(executablesToPrivateFrameworksPathBuff
)) && _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
) && _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, LENGTH_OF(frameworksExtension
))) {
3754 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3755 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3756 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3757 CFRelease(bundleURL
);
3763 // * Finally check the executable inside the framework case.
3765 length
= savedLength
;
3766 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
3768 CFStringRef name
= permissive
? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, (const char *)nameBuff
);
3770 while (length
> 0) {
3771 CFIndex curStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3772 if (curStart
>= length
) break;
3773 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[curStart
]), length
- curStart
, CFMaxPathSize
- curStart
);
3774 if (!permissive
&& CFEqual(cheapStr
, _CFBundleResourcesDirectoryName
)) break;
3775 if (CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName1
) || CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName2
)) {
3777 CFIndex fmwkStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
3778 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[fmwkStart
]), length
- fmwkStart
, CFMaxPathSize
- fmwkStart
);
3780 if (permissive
|| CFStringHasPrefix(cheapStr
, name
)) {
3781 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3782 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3784 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3785 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3786 CFRelease(bundleURL
);
3791 } else if (CFStringHasSuffix(cheapStr
, CFSTR(".framework")) && (permissive
|| CFStringHasPrefix(cheapStr
, name
))) {
3792 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
3793 bundleURL
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, cheapStr
, PLATFORM_PATH_STYLE
, true);
3794 if (!_CFBundleCouldBeBundle(bundleURL
)) {
3795 CFRelease(bundleURL
);
3800 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
3802 if (!permissive
) CFRelease(name
);
3804 CFStringSetExternalCharactersNoCopy(cheapStr
, NULL
, 0, 0);
3805 CFRelease(cheapStr
);
3810 //SPI version; separated out to minimize linkage changes
3811 CFURLRef
_CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath
) {
3812 return __CFBundleCopyFrameworkURLForExecutablePath(executablePath
, false);
3815 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
) {
3816 // This finds the bundle for the given path.
3817 // 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.
3819 CFURLRef curURL
= __CFBundleCopyFrameworkURLForExecutablePath(imagePath
, true);
3820 Boolean createdBundle
= false;
3823 bundle
= _CFBundleCopyBundleForURL(curURL
, true);
3825 // Ensure bundle exists by creating it if necessary
3826 // NB doFinalProcessing must be false here, see below
3827 bundle
= _CFBundleCreate(kCFAllocatorSystemDefault
, curURL
, true, false);
3828 createdBundle
= true;
3831 pthread_mutex_lock(&(bundle
->_bundleLoadingLock
));
3832 if (!bundle
->_isLoaded
) {
3833 // 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)
3834 #if defined(BINARY_SUPPORT_DLFCN)
3835 if (!bundle
->_isLoaded
) _CFBundleDlfcnCheckLoaded(bundle
);
3836 #elif defined(BINARY_SUPPORT_DYLD)
3837 if (!bundle
->_isLoaded
) _CFBundleDYLDCheckLoaded(bundle
);
3838 #endif /* BINARY_SUPPORT_DLFCN */
3839 #if defined(BINARY_SUPPORT_DYLD)
3840 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
3841 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) bundle
->_resourceData
._executableLacksResourceFork
= true;
3842 #endif /* BINARY_SUPPORT_DYLD */
3844 if (!bundle
->_isLoaded
) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle
, bundle
->_handleCookie
, bundle
->_imageCookie
, bundle
->_connectionCookie
);
3845 #endif /* LOG_BUNDLE_LOAD */
3846 bundle
->_isLoaded
= true;
3848 pthread_mutex_unlock(&(bundle
->_bundleLoadingLock
));
3849 if (createdBundle
) {
3850 // Perform delayed final processing steps.
3851 // This must be done after _isLoaded has been set, for security reasons (3624341).
3852 if (_CFBundleNeedsInitPlugIn(bundle
)) {
3853 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3854 _CFBundleInitPlugIn(bundle
);
3855 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3858 // Release the bundle if we did not create it here
3866 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
) {
3867 // This finds the bundles for the given paths.
3868 // 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).
3869 CFIndex i
, imagePathCount
= CFArrayGetCount(imagePaths
);
3870 for (i
= 0; i
< imagePathCount
; i
++) _CFBundleEnsureBundleExistsForImagePath((CFStringRef
)CFArrayGetValueAtIndex(imagePaths
, i
));
3873 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
) {
3874 CFArrayRef imagePaths
= NULL
;
3875 // Tickle the main bundle into existence
3876 (void)_CFBundleGetMainBundleAlreadyLocked();
3877 #if defined(BINARY_SUPPORT_DYLD)
3878 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsForHint(hint
);
3879 #endif /* BINARY_SUPPORT_DYLD */
3881 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
3882 CFRelease(imagePaths
);
3886 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
3887 // 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.
3888 CFArrayRef imagePaths
= NULL
;
3889 // Tickle the main bundle into existence
3890 (void)_CFBundleGetMainBundleAlreadyLocked();
3892 #if defined(BINARY_SUPPORT_DLL)
3893 // Dont know how to find static bundles for DLLs
3894 #endif /* BINARY_SUPPORT_DLL */
3896 #if defined(BINARY_SUPPORT_DYLD)
3897 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsIfChanged();
3898 #endif /* BINARY_SUPPORT_DYLD */
3900 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
3901 CFRelease(imagePaths
);
3905 CFArrayRef
CFBundleGetAllBundles(void) {
3906 // To answer this properly, we have to have created the static bundles!
3907 #if !AVOID_WEAK_COLLECTIONS
3908 static CFMutableArrayRef externalAllBundles
= NULL
;
3909 #endif /* AVOID_WEAK_COLLECTIONS */
3911 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3912 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
3913 #if AVOID_WEAK_COLLECTIONS
3914 bundles
= _allBundles
;
3915 #else /* AVOID_WEAK_COLLECTIONS */
3916 if (!externalAllBundles
) {
3917 CFArrayCallBacks nonRetainingArrayCallbacks
= kCFTypeArrayCallBacks
;
3918 nonRetainingArrayCallbacks
.retain
= NULL
;
3919 nonRetainingArrayCallbacks
.release
= NULL
;
3920 externalAllBundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &nonRetainingArrayCallbacks
);
3922 CFArrayRemoveAllValues(externalAllBundles
);
3923 for (id value in _allBundles
) CFArrayAppendValue(externalAllBundles
, value
);
3924 bundles
= externalAllBundles
;
3925 #endif /* AVOID_WEAK_COLLECTIONS */
3926 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3930 CF_EXPORT CFArrayRef
_CFBundleCopyAllBundles(void) {
3931 // To answer this properly, we have to have created the static bundles!
3932 pthread_mutex_lock(&CFBundleGlobalDataLock
);
3933 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
3934 #if AVOID_WEAK_COLLECTIONS
3935 CFArrayRef bundles
= CFArrayCreateCopy(kCFAllocatorSystemDefault
, _allBundles
);
3936 #else /* AVOID_WEAK_COLLECTIONS */
3937 CFMutableArrayRef bundles
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
3938 for (id value in _allBundles
) CFArrayAppendValue(bundles
, value
);
3939 #endif /* AVOID_WEAK_COLLECTIONS */
3940 pthread_mutex_unlock(&CFBundleGlobalDataLock
);
3944 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle
) {
3945 return bundle
->_version
;
3948 static void __addPlatformAndProductNamesToKeys(const void *value
, void *context
) {
3949 CFMutableSetRef newKeys
= (CFMutableSetRef
)context
;
3950 CFStringRef key
= (CFStringRef
)value
;
3951 CFStringRef firstPartOfKey
= NULL
;
3952 CFStringRef restOfKey
= NULL
;
3954 // Find the first ':'
3956 Boolean success
= CFStringFindWithOptions(key
, CFSTR(":"), CFRangeMake(0, CFStringGetLength(key
)), 0, &range
);
3958 firstPartOfKey
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, key
, CFRangeMake(0, range
.location
));
3959 restOfKey
= CFStringCreateWithSubstring(kCFAllocatorSystemDefault
, key
, CFRangeMake(range
.location
+ 1, CFStringGetLength(key
) - range
.location
- 1));
3961 firstPartOfKey
= (CFStringRef
)CFRetain(key
);
3964 // only apply product and platform to top-level key
3965 CFStringRef newKeyWithPlatform
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@-%@%@%@"), firstPartOfKey
, _CFGetPlatformName(), restOfKey
? CFSTR(":") : CFSTR(""), restOfKey
? restOfKey
: CFSTR(""));
3966 CFStringRef newKeyWithProduct
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@~%@%@%@"), firstPartOfKey
, _CFGetProductName(), restOfKey
? CFSTR(":") : CFSTR(""), restOfKey
? restOfKey
: CFSTR(""));
3967 CFStringRef newKeyWithProductAndPlatform
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@-%@~%@%@%@"), firstPartOfKey
, _CFGetPlatformName(), _CFGetProductName(), restOfKey
? CFSTR(":") : CFSTR(""), restOfKey
? restOfKey
: CFSTR(""));
3969 CFSetAddValue(newKeys
, key
);
3970 CFSetAddValue(newKeys
, newKeyWithPlatform
);
3971 CFSetAddValue(newKeys
, newKeyWithProduct
);
3972 CFSetAddValue(newKeys
, newKeyWithProductAndPlatform
);
3974 if (firstPartOfKey
) CFRelease(firstPartOfKey
);
3975 if (restOfKey
) CFRelease(restOfKey
);
3976 CFRelease(newKeyWithPlatform
);
3977 CFRelease(newKeyWithProduct
);
3978 CFRelease(newKeyWithProductAndPlatform
);
3981 // from CFUtilities.c
3982 __private_extern__ Boolean
_CFReadMappedFromFile(CFStringRef path
, Boolean map
, Boolean uncached
, void **outBytes
, CFIndex
*outLength
, CFErrorRef
*errorPtr
);
3984 // implementation of below functions - takes URL as parameter
3985 static CFPropertyListRef
_CFBundleCreateFilteredInfoPlistWithURL(CFURLRef infoPlistURL
, CFSetRef keyPaths
, _CFBundleFilteredPlistOptions options
) {
3986 CFPropertyListRef result
= NULL
;
3988 if (!infoPlistURL
) return CFDictionaryCreate(kCFAllocatorSystemDefault
, NULL
, NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3990 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(infoPlistURL
);
3991 CFStringRef filePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
3992 CFRelease(absoluteURL
);
3994 if (!filePath
) return CFDictionaryCreate(kCFAllocatorSystemDefault
, NULL
, NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
3998 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
3999 Boolean mapped
= options
& _CFBundleFilteredPlistMemoryMapped
? true : false;
4001 Boolean mapped
= false;
4003 Boolean success
= _CFReadMappedFromFile(filePath
, mapped
, false, &bytes
, &length
, NULL
);
4004 CFRelease(filePath
);
4005 if (!success
) return CFDictionaryCreate(kCFAllocatorSystemDefault
, NULL
, NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
4007 CFDataRef infoPlistData
= CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault
, (const UInt8
*)bytes
, length
, kCFAllocatorNull
);
4008 // We need to include all possible variants of the platform/product combo as possible keys.
4009 CFMutableSetRef newKeyPaths
= CFSetCreateMutable(kCFAllocatorSystemDefault
, CFSetGetCount(keyPaths
), &kCFTypeSetCallBacks
);
4010 CFSetApplyFunction(keyPaths
, __addPlatformAndProductNamesToKeys
, newKeyPaths
);
4012 success
= _CFPropertyListCreateFiltered(kCFAllocatorSystemDefault
, infoPlistData
, kCFPropertyListMutableContainers
, newKeyPaths
, &result
, NULL
);
4015 result
= CFDictionaryCreate(kCFAllocatorSystemDefault
, NULL
, NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
4017 _processInfoDictionary((CFMutableDictionaryRef
)result
, _CFGetPlatformName(), _CFGetProductName());
4020 CFRelease(newKeyPaths
);
4021 CFRelease(infoPlistData
);
4023 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
4024 munmap(bytes
, length
);
4033 // Returns a subset of the bundle's property list, only including the keyPaths in the CFSet. If the top level object is not a dictionary, you will get back an empty dictionary as the result. If the Info.plist does not exist or could not be parsed, you will get back an empty dictionary.
4034 CF_EXPORT CFPropertyListRef
_CFBundleCreateFilteredInfoPlist(CFBundleRef bundle
, CFSetRef keyPaths
, _CFBundleFilteredPlistOptions options
) {
4035 CFURLRef infoPlistURL
= _CFBundleCopyInfoPlistURL(bundle
);
4036 CFPropertyListRef result
= _CFBundleCreateFilteredInfoPlistWithURL(infoPlistURL
, keyPaths
, options
);
4037 if (infoPlistURL
) CFRelease(infoPlistURL
);
4041 CF_EXPORT CFPropertyListRef
_CFBundleCreateFilteredLocalizedInfoPlist(CFBundleRef bundle
, CFSetRef keyPaths
, CFStringRef localizationName
, _CFBundleFilteredPlistOptions options
) {
4042 CFURLRef infoPlistURL
= CFBundleCopyResourceURLForLocalization(bundle
, _CFBundleLocalInfoName
, _CFBundleStringTableType
, NULL
, localizationName
);
4043 CFPropertyListRef result
= _CFBundleCreateFilteredInfoPlistWithURL(infoPlistURL
, keyPaths
, options
);
4044 if (infoPlistURL
) CFRelease(infoPlistURL
);
4048 CF_EXPORT CFURLRef
_CFBundleCopyInfoPlistURL(CFBundleRef bundle
) {
4049 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
4050 CFURLRef url
= (CFURLRef
)CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
);
4051 if (!url
) url
= (CFURLRef
)CFDictionaryGetValue(infoDict
, _kCFBundleRawInfoPlistURLKey
);
4052 return (url
? (CFURLRef
)CFRetain(url
) : NULL
);
4055 CF_EXPORT CFURLRef
_CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
4056 return CFBundleCopyPrivateFrameworksURL(bundle
);
4059 CF_EXPORT CFURLRef
CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
4060 CFURLRef result
= NULL
;
4062 if (1 == bundle
->_version
) {
4063 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase1
, bundle
->_url
);
4064 } else if (2 == bundle
->_version
) {
4065 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase2
, bundle
->_url
);
4067 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase0
, bundle
->_url
);
4072 CF_EXPORT CFURLRef
_CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
4073 return CFBundleCopySharedFrameworksURL(bundle
);
4076 CF_EXPORT CFURLRef
CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
4077 CFURLRef result
= NULL
;
4079 if (1 == bundle
->_version
) {
4080 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase1
, bundle
->_url
);
4081 } else if (2 == bundle
->_version
) {
4082 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase2
, bundle
->_url
);
4084 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase0
, bundle
->_url
);
4089 CF_EXPORT CFURLRef
_CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
4090 return CFBundleCopySharedSupportURL(bundle
);
4093 CF_EXPORT CFURLRef
CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
4094 CFURLRef result
= NULL
;
4096 if (1 == bundle
->_version
) {
4097 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase1
, bundle
->_url
);
4098 } else if (2 == bundle
->_version
) {
4099 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase2
, bundle
->_url
);
4101 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase0
, bundle
->_url
);
4106 __private_extern__ CFURLRef
_CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
4107 return CFBundleCopyBuiltInPlugInsURL(bundle
);
4110 CF_EXPORT CFURLRef
CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
4111 CFURLRef result
= NULL
, alternateResult
= NULL
;
4113 CFAllocatorRef alloc
= CFGetAllocator(bundle
);
4114 if (1 == bundle
->_version
) {
4115 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase1
, bundle
->_url
);
4116 } else if (2 == bundle
->_version
) {
4117 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase2
, bundle
->_url
);
4119 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase0
, bundle
->_url
);
4121 if (!result
|| !_urlExists(result
)) {
4122 if (1 == bundle
->_version
) {
4123 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase1
, bundle
->_url
);
4124 } else if (2 == bundle
->_version
) {
4125 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase2
, bundle
->_url
);
4127 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase0
, bundle
->_url
);
4129 if (alternateResult
&& _urlExists(alternateResult
)) {
4130 if (result
) CFRelease(result
);
4131 result
= alternateResult
;
4133 if (alternateResult
) CFRelease(alternateResult
);
4139 #if defined(BINARY_SUPPORT_DYLD)
4141 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint
) {
4142 uint32_t i
, numImages
= _dyld_image_count();
4143 CFMutableArrayRef result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
4144 CFRange range
= CFRangeMake(0, CFStringGetLength(hint
)), altRange
= CFRangeMake(0, 0), testRange
= CFRangeMake(0, 0);
4145 const char *processPath
= _CFProcessPath();
4146 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
4148 if (range
.length
> 14) {
4149 // handle some common variations on framework bundle identifiers
4150 if (CFStringFindWithOptions(hint
, CFSTR(".framework"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4151 // identifier has .framework appended
4152 altRange
.length
= testRange
.location
;
4153 } else if (CFStringFindWithOptions(hint
, CFSTR("framework"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4154 // identifier has Framework appended
4155 altRange
.length
= testRange
.location
;
4156 } else if (CFStringFindWithOptions(hint
, CFSTR("fw"), range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, &testRange
) && testRange
.location
> 0 && testRange
.length
> 0) {
4157 // identifier has FW appended
4158 altRange
.length
= testRange
.location
;
4161 for (i
= 0; i
< numImages
; i
++) {
4162 const char *curName
= _dyld_get_image_name(i
), *lastComponent
= NULL
;
4163 if (curName
&& (!processPath
|| 0 != strcmp(curName
, processPath
)) && mhp
!= (void *)_dyld_get_image_header(i
)) lastComponent
= strrchr(curName
, '/');
4164 if (lastComponent
) {
4165 CFStringRef str
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, lastComponent
+ 1);
4167 if (CFStringFindWithOptions(hint
, str
, range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
) || (altRange
.length
> 0 && CFStringFindWithOptions(hint
, str
, altRange
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
))) {
4168 CFStringRef curStr
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, curName
);
4170 CFArrayAppendValue(result
, curStr
);
4181 static char *_cleanedPathForPath(const char *curName
) {
4182 char *thePath
= strdup(curName
);
4184 // We are going to process the buffer replacing all "/./" and "//" with "/"
4185 CFIndex srcIndex
= 0, dstIndex
= 0;
4186 CFIndex len
= strlen(thePath
);
4187 for (srcIndex
=0; srcIndex
<len
; srcIndex
++) {
4188 thePath
[dstIndex
] = thePath
[srcIndex
];
4190 while (srcIndex
< len
-1 && thePath
[srcIndex
] == '/' && (thePath
[srcIndex
+1] == '/' || (thePath
[srcIndex
+1] == '.' && srcIndex
< len
-2 && thePath
[srcIndex
+2] == '/'))) srcIndex
+= (thePath
[srcIndex
+1] == '/' ? 1 : 2);
4192 thePath
[dstIndex
] = 0;
4197 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
4198 // 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.
4199 uint32_t i
, numImages
= _dyld_image_count();
4200 CFMutableArrayRef result
= NULL
;
4201 static uint32_t _cachedDYLDImageCount
= -1;
4203 if (numImages
!= _cachedDYLDImageCount
) {
4204 const char *curName
;
4205 char *cleanedCurName
= NULL
;
4207 const char *processPath
= _CFProcessPath();
4208 const void *mhp
= (const void *)_NSGetMachExecuteHeader();
4210 result
= CFArrayCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFTypeArrayCallBacks
);
4212 for (i
= 0; i
< numImages
; i
++) {
4213 curName
= _dyld_get_image_name(i
);
4214 if (curName
&& i
== 0) cleanedCurName
= _cleanedPathForPath(curName
);
4215 if (curName
&& (!processPath
|| 0 != strcmp(curName
, processPath
)) && (!processPath
|| !cleanedCurName
|| 0 != strcmp(cleanedCurName
, processPath
)) && mhp
!= (void *)_dyld_get_image_header(i
)) {
4216 curStr
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, curName
);
4218 CFArrayAppendValue(result
, curStr
);
4222 if (cleanedCurName
) {
4223 free(cleanedCurName
);
4224 cleanedCurName
= NULL
;
4227 _cachedDYLDImageCount
= numImages
;
4232 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
) {
4233 CFStringRef result
= NULL
;
4234 #if defined(USE_DYLD_PRIV)
4235 const char *name
= dyld_image_path_containing_address(p
);
4236 if (name
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, name
);
4237 #else /* USE_DYLD_PRIV */
4239 uint32_t i
, j
, n
= _dyld_image_count();
4240 Boolean foundit
= false;
4243 #define MACH_HEADER_TYPE struct mach_header_64
4244 #define MACH_SEGMENT_CMD_TYPE struct segment_command_64
4245 #define MACH_SEGMENT_FLAVOR LC_SEGMENT_64
4247 #define MACH_HEADER_TYPE struct mach_header
4248 #define MACH_SEGMENT_CMD_TYPE struct segment_command
4249 #define MACH_SEGMENT_FLAVOR LC_SEGMENT
4251 for (i
= 0; !foundit
&& i
< n
; i
++) {
4252 const MACH_HEADER_TYPE
*mh
= (const MACH_HEADER_TYPE
*)_dyld_get_image_header(i
);
4253 uintptr_t addr
= (uintptr_t)p
- _dyld_get_image_vmaddr_slide(i
);
4255 struct load_command
*lc
= (struct load_command
*)((char *)mh
+ sizeof(MACH_HEADER_TYPE
));
4256 for (j
= 0; !foundit
&& j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
)) {
4257 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
) {
4259 name
= _dyld_get_image_name(i
);
4260 if (name
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, name
);
4265 #undef MACH_HEADER_TYPE
4266 #undef MACH_SEGMENT_CMD_TYPE
4267 #undef MACH_SEGMENT_FLAVOR
4269 #endif /* USE_DYLD_PRIV */
4271 printf("dyld image path for pointer %p is %p\n", p
, result
);
4272 #endif /* LOG_BUNDLE_LOAD */
4276 #if !defined(BINARY_SUPPORT_DLFCN)
4278 static const void *__CFBundleDYLDFindImage(char *buff
) {
4279 const void *header
= NULL
;
4280 uint32_t i
, numImages
= _dyld_image_count(), numMatches
= 0;
4281 const char *curName
, *p
, *q
;
4283 for (i
= 0; !header
&& i
< numImages
; i
++) {
4284 curName
= _dyld_get_image_name(i
);
4285 if (curName
&& 0 == strncmp(curName
, buff
, CFMaxPathSize
)) {
4286 header
= _dyld_get_image_header(i
);
4291 for (i
= 0; i
< numImages
; i
++) {
4292 curName
= _dyld_get_image_name(i
);
4294 for (p
= buff
, q
= curName
; *p
&& *q
&& (q
- curName
< CFMaxPathSize
); p
++, q
++) {
4295 if (*p
!= *q
&& (q
- curName
> 11) && 0 == strncmp(q
- 11, ".framework/Versions/", 20) && *(q
+ 9) && '/' == *(q
+ 10)) q
+= 11;
4296 else if (*p
!= *q
&& (q
- curName
> 12) && 0 == strncmp(q
- 12, ".framework/Versions/", 20) && *(q
+ 8) && '/' == *(q
+ 9)) q
+= 10;
4297 if (*p
!= *q
) break;
4300 header
= _dyld_get_image_header(i
);
4306 return (numMatches
== 1) ? header
: NULL
;
4309 __private_extern__ Boolean
_CFBundleDYLDCheckLoaded(CFBundleRef bundle
) {
4310 if (!bundle
->_isLoaded
) {
4311 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4312 char buff
[CFMaxPathSize
];
4314 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4315 const void *header
= __CFBundleDYLDFindImage(buff
);
4317 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
4318 if (!bundle
->_imageCookie
) {
4319 bundle
->_imageCookie
= header
;
4321 printf("dyld check load bundle %p, find %s getting image %p\n", bundle
, buff
, bundle
->_imageCookie
);
4322 #endif /* LOG_BUNDLE_LOAD */
4324 bundle
->_isLoaded
= true;
4327 printf("dyld check load bundle %p, find %s no image\n", bundle
, buff
);
4328 #endif /* LOG_BUNDLE_LOAD */
4331 if (executableURL
) CFRelease(executableURL
);
4333 return bundle
->_isLoaded
;
4336 __private_extern__ Boolean
_CFBundleDYLDLoadBundle(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
4337 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4338 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
4339 int errorNumber
= 0;
4340 const char *fileName
= NULL
;
4341 const char *errorString
= NULL
;
4343 if (!bundle
->_isLoaded
) {
4344 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4345 char buff
[CFMaxPathSize
];
4347 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4348 NSObjectFileImage image
;
4349 NSObjectFileImageReturnCode retCode
= NSCreateObjectFileImageFromFile(buff
, &image
);
4351 printf("dyld load bundle %p, create image of %s returns image %p retcode %d\n", bundle
, buff
, image
, retCode
);
4352 #endif /* LOG_BUNDLE_LOAD */
4353 if (retCode
== NSObjectFileImageSuccess
) {
4354 uint32_t options
= forceGlobal
? NSLINKMODULE_OPTION_RETURN_ON_ERROR
: (NSLINKMODULE_OPTION_BINDNOW
| NSLINKMODULE_OPTION_PRIVATE
| NSLINKMODULE_OPTION_RETURN_ON_ERROR
);
4355 NSModule
module = NSLinkModule(image
, buff
, options
);
4357 printf("dyld load bundle %p, link module of %s options 0x%x returns module %p image %p\n", bundle
, buff
, options
, module, image
);
4358 #endif /* LOG_BUNDLE_LOAD */
4360 bundle
->_imageCookie
= image
;
4361 bundle
->_moduleCookie
= module;
4362 bundle
->_isLoaded
= true;
4364 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
4366 #if defined(BINARY_SUPPORT_DLFCN)
4367 _CFBundleDlfcnPreflight(bundle
, subError
);
4368 #endif /* BINARY_SUPPORT_DLFCN */
4370 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("error code %d, error number %d (%@)"), c
, errorNumber
, tempString
);
4371 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4372 if (tempString
) CFRelease(tempString
);
4373 if (debugString
) CFRelease(debugString
);
4376 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, fileName
);
4377 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString
, c
, errorNumber
, tempString
);
4378 if (tempString
) CFRelease(tempString
);
4379 if (executableString
) CFRelease(executableString
);
4381 (void)NSDestroyObjectFileImage(image
);
4385 if (retCode
== NSObjectFileImageArch
) {
4386 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableArchitectureMismatchError
);
4387 } else if (retCode
== NSObjectFileImageInappropriateFile
) {
4388 Boolean hasRuntimeMismatch
= false;
4389 uint32_t mainFlags
= 0, bundleFlags
= 0;
4390 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL
, &mainFlags
) && (mainFlags
& 0x2) != 0) {
4391 if (_CFBundleGetObjCImageInfo(bundle
, NULL
, &bundleFlags
) && (bundleFlags
& 0x2) == 0) hasRuntimeMismatch
= true;
4393 if (hasRuntimeMismatch
) {
4394 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableRuntimeMismatchError
);
4396 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotLoadableError
);
4399 #if defined(BINARY_SUPPORT_DLFCN)
4400 _CFBundleDlfcnPreflight(bundle
, subError
);
4401 #endif /* BINARY_SUPPORT_DLFCN */
4403 CFStringRef debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("dyld returns %d"), retCode
);
4404 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4405 CFRelease(debugString
);
4409 CFLog(__kCFLogBundle
, CFSTR("dyld returns %d when trying to load %@"), retCode
, executableURL
);
4414 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4416 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4419 if (executableURL
) CFRelease(executableURL
);
4421 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4422 return bundle
->_isLoaded
;
4425 __private_extern__ Boolean
_CFBundleDYLDLoadFramework(CFBundleRef bundle
, CFErrorRef
*error
) {
4426 // !!! Framework loading should be better. Can't unload frameworks.
4427 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4428 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
4429 int errorNumber
= 0;
4430 const char *fileName
= NULL
;
4431 const char *errorString
= NULL
;
4433 if (!bundle
->_isLoaded
) {
4434 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4435 char buff
[CFMaxPathSize
];
4437 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4438 void *image
= (void *)NSAddImage(buff
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
4440 printf("dyld load framework %p, add image of %s returns image %p\n", bundle
, buff
, image
);
4441 #endif /* LOG_BUNDLE_LOAD */
4443 bundle
->_imageCookie
= image
;
4444 bundle
->_isLoaded
= true;
4446 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
4448 #if defined(BINARY_SUPPORT_DLFCN)
4449 _CFBundleDlfcnPreflight(bundle
, subError
);
4450 #endif /* BINARY_SUPPORT_DLFCN */
4452 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), debugString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("error code %d, error number %d (%@)"), c
, errorNumber
, tempString
);
4453 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4454 if (tempString
) CFRelease(tempString
);
4455 if (debugString
) CFRelease(debugString
);
4458 CFStringRef tempString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
), executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, fileName
);
4459 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString
, c
, errorNumber
, tempString
);
4460 if (tempString
) CFRelease(tempString
);
4461 if (executableString
) CFRelease(executableString
);
4466 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4468 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4471 if (executableURL
) CFRelease(executableURL
);
4473 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4474 return bundle
->_isLoaded
;
4477 __private_extern__
void _CFBundleDYLDUnloadBundle(CFBundleRef bundle
) {
4478 if (bundle
->_isLoaded
) {
4480 printf("dyld unload bundle %p, handle %p module %p image %p\n", bundle
, bundle
->_handleCookie
, bundle
->_moduleCookie
, bundle
->_imageCookie
);
4481 #endif /* LOG_BUNDLE_LOAD */
4482 if (bundle
->_moduleCookie
&& !NSUnLinkModule((NSModule
)(bundle
->_moduleCookie
), NSUNLINKMODULE_OPTION_NONE
)) {
4483 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
4485 if (bundle
->_moduleCookie
&& bundle
->_imageCookie
) (void)NSDestroyObjectFileImage((NSObjectFileImage
)(bundle
->_imageCookie
));
4486 bundle
->_connectionCookie
= bundle
->_handleCookie
= NULL
;
4487 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
4488 bundle
->_isLoaded
= false;
4493 __private_extern__
void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4494 return _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, symbolName
, false);
4497 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
4498 void *result
= NULL
;
4500 NSSymbol symbol
= NULL
;
4503 if (CFStringGetCString(symbolName
, &(buff
[1]), 1024, kCFStringEncodingUTF8
)) {
4504 if (bundle
->_moduleCookie
) {
4505 symbol
= NSLookupSymbolInModule((NSModule
)(bundle
->_moduleCookie
), buff
);
4506 } else if (bundle
->_imageCookie
) {
4507 symbol
= NSLookupSymbolInImage(bundle
->_imageCookie
, buff
, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
4509 if (!symbol
&& !bundle
->_moduleCookie
&& (!bundle
->_imageCookie
|| globalSearch
)) {
4510 char hintBuff
[1026];
4511 CFStringRef executableName
= _CFBundleCopyExecutableName(bundle
, NULL
, NULL
);
4513 if (executableName
) {
4514 if (!CFStringGetCString(executableName
, hintBuff
, 1024, kCFStringEncodingUTF8
)) hintBuff
[0] = '\0';
4515 CFRelease(executableName
);
4517 // Nowdays, NSIsSymbolNameDefinedWithHint() and NSLookupAndBindSymbolWithHint()
4518 // are identical, except the first just returns a bool, so checking with the
4519 // Is function first just causes a redundant lookup.
4520 // This returns NULL on failure.
4521 symbol
= NSLookupAndBindSymbolWithHint(buff
, hintBuff
);
4523 if (symbol
) result
= NSAddressOfSymbol(symbol
);
4525 if (!result
) CFLog(__kCFLogBundle
, CFSTR("dyld cannot find symbol %@ in %@"), symbolName
, bundle
);
4528 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);
4529 #endif /* LOG_BUNDLE_LOAD */
4534 #endif /* !BINARY_SUPPORT_DLFCN */
4535 #endif /* BINARY_SUPPORT_DYLD */
4537 #if defined(BINARY_SUPPORT_DLFCN)
4539 __private_extern__ Boolean
_CFBundleDlfcnCheckLoaded(CFBundleRef bundle
) {
4540 if (!bundle
->_isLoaded
) {
4541 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4542 char buff
[CFMaxPathSize
];
4544 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4545 int mode
= RTLD_LAZY
| RTLD_LOCAL
| RTLD_NOLOAD
| RTLD_FIRST
;
4546 void *handle
= dlopen(buff
, mode
);
4548 if (!bundle
->_handleCookie
) {
4549 bundle
->_handleCookie
= handle
;
4551 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x getting handle %p\n", bundle
, buff
, mode
, bundle
->_handleCookie
);
4552 #endif /* LOG_BUNDLE_LOAD */
4554 bundle
->_isLoaded
= true;
4557 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x no handle\n", bundle
, buff
, mode
);
4558 #endif /* LOG_BUNDLE_LOAD */
4561 if (executableURL
) CFRelease(executableURL
);
4563 return bundle
->_isLoaded
;
4566 CF_EXPORT Boolean
_CFBundleDlfcnPreflight(CFBundleRef bundle
, CFErrorRef
*error
) {
4567 Boolean retval
= true;
4568 CFErrorRef localError
= NULL
;
4569 if (!bundle
->_isLoaded
) {
4570 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4571 char buff
[CFMaxPathSize
];
4574 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4575 retval
= dlopen_preflight(buff
);
4576 if (!retval
&& error
) {
4577 CFArrayRef archs
= CFBundleCopyExecutableArchitectures(bundle
);
4578 CFStringRef debugString
= NULL
;
4579 const char *errorString
= dlerror();
4580 if (errorString
&& strlen(errorString
) > 0) debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4582 Boolean hasSuitableArch
= false, hasRuntimeMismatch
= false;
4583 CFIndex i
, count
= CFArrayGetCount(archs
);
4584 SInt32 arch
, curArch
= _CFBundleCurrentArchitecture();
4585 for (i
= 0; !hasSuitableArch
&& i
< count
; i
++) {
4586 if (CFNumberGetValue((CFNumberRef
)CFArrayGetValueAtIndex(archs
, i
), kCFNumberSInt32Type
, (void *)&arch
) && arch
== curArch
) hasSuitableArch
= true;
4588 #if defined(BINARY_SUPPORT_DYLD)
4589 if (hasSuitableArch
) {
4590 uint32_t mainFlags
= 0;
4591 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL
, &mainFlags
) && (mainFlags
& 0x2) != 0) {
4592 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
4593 uint32_t bundleFlags
= 0;
4594 if (_CFBundleGetObjCImageInfo(bundle
, NULL
, &bundleFlags
) && (bundleFlags
& 0x2) == 0) hasRuntimeMismatch
= true;
4598 #endif /* BINARY_SUPPORT_DYLD */
4599 if (hasRuntimeMismatch
) {
4600 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableRuntimeMismatchError
, debugString
);
4601 } else if (!hasSuitableArch
) {
4602 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableArchitectureMismatchError
, debugString
);
4604 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLoadError
, debugString
);
4608 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLoadError
, debugString
);
4610 if (debugString
) CFRelease(debugString
);
4613 if (error
) localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4615 if (executableURL
) CFRelease(executableURL
);
4617 if (!retval
&& error
) *error
= localError
;
4621 __private_extern__ Boolean
_CFBundleDlfcnLoadBundle(CFBundleRef bundle
, Boolean forceGlobal
, CFErrorRef
*error
) {
4622 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4623 if (!bundle
->_isLoaded
) {
4624 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4625 char buff
[CFMaxPathSize
];
4626 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4627 int mode
= forceGlobal
? (RTLD_LAZY
| RTLD_GLOBAL
| RTLD_FIRST
) : (RTLD_NOW
| RTLD_LOCAL
| RTLD_FIRST
);
4628 void *cookie
= dlopen(buff
, mode
);
4630 printf("dlfcn load bundle %p, dlopen of %s mode 0x%x returns handle %p\n", bundle
, buff
, mode
, cookie
);
4631 #endif /* LOG_BUNDLE_LOAD */
4632 if (cookie
&& cookie
== bundle
->_handleCookie
) {
4633 // 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
4635 printf("dlfcn load bundle %p closing existing reference to handle %p\n", bundle
, cookie
);
4636 #endif /* LOG_BUNDLE_LOAD */
4637 dlclose(bundle
->_handleCookie
);
4639 bundle
->_handleCookie
= cookie
;
4640 if (bundle
->_handleCookie
) {
4641 bundle
->_isLoaded
= true;
4643 const char *errorString
= dlerror();
4645 _CFBundleDlfcnPreflight(bundle
, subError
);
4647 CFStringRef debugString
= errorString
? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
) : NULL
;
4648 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4649 if (debugString
) CFRelease(debugString
);
4652 CFStringRef executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
4654 CFStringRef debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4655 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: %@"), executableString
, debugString
);
4656 if (debugString
) CFRelease(debugString
);
4658 CFLog(__kCFLogBundle
, CFSTR("Error loading %@"), executableString
);
4660 if (executableString
) CFRelease(executableString
);
4665 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4667 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4670 if (executableURL
) CFRelease(executableURL
);
4672 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4673 return bundle
->_isLoaded
;
4676 __private_extern__ Boolean
_CFBundleDlfcnLoadFramework(CFBundleRef bundle
, CFErrorRef
*error
) {
4677 CFErrorRef localError
= NULL
, *subError
= (error
? &localError
: NULL
);
4678 if (!bundle
->_isLoaded
) {
4679 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4680 char buff
[CFMaxPathSize
];
4681 if (executableURL
&& CFURLGetFileSystemRepresentation(executableURL
, true, (uint8_t *)buff
, CFMaxPathSize
)) {
4682 int mode
= RTLD_LAZY
| RTLD_GLOBAL
| RTLD_FIRST
;
4683 void *cookie
= dlopen(buff
, mode
);
4685 printf("dlfcn load framework %p, dlopen of %s mode 0x%x returns handle %p\n", bundle
, buff
, mode
, cookie
);
4686 #endif /* LOG_BUNDLE_LOAD */
4687 if (cookie
&& cookie
== bundle
->_handleCookie
) {
4688 // 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
4690 printf("dlfcn load framework %p closing existing reference to handle %p\n", bundle
, cookie
);
4691 #endif /* LOG_BUNDLE_LOAD */
4692 dlclose(bundle
->_handleCookie
);
4694 bundle
->_handleCookie
= cookie
;
4695 if (bundle
->_handleCookie
) {
4696 bundle
->_isLoaded
= true;
4698 const char *errorString
= dlerror();
4700 _CFBundleDlfcnPreflight(bundle
, subError
);
4702 CFStringRef debugString
= errorString
? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
) : NULL
;
4703 localError
= _CFBundleCreateErrorDebug(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
, debugString
);
4704 if (debugString
) CFRelease(debugString
);
4707 CFStringRef executableString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, buff
);
4709 CFStringRef debugString
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, errorString
);
4710 CFLog(__kCFLogBundle
, CFSTR("Error loading %@: %@"), executableString
, debugString
);
4711 if (debugString
) CFRelease(debugString
);
4713 CFLog(__kCFLogBundle
, CFSTR("Error loading %@"), executableString
);
4715 if (executableString
) CFRelease(executableString
);
4720 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4722 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4725 if (executableURL
) CFRelease(executableURL
);
4727 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4728 return bundle
->_isLoaded
;
4731 __private_extern__
void _CFBundleDlfcnUnload(CFBundleRef bundle
) {
4732 if (bundle
->_isLoaded
) {
4734 printf("dlfcn unload bundle %p, handle %p module %p image %p\n", bundle
, bundle
->_handleCookie
, bundle
->_moduleCookie
, bundle
->_imageCookie
);
4735 #endif /* LOG_BUNDLE_LOAD */
4736 if (0 != dlclose(bundle
->_handleCookie
)) {
4737 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
4739 bundle
->_connectionCookie
= bundle
->_handleCookie
= NULL
;
4740 bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
4741 bundle
->_isLoaded
= false;
4746 __private_extern__
void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4747 return _CFBundleDlfcnGetSymbolByNameWithSearch(bundle
, symbolName
, false);
4750 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
4751 void *result
= NULL
;
4754 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingUTF8
)) {
4755 result
= dlsym(bundle
->_handleCookie
, buff
);
4756 if (!result
&& globalSearch
) result
= dlsym(RTLD_DEFAULT
, buff
);
4758 if (!result
) CFLog(__kCFLogBundle
, CFSTR("dlsym cannot find symbol %@ in %@"), symbolName
, bundle
);
4761 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
);
4762 #endif /* LOG_BUNDLE_LOAD */
4767 #if !defined(BINARY_SUPPORT_DYLD)
4769 static CFStringRef
_CFBundleDlfcnCopyLoadedImagePathForPointer(void *p
) {
4770 CFStringRef result
= NULL
;
4772 if (0 != dladdr(p
, &info
) && info
.dli_fname
) result
= CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault
, info
.dli_fname
);
4774 printf("dlfcn image path for pointer %p is %p\n", p
, result
);
4775 #endif /* LOG_BUNDLE_LOAD */
4779 #endif /* !BINARY_SUPPORT_DYLD */
4780 #endif /* BINARY_SUPPORT_DLFCN */
4782 #if defined(BINARY_SUPPORT_DLL)
4784 __private_extern__ Boolean
_CFBundleDLLLoad(CFBundleRef bundle
, CFErrorRef
*error
) {
4785 CFErrorRef localError
= NULL
;
4786 if (!bundle
->_isLoaded
) {
4787 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
4788 wchar_t buff
[CFMaxPathSize
];
4790 if (executableURL
&& _CFURLGetWideFileSystemRepresentation(executableURL
, true, (wchar_t *)buff
, CFMaxPathSize
)) {
4791 bundle
->_hModule
= LoadLibraryW(buff
);
4792 if (bundle
->_hModule
) {
4793 bundle
->_isLoaded
= true;
4796 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableLinkError
);
4798 CFLog(__kCFLogBundle
, CFSTR("Failed to load bundle %@"), bundle
);
4803 localError
= _CFBundleCreateError(CFGetAllocator(bundle
), bundle
, CFBundleExecutableNotFoundError
);
4805 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
4808 if (executableURL
) CFRelease(executableURL
);
4810 if (!bundle
->_isLoaded
&& error
) *error
= localError
;
4811 return bundle
->_isLoaded
;
4814 __private_extern__
void _CFBundleDLLUnload(CFBundleRef bundle
) {
4815 if (bundle
->_isLoaded
) {
4816 FreeLibrary(bundle
->_hModule
);
4817 bundle
->_hModule
= NULL
;
4818 bundle
->_isLoaded
= false;
4822 __private_extern__
void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
4823 void *result
= NULL
;
4825 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingWindowsLatin1
)) result
= GetProcAddress(bundle
->_hModule
, buff
);
4829 #endif /* BINARY_SUPPORT_DLL */
4831 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
4835 __private_extern__ CFStringRef
_CFBundleGetBundlePath(CFBundleRef bundle
){
4836 return bundle
->_bundleBasePath
;
4839 // caller need to release the table
4840 __private_extern__ CFDictionaryRef
_CFBundleCopyQueryTable(CFBundleRef bundle
, CFURLRef bundleURL
, CFArrayRef languages
, UniChar
*resDir
, CFIndex resDirLen
, UniChar
*subDirBuffer
, CFIndex subDirLen
)
4842 CFDictionaryRef subTable
= NULL
;
4843 CFIndex savedResDirLen
= resDirLen
;
4844 Boolean appendSucc
= true;
4846 if (subDirLen
> 0) {
4847 appendSucc
= _CFAppendPathComponent(resDir
, &resDirLen
, CFMaxPathSize
, subDirBuffer
, subDirLen
);
4851 CFStringRef argDirStr
= CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault
, resDir
, resDirLen
, CFMaxPathSize
, kCFAllocatorNull
);
4854 __CFSpinLock(&bundle
->_queryLock
);
4856 // check if the query table for the given sub dir has been created
4857 subTable
= (CFDictionaryRef
) CFDictionaryGetValue(bundle
->_queryTable
, argDirStr
);
4860 // create the query table for the given sub dir
4861 subTable
= _CFBundleCreateQueryTableAtPath(bundle
, bundleURL
, languages
, resDir
, savedResDirLen
, subDirBuffer
, subDirLen
);
4863 CFDictionarySetValue(bundle
->_queryTable
, argDirStr
, subTable
);
4867 __CFSpinUnlock(&bundle
->_queryLock
);
4869 subTable
= _CFBundleCreateQueryTableAtPath(NULL
, bundleURL
, languages
, resDir
, savedResDirLen
, subDirBuffer
, subDirLen
);
4871 CFRelease(argDirStr
);