]> git.saurik.com Git - apple/cf.git/blob - CFBundle.c
CF-635.tar.gz
[apple/cf.git] / CFBundle.c
1 /*
2 * Copyright (c) 2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFBundle.c
25 Copyright (c) 1999-2011, Apple Inc. All rights reserved.
26 Responsibility: David Smith
27 */
28
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>
35 #include <string.h>
36 #include <CoreFoundation/CFPriv.h>
37 #include "CFInternal.h"
38 #include <CoreFoundation/CFByteOrder.h>
39 #include "CFBundle_BinaryTypes.h"
40 #include <CoreFoundation/CFVersionCheck.h>
41 #include <ctype.h>
42 #include <sys/stat.h>
43 #include <stdlib.h>
44
45 #define AVOID_WEAK_COLLECTIONS 1
46
47 #if !defined(AVOID_WEAK_COLLECTIONS)
48 #include "CFHashTable.h"
49 #include "CFMapTable.h"
50 #include "CFPointerArray.h"
51 #endif /* !AVOID_WEAK_COLLECTIONS */
52
53 #if defined(BINARY_SUPPORT_DYLD)
54 // Import the mach-o headers that define the macho magic numbers
55 #include <mach-o/loader.h>
56 #include <mach-o/fat.h>
57 #include <mach-o/arch.h>
58 #include <mach-o/dyld.h>
59 #include <mach-o/getsect.h>
60 #include <unistd.h>
61 #include <fcntl.h>
62 #include <sys/mman.h>
63 #include <crt_externs.h>
64 #if defined(USE_DYLD_PRIV)
65 #include <mach-o/dyld_priv.h>
66 #endif /* USE_DYLD_PRIV */
67 #endif /* BINARY_SUPPORT_DYLD */
68
69 #if defined(BINARY_SUPPORT_DLFCN)
70 #include <dlfcn.h>
71 #endif /* BINARY_SUPPORT_DLFCN */
72
73 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
74 #include <fcntl.h>
75 #elif DEPLOYMENT_TARGET_WINDOWS
76 #include <fcntl.h>
77 #include <io.h>
78
79 #define open _NS_open
80 #define stat(x,y) _NS_stat(x,y)
81
82 #else
83 #error Unknown or unspecified DEPLOYMENT_TARGET
84 #endif
85
86 extern void _processInfoDictionary(CFMutableDictionaryRef dict, CFStringRef platformSuffix, CFStringRef productSuffix);
87 extern CFStringRef _CFGetProductName(void);
88 extern CFStringRef _CFGetPlatformName(void);
89 extern CFStringRef _CFGetAlternatePlatformName(void);
90
91 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked);
92
93 #define LOG_BUNDLE_LOAD 0
94
95 // Public CFBundle Info plist keys
96 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey, "CFBundleInfoDictionaryVersion")
97 CONST_STRING_DECL(kCFBundleExecutableKey, "CFBundleExecutable")
98 CONST_STRING_DECL(kCFBundleIdentifierKey, "CFBundleIdentifier")
99 CONST_STRING_DECL(kCFBundleVersionKey, "CFBundleVersion")
100 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey, "CFBundleDevelopmentRegion")
101 CONST_STRING_DECL(kCFBundleLocalizationsKey, "CFBundleLocalizations")
102
103 // Private CFBundle Info plist keys, possible candidates for public constants
104 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey, "CFBundleAllowMixedLocalizations")
105 CONST_STRING_DECL(_kCFBundleSupportedPlatformsKey, "CFBundleSupportedPlatforms")
106 CONST_STRING_DECL(_kCFBundleResourceSpecificationKey, "CFBundleResourceSpecification")
107
108 // Finder stuff
109 CONST_STRING_DECL(_kCFBundlePackageTypeKey, "CFBundlePackageType")
110 CONST_STRING_DECL(_kCFBundleSignatureKey, "CFBundleSignature")
111 CONST_STRING_DECL(_kCFBundleIconFileKey, "CFBundleIconFile")
112 CONST_STRING_DECL(_kCFBundleDocumentTypesKey, "CFBundleDocumentTypes")
113 CONST_STRING_DECL(_kCFBundleURLTypesKey, "CFBundleURLTypes")
114
115 // Keys that are usually localized in InfoPlist.strings
116 CONST_STRING_DECL(kCFBundleNameKey, "CFBundleName")
117 CONST_STRING_DECL(_kCFBundleDisplayNameKey, "CFBundleDisplayName")
118 CONST_STRING_DECL(_kCFBundleShortVersionStringKey, "CFBundleShortVersionString")
119 CONST_STRING_DECL(_kCFBundleGetInfoStringKey, "CFBundleGetInfoString")
120 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey, "CFBundleGetInfoHTML")
121
122 // Sub-keys for CFBundleDocumentTypes dictionaries
123 CONST_STRING_DECL(_kCFBundleTypeNameKey, "CFBundleTypeName")
124 CONST_STRING_DECL(_kCFBundleTypeRoleKey, "CFBundleTypeRole")
125 CONST_STRING_DECL(_kCFBundleTypeIconFileKey, "CFBundleTypeIconFile")
126 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey, "CFBundleTypeOSTypes")
127 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey, "CFBundleTypeExtensions")
128 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey, "CFBundleTypeMIMETypes")
129
130 // Sub-keys for CFBundleURLTypes dictionaries
131 CONST_STRING_DECL(_kCFBundleURLNameKey, "CFBundleURLName")
132 CONST_STRING_DECL(_kCFBundleURLIconFileKey, "CFBundleURLIconFile")
133 CONST_STRING_DECL(_kCFBundleURLSchemesKey, "CFBundleURLSchemes")
134
135 // Compatibility key names
136 CONST_STRING_DECL(_kCFBundleOldExecutableKey, "NSExecutable")
137 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey, "NSInfoPlistVersion")
138 CONST_STRING_DECL(_kCFBundleOldNameKey, "NSHumanReadableName")
139 CONST_STRING_DECL(_kCFBundleOldIconFileKey, "NSIcon")
140 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey, "NSTypes")
141 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey, "NSAppVersion")
142
143 // Compatibility CFBundleDocumentTypes key names
144 CONST_STRING_DECL(_kCFBundleOldTypeNameKey, "NSName")
145 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey, "NSRole")
146 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey, "NSIcon")
147 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key, "NSUnixExtensions")
148 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key, "NSDOSExtensions")
149 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey, "NSMacOSType")
150
151 // Internally used keys for loaded Info plists.
152 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey, "CFBundleInfoPlistURL")
153 CONST_STRING_DECL(_kCFBundleRawInfoPlistURLKey, "CFBundleRawInfoPlistURL")
154 CONST_STRING_DECL(_kCFBundleNumericVersionKey, "CFBundleNumericVersion")
155 CONST_STRING_DECL(_kCFBundleExecutablePathKey, "CFBundleExecutablePath")
156 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey, "CSResourcesFileMapped")
157 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey, "CFBundleCFMLoadAsBundle")
158
159 // Keys used by NSBundle for loaded Info plists.
160 CONST_STRING_DECL(_kCFBundleInitialPathKey, "NSBundleInitialPath")
161 CONST_STRING_DECL(_kCFBundleResolvedPathKey, "NSBundleResolvedPath")
162 CONST_STRING_DECL(_kCFBundlePrincipalClassKey, "NSPrincipalClass")
163
164 static char __CFBundleMainID__[1026] = {0};
165 __private_extern__ char *__CFBundleMainID = __CFBundleMainID__;
166
167 static CFTypeID __kCFBundleTypeID = _kCFRuntimeNotATypeID;
168
169 struct __CFBundle {
170 CFRuntimeBase _base;
171
172 CFURLRef _url;
173 CFDateRef _modDate;
174
175 __strong CFDictionaryRef _infoDict; // the ref stored in here must always be allocated with kCFAllocatorSystemDefaultGCRefZero
176 __strong CFDictionaryRef _localInfoDict; // the ref stored in here must always be allocated with kCFAllocatorSystemDefaultGCRefZero
177 CFArrayRef _searchLanguages;
178
179 __CFPBinaryType _binaryType;
180 Boolean _isLoaded;
181 uint8_t _version;
182 Boolean _sharesStringsFiles;
183 char _padding[1];
184
185 /* CFM goop */
186 void *_connectionCookie;
187
188 /* DYLD goop */
189 const void *_imageCookie;
190 const void *_moduleCookie;
191
192 /* dlfcn goop */
193 void *_handleCookie;
194
195 /* CFM<->DYLD glue */
196 CFMutableDictionaryRef _glueDict;
197
198 /* Resource fork goop */
199 _CFResourceData _resourceData;
200
201 _CFPlugInData _plugInData;
202
203 CFSpinLock_t _bundleLoadingLock;
204
205 #if defined(BINARY_SUPPORT_DLL)
206 HMODULE _hModule;
207 #endif /* BINARY_SUPPORT_DLL */
208
209 };
210
211 static CFSpinLock_t CFBundleGlobalDataLock = CFSpinLockInit;
212
213 static CFMutableDictionaryRef _bundlesByIdentifier = NULL;
214 #if defined(AVOID_WEAK_COLLECTIONS)
215 static CFMutableDictionaryRef _bundlesByURL = NULL;
216 static CFMutableArrayRef _allBundles = NULL;
217 static CFMutableSetRef _bundlesToUnload = NULL;
218 #else /* AVOID_WEAK_COLLECTIONS */
219 static __CFHashTable *_allBundles = nil;
220 static __CFHashTable *_bundlesToUnload = nil;
221 #endif /* AVOID_WEAK_COLLECTIONS */
222 static Boolean _scheduledBundlesAreUnloading = false;
223
224 static Boolean _initedMainBundle = false;
225 static CFBundleRef _mainBundle = NULL;
226 static CFStringRef _defaultLocalization = NULL;
227
228 // Forward declares functions.
229 static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing);
230 static CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict);
231 static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle);
232 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint);
233 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
234 static void _CFBundleCheckWorkarounds(CFBundleRef bundle);
235 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath);
236 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths);
237 #if defined(BINARY_SUPPORT_DYLD)
238 static CFMutableDictionaryRef _CFBundleGrokInfoDictFromMainExecutable(void);
239 static Boolean _CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion, uint32_t *objcFlags);
240 static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p);
241 #if !defined(BINARY_SUPPORT_DLFCN)
242 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch);
243 #endif /* !BINARY_SUPPORT_DLFCN */
244 #endif /* BINARY_SUPPORT_DYLD */
245 #if defined(BINARY_SUPPORT_DLFCN)
246 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch);
247 #if !defined(BINARY_SUPPORT_DYLD)
248 static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p);
249 #endif /* !BINARY_SUPPORT_DYLD */
250 #endif /* BINARY_SUPPORT_DLFCN */
251
252
253 #if defined(AVOID_WEAK_COLLECTIONS)
254
255 static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) {
256 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
257
258 if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock);
259
260 // Add to the _allBundles list
261 if (!_allBundles) {
262 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
263 nonRetainingArrayCallbacks.retain = NULL;
264 nonRetainingArrayCallbacks.release = NULL;
265 _allBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks);
266 }
267 CFArrayAppendValue(_allBundles, bundle);
268
269 // Add to the table that maps urls to bundles
270 if (!_bundlesByURL) {
271 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
272 nonRetainingDictionaryValueCallbacks.retain = NULL;
273 nonRetainingDictionaryValueCallbacks.release = NULL;
274 _bundlesByURL = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
275 }
276 CFDictionarySetValue(_bundlesByURL, bundle->_url, bundle);
277
278 // Add to the table that maps identifiers to bundles
279 if (bundleID) {
280 CFMutableArrayRef bundlesWithThisID = NULL;
281 CFBundleRef existingBundle = NULL;
282 if (!_bundlesByIdentifier) {
283 _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
284 }
285 bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
286 if (bundlesWithThisID) {
287 CFIndex i, count = CFArrayGetCount(bundlesWithThisID);
288 UInt32 existingVersion, newVersion = CFBundleGetVersionNumber(bundle);
289 for (i = 0; i < count; i++) {
290 existingBundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i);
291 existingVersion = CFBundleGetVersionNumber(existingBundle);
292 // If you load two bundles with the same identifier and the same version, the last one wins.
293 if (newVersion >= existingVersion) break;
294 }
295 CFArrayInsertValueAtIndex(bundlesWithThisID, i, bundle);
296 } else {
297 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
298 nonRetainingArrayCallbacks.retain = NULL;
299 nonRetainingArrayCallbacks.release = NULL;
300 bundlesWithThisID = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks);
301 CFArrayAppendValue(bundlesWithThisID, bundle);
302 CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundlesWithThisID);
303 CFRelease(bundlesWithThisID);
304 }
305 }
306 if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock);
307 }
308
309 static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) {
310 __CFSpinLock(&CFBundleGlobalDataLock);
311 // Remove from the various lists
312 if (_allBundles) {
313 CFIndex i = CFArrayGetFirstIndexOfValue(_allBundles, CFRangeMake(0, CFArrayGetCount(_allBundles)), bundle);
314 if (i >= 0) CFArrayRemoveValueAtIndex(_allBundles, i);
315 }
316
317 // Remove from the table that maps urls to bundles
318 if (bundleURL && _bundlesByURL) {
319 CFBundleRef bundleForURL = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, bundleURL);
320 if (bundleForURL == bundle) CFDictionaryRemoveValue(_bundlesByURL, bundleURL);
321 }
322
323 // Remove from the table that maps identifiers to bundles
324 if (bundleID && _bundlesByIdentifier) {
325 CFMutableArrayRef bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
326 if (bundlesWithThisID) {
327 CFIndex count = CFArrayGetCount(bundlesWithThisID);
328 while (count-- > 0) if (bundle == (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, count)) CFArrayRemoveValueAtIndex(bundlesWithThisID, count);
329 if (0 == CFArrayGetCount(bundlesWithThisID)) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID);
330 }
331 }
332 __CFSpinUnlock(&CFBundleGlobalDataLock);
333 }
334
335 static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) {
336 CFBundleRef result = NULL;
337 if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock);
338 if (_bundlesByURL) result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url);
339 if (result && !result->_url) {
340 result = NULL;
341 CFDictionaryRemoveValue(_bundlesByURL, url);
342 }
343 if (result) CFRetain(result);
344 if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock);
345 return result;
346 }
347
348 static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID) {
349 CFBundleRef result = NULL, bundle;
350 if (_bundlesByIdentifier && bundleID) {
351 // Note that this array is maintained in descending order by version number
352 CFArrayRef bundlesWithThisID = (CFArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
353 if (bundlesWithThisID) {
354 CFIndex i, count = CFArrayGetCount(bundlesWithThisID);
355 if (count > 0) {
356 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
357 for (i = 0; !result && i < count; i++) {
358 bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i);
359 if (CFBundleIsExecutableLoaded(bundle)) result = bundle;
360 }
361 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
362 if (!result) result = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, 0);
363 }
364 }
365 }
366 return result;
367 }
368
369 #else /* AVOID_WEAK_COLLECTIONS */
370
371 /*
372 An explanation of what I'm doing here is probably in order.
373 8029300 has cast suspicion on the correctness of __CFMapTable with strong keys and weak values, at least under non-GC.
374 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
375 This indicates that it's not an overrelease in securityd, since AVOID_WEAK_COLLECTIONS wouldn't help in that case.
376 Therefore, these functions following this comment allow us to have _bundlesByURL be a CFDictionary on non-GC and keep __CFMapTable to GC where it's needed.
377 */
378 static inline id _getBundlesByURL() {
379 static id _bundles = nil;
380 static dispatch_once_t onceToken;
381 dispatch_once(&onceToken, ^{
382 if (CF_USING_COLLECTABLE_MEMORY) {
383 _bundles = [[__CFMapTable alloc] initWithKeyOptions:CFPointerFunctionsStrongMemory valueOptions:CFPointerFunctionsZeroingWeakMemory capacity:0];
384 } else {
385 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
386 nonRetainingDictionaryValueCallbacks.retain = NULL;
387 nonRetainingDictionaryValueCallbacks.release = NULL;
388 _bundles = (id)CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
389 }
390 });
391 return _bundles;
392 }
393
394 #define _bundlesByURL _getBundlesByURL()
395
396 static void _setInBundlesByURL(CFURLRef key, CFBundleRef bundle) {
397 if (CF_USING_COLLECTABLE_MEMORY) {
398 [(__CFMapTable *)_bundlesByURL setObject:(id)bundle forKey:(id)key];
399 } else {
400 CFDictionarySetValue((CFMutableDictionaryRef)_bundlesByURL, key, bundle);
401 }
402 }
403
404 static void _removeFromBundlesByURL(CFURLRef key) {
405 if (CF_USING_COLLECTABLE_MEMORY) {
406 [(__CFMapTable *)_bundlesByURL removeObjectForKey:(id)key];
407 } else {
408 CFDictionaryRemoveValue((CFMutableDictionaryRef)_bundlesByURL, key);
409 }
410 }
411
412 static CFBundleRef _getFromBundlesByURL(CFURLRef key) {
413 if (CF_USING_COLLECTABLE_MEMORY) {
414 return (CFBundleRef)[(__CFMapTable *)_bundlesByURL objectForKey:(id)key];
415 } else {
416 return (CFBundleRef)CFDictionaryGetValue((CFMutableDictionaryRef)_bundlesByURL, key);
417 }
418 }
419
420 static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) {
421 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
422
423 if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock);
424
425 // Add to the _allBundles list
426 if (!_allBundles) _allBundles = [[__CFHashTable alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory capacity:0];
427 [_allBundles addObject:(id)bundle];
428
429 // Add to the table that maps urls to bundles
430 _setInBundlesByURL(bundle->_url, bundle);
431
432 // Add to the table that maps identifiers to bundles
433 if (bundleID) {
434 __CFPointerArray *bundlesWithThisID = nil;
435 CFBundleRef existingBundle = NULL;
436 if (!_bundlesByIdentifier) {
437 _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
438 }
439 bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
440 if (bundlesWithThisID) {
441 CFIndex i, count = (CFIndex)[bundlesWithThisID count];
442 UInt32 existingVersion, newVersion = CFBundleGetVersionNumber(bundle);
443 for (i = 0; i < count; i++) {
444 existingBundle = (CFBundleRef)[bundlesWithThisID pointerAtIndex:i];
445 if (!existingBundle) continue;
446 existingVersion = CFBundleGetVersionNumber(existingBundle);
447 // If you load two bundles with the same identifier and the same version, the last one wins.
448 if (newVersion >= existingVersion) break;
449 }
450 if (i < count) {
451 [bundlesWithThisID insertPointer:bundle atIndex:i];
452 } else {
453 [bundlesWithThisID addPointer:bundle];
454 }
455 } else {
456 bundlesWithThisID = [[__CFPointerArray alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory];
457 [bundlesWithThisID addPointer:bundle];
458 CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundlesWithThisID);
459 [bundlesWithThisID release];
460 }
461 }
462 if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock);
463 }
464
465 static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) {
466 __CFSpinLock(&CFBundleGlobalDataLock);
467 // Remove from the various lists
468 if (_allBundles && [_allBundles member:(id)bundle]) [_allBundles removeObject:(id)bundle];
469
470 // Remove from the table that maps urls to bundles
471 if (bundleURL) {
472 _removeFromBundlesByURL(bundleURL);
473 }
474
475 // Remove from the table that maps identifiers to bundles
476 if (bundleID && _bundlesByIdentifier) {
477 __CFPointerArray *bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
478 if (bundlesWithThisID) {
479 CFIndex count = (CFIndex)[bundlesWithThisID count];
480 while (count-- > 0) if (bundle == (CFBundleRef)[bundlesWithThisID pointerAtIndex:count]) [bundlesWithThisID removePointerAtIndex:count];
481 [bundlesWithThisID compact];
482 if (0 == [bundlesWithThisID count]) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID);
483 }
484 }
485 __CFSpinUnlock(&CFBundleGlobalDataLock);
486 }
487
488 static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) {
489 CFBundleRef result = NULL;
490 if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock);
491 result = _getFromBundlesByURL(url);
492 if (result && !result->_url) {
493 result = NULL;
494 _removeFromBundlesByURL(url);
495 }
496 if (result) CFRetain(result);
497 if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock);
498 return result;
499 }
500
501 static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID) {
502 CFBundleRef result = NULL;
503 if (_bundlesByIdentifier && bundleID) {
504 // Note that this array is maintained in descending order by version number
505 __CFPointerArray *bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
506 if (bundlesWithThisID && [bundlesWithThisID count] > 0) {
507 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle
508 for (id bundle in bundlesWithThisID) {
509 if (bundle && CFBundleIsExecutableLoaded((CFBundleRef)bundle)) {
510 result = (CFBundleRef)bundle;
511 break;
512 }
513 }
514 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number
515 if (!result) {
516 for (id bundle in bundlesWithThisID) {
517 if (bundle) {
518 result = (CFBundleRef)bundle;
519 break;
520 }
521 }
522 }
523 }
524 }
525 return result;
526 }
527
528 #endif /* AVOID_WEAK_COLLECTIONS */
529
530 #if 0 && DEPLOYMENT_TARGET_WINDOWS
531 static CFStringRef _CFBundleCopyWrapperInBinaryDirectory(CFStringRef strippedExeName) {
532 char buff[CFMaxPathSize];
533 CFIndex buffLen;
534 int i;
535
536 CFArrayRef binaryDirs = _CFGetWindowsBinaryDirectories();
537 int count = CFArrayGetCount(binaryDirs);
538 CFStringRef str;
539 struct stat garbage;
540 for (i = 0; i < count; i++) {
541 str = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@\\%@.app"), CFArrayGetValueAtIndex(binaryDirs,i), strippedExeName);
542 buffLen = CFStringGetLength(str);
543 CFStringGetFileSystemRepresentation(str, buff, CFMaxPathSize);
544 if (stat(buff, &garbage) == 0) return str;
545 CFRelease(str);
546 }
547 return NULL;
548 }
549 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
550 #else
551 #error Unknown or unspecified DEPLOYMENT_TARGET
552 #endif
553
554 static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) {
555 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
556 UniChar buff[CFMaxPathSize];
557 CFIndex buffLen;
558 CFURLRef url = NULL;
559 CFStringRef outstr;
560
561 buffLen = CFStringGetLength(str);
562 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
563 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
564
565 #if 0 && DEPLOYMENT_TARGET_WINDOWS
566 CFIndex startOfBinaryName = _CFLengthAfterDeletingLastPathComponent(buff, buffLen) + 1; // Remove exe name
567 CFIndex endOfBinaryName = _CFLengthAfterDeletingPathExtension(buff, buffLen);
568 if (startOfBinaryName > 0 && startOfBinaryName < buffLen && endOfBinaryName > 0 && endOfBinaryName <= buffLen) {
569 CFStringRef strippedExeName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfBinaryName]), endOfBinaryName - startOfBinaryName);
570 CFStringRef wrapperInBinaryDirectory = _CFBundleCopyWrapperInBinaryDirectory(strippedExeName);
571 if (wrapperInBinaryDirectory) {
572 buffLen = CFStringGetLength(wrapperInBinaryDirectory);
573 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
574 CFStringGetCharacters(wrapperInBinaryDirectory, CFRangeMake(0, buffLen), buff);
575 CFRelease(wrapperInBinaryDirectory);
576 outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull);
577 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true);
578 CFRelease(outstr);
579 return url;
580 }
581 }
582 #elif DEPLOYMENT_TARGET_WINDOWS
583 // Is this a .dll or .exe?
584 if (buffLen >= 5 && (_wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".exe", 4) == 0)) {
585 CFIndex extensionLength = CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension);
586 buffLen -= 4;
587 // If this is an _debug, we should strip that before looking for the bundle
588 if (buffLen >= 7 && (_wcsnicmp((wchar_t *)&buff[buffLen-6], L"_debug", 6) == 0)) buffLen -= 6;
589
590 if (buffLen + 1 + extensionLength < CFMaxPathSize) {
591 buff[buffLen] = '.';
592 buffLen ++;
593 CFStringGetCharacters(_CFBundleWindowsResourceDirectoryExtension, CFRangeMake(0, extensionLength), buff + buffLen);
594 buffLen += extensionLength;
595 outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull);
596 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true);
597 CFRelease(outstr);
598 }
599 }
600 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
601 #else
602 #error Unknown or unspecified DEPLOYMENT_TARGET
603 #endif
604
605 if (!url) {
606 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); // Remove exe name
607
608 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
609 if (buffLen > 0) {
610 // See if this is a new bundle. If it is, we have to remove more path components.
611 CFIndex startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen);
612 if (startOfLastDir > 0 && startOfLastDir < buffLen) {
613 CFStringRef lastDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir);
614
615 if (CFEqual(lastDirName, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
616 // This is a new bundle. Back off a few more levels
617 if (buffLen > 0) {
618 // Remove platform folder
619 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
620 }
621 if (buffLen > 0) {
622 // Remove executables folder (if present)
623 CFIndex startOfNextDir = _CFStartOfLastPathComponent(buff, buffLen);
624 if (startOfNextDir > 0 && startOfNextDir < buffLen) {
625 CFStringRef nextDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfNextDir]), buffLen - startOfNextDir);
626 if (CFEqual(nextDirName, _CFBundleExecutablesDirectoryName)) buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
627 CFRelease(nextDirName);
628 }
629 }
630 if (buffLen > 0) {
631 // Remove support files folder
632 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
633 #elif 0 && DEPLOYMENT_TARGET_WINDOWS
634 if (buffLen > 0) {
635 // See if this is a new bundle. If it is, we have to remove more path components.
636 CFIndex startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen);
637 if (startOfLastDir > 0 && startOfLastDir < buffLen) {
638 CFStringRef lastDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir);
639
640 if (CFEqual(lastDirName, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
641 // This is a new bundle. Back off a few more levels
642 if (buffLen > 0) {
643 // Remove platform folder
644 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
645 }
646 if (buffLen > 0) {
647 // Remove executables folder (if present)
648 CFIndex startOfNextDir = _CFStartOfLastPathComponent(buff, buffLen);
649 if (startOfNextDir > 0 && startOfNextDir < buffLen) {
650 CFStringRef nextDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfNextDir]), buffLen - startOfNextDir);
651 if (CFEqual(nextDirName, _CFBundleExecutablesDirectoryName)) buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
652 CFRelease(nextDirName);
653 #else
654 #error Unknown or unspecified DEPLOYMENT_TARGET
655 #endif
656 }
657 }
658 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS
659 CFRelease(lastDirName);
660 }
661 }
662 #elif 0 && DEPLOYMENT_TARGET_WINDOWS
663 if (buffLen > 0) {
664 // Remove support files folder
665 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
666 }
667 }
668 CFRelease(lastDirName);
669 }
670 }
671 #else
672 #error Unknown or unspecified DEPLOYMENT_TARGET
673 #endif
674
675 if (buffLen > 0) {
676 outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull);
677 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true);
678 CFRelease(outstr);
679 }
680 }
681 return url;
682 }
683
684 static CFURLRef _CFBundleCopyResolvedURLForExecutableURL(CFURLRef url) {
685 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
686 CFURLRef absoluteURL, url1, url2, outURL = NULL;
687 CFStringRef str, str1, str2;
688 absoluteURL = CFURLCopyAbsoluteURL(url);
689 str = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
690 if (str) {
691 UniChar buff[CFMaxPathSize];
692 CFIndex buffLen = CFStringGetLength(str), len1;
693 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
694 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
695 len1 = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
696 if (len1 > 0 && len1 + 1 < buffLen) {
697 str1 = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buff, len1);
698 CFIndex skipSlashCount = 1;
699 #if DEPLOYMENT_TARGET_WINDOWS
700 // 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
701 if (len1 == 3 && buff[1] == ':' && buff[2] == '\\') {
702 skipSlashCount = 0;
703 }
704 #endif
705 str2 = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buff + len1 + skipSlashCount, buffLen - len1 - skipSlashCount);
706 if (str1 && str2) {
707 url1 = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str1, PLATFORM_PATH_STYLE, true);
708 if (url1) {
709 url2 = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, str2, PLATFORM_PATH_STYLE, false, url1);
710 if (url2) {
711 outURL = CFURLCopyAbsoluteURL(url2);
712 CFRelease(url2);
713 }
714 CFRelease(url1);
715 }
716 }
717 if (str1) CFRelease(str1);
718 if (str2) CFRelease(str2);
719 }
720 CFRelease(str);
721 }
722 if (!outURL) {
723 outURL = absoluteURL;
724 } else {
725 CFRelease(absoluteURL);
726 }
727 return outURL;
728 }
729
730 CFURLRef _CFBundleCopyBundleURLForExecutableURL(CFURLRef url) {
731 CFURLRef resolvedURL, outurl = NULL;
732 CFStringRef str;
733 resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url);
734 str = CFURLCopyFileSystemPath(resolvedURL, PLATFORM_PATH_STYLE);
735 if (str) {
736 outurl = _CFBundleCopyBundleURLForExecutablePath(str);
737 CFRelease(str);
738 }
739 CFRelease(resolvedURL);
740 return outurl;
741 }
742
743 static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle) {
744 uint8_t localVersion = bundle->_version;
745 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives
746 if (0 == localVersion) {
747 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
748 if (!infoDict || 0 == CFDictionaryGetCount(infoDict)) {
749 #if defined(BINARY_SUPPORT_DYLD)
750 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
751 if (executableURL) {
752 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
753 if (bundle->_binaryType == __CFBundleCFMBinary || bundle->_binaryType == __CFBundleUnreadableBinary) {
754 localVersion = 4;
755 } else {
756 bundle->_resourceData._executableLacksResourceFork = true;
757 }
758 CFRelease(executableURL);
759 } else {
760 localVersion = 4;
761 }
762 #else
763 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
764 if (executableURL) {
765 CFRelease(executableURL);
766 } else {
767 localVersion = 4;
768 }
769 #endif /* BINARY_SUPPORT_DYLD */
770 }
771 }
772 return localVersion;
773 }
774
775 CFBundleRef _CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) {
776 CFBundleRef bundle = CFBundleCreate(allocator, url);
777 if (bundle) {
778 uint8_t localVersion = _CFBundleEffectiveLayoutVersion(bundle);
779 if (3 == localVersion || 4 == localVersion) {
780 CFRelease(bundle);
781 bundle = NULL;
782 }
783 }
784 return bundle;
785 }
786
787 CFBundleRef _CFBundleGetMainBundleIfLooksLikeBundle(void) {
788 CFBundleRef mainBundle = CFBundleGetMainBundle();
789 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL;
790 return mainBundle;
791 }
792
793 Boolean _CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) {
794 CFBundleRef mainBundle = CFBundleGetMainBundle();
795 return (mainBundle && mainBundle->_resourceData._infoDictionaryFromResourceFork);
796 }
797
798 CFBundleRef _CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) {
799 CFBundleRef bundle = NULL;
800 CFURLRef bundleURL = _CFBundleCopyBundleURLForExecutableURL(url), resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url);
801 if (bundleURL && resolvedURL) {
802 bundle = _CFBundleCreateIfLooksLikeBundle(allocator, bundleURL);
803 if (bundle) {
804 CFURLRef executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle);
805 char buff1[CFMaxPathSize], buff2[CFMaxPathSize];
806 if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, (uint8_t *)buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) {
807 CFRelease(bundle);
808 bundle = NULL;
809 }
810 if (executableURL) CFRelease(executableURL);
811 }
812 }
813 if (bundleURL) CFRelease(bundleURL);
814 if (resolvedURL) CFRelease(resolvedURL);
815 return bundle;
816 }
817
818 CFBundleRef _CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator, CFURLRef url) {
819 CFBundleRef bundle = CFBundleCreate(allocator, url);
820 if (bundle) {
821 Boolean mightBeBundle = true, isDir = false;
822 uint8_t localVersion = _CFBundleEffectiveLayoutVersion(bundle);
823 if (3 == localVersion) {
824 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
825 CFURLRef executableURL, supportFilesURL, resourceSpecificationFileURL;
826 CFArrayRef supportedPlatforms;
827 CFStringRef resourceSpecificationFile;
828
829 mightBeBundle = false;
830 if (infoDict && CFDictionaryGetValue(infoDict, kCFBundleExecutableKey) && (executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle))) {
831 supportedPlatforms = _CFBundleGetSupportedPlatforms(bundle);
832 resourceSpecificationFile = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey);
833 if (supportedPlatforms && CFArrayGetCount(supportedPlatforms) > 0 && CFArrayGetFirstIndexOfValue(supportedPlatforms, CFRangeMake(0, CFArrayGetCount(supportedPlatforms)), CFSTR("iPhoneOS")) >= 0) {
834 mightBeBundle = true;
835 } else if (resourceSpecificationFile && CFGetTypeID(resourceSpecificationFile) == CFStringGetTypeID() && (supportFilesURL = CFBundleCopySupportFilesDirectoryURL(bundle))) {
836 resourceSpecificationFileURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, resourceSpecificationFile, kCFURLPOSIXPathStyle, false, supportFilesURL);
837 if (resourceSpecificationFileURL) {
838 if (_CFIsResourceAtURL(resourceSpecificationFileURL, &isDir) && !isDir) mightBeBundle = true;
839 CFRelease(resourceSpecificationFileURL);
840 }
841 CFRelease(supportFilesURL);
842 }
843 CFRelease(executableURL);
844 }
845 } else if (4 == localVersion) {
846 mightBeBundle = false;
847 }
848 if (!mightBeBundle) {
849 CFRelease(bundle);
850 bundle = NULL;
851 }
852 }
853 return bundle;
854 }
855
856 CFBundleRef _CFBundleCreateWithExecutableURLIfMightBeBundle(CFAllocatorRef allocator, CFURLRef url) {
857 CFBundleRef bundle = NULL;
858 CFURLRef bundleURL = _CFBundleCopyBundleURLForExecutableURL(url), resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url);
859 if (bundleURL && resolvedURL) {
860 bundle = _CFBundleCreateIfMightBeBundle(allocator, bundleURL);
861 if (bundle) {
862 CFURLRef executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle);
863 char buff1[CFMaxPathSize], buff2[CFMaxPathSize];
864 if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, (uint8_t *)buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) {
865 CFRelease(bundle);
866 bundle = NULL;
867 }
868 if (executableURL) CFRelease(executableURL);
869 }
870 }
871 if (bundleURL) CFRelease(bundleURL);
872 if (resolvedURL) CFRelease(resolvedURL);
873 return bundle;
874 }
875
876 CFURLRef _CFBundleCopyMainBundleExecutableURL(Boolean *looksLikeBundle) {
877 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
878 const char *processPath;
879 CFStringRef str = NULL;
880 CFURLRef executableURL = NULL;
881 processPath = _CFProcessPath();
882 if (processPath) {
883 str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, processPath);
884 if (str) {
885 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false);
886 CFRelease(str);
887 }
888 }
889 if (looksLikeBundle) {
890 CFBundleRef mainBundle = _mainBundle;
891 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL;
892 *looksLikeBundle = (mainBundle ? true : false);
893 }
894 return executableURL;
895 }
896
897 static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef executablePath) {
898 CFBundleGetInfoDictionary(_mainBundle);
899 if (!_mainBundle->_infoDict || CFDictionaryGetCount(_mainBundle->_infoDict) == 0) {
900 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
901 if (_mainBundle->_version == 3) _mainBundle->_version = 4;
902 if (_mainBundle->_version == 0) {
903 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
904 CFStringRef executableName = _CFBundleCopyExecutableName(_mainBundle, NULL, NULL);
905 if (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName)) _mainBundle->_version = 4;
906 if (executableName) CFRelease(executableName);
907 }
908 #if defined(BINARY_SUPPORT_DYLD)
909 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) {
910 if (_mainBundle->_infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(_mainBundle->_infoDict);
911 _mainBundle->_infoDict = (CFDictionaryRef)_CFBundleGrokInfoDictFromMainExecutable();
912 }
913 #endif /* BINARY_SUPPORT_DYLD */
914 } else {
915 #if defined(BINARY_SUPPORT_DYLD)
916 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) {
917 // if dyld and not main executable for bundle, prefer info dictionary from executable
918 CFStringRef executableName = _CFBundleCopyExecutableName(_mainBundle, NULL, NULL);
919 if (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName)) {
920 CFDictionaryRef infoDictFromExecutable = (CFDictionaryRef)_CFBundleGrokInfoDictFromMainExecutable();
921 if (infoDictFromExecutable && CFDictionaryGetCount(infoDictFromExecutable) > 0) {
922 if (_mainBundle->_infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(_mainBundle->_infoDict);
923 _mainBundle->_infoDict = infoDictFromExecutable;
924 }
925 }
926 if (executableName) CFRelease(executableName);
927 }
928 #endif /* BINARY_SUPPORT_DYLD */
929 }
930 if (!_mainBundle->_infoDict) _mainBundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
931 if (!CFDictionaryGetValue(_mainBundle->_infoDict, _kCFBundleExecutablePathKey)) CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), _kCFBundleExecutablePathKey, executablePath);
932 CFStringRef bundleID = (CFStringRef)CFDictionaryGetValue(_mainBundle->_infoDict, kCFBundleIdentifierKey);
933 if (bundleID) {
934 if (!CFStringGetCString(bundleID, __CFBundleMainID__, sizeof(__CFBundleMainID__) - 2, kCFStringEncodingUTF8)) {
935 __CFBundleMainID__[0] = '\0';
936 }
937 }
938 }
939
940 static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked) {
941 CFDictionaryRef oldInfoDict = bundle->_infoDict;
942 CFTypeRef val;
943
944 _CFBundleFlushCachesForURL(bundle->_url);
945 bundle->_infoDict = NULL;
946 if (bundle->_localInfoDict) {
947 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(bundle->_localInfoDict);
948 bundle->_localInfoDict = NULL;
949 }
950 if (bundle->_searchLanguages) {
951 CFRelease(bundle->_searchLanguages);
952 bundle->_searchLanguages = NULL;
953 }
954 if (bundle->_resourceData._stringTableCache) {
955 CFRelease(bundle->_resourceData._stringTableCache);
956 bundle->_resourceData._stringTableCache = NULL;
957 }
958 if (bundle == _mainBundle) {
959 CFStringRef executablePath = oldInfoDict ? (CFStringRef)CFDictionaryGetValue(oldInfoDict, _kCFBundleExecutablePathKey) : NULL;
960 if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock);
961 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath);
962 if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock);
963 } else {
964 CFBundleGetInfoDictionary(bundle);
965 }
966 if (oldInfoDict) {
967 if (!bundle->_infoDict) bundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
968 val = CFDictionaryGetValue(oldInfoDict, _kCFBundleInitialPathKey);
969 if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundleInitialPathKey, val);
970 val = CFDictionaryGetValue(oldInfoDict, _kCFBundleResolvedPathKey);
971 if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundleResolvedPathKey, val);
972 val = CFDictionaryGetValue(oldInfoDict, _kCFBundlePrincipalClassKey);
973 if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundlePrincipalClassKey, val);
974 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(oldInfoDict);
975 }
976 }
977
978 CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle) {
979 _CFBundleFlushBundleCachesAlreadyLocked(bundle, false);
980 }
981
982 static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) {
983 if (!_initedMainBundle) {
984 const char *processPath;
985 CFStringRef str = NULL;
986 CFURLRef executableURL = NULL, bundleURL = NULL;
987 _initedMainBundle = true;
988 processPath = _CFProcessPath();
989 if (processPath) {
990 str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, processPath);
991 if (!executableURL) executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false);
992 }
993 if (executableURL) bundleURL = _CFBundleCopyBundleURLForExecutableURL(executableURL);
994 if (bundleURL) {
995 // make sure that main bundle has executable path
996 //??? what if we are not the main executable in the bundle?
997 // NB doFinalProcessing must be false here, see below
998 _mainBundle = _CFBundleCreate(kCFAllocatorSystemDefault, bundleURL, true, false);
999 if (_mainBundle) {
1000 // make sure that the main bundle is listed as loaded, and mark it as executable
1001 _mainBundle->_isLoaded = true;
1002 #if defined(BINARY_SUPPORT_DYLD)
1003 if (_mainBundle->_binaryType == __CFBundleUnknownBinary) {
1004 if (!executableURL) {
1005 _mainBundle->_binaryType = __CFBundleNoBinary;
1006 } else {
1007 _mainBundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
1008 if (_mainBundle->_binaryType != __CFBundleCFMBinary && _mainBundle->_binaryType != __CFBundleUnreadableBinary) _mainBundle->_resourceData._executableLacksResourceFork = true;
1009 }
1010 }
1011 #endif /* BINARY_SUPPORT_DYLD */
1012 // get cookie for already-loaded main bundle
1013 #if defined(BINARY_SUPPORT_DLFCN)
1014 if (!_mainBundle->_handleCookie) {
1015 _mainBundle->_handleCookie = dlopen(NULL, RTLD_NOLOAD | RTLD_FIRST);
1016 #if LOG_BUNDLE_LOAD
1017 printf("main bundle %p getting handle %p\n", _mainBundle, _mainBundle->_handleCookie);
1018 #endif /* LOG_BUNDLE_LOAD */
1019 }
1020 #elif defined(BINARY_SUPPORT_DYLD)
1021 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary && !_mainBundle->_imageCookie) {
1022 _mainBundle->_imageCookie = (void *)_dyld_get_image_header(0);
1023 #if LOG_BUNDLE_LOAD
1024 printf("main bundle %p getting image %p\n", _mainBundle, _mainBundle->_imageCookie);
1025 #endif /* LOG_BUNDLE_LOAD */
1026 }
1027 #endif /* BINARY_SUPPORT_DLFCN */
1028 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str);
1029 // Perform delayed final processing steps.
1030 // This must be done after _isLoaded has been set, for security reasons (3624341).
1031 _CFBundleCheckWorkarounds(_mainBundle);
1032 if (_CFBundleNeedsInitPlugIn(_mainBundle)) {
1033 __CFSpinUnlock(&CFBundleGlobalDataLock);
1034 _CFBundleInitPlugIn(_mainBundle);
1035 __CFSpinLock(&CFBundleGlobalDataLock);
1036 }
1037 }
1038 }
1039 if (bundleURL) CFRelease(bundleURL);
1040 if (str) CFRelease(str);
1041 if (executableURL) CFRelease(executableURL);
1042 }
1043 return _mainBundle;
1044 }
1045
1046 CFBundleRef CFBundleGetMainBundle(void) {
1047 CFBundleRef mainBundle;
1048 __CFSpinLock(&CFBundleGlobalDataLock);
1049 mainBundle = _CFBundleGetMainBundleAlreadyLocked();
1050 __CFSpinUnlock(&CFBundleGlobalDataLock);
1051 return mainBundle;
1052 }
1053
1054 CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) {
1055 CFBundleRef result = NULL;
1056 if (bundleID) {
1057 __CFSpinLock(&CFBundleGlobalDataLock);
1058 (void)_CFBundleGetMainBundleAlreadyLocked();
1059 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID);
1060 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1061 if (!result) {
1062 // Try to create the bundle for the caller and try again
1063 void *p = __builtin_return_address(0);
1064 if (p) {
1065 CFStringRef imagePath = NULL;
1066 #if defined(BINARY_SUPPORT_DYLD)
1067 if (!imagePath) imagePath = _CFBundleDYLDCopyLoadedImagePathForPointer(p);
1068 #elif defined(BINARY_SUPPORT_DLFCN)
1069 if (!imagePath) imagePath = _CFBundleDlfcnCopyLoadedImagePathForPointer(p);
1070 #endif /* BINARY_SUPPORT_DYLD */
1071 if (imagePath) {
1072 _CFBundleEnsureBundleExistsForImagePath(imagePath);
1073 CFRelease(imagePath);
1074 }
1075 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID);
1076 }
1077 }
1078 #elif DEPLOYMENT_TARGET_WINDOWS
1079 #else
1080 #error Unknown or unspecified DEPLOYMENT_TARGET
1081 #endif
1082 if (!result) {
1083 // Try to guess the bundle from the identifier and try again
1084 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID);
1085 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID);
1086 }
1087 if (!result) {
1088 // Make sure all bundles have been created and try again.
1089 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
1090 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID);
1091 }
1092 __CFSpinUnlock(&CFBundleGlobalDataLock);
1093 }
1094 return result;
1095 }
1096
1097 static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) {
1098 char buff[CFMaxPathSize];
1099 CFStringRef path = NULL, binaryType = NULL, retval = NULL;
1100 if (((CFBundleRef)cf)->_url && CFURLGetFileSystemRepresentation(((CFBundleRef)cf)->_url, true, (uint8_t *)buff, CFMaxPathSize)) path = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff);
1101 switch (((CFBundleRef)cf)->_binaryType) {
1102 case __CFBundleCFMBinary:
1103 binaryType = CFSTR("");
1104 break;
1105 case __CFBundleDYLDExecutableBinary:
1106 binaryType = CFSTR("executable, ");
1107 break;
1108 case __CFBundleDYLDBundleBinary:
1109 binaryType = CFSTR("bundle, ");
1110 break;
1111 case __CFBundleDYLDFrameworkBinary:
1112 binaryType = CFSTR("framework, ");
1113 break;
1114 case __CFBundleDLLBinary:
1115 binaryType = CFSTR("DLL, ");
1116 break;
1117 case __CFBundleUnreadableBinary:
1118 binaryType = CFSTR("");
1119 break;
1120 default:
1121 binaryType = CFSTR("");
1122 break;
1123 }
1124 if (((CFBundleRef)cf)->_plugInData._isPlugIn) {
1125 retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle/CFPlugIn %p <%@> (%@%@loaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? CFSTR("") : CFSTR("not "));
1126 } else {
1127 retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle %p <%@> (%@%@loaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? CFSTR("") : CFSTR("not "));
1128 }
1129 if (path) CFRelease(path);
1130 return retval;
1131 }
1132
1133 static void _CFBundleDeallocateGlue(const void *key, const void *value, void *context) {
1134 CFAllocatorRef allocator = (CFAllocatorRef)context;
1135 if (value) CFAllocatorDeallocate(allocator, (void *)value);
1136 }
1137
1138 static void __CFBundleDeallocate(CFTypeRef cf) {
1139 CFBundleRef bundle = (CFBundleRef)cf;
1140 CFURLRef bundleURL;
1141 CFStringRef bundleID = NULL;
1142
1143 __CFGenericValidateType(cf, __kCFBundleTypeID);
1144 bundleURL = bundle->_url;
1145 bundle->_url = NULL;
1146 if (bundle->_infoDict) bundleID = (CFStringRef)CFDictionaryGetValue(bundle->_infoDict, kCFBundleIdentifierKey);
1147 _CFBundleRemoveFromTables(bundle, bundleURL, bundleID);
1148 CFBundleUnloadExecutable(bundle);
1149 _CFBundleDeallocatePlugIn(bundle);
1150 if (bundleURL) {
1151 _CFBundleFlushCachesForURL(bundleURL);
1152 CFRelease(bundleURL);
1153 }
1154 if (bundle->_infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(bundle->_infoDict);
1155 if (bundle->_modDate) CFRelease(bundle->_modDate);
1156 if (bundle->_localInfoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(bundle->_localInfoDict);
1157 if (bundle->_searchLanguages) CFRelease(bundle->_searchLanguages);
1158 if (bundle->_glueDict) {
1159 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle));
1160 CFRelease(bundle->_glueDict);
1161 }
1162 if (bundle->_resourceData._stringTableCache) CFRelease(bundle->_resourceData._stringTableCache);
1163 }
1164
1165 static const CFRuntimeClass __CFBundleClass = {
1166 _kCFRuntimeScannedObject,
1167 "CFBundle",
1168 NULL, // init
1169 NULL, // copy
1170 __CFBundleDeallocate,
1171 NULL, // equal
1172 NULL, // hash
1173 NULL, //
1174 __CFBundleCopyDescription
1175 };
1176
1177 // From CFBundle_Resources.c
1178 void _CFBundleResourcesInitialize();
1179
1180 __private_extern__ void __CFBundleInitialize(void) {
1181 __kCFBundleTypeID = _CFRuntimeRegisterClass(&__CFBundleClass);
1182 _CFBundleResourcesInitialize();
1183 }
1184
1185 CFTypeID CFBundleGetTypeID(void) {
1186 return __kCFBundleTypeID;
1187 }
1188
1189 CFBundleRef _CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL) {
1190 CFBundleRef bundle = NULL;
1191 char buff[CFMaxPathSize];
1192 CFURLRef newURL = NULL;
1193
1194 if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL;
1195
1196 newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)buff, strlen(buff), true);
1197 if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL);
1198 bundle = _CFBundleCopyBundleForURL(newURL, false);
1199 if (bundle) CFRelease(bundle);
1200 CFRelease(newURL);
1201 return bundle;
1202 }
1203
1204 static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing) {
1205 allocator = _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator);
1206 CFBundleRef bundle = NULL;
1207 char buff[CFMaxPathSize];
1208 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
1209 Boolean exists = false;
1210 SInt32 mode = 0;
1211 CFURLRef newURL = NULL;
1212 uint8_t localVersion = 0;
1213
1214 if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL;
1215
1216 newURL = CFURLCreateFromFileSystemRepresentation(allocator, (uint8_t *)buff, strlen(buff), true);
1217 if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL);
1218 bundle = _CFBundleCopyBundleForURL(newURL, alreadyLocked);
1219 if (bundle) {
1220 CFRelease(newURL);
1221 return bundle;
1222 }
1223
1224 if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) {
1225 localVersion = 3;
1226 SInt32 res = _CFGetPathProperties(allocator, (char *)buff, &exists, &mode, NULL, NULL, NULL, NULL);
1227 #if DEPLOYMENT_TARGET_WINDOWS
1228 if (!(res == 0 && exists && ((mode & S_IFMT) == S_IFDIR))) {
1229 // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again
1230 if (modDate) {
1231 CFRelease(modDate);
1232 modDate = NULL;
1233 }
1234 CFURLRef shorterPath = CFURLCreateCopyDeletingLastPathComponent(allocator, newURL);
1235 CFRelease(newURL);
1236 newURL = shorterPath;
1237 res = _CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, NULL, NULL, NULL);
1238 }
1239 #endif
1240 if (res == 0) {
1241 if (!exists || ((mode & S_IFMT) != S_IFDIR)) {
1242 if (modDate) CFRelease(modDate);
1243 CFRelease(newURL);
1244 return NULL;
1245 }
1246 } else {
1247 CFRelease(newURL);
1248 return NULL;
1249 }
1250 }
1251
1252 bundle = (CFBundleRef)_CFRuntimeCreateInstance(allocator, __kCFBundleTypeID, sizeof(struct __CFBundle) - sizeof(CFRuntimeBase), NULL);
1253 if (!bundle) {
1254 CFRelease(newURL);
1255 return NULL;
1256 }
1257
1258 bundle->_url = newURL;
1259
1260 bundle->_modDate = modDate;
1261 bundle->_version = localVersion;
1262 bundle->_infoDict = NULL;
1263 bundle->_localInfoDict = NULL;
1264 bundle->_searchLanguages = NULL;
1265
1266 #if defined(BINARY_SUPPORT_DYLD)
1267 /* We'll have to figure it out later */
1268 bundle->_binaryType = __CFBundleUnknownBinary;
1269 #elif defined(BINARY_SUPPORT_DLL)
1270 /* We support DLL only */
1271 bundle->_binaryType = __CFBundleDLLBinary;
1272 bundle->_hModule = NULL;
1273 #else
1274 /* We'll have to figure it out later */
1275 bundle->_binaryType = __CFBundleUnknownBinary;
1276 #endif /* BINARY_SUPPORT_DYLD */
1277
1278 bundle->_isLoaded = false;
1279 bundle->_sharesStringsFiles = false;
1280
1281 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1282 if (!__CFgetenv("CFBundleDisableStringsSharing") &&
1283 (strncmp(buff, "/System/Library/Frameworks", 26) == 0) &&
1284 (strncmp(buff + strlen(buff) - 10, ".framework", 10) == 0)) bundle->_sharesStringsFiles = true;
1285 #elif DEPLOYMENT_TARGET_WINDOWS
1286 #else
1287 #error Unknown or unspecified DEPLOYMENT_TARGET
1288 #endif
1289
1290 bundle->_connectionCookie = NULL;
1291 bundle->_handleCookie = NULL;
1292 bundle->_imageCookie = NULL;
1293 bundle->_moduleCookie = NULL;
1294
1295 bundle->_glueDict = NULL;
1296
1297 bundle->_resourceData._executableLacksResourceFork = false;
1298 bundle->_resourceData._infoDictionaryFromResourceFork = false;
1299 bundle->_resourceData._stringTableCache = NULL;
1300
1301 bundle->_plugInData._isPlugIn = false;
1302 bundle->_plugInData._loadOnDemand = false;
1303 bundle->_plugInData._isDoingDynamicRegistration = false;
1304 bundle->_plugInData._instanceCount = 0;
1305 bundle->_plugInData._factories = NULL;
1306
1307 bundle->_bundleLoadingLock = CFSpinLockInit;
1308
1309 CFBundleGetInfoDictionary(bundle);
1310
1311 _CFBundleAddToTables(bundle, alreadyLocked);
1312
1313 if (doFinalProcessing) {
1314 _CFBundleCheckWorkarounds(bundle);
1315 if (_CFBundleNeedsInitPlugIn(bundle)) {
1316 if (alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock);
1317 _CFBundleInitPlugIn(bundle);
1318 if (alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock);
1319 }
1320 }
1321
1322 return bundle;
1323 }
1324
1325 CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL) {
1326 return _CFBundleCreate(allocator, bundleURL, false, true);
1327 }
1328
1329 CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc, CFURLRef directoryURL, CFStringRef bundleType) {
1330 alloc = _CFConvertAllocatorToNonGCRefZeroEquivalent(alloc);
1331 CFMutableArrayRef bundles = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
1332 CFArrayRef URLs = _CFContentsOfDirectory(alloc, NULL, NULL, directoryURL, bundleType);
1333 if (URLs) {
1334 CFIndex i, c = CFArrayGetCount(URLs);
1335 CFURLRef curURL;
1336 CFBundleRef curBundle;
1337
1338 for (i = 0; i < c; i++) {
1339 curURL = (CFURLRef)CFArrayGetValueAtIndex(URLs, i);
1340 curBundle = CFBundleCreate(alloc, curURL);
1341 if (curBundle) CFArrayAppendValue(bundles, curBundle);
1342 }
1343 CFRelease(URLs);
1344 }
1345
1346 return bundles;
1347 }
1348
1349 CFURLRef CFBundleCopyBundleURL(CFBundleRef bundle) {
1350 if (bundle->_url) CFRetain(bundle->_url);
1351 return bundle->_url;
1352 }
1353
1354 void _CFBundleSetDefaultLocalization(CFStringRef localizationName) {
1355 CFStringRef newLocalization = localizationName ? (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, localizationName) : NULL;
1356 if (_defaultLocalization) CFRelease(_defaultLocalization);
1357 _defaultLocalization = newLocalization;
1358 }
1359
1360 CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle) {
1361 if (!bundle->_searchLanguages) {
1362 CFMutableArrayRef langs = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
1363 CFStringRef devLang = CFBundleGetDevelopmentRegion(bundle);
1364
1365 #if DEPLOYMENT_TARGET_WINDOWS
1366 if (_defaultLocalization) CFArrayAppendValue(langs, _defaultLocalization);
1367 #endif
1368 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, devLang);
1369
1370 if (CFArrayGetCount(langs) == 0) {
1371 // If the user does not prefer any of our languages, and devLang is not present, try English
1372 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, CFSTR("en_US"));
1373 }
1374 if (CFArrayGetCount(langs) == 0) {
1375 // if none of the preferred localizations are present, fall back on a random localization that is present
1376 CFArrayRef localizations = CFBundleCopyBundleLocalizations(bundle);
1377 if (localizations) {
1378 if (CFArrayGetCount(localizations) > 0) _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, (CFStringRef)CFArrayGetValueAtIndex(localizations, 0));
1379 CFRelease(localizations);
1380 }
1381 }
1382
1383 if (devLang && !CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang)) {
1384 // Make sure that devLang is on the list as a fallback for individual resources that are not present
1385 CFArrayAppendValue(langs, devLang);
1386 } else if (!devLang) {
1387 // Or if there is no devLang, try some variation of English that is present
1388 CFArrayRef localizations = CFBundleCopyBundleLocalizations(bundle);
1389 if (localizations) {
1390 CFStringRef en_US = CFSTR("en_US"), en = CFSTR("en"), English = CFSTR("English");
1391 CFRange range = CFRangeMake(0, CFArrayGetCount(localizations));
1392 if (CFArrayContainsValue(localizations, range, en)) {
1393 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), en)) CFArrayAppendValue(langs, en);
1394 } else if (CFArrayContainsValue(localizations, range, English)) {
1395 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), English)) CFArrayAppendValue(langs, English);
1396 } else if (CFArrayContainsValue(localizations, range, en_US)) {
1397 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), en_US)) CFArrayAppendValue(langs, en_US);
1398 }
1399 CFRelease(localizations);
1400 }
1401 }
1402 if (CFArrayGetCount(langs) == 0) {
1403 // Total backstop behavior to avoid having an empty array.
1404 if (_defaultLocalization) {
1405 CFArrayAppendValue(langs, _defaultLocalization);
1406 } else {
1407 CFArrayAppendValue(langs, CFSTR("en"));
1408 }
1409 }
1410 if (!OSAtomicCompareAndSwapPtrBarrier(NULL, (void *)langs, (void * volatile *)&(bundle->_searchLanguages))) CFRelease(langs);
1411 }
1412 return bundle->_searchLanguages;
1413 }
1414
1415 CFDictionaryRef CFBundleCopyInfoDictionaryInDirectory(CFURLRef url) {
1416 CFDictionaryRef dict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero, url, NULL);
1417 if (dict && _CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRetain(dict); // conditionally put on a retain for a Copy function
1418 return dict;
1419 }
1420
1421 CFDictionaryRef CFBundleGetInfoDictionary(CFBundleRef bundle) {
1422 if (!bundle->_infoDict) bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(kCFAllocatorSystemDefaultGCRefZero, bundle->_url, bundle->_version);
1423 return bundle->_infoDict;
1424 }
1425
1426 CFDictionaryRef _CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {
1427 return CFBundleGetLocalInfoDictionary(bundle);
1428 }
1429
1430 CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {
1431 static CFSpinLock_t CFBundleLocalInfoLock = CFSpinLockInit;
1432 CFDictionaryRef localInfoDict = bundle->_localInfoDict;
1433 if (!localInfoDict) {
1434 CFURLRef url = CFBundleCopyResourceURL(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL);
1435 if (url) {
1436 CFDataRef data;
1437 SInt32 errCode;
1438 CFStringRef errStr = NULL;
1439
1440 if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, &errCode)) {
1441 localInfoDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero, data, kCFPropertyListMutableContainers, &errStr);
1442 if (errStr) CFRelease(errStr);
1443 if (localInfoDict && CFDictionaryGetTypeID() != CFGetTypeID(localInfoDict)) {
1444 if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(localInfoDict);
1445 localInfoDict = NULL;
1446 }
1447 CFRelease(data);
1448 }
1449 CFRelease(url);
1450 }
1451 if (localInfoDict) _processInfoDictionary((CFMutableDictionaryRef)localInfoDict, _CFGetPlatformName(), _CFGetProductName());
1452 __CFSpinLock(&CFBundleLocalInfoLock);
1453 if (!bundle->_localInfoDict) {
1454 bundle->_localInfoDict = localInfoDict;
1455 } else {
1456 if (localInfoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(localInfoDict);
1457 localInfoDict = bundle->_localInfoDict;
1458 }
1459 __CFSpinUnlock(&CFBundleLocalInfoLock);
1460 }
1461 return localInfoDict;
1462 }
1463
1464 CFPropertyListRef _CFBundleGetValueForInfoKey(CFBundleRef bundle, CFStringRef key) {
1465 return (CFPropertyListRef)CFBundleGetValueForInfoDictionaryKey(bundle, key);
1466 }
1467
1468 CFTypeRef CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle, CFStringRef key) {
1469 // Look in InfoPlist.strings first. Then look in Info.plist
1470 CFTypeRef result = NULL;
1471 if (bundle && key) {
1472 CFDictionaryRef dict = CFBundleGetLocalInfoDictionary(bundle);
1473 if (dict) result = CFDictionaryGetValue(dict, key);
1474 if (!result) {
1475 dict = CFBundleGetInfoDictionary(bundle);
1476 if (dict) result = CFDictionaryGetValue(dict, key);
1477 }
1478 }
1479 return result;
1480 }
1481
1482 CFStringRef CFBundleGetIdentifier(CFBundleRef bundle) {
1483 CFStringRef bundleID = NULL;
1484 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1485 if (infoDict) bundleID = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleIdentifierKey);
1486 return bundleID;
1487 }
1488
1489 #define DEVELOPMENT_STAGE 0x20
1490 #define ALPHA_STAGE 0x40
1491 #define BETA_STAGE 0x60
1492 #define RELEASE_STAGE 0x80
1493
1494 #define MAX_VERS_LEN 10
1495
1496 CF_INLINE Boolean _isDigit(UniChar aChar) {return ((aChar >= (UniChar)'0' && aChar <= (UniChar)'9') ? true : false);}
1497
1498 __private_extern__ CFStringRef _CFCreateStringFromVersionNumber(CFAllocatorRef alloc, UInt32 vers) {
1499 CFStringRef result = NULL;
1500 uint8_t major1, major2, minor1, minor2, stage, build;
1501
1502 major1 = (vers & 0xF0000000) >> 28;
1503 major2 = (vers & 0x0F000000) >> 24;
1504 minor1 = (vers & 0x00F00000) >> 20;
1505 minor2 = (vers & 0x000F0000) >> 16;
1506 stage = (vers & 0x0000FF00) >> 8;
1507 build = (vers & 0x000000FF);
1508
1509 if (stage == RELEASE_STAGE) {
1510 if (major1 > 0) {
1511 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d"), major1, major2, minor1, minor2);
1512 } else {
1513 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d"), major2, minor1, minor2);
1514 }
1515 } else {
1516 if (major1 > 0) {
1517 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d%C%d"), major1, major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? 'd' : ((stage == ALPHA_STAGE) ? 'a' : 'b')), build);
1518 } else {
1519 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d%C%d"), major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? 'd' : ((stage == ALPHA_STAGE) ? 'a' : 'b')), build);
1520 }
1521 }
1522 return result;
1523 }
1524
1525 __private_extern__ UInt32 _CFVersionNumberFromString(CFStringRef versStr) {
1526 // Parse version number from string.
1527 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1528 UInt32 major1 = 0, major2 = 0, minor1 = 0, minor2 = 0, stage = RELEASE_STAGE, build = 0;
1529 UniChar versChars[MAX_VERS_LEN];
1530 UniChar *chars = NULL;
1531 CFIndex len;
1532 UInt32 theVers;
1533 Boolean digitsDone = false;
1534
1535 if (!versStr) return 0;
1536 len = CFStringGetLength(versStr);
1537 if (len <= 0 || len > MAX_VERS_LEN) return 0;
1538
1539 CFStringGetCharacters(versStr, CFRangeMake(0, len), versChars);
1540 chars = versChars;
1541
1542 // Get major version number.
1543 major1 = major2 = 0;
1544 if (_isDigit(*chars)) {
1545 major2 = *chars - (UniChar)'0';
1546 chars++;
1547 len--;
1548 if (len > 0) {
1549 if (_isDigit(*chars)) {
1550 major1 = major2;
1551 major2 = *chars - (UniChar)'0';
1552 chars++;
1553 len--;
1554 if (len > 0) {
1555 if (*chars == (UniChar)'.') {
1556 chars++;
1557 len--;
1558 } else {
1559 digitsDone = true;
1560 }
1561 }
1562 } else if (*chars == (UniChar)'.') {
1563 chars++;
1564 len--;
1565 } else {
1566 digitsDone = true;
1567 }
1568 }
1569 } else if (*chars == (UniChar)'.') {
1570 chars++;
1571 len--;
1572 } else {
1573 digitsDone = true;
1574 }
1575
1576 // Now major1 and major2 contain first and second digit of the major version number as ints.
1577 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1578
1579 // Get the first minor version number.
1580 if (len > 0 && !digitsDone) {
1581 if (_isDigit(*chars)) {
1582 minor1 = *chars - (UniChar)'0';
1583 chars++;
1584 len--;
1585 if (len > 0) {
1586 if (*chars == (UniChar)'.') {
1587 chars++;
1588 len--;
1589 } else {
1590 digitsDone = true;
1591 }
1592 }
1593 } else {
1594 digitsDone = true;
1595 }
1596 }
1597
1598 // Now minor1 contains the first minor version number as an int.
1599 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1600
1601 // Get the second minor version number.
1602 if (len > 0 && !digitsDone) {
1603 if (_isDigit(*chars)) {
1604 minor2 = *chars - (UniChar)'0';
1605 chars++;
1606 len--;
1607 } else {
1608 digitsDone = true;
1609 }
1610 }
1611
1612 // Now minor2 contains the second minor version number as an int.
1613 // Now either len is 0 or chars points at the build stage letter.
1614
1615 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1616 if (len > 0) {
1617 if (*chars == (UniChar)'d') {
1618 stage = DEVELOPMENT_STAGE;
1619 } else if (*chars == (UniChar)'a') {
1620 stage = ALPHA_STAGE;
1621 } else if (*chars == (UniChar)'b') {
1622 stage = BETA_STAGE;
1623 } else if (*chars == (UniChar)'f') {
1624 stage = RELEASE_STAGE;
1625 } else {
1626 return 0;
1627 }
1628 chars++;
1629 len--;
1630 }
1631
1632 // Now stage contains the release stage.
1633 // Now either len is 0 or chars points at the build number.
1634
1635 // Get the first digit of the build number.
1636 if (len > 0) {
1637 if (_isDigit(*chars)) {
1638 build = *chars - (UniChar)'0';
1639 chars++;
1640 len--;
1641 } else {
1642 return 0;
1643 }
1644 }
1645 // Get the second digit of the build number.
1646 if (len > 0) {
1647 if (_isDigit(*chars)) {
1648 build *= 10;
1649 build += *chars - (UniChar)'0';
1650 chars++;
1651 len--;
1652 } else {
1653 return 0;
1654 }
1655 }
1656 // Get the third digit of the build number.
1657 if (len > 0) {
1658 if (_isDigit(*chars)) {
1659 build *= 10;
1660 build += *chars - (UniChar)'0';
1661 chars++;
1662 len--;
1663 } else {
1664 return 0;
1665 }
1666 }
1667
1668 // Range check the build number and make sure we exhausted the string.
1669 if (build > 0xFF || len > 0) return 0;
1670
1671 // Build the number
1672 theVers = major1 << 28;
1673 theVers += major2 << 24;
1674 theVers += minor1 << 20;
1675 theVers += minor2 << 16;
1676 theVers += stage << 8;
1677 theVers += build;
1678
1679 return theVers;
1680 }
1681
1682 UInt32 CFBundleGetVersionNumber(CFBundleRef bundle) {
1683 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1684 CFTypeRef unknownVersionValue = CFDictionaryGetValue(infoDict, _kCFBundleNumericVersionKey);
1685 CFNumberRef versNum;
1686 UInt32 vers = 0;
1687
1688 if (!unknownVersionValue) unknownVersionValue = CFDictionaryGetValue(infoDict, kCFBundleVersionKey);
1689 if (unknownVersionValue) {
1690 if (CFGetTypeID(unknownVersionValue) == CFStringGetTypeID()) {
1691 // Convert a string version number into a numeric one.
1692 vers = _CFVersionNumberFromString((CFStringRef)unknownVersionValue);
1693
1694 versNum = CFNumberCreate(CFGetAllocator(bundle), kCFNumberSInt32Type, &vers);
1695 CFDictionarySetValue((CFMutableDictionaryRef)infoDict, _kCFBundleNumericVersionKey, versNum);
1696 CFRelease(versNum);
1697 } else if (CFGetTypeID(unknownVersionValue) == CFNumberGetTypeID()) {
1698 CFNumberGetValue((CFNumberRef)unknownVersionValue, kCFNumberSInt32Type, &vers);
1699 } else {
1700 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleNumericVersionKey);
1701 }
1702 }
1703 return vers;
1704 }
1705
1706 CFStringRef CFBundleGetDevelopmentRegion(CFBundleRef bundle) {
1707 CFStringRef devLang = NULL;
1708 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1709 if (infoDict) {
1710 devLang = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
1711 if (devLang && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) {
1712 devLang = NULL;
1713 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleDevelopmentRegionKey);
1714 }
1715 }
1716
1717 return devLang;
1718 }
1719
1720 Boolean _CFBundleGetHasChanged(CFBundleRef bundle) {
1721 CFDateRef modDate;
1722 Boolean result = false;
1723 Boolean exists = false;
1724 SInt32 mode = 0;
1725
1726 if (_CFGetFileProperties(CFGetAllocator(bundle), bundle->_url, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) {
1727 // If the bundle no longer exists or is not a folder, it must have "changed"
1728 if (!exists || ((mode & S_IFMT) != S_IFDIR)) result = true;
1729 } else {
1730 // Something is wrong. The stat failed.
1731 result = true;
1732 }
1733 if (bundle->_modDate && !CFEqual(bundle->_modDate, modDate)) {
1734 // mod date is different from when we created.
1735 result = true;
1736 }
1737 CFRelease(modDate);
1738 return result;
1739 }
1740
1741 void _CFBundleSetStringsFilesShared(CFBundleRef bundle, Boolean flag) {
1742 bundle->_sharesStringsFiles = flag;
1743 }
1744
1745 Boolean _CFBundleGetStringsFilesShared(CFBundleRef bundle) {
1746 return bundle->_sharesStringsFiles;
1747 }
1748
1749 static Boolean _urlExists(CFURLRef url) {
1750 Boolean exists;
1751 return url && (0 == _CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, NULL, NULL, NULL, NULL, NULL)) && exists;
1752 }
1753
1754 // This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their
1755 // original locations on disk, so checking whether a binary's path exists is no longer sufficient.
1756 // For performance reasons, we only call dlopen_preflight() after we've verified that the binary
1757 // does not exist at its original path with _urlExists().
1758 // See <rdar://problem/6956670>
1759 static Boolean _binaryLoadable(CFURLRef url) {
1760 Boolean loadable = _urlExists(url);
1761 #if DEPLOYMENT_TARGET_EMBEDDED
1762 if (!loadable) {
1763 uint8_t path[PATH_MAX];
1764 if (url && CFURLGetFileSystemRepresentation(url, true, path, sizeof(path))) {
1765 loadable = dlopen_preflight((char *)path);
1766 }
1767 }
1768 #endif
1769 return loadable;
1770 }
1771
1772 __private_extern__ CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL, uint8_t version) {
1773 CFURLRef result = NULL;
1774 if (bundleURL) {
1775 if (1 == version) {
1776 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase1, bundleURL);
1777 } else if (2 == version) {
1778 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase2, bundleURL);
1779 } else {
1780 result = (CFURLRef)CFRetain(bundleURL);
1781 }
1782 }
1783 return result;
1784 }
1785
1786 CF_EXPORT CFURLRef CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle) {
1787 return _CFBundleCopySupportFilesDirectoryURLInDirectory(bundle->_url, bundle->_version);
1788 }
1789
1790 __private_extern__ CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL, uint8_t version) {
1791 CFURLRef result = NULL;
1792 if (bundleURL) {
1793 if (0 == version) {
1794 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase0, bundleURL);
1795 } else if (1 == version) {
1796 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase1, bundleURL);
1797 } else if (2 == version) {
1798 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase2, bundleURL);
1799 } else {
1800 result = (CFURLRef)CFRetain(bundleURL);
1801 }
1802 }
1803 return result;
1804 }
1805
1806 CFURLRef CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) {
1807 return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle->_url, bundle->_version);
1808 }
1809
1810 __private_extern__ CFURLRef _CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL, uint8_t version) {
1811 CFURLRef result = NULL;
1812 if (bundleURL) {
1813 if (0 == version) {
1814 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase0, bundleURL);
1815 } else if (1 == version) {
1816 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase1, bundleURL);
1817 } else if (2 == version) {
1818 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase2, bundleURL);
1819 }
1820 }
1821 return result;
1822 }
1823
1824 CFURLRef _CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle) {
1825 return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle->_url, bundle->_version);
1826 }
1827
1828 static CFURLRef _CFBundleCopyExecutableURLRaw(CFURLRef urlPath, CFStringRef exeName) {
1829 // 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.
1830 CFURLRef executableURL = NULL;
1831 if (!urlPath || !exeName) return NULL;
1832
1833 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
1834 const uint8_t *image_suffix = (uint8_t *)__CFgetenv("DYLD_IMAGE_SUFFIX");
1835 if (image_suffix) {
1836 CFStringRef newExeName, imageSuffix;
1837 imageSuffix = CFStringCreateWithCString(kCFAllocatorSystemDefault, (char *)image_suffix, kCFStringEncodingUTF8);
1838 if (CFStringHasSuffix(exeName, CFSTR(".dylib"))) {
1839 CFStringRef bareExeName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6));
1840 newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix);
1841 CFRelease(bareExeName);
1842 } else {
1843 newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, imageSuffix);
1844 }
1845 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, newExeName, kCFURLPOSIXPathStyle, false, urlPath);
1846 if (executableURL && !_binaryLoadable(executableURL)) {
1847 CFRelease(executableURL);
1848 executableURL = NULL;
1849 }
1850 CFRelease(newExeName);
1851 CFRelease(imageSuffix);
1852 }
1853 if (!executableURL) {
1854 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLPOSIXPathStyle, false, urlPath);
1855 if (executableURL && !_binaryLoadable(executableURL)) {
1856 CFRelease(executableURL);
1857 executableURL = NULL;
1858 }
1859 }
1860 #elif DEPLOYMENT_TARGET_WINDOWS
1861 if (!executableURL) {
1862 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLWindowsPathStyle, false, urlPath);
1863 if (executableURL && !_urlExists(executableURL)) {
1864 CFRelease(executableURL);
1865 executableURL = NULL;
1866 }
1867 }
1868 if (!executableURL) {
1869 if (!CFStringFindWithOptions(exeName, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) {
1870 #if defined(DEBUG)
1871 CFStringRef extension = CFSTR("_debug.dll");
1872 #else
1873 CFStringRef extension = CFSTR(".dll");
1874 #endif
1875 CFStringRef newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, extension);
1876 executableURL = CFURLCreateWithString(kCFAllocatorSystemDefault, newExeName, urlPath);
1877 if (executableURL && !_binaryLoadable(executableURL)) {
1878 CFRelease(executableURL);
1879 executableURL = NULL;
1880 }
1881 CFRelease(newExeName);
1882 }
1883 }
1884 if (!executableURL) {
1885 if (!CFStringFindWithOptions(exeName, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) {
1886 #if defined(DEBUG)
1887 CFStringRef extension = CFSTR("_debug.exe");
1888 #else
1889 CFStringRef extension = CFSTR(".exe");
1890 #endif
1891 CFStringRef newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, extension);
1892 executableURL = CFURLCreateWithString(kCFAllocatorSystemDefault, newExeName, urlPath);
1893 if (executableURL && !_binaryLoadable(executableURL)) {
1894 CFRelease(executableURL);
1895 executableURL = NULL;
1896 }
1897 CFRelease(newExeName);
1898 }
1899 }
1900 #else
1901 #error Unknown or unspecified DEPLOYMENT_TARGET
1902 #endif
1903 return executableURL;
1904 }
1905
1906 static CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) {
1907 CFStringRef executableName = NULL;
1908
1909 if (!infoDict && bundle) infoDict = CFBundleGetInfoDictionary(bundle);
1910 if (!url && bundle) url = bundle->_url;
1911
1912 if (infoDict) {
1913 // Figure out the name of the executable.
1914 // First try for the new key in the plist.
1915 executableName = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleExecutableKey);
1916 // Second try for the old key in the plist.
1917 if (!executableName) executableName = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey);
1918 if (executableName && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) {
1919 CFRetain(executableName);
1920 } else {
1921 executableName = NULL;
1922 }
1923 }
1924 if (!executableName && url) {
1925 // Third, take the name of the bundle itself (with path extension stripped)
1926 CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url);
1927 CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
1928 CFRelease(absoluteURL);
1929 if (bundlePath) {
1930 UniChar buff[CFMaxPathSize];
1931 CFIndex len = CFStringGetLength(bundlePath);
1932 CFIndex startOfBundleName, endOfBundleName;
1933
1934 if (len > CFMaxPathSize) len = CFMaxPathSize;
1935 CFStringGetCharacters(bundlePath, CFRangeMake(0, len), buff);
1936 startOfBundleName = _CFStartOfLastPathComponent(buff, len);
1937 endOfBundleName = _CFLengthAfterDeletingPathExtension(buff, len);
1938
1939 if (startOfBundleName <= len && endOfBundleName <= len && startOfBundleName < endOfBundleName) executableName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfBundleName]), endOfBundleName - startOfBundleName);
1940 CFRelease(bundlePath);
1941 }
1942 }
1943
1944 return executableName;
1945 }
1946
1947 __private_extern__ CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boolean mayBeLocal) {
1948 CFStringRef executableName = _CFBundleCopyExecutableName(bundle, NULL, NULL);
1949 CFURLRef resourceForkURL = NULL;
1950 if (executableName) {
1951 if (mayBeLocal) {
1952 resourceForkURL = CFBundleCopyResourceURL(bundle, executableName, CFSTR("rsrc"), NULL);
1953 } else {
1954 resourceForkURL = CFBundleCopyResourceURLForLocalization(bundle, executableName, CFSTR("rsrc"), NULL, NULL);
1955 }
1956 CFRelease(executableName);
1957 }
1958
1959 return resourceForkURL;
1960 }
1961
1962 CFURLRef _CFBundleCopyResourceForkURL(CFBundleRef bundle) {
1963 return _CFBundleCopyResourceForkURLMayBeLocal(bundle, true);
1964 }
1965
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;
1974
1975 if (bundle) {
1976 infoDict = CFBundleGetInfoDictionary(bundle);
1977 version = bundle->_version;
1978 } else {
1979 infoDict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero, url, &version);
1980 }
1981
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
1990 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLPOSIXPathStyle, false);
1991 #elif DEPLOYMENT_TARGET_WINDOWS
1992 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLWindowsPathStyle, false);
1993 #else
1994 #error Unknown or unspecified DEPLOYMENT_TARGET
1995 #endif
1996 if (executableURL) {
1997 foundIt = true;
1998 } else {
1999 __CFSpinLock(&CFBundleExecutablePathLock);
2000 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleExecutablePathKey);
2001 __CFSpinUnlock(&CFBundleExecutablePathLock);
2002 }
2003 CFRelease(executablePath);
2004 }
2005 }
2006
2007 if (!foundIt) {
2008 if (lookupMainExe) executableName = _CFBundleCopyExecutableName(bundle, url, infoDict);
2009 if (executableName) {
2010 #if DEPLOYMENT_TARGET_EMBEDDED
2011 Boolean doExecSearch = false;
2012 #else
2013 Boolean doExecSearch = true;
2014 #endif
2015 // Now, look for the executable inside the bundle.
2016 if (doExecSearch && 0 != version) {
2017 CFURLRef exeDirURL;
2018 CFURLRef exeSubdirURL;
2019
2020 if (1 == version) {
2021 exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase1, url);
2022 } else if (2 == version) {
2023 exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase2, url);
2024 } else {
2025 #if DEPLOYMENT_TARGET_WINDOWS
2026 // On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory
2027 CFStringRef extension = CFURLCopyPathExtension(url);
2028 if (extension && CFEqual(extension, _CFBundleWindowsResourceDirectoryExtension)) {
2029 exeDirURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, url);
2030 } else {
2031 exeDirURL = (CFURLRef)CFRetain(url);
2032 }
2033 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2034 exeDirURL = (CFURLRef)CFRetain(url);
2035 #else
2036 #error Unknown or unspecified DEPLOYMENT_TARGET
2037 #endif
2038 }
2039 CFStringRef platformSubDir = useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName();
2040 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL);
2041 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName);
2042 if (!executableURL) {
2043 CFRelease(exeSubdirURL);
2044 platformSubDir = useOtherPlatform ? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName();
2045 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL);
2046 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName);
2047 }
2048 if (!executableURL) {
2049 CFRelease(exeSubdirURL);
2050 platformSubDir = useOtherPlatform ? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName();
2051 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL);
2052 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName);
2053 }
2054 if (!executableURL) {
2055 CFRelease(exeSubdirURL);
2056 platformSubDir = useOtherPlatform ? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName();
2057 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL);
2058 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName);
2059 }
2060 if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName);
2061 CFRelease(exeDirURL);
2062 CFRelease(exeSubdirURL);
2063 }
2064
2065 // If this was an old bundle, or we did not find the executable in the Executables subdirectory, look directly in the bundle wrapper.
2066 if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(url, executableName);
2067
2068 #if DEPLOYMENT_TARGET_WINDOWS
2069 // Windows only: If we still haven't found the exe, look in the Executables folder.
2070 // But only for the main bundle exe
2071 if (lookupMainExe && !executableURL) {
2072 CFURLRef exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, CFSTR("../../Executables"), url);
2073 executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName);
2074 CFRelease(exeDirURL);
2075 }
2076 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2077 #else
2078 #error Unknown or unspecified DEPLOYMENT_TARGET
2079 #endif
2080
2081 if (lookupMainExe && !ignoreCache && !useOtherPlatform && bundle && infoDict && executableURL) {
2082 // We found it. Cache the path.
2083 CFURLRef absURL = CFURLCopyAbsoluteURL(executableURL);
2084 #if DEPLOYMENT_TARGET_WINDOWS
2085 executablePath = CFURLCopyFileSystemPath(absURL, kCFURLWindowsPathStyle);
2086 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2087 executablePath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
2088 #else
2089 #error Unknown or unspecified DEPLOYMENT_TARGET
2090 #endif
2091 CFRelease(absURL);
2092 __CFSpinLock(&CFBundleExecutablePathLock);
2093 CFDictionarySetValue((CFMutableDictionaryRef)infoDict, _kCFBundleExecutablePathKey, executablePath);
2094 __CFSpinUnlock(&CFBundleExecutablePathLock);
2095 CFRelease(executablePath);
2096 }
2097 if (lookupMainExe && !useOtherPlatform && bundle && !executableURL) bundle->_binaryType = __CFBundleNoBinary;
2098 if (lookupMainExe) CFRelease(executableName);
2099 }
2100 }
2101 if (!bundle && infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(infoDict);
2102 return executableURL;
2103 }
2104
2105 CFURLRef _CFBundleCopyExecutableURLInDirectory(CFURLRef url) {
2106 return _CFBundleCopyExecutableURLInDirectory2(NULL, url, NULL, true, false);
2107 }
2108
2109 CFURLRef _CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url) {
2110 return _CFBundleCopyExecutableURLInDirectory2(NULL, url, NULL, true, true);
2111 }
2112
2113 CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle) {
2114 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, NULL, false, false);
2115 }
2116
2117 static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle) {
2118 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, NULL, true, false);
2119 }
2120
2121 CFURLRef CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle, CFStringRef executableName) {
2122 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, executableName, true, false);
2123 }
2124
2125 Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle) {
2126 return bundle->_isLoaded;
2127 }
2128
2129 CFBundleExecutableType CFBundleGetExecutableType(CFBundleRef bundle) {
2130 CFBundleExecutableType result = kCFBundleOtherExecutableType;
2131 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2132
2133 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
2134 #if defined(BINARY_SUPPORT_DYLD)
2135 if (bundle->_binaryType == __CFBundleUnknownBinary) {
2136 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
2137 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
2138 }
2139 #endif /* BINARY_SUPPORT_DYLD */
2140 if (executableURL) CFRelease(executableURL);
2141
2142 if (bundle->_binaryType == __CFBundleCFMBinary) {
2143 result = kCFBundlePEFExecutableType;
2144 } else if (bundle->_binaryType == __CFBundleDYLDExecutableBinary || bundle->_binaryType == __CFBundleDYLDBundleBinary || bundle->_binaryType == __CFBundleDYLDFrameworkBinary) {
2145 result = kCFBundleMachOExecutableType;
2146 } else if (bundle->_binaryType == __CFBundleDLLBinary) {
2147 result = kCFBundleDLLExecutableType;
2148 } else if (bundle->_binaryType == __CFBundleELFBinary) {
2149 result = kCFBundleELFExecutableType;
2150 }
2151 return result;
2152 }
2153
2154 static SInt32 _CFBundleCurrentArchitecture(void) {
2155 SInt32 arch = 0;
2156 #if defined(__ppc__)
2157 arch = kCFBundleExecutableArchitecturePPC;
2158 #elif defined(__ppc64__)
2159 arch = kCFBundleExecutableArchitecturePPC64;
2160 #elif defined(__i386__)
2161 arch = kCFBundleExecutableArchitectureI386;
2162 #elif defined(__x86_64__)
2163 arch = kCFBundleExecutableArchitectureX86_64;
2164 #elif defined(BINARY_SUPPORT_DYLD)
2165 const NXArchInfo *archInfo = NXGetLocalArchInfo();
2166 if (archInfo) arch = archInfo->cputype;
2167 #endif
2168 return arch;
2169 }
2170
2171 #define UNKNOWN_FILETYPE 0x0
2172 #define PEF_FILETYPE 0x1000
2173 #define PEF_MAGIC 0x4a6f7921
2174 #define PEF_CIGAM 0x21796f4a
2175 #define TEXT_SEGMENT "__TEXT"
2176 #define PLIST_SECTION "__info_plist"
2177 #define OBJC_SEGMENT "__OBJC"
2178 #define IMAGE_INFO_SECTION "__image_info"
2179 #define OBJC_SEGMENT_64 "__DATA"
2180 #define IMAGE_INFO_SECTION_64 "__objc_imageinfo"
2181 #define LIB_X11 "/usr/X11R6/lib/libX"
2182
2183 #define XLS_NAME "Book"
2184 #define XLS_NAME2 "Workbook"
2185 #define DOC_NAME "WordDocument"
2186 #define PPT_NAME "PowerPoint Document"
2187
2188 #define ustrncmp(x, y, z) strncmp((char *)(x), (char *)(y), (z))
2189 #define ustrncasecmp(x, y, z) strncasecmp_l((char *)(x), (char *)(y), (z), NULL)
2190
2191 static const uint32_t __CFBundleMagicNumbersArray[] = {
2192 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0xfeedfacf, 0xcffaedfe, 0x4a6f7921, 0x21796f4a,
2193 0x7f454c46, 0xffd8ffe0, 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100,
2194 0x7b5c7274, 0x25504446, 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646,
2195 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435,
2196 0x53495444, 0x53747566, 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x3d796265,
2197 0x6b6f6c79, 0x3026b275, 0x0000000c, 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143,
2198 0x00010000, 0x74727565, 0x4f54544f, 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70,
2199 0x3c435058, 0x28445746, 0x424f4d53, 0x49544f4c, 0x72746664, 0x63616666, 0x802a5fd7, 0x762f3101
2200 };
2201
2202 // string, with groups of 5 characters being 1 element in the array
2203 static const char * __CFBundleExtensionsArray =
2204 "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0"
2205 "elf\0\0" "jpeg\0" "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0"
2206 "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"
2207 "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0"
2208 "sit\0\0" "sit\0\0" "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""ync\0\0"
2209 "dmg\0\0" "wmv\0\0" "jp2\0\0" "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0"
2210 "ttf\0\0" "ttf\0\0" "otf\0\0" "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0"
2211 "cpx\0\0" "dwf\0\0" "bom\0\0" "lit\0\0" "rtfd\0" "caf\0\0" "cin\0\0" "exr\0\0";
2212
2213 static const char * __CFBundleOOExtensionsArray = "sxc\0\0" "sxd\0\0" "sxg\0\0" "sxi\0\0" "sxm\0\0" "sxw\0\0";
2214 static const char * __CFBundleODExtensionsArray = "odc\0\0" "odf\0\0" "odg\0\0" "oth\0\0" "odi\0\0" "odm\0\0" "odp\0\0" "ods\0\0" "odt\0\0";
2215
2216 #define EXTENSION_LENGTH 5
2217 #define NUM_EXTENSIONS 64
2218 #define MAGIC_BYTES_TO_READ 512
2219 #define DMG_BYTES_TO_READ 512
2220 #define ZIP_BYTES_TO_READ 1024
2221 #define OLE_BYTES_TO_READ 512
2222 #define X11_BYTES_TO_READ 4096
2223 #define IMAGE_INFO_BYTES_TO_READ 4096
2224
2225 #if defined(BINARY_SUPPORT_DYLD)
2226
2227 CF_INLINE uint32_t _CFBundleSwapInt32Conditional(uint32_t arg, Boolean swap) {return swap ? CFSwapInt32(arg) : arg;}
2228 CF_INLINE uint32_t _CFBundleSwapInt64Conditional(uint64_t arg, Boolean swap) {return swap ? CFSwapInt64(arg) : arg;}
2229
2230 // returns zero-ref dictionary under GC
2231 static CFMutableDictionaryRef _CFBundleGrokInfoDictFromData(const char *bytes, uint32_t length) {
2232 CFMutableDictionaryRef result = NULL;
2233 CFDataRef infoData = NULL;
2234 if (bytes && 0 < length) {
2235 infoData = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (uint8_t *)bytes, length, kCFAllocatorNull);
2236 if (infoData) {
2237 result = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero, infoData, kCFPropertyListMutableContainers, NULL);
2238 if (result && CFDictionaryGetTypeID() != CFGetTypeID(result)) {
2239 CFRelease(result);
2240 result = NULL;
2241 }
2242 CFRelease(infoData);
2243 }
2244 if (!result) result = CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
2245 }
2246 if (result) _processInfoDictionary((CFMutableDictionaryRef)result, _CFGetPlatformName(), _CFGetProductName());
2247 return result;
2248 }
2249
2250 static char *_CFBundleGetSectData(const char *segname, const char *sectname, unsigned long *size) {
2251 char *retval = NULL;
2252 unsigned long localSize = 0;
2253 uint32_t i, numImages = _dyld_image_count();
2254 const void *mhp = (const void *)_NSGetMachExecuteHeader();
2255
2256 for (i = 0; i < numImages; i++) {
2257 if (mhp == (void *)_dyld_get_image_header(i)) {
2258 #if __LP64__
2259 const struct section_64 *sp = getsectbynamefromheader_64((const struct mach_header_64 *)mhp, segname, sectname);
2260 if (sp) {
2261 retval = (char *)(sp->addr + _dyld_get_image_vmaddr_slide(i));
2262 localSize = (unsigned long)sp->size;
2263 }
2264 #else /* __LP64__ */
2265 const struct section *sp = getsectbynamefromheader((const struct mach_header *)mhp, segname, sectname);
2266 if (sp) {
2267 retval = (char *)(sp->addr + _dyld_get_image_vmaddr_slide(i));
2268 localSize = (unsigned long)sp->size;
2269 }
2270 #endif /* __LP64__ */
2271 break;
2272 }
2273 }
2274 if (size) *size = localSize;
2275 return retval;
2276 }
2277
2278 // returns zero-ref dictionary under GC
2279 static CFMutableDictionaryRef _CFBundleGrokInfoDictFromMainExecutable() {
2280 char *bytes = NULL;
2281 unsigned long length = 0;
2282 if (getsegbyname(TEXT_SEGMENT)) bytes = _CFBundleGetSectData(TEXT_SEGMENT, PLIST_SECTION, &length);
2283 return _CFBundleGrokInfoDictFromData(bytes, length);
2284 }
2285
2286 static Boolean _CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion, uint32_t *objcFlags) {
2287 Boolean retval = false;
2288 uint32_t localVersion = 0, localFlags = 0;
2289 char *bytes = NULL;
2290 unsigned long length = 0;
2291 #if __LP64__
2292 if (getsegbyname(OBJC_SEGMENT_64)) bytes = _CFBundleGetSectData(OBJC_SEGMENT_64, IMAGE_INFO_SECTION_64, &length);
2293 #else /* __LP64__ */
2294 if (getsegbyname(OBJC_SEGMENT)) bytes = _CFBundleGetSectData(OBJC_SEGMENT, IMAGE_INFO_SECTION, &length);
2295 #endif /* __LP64__ */
2296 if (bytes && length >= 8) {
2297 localVersion = *(uint32_t *)bytes;
2298 localFlags = *(uint32_t *)(bytes + 4);
2299 retval = true;
2300 }
2301 if (objcVersion) *objcVersion = localVersion;
2302 if (objcFlags) *objcFlags = localFlags;
2303 return retval;
2304 }
2305
2306 static Boolean _CFBundleGrokX11FromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) {
2307 static const char libX11name[] = LIB_X11;
2308 char *buffer = NULL;
2309 const char *loc = NULL;
2310 unsigned i;
2311 Boolean result = false;
2312
2313 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) {
2314 buffer = malloc(X11_BYTES_TO_READ);
2315 if (buffer && read(fd, buffer, X11_BYTES_TO_READ) >= X11_BYTES_TO_READ) loc = buffer;
2316 } else if (bytes && length >= offset + X11_BYTES_TO_READ) {
2317 loc = bytes + offset;
2318 }
2319 if (loc) {
2320 if (sixtyFour) {
2321 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->ncmds, swapped);
2322 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->sizeofcmds, swapped);
2323 const char *startofcmds = loc + sizeof(struct mach_header_64);
2324 const char *endofcmds = startofcmds + sizeofcmds;
2325 struct dylib_command *dlp = (struct dylib_command *)startofcmds;
2326 if (endofcmds > loc + X11_BYTES_TO_READ) endofcmds = loc + X11_BYTES_TO_READ;
2327 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) {
2328 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) {
2329 uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped);
2330 const char *name = (const char *)dlp + nameoffset;
2331 if (startofcmds <= name && name + sizeof(libX11name) <= endofcmds && 0 == strncmp(name, libX11name, sizeof(libX11name) - 1)) result = true;
2332 }
2333 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped));
2334 }
2335 } else {
2336 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->ncmds, swapped);
2337 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->sizeofcmds, swapped);
2338 const char *startofcmds = loc + sizeof(struct mach_header);
2339 const char *endofcmds = startofcmds + sizeofcmds;
2340 struct dylib_command *dlp = (struct dylib_command *)startofcmds;
2341 if (endofcmds > loc + X11_BYTES_TO_READ) endofcmds = loc + X11_BYTES_TO_READ;
2342 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) {
2343 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) {
2344 uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped);
2345 const char *name = (const char *)dlp + nameoffset;
2346 if (startofcmds <= name && name + sizeof(libX11name) <= endofcmds && 0 == strncmp(name, libX11name, sizeof(libX11name) - 1)) result = true;
2347 }
2348 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped));
2349 }
2350 }
2351 }
2352 if (buffer) free(buffer);
2353 return result;
2354 }
2355
2356 // returns zero-ref dictionary under GC
2357 static CFDictionaryRef _CFBundleGrokInfoDictFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) {
2358 struct stat statBuf;
2359 off_t fileLength = 0;
2360 char *maploc = NULL;
2361 const char *loc;
2362 unsigned i, j;
2363 CFDictionaryRef result = NULL;
2364 Boolean foundit = false;
2365 if (fd >= 0 && fstat(fd, &statBuf) == 0 && (maploc = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != (void *)-1) {
2366 loc = maploc;
2367 fileLength = statBuf.st_size;
2368 } else {
2369 loc = bytes;
2370 fileLength = length;
2371 }
2372 if (fileLength > offset + sizeof(struct mach_header_64)) {
2373 if (sixtyFour) {
2374 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->ncmds, swapped);
2375 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->sizeofcmds, swapped);
2376 const char *startofcmds = loc + offset + sizeof(struct mach_header_64);
2377 const char *endofcmds = startofcmds + sizeofcmds;
2378 struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds;
2379 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength;
2380 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) {
2381 if (LC_SEGMENT_64 == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) {
2382 struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64));
2383 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped);
2384 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) {
2385 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, TEXT_SEGMENT, sizeof(sp->segname))) {
2386 uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped);
2387 uint32_t sectlength = (uint32_t)(sectlength64 & 0xffffffff);
2388 uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped);
2389 const char *sectbytes = loc + offset + sectoffset;
2390 // we don't support huge-sized plists
2391 if (sectlength64 <= 0xffffffff && loc <= sectbytes && sectbytes + sectlength <= loc + fileLength) result = (CFDictionaryRef)_CFBundleGrokInfoDictFromData(sectbytes, sectlength);
2392 foundit = true;
2393 }
2394 sp = (struct section_64 *)((char *)sp + sizeof(struct section_64));
2395 }
2396 }
2397 sgp = (struct segment_command_64 *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped));
2398 }
2399 } else {
2400 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->ncmds, swapped);
2401 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->sizeofcmds, swapped);
2402 const char *startofcmds = loc + offset + sizeof(struct mach_header);
2403 const char *endofcmds = startofcmds + sizeofcmds;
2404 struct segment_command *sgp = (struct segment_command *)startofcmds;
2405 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength;
2406 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) {
2407 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) {
2408 struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command));
2409 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped);
2410 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) {
2411 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, TEXT_SEGMENT, sizeof(sp->segname))) {
2412 uint32_t sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped);
2413 uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped);
2414 const char *sectbytes = loc + offset + sectoffset;
2415 if (loc <= sectbytes && sectbytes + sectlength <= loc + fileLength) result = (CFDictionaryRef)_CFBundleGrokInfoDictFromData(sectbytes, sectlength);
2416 foundit = true;
2417 }
2418 sp = (struct section *)((char *)sp + sizeof(struct section));
2419 }
2420 }
2421 sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped));
2422 }
2423 }
2424 }
2425 if (maploc) munmap(maploc, statBuf.st_size);
2426 return result;
2427 }
2428
2429 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) {
2430 uint32_t sectlength = 0, sectoffset = 0, localVersion = 0, localFlags = 0;
2431 char *buffer = NULL;
2432 char sectbuffer[8];
2433 const char *loc = NULL;
2434 unsigned i, j;
2435 Boolean foundit = false, localHasObjc = false;
2436
2437 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) {
2438 buffer = malloc(IMAGE_INFO_BYTES_TO_READ);
2439 if (buffer && read(fd, buffer, IMAGE_INFO_BYTES_TO_READ) >= IMAGE_INFO_BYTES_TO_READ) loc = buffer;
2440 } else if (bytes && length >= offset + IMAGE_INFO_BYTES_TO_READ) {
2441 loc = bytes + offset;
2442 }
2443 if (loc) {
2444 if (sixtyFour) {
2445 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->ncmds, swapped);
2446 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->sizeofcmds, swapped);
2447 const char *startofcmds = loc + sizeof(struct mach_header_64);
2448 const char *endofcmds = startofcmds + sizeofcmds;
2449 struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds;
2450 if (endofcmds > loc + IMAGE_INFO_BYTES_TO_READ) endofcmds = loc + IMAGE_INFO_BYTES_TO_READ;
2451 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) {
2452 if (LC_SEGMENT_64 == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) {
2453 struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64));
2454 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped);
2455 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) {
2456 if (0 == strncmp(sp->segname, OBJC_SEGMENT_64, sizeof(sp->segname))) localHasObjc = true;
2457 if (0 == strncmp(sp->sectname, IMAGE_INFO_SECTION_64, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, OBJC_SEGMENT_64, sizeof(sp->segname))) {
2458 uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped);
2459 sectlength = (uint32_t)(sectlength64 & 0xffffffff);
2460 sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped);
2461 foundit = true;
2462 }
2463 sp = (struct section_64 *)((char *)sp + sizeof(struct section_64));
2464 }
2465 }
2466 sgp = (struct segment_command_64 *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped));
2467 }
2468 } else {
2469 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->ncmds, swapped);
2470 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->sizeofcmds, swapped);
2471 const char *startofcmds = loc + sizeof(struct mach_header);
2472 const char *endofcmds = startofcmds + sizeofcmds;
2473 struct segment_command *sgp = (struct segment_command *)startofcmds;
2474 if (endofcmds > loc + IMAGE_INFO_BYTES_TO_READ) endofcmds = loc + IMAGE_INFO_BYTES_TO_READ;
2475 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) {
2476 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) {
2477 struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command));
2478 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped);
2479 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) {
2480 if (0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) localHasObjc = true;
2481 if (0 == strncmp(sp->sectname, IMAGE_INFO_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) {
2482 sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped);
2483 sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped);
2484 foundit = true;
2485 }
2486 sp = (struct section *)((char *)sp + sizeof(struct section));
2487 }
2488 }
2489 sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped));
2490 }
2491 }
2492 if (sectlength >= 8) {
2493 if (fd >= 0 && lseek(fd, offset + sectoffset, SEEK_SET) == (off_t)(offset + sectoffset) && read(fd, sectbuffer, 8) >= 8) {
2494 localVersion = _CFBundleSwapInt32Conditional(*(uint32_t *)sectbuffer, swapped);
2495 localFlags = _CFBundleSwapInt32Conditional(*(uint32_t *)(sectbuffer + 4), swapped);
2496 } else if (bytes && length >= offset + sectoffset + 8) {
2497 localVersion = _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes + offset + sectoffset), swapped);
2498 localFlags = _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes + offset + sectoffset + 4), swapped);
2499 }
2500 }
2501 }
2502 if (buffer) free(buffer);
2503 if (hasObjc) *hasObjc = localHasObjc;
2504 if (objcVersion) *objcVersion = localVersion;
2505 if (objcFlags) *objcFlags = localFlags;
2506 }
2507
2508 // returns zero-ref dictionary in *infodict under GC
2509 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) {
2510 CFIndex headerLength = length;
2511 unsigned char headerBuffer[MAGIC_BYTES_TO_READ];
2512 UInt32 machtype = UNKNOWN_FILETYPE, magic, numFatHeaders, maxFatHeaders, i;
2513 unsigned char buffer[sizeof(struct mach_header_64)];
2514 const unsigned char *moreBytes = NULL;
2515 const NXArchInfo *archInfo = NXGetLocalArchInfo();
2516 SInt32 curArch = _CFBundleCurrentArchitecture();
2517
2518 struct fat_arch *fat = NULL;
2519
2520 if (isX11) *isX11 = false;
2521 if (architectures) *architectures = NULL;
2522 if (infodict) *infodict = NULL;
2523 if (hasObjc) *hasObjc = false;
2524 if (objcVersion) *objcVersion = 0;
2525 if (objcFlags) *objcFlags = 0;
2526
2527 if (headerLength > MAGIC_BYTES_TO_READ) headerLength = MAGIC_BYTES_TO_READ;
2528 (void)memmove(headerBuffer, bytes, headerLength);
2529 if (swap) {
2530 for (i = 0; i < headerLength; i += 4) *(UInt32 *)(headerBuffer + i) = CFSwapInt32(*(UInt32 *)(headerBuffer + i));
2531 }
2532 numFatHeaders = ((struct fat_header *)headerBuffer)->nfat_arch;
2533 maxFatHeaders = (headerLength - sizeof(struct fat_header)) / sizeof(struct fat_arch);
2534 if (numFatHeaders > maxFatHeaders) numFatHeaders = maxFatHeaders;
2535 if (numFatHeaders > 0) {
2536 if (archInfo) fat = NXFindBestFatArch(archInfo->cputype, archInfo->cpusubtype, (struct fat_arch *)(headerBuffer + sizeof(struct fat_header)), numFatHeaders);
2537 if (!fat && curArch != 0) fat = NXFindBestFatArch((cpu_type_t)curArch, (cpu_subtype_t)0, (struct fat_arch *)(headerBuffer + sizeof(struct fat_header)), numFatHeaders);
2538 if (!fat) fat = (struct fat_arch *)(headerBuffer + sizeof(struct fat_header));
2539 if (architectures) {
2540 CFMutableArrayRef mutableArchitectures = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
2541 for (i = 0; i < numFatHeaders; i++) {
2542 CFNumberRef architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, headerBuffer + sizeof(struct fat_header) + i * sizeof(struct fat_arch));
2543 if (CFArrayGetFirstIndexOfValue(mutableArchitectures, CFRangeMake(0, CFArrayGetCount(mutableArchitectures)), architecture) < 0) CFArrayAppendValue(mutableArchitectures, architecture);
2544 CFRelease(architecture);
2545 }
2546 *architectures = (CFArrayRef)mutableArchitectures;
2547 }
2548 }
2549 if (fat) {
2550 if (fd >= 0 && lseek(fd, fat->offset, SEEK_SET) == (off_t)fat->offset && read(fd, buffer, sizeof(struct mach_header_64)) >= (int)sizeof(struct mach_header_64)) {
2551 moreBytes = buffer;
2552 } else if (bytes && (uint32_t)length >= fat->offset + sizeof(struct mach_header_64)) {
2553 moreBytes = bytes + fat->offset;
2554 }
2555 if (moreBytes) {
2556 magic = *((UInt32 *)moreBytes);
2557 if (MH_MAGIC == magic) {
2558 machtype = ((struct mach_header *)moreBytes)->filetype;
2559 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, false, false);
2560 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, false, false);
2561 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, false, false, hasObjc, objcVersion, objcFlags);
2562 } else if (MH_CIGAM == magic) {
2563 machtype = CFSwapInt32(((struct mach_header *)moreBytes)->filetype);
2564 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, true, false);
2565 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, true, false);
2566 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, true, false, hasObjc, objcVersion, objcFlags);
2567 } else if (MH_MAGIC_64 == magic) {
2568 machtype = ((struct mach_header_64 *)moreBytes)->filetype;
2569 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, false, true);
2570 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, false, true);
2571 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, false, true, hasObjc, objcVersion, objcFlags);
2572 } else if (MH_CIGAM_64 == magic) {
2573 machtype = CFSwapInt32(((struct mach_header_64 *)moreBytes)->filetype);
2574 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, true, true);
2575 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, true, true);
2576 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, true, true, hasObjc, objcVersion, objcFlags);
2577 }
2578 }
2579 }
2580 return machtype;
2581 }
2582
2583 // returns zero-ref dictionary in *infodict under GC
2584 static UInt32 _CFBundleGrokMachType(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) {
2585 unsigned int magic = *((UInt32 *)bytes), machtype = UNKNOWN_FILETYPE, cputype;
2586 CFNumberRef architecture = NULL;
2587
2588 if (isX11) *isX11 = false;
2589 if (architectures) *architectures = NULL;
2590 if (infodict) *infodict = NULL;
2591 if (hasObjc) *hasObjc = false;
2592 if (objcVersion) *objcVersion = 0;
2593 if (objcFlags) *objcFlags = 0;
2594 if (MH_MAGIC == magic) {
2595 machtype = ((struct mach_header *)bytes)->filetype;
2596 cputype = ((struct mach_header *)bytes)->cputype;
2597 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype);
2598 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, false, false);
2599 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, false, false);
2600 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, false, false, hasObjc, objcVersion, objcFlags);
2601 } else if (MH_CIGAM == magic) {
2602 machtype = CFSwapInt32(((struct mach_header *)bytes)->filetype);
2603 cputype = CFSwapInt32(((struct mach_header *)bytes)->cputype);
2604 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype);
2605 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, true, false);
2606 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, true, false);
2607 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, true, false, hasObjc, objcVersion, objcFlags);
2608 } else if (MH_MAGIC_64 == magic) {
2609 machtype = ((struct mach_header_64 *)bytes)->filetype;
2610 cputype = ((struct mach_header_64 *)bytes)->cputype;
2611 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype);
2612 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, false, true);
2613 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, false, true);
2614 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, false, true, hasObjc, objcVersion, objcFlags);
2615 } else if (MH_CIGAM_64 == magic) {
2616 machtype = CFSwapInt32(((struct mach_header_64 *)bytes)->filetype);
2617 cputype = CFSwapInt32(((struct mach_header_64 *)bytes)->cputype);
2618 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype);
2619 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, true, true);
2620 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, true, true);
2621 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, true, true, hasObjc, objcVersion, objcFlags);
2622 } else if (FAT_MAGIC == magic) {
2623 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, false, isX11, architectures, infodict, hasObjc, objcVersion, objcFlags);
2624 } else if (FAT_CIGAM == magic) {
2625 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, true, isX11, architectures, infodict, hasObjc, objcVersion, objcFlags);
2626 } else if (PEF_MAGIC == magic || PEF_CIGAM == magic) {
2627 machtype = PEF_FILETYPE;
2628 }
2629 if (architectures && architecture) *architectures = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&architecture, 1, &kCFTypeArrayCallBacks);
2630 if (architecture) CFRelease(architecture);
2631 return machtype;
2632 }
2633
2634 #endif /* BINARY_SUPPORT_DYLD */
2635
2636 static Boolean _CFBundleGrokFileTypeForZipMimeType(const unsigned char *bytes, CFIndex length, const char **ext) {
2637 unsigned namelength = CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 26))), extralength = CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 28)));
2638 const unsigned char *data = bytes + 30 + namelength + extralength;
2639 int i = -1;
2640 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))) {
2641 data += ('.' == *(data + 15)) ? 16 : 18;
2642 if (0 == ustrncasecmp(data, "sun.xml.", 8)) {
2643 data += 8;
2644 if (0 == ustrncasecmp(data, "calc", 4)) i = 0;
2645 else if (0 == ustrncasecmp(data, "draw", 4)) i = 1;
2646 else if (0 == ustrncasecmp(data, "writer.global", 13)) i = 2;
2647 else if (0 == ustrncasecmp(data, "impress", 7)) i = 3;
2648 else if (0 == ustrncasecmp(data, "math", 4)) i = 4;
2649 else if (0 == ustrncasecmp(data, "writer", 6)) i = 5;
2650 if (i >= 0 && ext) *ext = __CFBundleOOExtensionsArray + i * EXTENSION_LENGTH;
2651 } else if (0 == ustrncasecmp(data, "oasis.opendocument.", 19)) {
2652 data += 19;
2653 if (0 == ustrncasecmp(data, "chart", 5)) i = 0;
2654 else if (0 == ustrncasecmp(data, "formula", 7)) i = 1;
2655 else if (0 == ustrncasecmp(data, "graphics", 8)) i = 2;
2656 else if (0 == ustrncasecmp(data, "text-web", 8)) i = 3;
2657 else if (0 == ustrncasecmp(data, "image", 5)) i = 4;
2658 else if (0 == ustrncasecmp(data, "text-master", 11)) i = 5;
2659 else if (0 == ustrncasecmp(data, "presentation", 12)) i = 6;
2660 else if (0 == ustrncasecmp(data, "spreadsheet", 11)) i = 7;
2661 else if (0 == ustrncasecmp(data, "text", 4)) i = 8;
2662 if (i >= 0 && ext) *ext = __CFBundleODExtensionsArray + i * EXTENSION_LENGTH;
2663 }
2664 } else if (bytes < data && data + 41 <= bytes + length && 8 == CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 8))) && 0x4b2c28c8 == CFSwapInt32HostToBig(*((UInt32 *)data)) && 0xc94c4e2c == CFSwapInt32HostToBig(*((UInt32 *)(data + 4)))) {
2665 // AbiWord compressed mimetype odt
2666 if (ext) *ext = "odt";
2667 }
2668 return (i >= 0);
2669 }
2670
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;
2675 CFIndex i;
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;
2677
2678 if (bytes) {
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)));
2684 offset = 46;
2685 } else if (0x03 == bytes[i + 2] && 0x04 == bytes[i + 3]) {
2686 namelength = (unsigned)CFSwapInt16HostToLittle(*((UInt16 *)(bytes + i + 26)));
2687 offset = 30;
2688 }
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;
2707 }
2708 }
2709 }
2710 }
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;
2718 }
2719 }
2720 if (moreBytes) {
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)));
2726 offset = 46;
2727 } else if (0x03 == moreBytes[i + 2] && 0x04 == moreBytes[i + 3]) {
2728 namelength = CFSwapInt16HostToLittle(*((UInt16 *)(moreBytes + i + 26)));
2729 offset = 30;
2730 }
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;
2748 }
2749 }
2750 }
2751 }
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";
2761
2762 if (buffer) free(buffer);
2763 }
2764 return ext;
2765 }
2766
2767 static Boolean _CFBundleCheckOLEName(const char *name, const char *bytes, unsigned length) {
2768 Boolean retval = true;
2769 unsigned j;
2770 for (j = 0; retval && j < length; j++) if (bytes[2 * j] != name[j]) retval = false;
2771 return retval;
2772 }
2773
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;
2777
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;
2783 }
2784 if (moreBytes) {
2785 Boolean foundit = false;
2786 unsigned i;
2787 for (i = 0; !foundit && i < 4; i++) {
2788 char namelength = moreBytes[128 * i + 64] / 2;
2789 foundit = true;
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;
2795 }
2796 }
2797 if (buffer) free(buffer);
2798 return ext;
2799 }
2800
2801 #if DEPLOYMENT_TARGET_WINDOWS
2802 // Windows isspace implementation limits the input chars to < 256 in the ASCII range. It will
2803 // assert in debug builds. This is annoying. We merrily grok chars > 256.
2804 static inline BOOL isspace(char c) {
2805 return (c == ' ' || c == '\t' || c == '\n' || c == '\r'|| c == '\v' || c == '\f');
2806 }
2807 #endif
2808
2809 // returns zero-ref dictionary in *infodict under GC
2810 static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef *extension, UInt32 *machtype, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) {
2811 int fd = -1;
2812 const unsigned char *bytes = NULL;
2813 unsigned char buffer[MAGIC_BYTES_TO_READ];
2814 CFIndex i, length = 0;
2815 off_t fileLength = 0;
2816 const char *ext = NULL;
2817 UInt32 mt = UNKNOWN_FILETYPE;
2818 #if defined(BINARY_SUPPORT_DYLD)
2819 Boolean isX11 = false;
2820 #endif /* BINARY_SUPPORT_DYLD */
2821 Boolean isFile = false, isPlain = true, isZero = true, isSpace = true, hasBOM = false;
2822 // 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
2823 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
2824 // ??? we do not distinguish between ordinary documents and template versions (often there is no difference in file contents)
2825 // ??? the distinctions between docx, xlsx, and pptx may not be entirely reliable
2826 if (architectures) *architectures = NULL;
2827 if (infodict) *infodict = NULL;
2828 if (hasObjc) *hasObjc = false;
2829 if (objcVersion) *objcVersion = 0;
2830 if (objcFlags) *objcFlags = 0;
2831 if (url) {
2832 Boolean gotPath = FALSE;
2833 char path[CFMaxPathSize];
2834 gotPath = CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize);
2835 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
2836 struct stat statBuf;
2837 #elif DEPLOYMENT_TARGET_WINDOWS
2838 struct _stat statBuf;
2839 #else
2840 #error Unknown or unspecified DEPLOYMENT_TARGET
2841 #endif
2842 if (gotPath && stat(path, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG && (fd = open(path, O_RDONLY | CF_OPENFLGS, 0777)) >= 0) {
2843 length = read(fd, buffer, MAGIC_BYTES_TO_READ);
2844 fileLength = statBuf.st_size;
2845 bytes = buffer;
2846 isFile = true;
2847 }
2848 }
2849 if (!isFile && data) {
2850 length = CFDataGetLength(data);
2851 fileLength = (off_t)length;
2852 bytes = CFDataGetBytePtr(data);
2853 if (length == 0) ext = "txt";
2854 }
2855 if (bytes) {
2856 if (length >= 4) {
2857 UInt32 magic = CFSwapInt32HostToBig(*((UInt32 *)bytes));
2858 for (i = 0; !ext && i < NUM_EXTENSIONS; i++) {
2859 if (__CFBundleMagicNumbersArray[i] == magic) ext = __CFBundleExtensionsArray + i * EXTENSION_LENGTH;
2860 }
2861 if (ext) {
2862 if (0xcafebabe == magic && 8 <= length && 0 != *((UInt16 *)(bytes + 4))) ext = "class";
2863 #if defined(BINARY_SUPPORT_DYLD)
2864 else if ((int)sizeof(struct mach_header_64) <= length) mt = _CFBundleGrokMachType(fd, bytes, length, extension ? &isX11 : NULL, architectures, infodict, hasObjc, objcVersion, objcFlags);
2865
2866 if (MH_OBJECT == mt) ext = "o";
2867 else if (MH_EXECUTE == mt) ext = isX11 ? "x11app" : "tool";
2868 else if (PEF_FILETYPE == mt) ext = "pef";
2869 else if (MH_CORE == mt) ext = "core";
2870 else if (MH_DYLIB == mt) ext = "dylib";
2871 else if (MH_BUNDLE == mt) ext = "bundle";
2872 #endif /* BINARY_SUPPORT_DYLD */
2873 else if (0x7b5c7274 == magic && (6 > length || 'f' != bytes[4])) ext = NULL;
2874 else if (0x25504446 == magic && (6 > length || '-' != bytes[4])) ext = NULL;
2875 else if (0x00010000 == magic && (6 > length || 0 != bytes[4])) ext = NULL;
2876 else if (0x47494638 == magic && (6 > length || (0x3761 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4)))))) ext = NULL;
2877 else if (0x0000000c == magic && (6 > length || 0x6a50 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL;
2878 else if (0x2356524d == magic && (6 > length || 0x4c20 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL;
2879 else if (0x28445746 == magic && (6 > length || 0x2056 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL;
2880 else if (0x30373037 == magic && (6 > length || 0x30 != bytes[4] || !isdigit(bytes[5]))) ext = NULL;
2881 else if (0x41433130 == magic && (6 > length || 0x31 != bytes[4] || !isdigit(bytes[5]))) ext = NULL;
2882 else if (0x89504e47 == magic && (8 > length || 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2883 else if (0x53747566 == magic && (8 > length || 0x66497420 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2884 else if (0x3026b275 == magic && (8 > length || 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2885 else if (0x67696d70 == magic && (8 > length || 0x20786366 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2886 else if (0x424f4d53 == magic && (8 > length || 0x746f7265 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2887 else if (0x49544f4c == magic && (8 > length || 0x49544c53 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2888 else if (0x72746664 == magic && (8 > length || 0x00000000 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2889 else if (0x3d796265 == magic && (12 > length || 0x67696e20 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || (0x6c696e65 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))) && 0x70617274 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))))) ext = NULL;
2890 else if (0x63616666 == magic && (12 > length || 0 != bytes[4] || 0x64657363 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))))) ext = NULL;
2891 else if (0x504b0304 == magic) ext = _CFBundleGrokFileTypeForZipFile(fd, bytes, length, fileLength);
2892 else if (0x25215053 == magic) {
2893 if (11 <= length && 0 == ustrncmp(bytes + 4, "-Adobe-", 7)) ext = "ps";
2894 else if (14 <= length && 0 == ustrncmp(bytes + 4, "-AdobeFont", 10)) ext = "pfa";
2895 else ext = NULL;
2896 } else if (0x464f524d == magic) {
2897 // IFF
2898 ext = NULL;
2899 if (12 <= length) {
2900 UInt32 iffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)));
2901 if (0x41494646 == iffMagic) ext = "aiff";
2902 else if (0x414946 == iffMagic) ext = "aifc";
2903 }
2904 } else if (0x52494646 == magic) {
2905 // RIFF
2906 ext = NULL;
2907 if (12 <= length) {
2908 UInt32 riffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)));
2909 if (0x57415645 == riffMagic) ext = "wav";
2910 else if (0x41564920 == riffMagic) ext = "avi";
2911 }
2912 } else if (0xd0cf11e0 == magic) {
2913 // OLE
2914 if (52 <= length) ext = _CFBundleGrokFileTypeForOLEFile(fd, bytes, length, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 48)))));
2915 } else if (0x62656769 == magic) {
2916 // uu
2917 ext = NULL;
2918 if (76 <= length && 'n' == bytes[4] && ' ' == bytes[5] && isdigit(bytes[6]) && isdigit(bytes[7]) && isdigit(bytes[8]) && ' ' == bytes[9]) {
2919 CFIndex endOfLine = 0;
2920 for (i = 10; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i;
2921 if (10 <= endOfLine && endOfLine + 62 < length && 'M' == bytes[endOfLine + 1] && '\n' == bytes[endOfLine + 62]) {
2922 ext = "uu";
2923 for (i = endOfLine + 1; ext && i < endOfLine + 62; i++) if (!isprint(bytes[i])) ext = NULL;
2924 }
2925 }
2926 }
2927 }
2928 if (extension && !ext) {
2929 UInt16 shortMagic = CFSwapInt16HostToBig(*((UInt16 *)bytes));
2930 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";
2931 else if (8 <= length && (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "mov";
2932 else if (8 <= length && (0x69647363 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "qtif";
2933 else if (8 <= length && 0x424f424f == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) ext = "cwk";
2934 else if (8 <= length && 0x62706c69 == magic && 0x7374 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && isdigit(bytes[6]) && isdigit(bytes[7])) {
2935 for (i = 8; !ext && i < 128 && i + 16 <= length; i++) {
2936 if (0 == ustrncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive";
2937 }
2938 if (!ext) ext = "plist";
2939 } else if (0 == shortMagic && 12 <= length && 0x66747970 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) {
2940 // ??? may want more ftyp values
2941 UInt32 ftyp = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)));
2942 if (0x6d703431 == ftyp || 0x6d703432 == ftyp || 0x69736f6d == ftyp || 0x69736f32 == ftyp) ext = "mp4";
2943 else if (0x4d344120 == ftyp) ext = "m4a";
2944 else if (0x4d344220 == ftyp) ext = "m4b";
2945 else if (0x4d345020 == ftyp) ext = "m4p";
2946 else if (0x4d345620 == ftyp || 0x4d345648 == ftyp || 0x4d345650 == ftyp) ext = "m4v";
2947 else if (0x3367 == (ftyp >> 16)) {
2948 UInt16 remainder = (ftyp & 0xffff);
2949 if (0x6536 == remainder || 0x6537 == remainder || 0x6736 == remainder || 0x7034 == remainder || 0x7035 == remainder || 0x7036 == remainder || 0x7236 == remainder || 0x7336 == remainder || 0x7337 == remainder) ext = "3gp";
2950 else if (0x3261 == remainder) ext = "3g2";
2951 }
2952 } else if (0x424d == shortMagic && 18 <= length) {
2953 UInt32 btyp = CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 14)));
2954 if (40 == btyp || btyp == 12 || btyp == 64 || btyp == 108 || btyp == 124) ext = "bmp";
2955 } else if (20 <= length && 0 == ustrncmp(bytes + 6, "%!PS-AdobeFont", 14)) ext = "pfb";
2956 else if (40 <= length && 0x42696e48 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 38)))) ext = "hqx";
2957 else if (128 <= length && 0x6d42494e == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 102)))) ext = "bin";
2958 else if (128 <= length && 0 == bytes[0] && 0 < bytes[1] && bytes[1] < 64 && 0 == bytes[74] && 0 == bytes[82] && 0 == (fileLength % 128)) {
2959 UInt32 df = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 83))), rf = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 87))), blocks = 1 + (df + 127) / 128 + (rf + 127) / 128;
2960 if (df < 0x00800000 && rf < 0x00800000 && 1 < blocks && (off_t)(128 * blocks) == fileLength) ext = "bin";
2961 } else if (265 <= length && 0x75737461 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 261))))) ext = "tar";
2962 else if (0xfeff == shortMagic || 0xfffe == shortMagic) {
2963 ext = "txt";
2964 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";
2965 } else if (0x1f9d == shortMagic) ext = "Z";
2966 else if (0x1f8b == shortMagic) ext = "gz";
2967 else if (0x71c7 == shortMagic || 0xc771 == shortMagic) ext = "cpio";
2968 else if (0xf702 == shortMagic) ext = "dvi";
2969 else if (0x01da == shortMagic && (0 == bytes[2] || 1 == bytes[2]) && (0 < bytes[3] && 16 > bytes[3])) ext = "sgi";
2970 else if (0x2321 == shortMagic) {
2971 CFIndex endOfLine = 0, lastSlash = 0;
2972 for (i = 2; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i;
2973 if (endOfLine > 3) {
2974 for (i = endOfLine - 1; 0 == lastSlash && i > 1; i--) if ('/' == bytes[i]) lastSlash = i;
2975 if (lastSlash > 0) {
2976 if (0 == ustrncmp(bytes + lastSlash + 1, "perl", 4)) ext = "pl";
2977 else if (0 == ustrncmp(bytes + lastSlash + 1, "python", 6)) ext = "py";
2978 else if (0 == ustrncmp(bytes + lastSlash + 1, "ruby", 4)) ext = "rb";
2979 else ext = "sh";
2980 }
2981 }
2982 } else if (0xffd8 == shortMagic && 0xff == bytes[2]) ext = "jpeg";
2983 else if (0x4657 == shortMagic && 0x53 == bytes[2]) ext = "swf";
2984 else if (0x4357 == shortMagic && 0x53 == bytes[2]) ext = "swc";
2985 else if (0x4944 == shortMagic && '3' == bytes[2] && 0x20 > bytes[3]) ext = "mp3";
2986 else if (0x425a == shortMagic && isdigit(bytes[2]) && isdigit(bytes[3])) ext = "bz";
2987 else if (0x425a == shortMagic && 'h' == bytes[2] && isdigit(bytes[3]) && 8 <= length && (0x31415926 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "bz2";
2988 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2)))) ext = "tfm";
2989 }
2990 }
2991 if (extension && !ext) {
2992 //??? what about MacOSRoman?
2993 if (0xef == bytes[0] && 0xbb == bytes[1] && 0xbf == bytes[2]) { // UTF-8 BOM
2994 hasBOM = true;
2995 isZero = false;
2996 }
2997 for (i = (hasBOM ? 3 : 0); (isPlain || isZero) && !ext && i < length && i < 512; i++) {
2998 char c = bytes[i];
2999 if (isPlain && '<' == c && i + 14 <= length && 0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html";
3000 if (isSpace && '<' == c && i + 14 <= length) {
3001 if (0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13) || 0 == ustrncasecmp(bytes + i + 1, "head", 4) || 0 == ustrncasecmp(bytes + i + 1, "title", 5) || 0 == ustrncasecmp(bytes + i + 1, "script", 6) || 0 == ustrncasecmp(bytes + i + 1, "html", 4)) {
3002 ext = "html";
3003 } else if (0 == ustrncasecmp(bytes + i + 1, "?xml", 4)) {
3004 for (i += 4; !ext && i < 128 && i + 20 <= length; i++) {
3005 if ('<' == bytes[i]) {
3006 if (0 == ustrncasecmp(bytes + i + 1, "abiword", 7)) ext = "abw";
3007 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype svg", 12)) ext = "svg";
3008 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype rdf", 12)) ext = "rdf";
3009 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype x3d", 12)) ext = "x3d";
3010 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html";
3011 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype posingfont", 19)) ext = "sfont";
3012 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype plist", 14)) {
3013 for (i += 14; !ext && i < 256 && i + 16 <= length; i++) {
3014 if (0 == ustrncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive";
3015 }
3016 if (!ext) ext = "plist";
3017 }
3018 }
3019 }
3020 if (!ext) ext = "xml";
3021 }
3022 }
3023 if (0 != c) isZero = false;
3024 if (isZero || 0x7f <= c || (0x20 > c && !isspace(c))) isPlain = false;
3025 if (isZero || !isspace(c)) isSpace = false;
3026 }
3027 if (!ext) {
3028 if (isPlain) {
3029 if (16 <= length && 0 == ustrncmp(bytes, "StartFontMetrics", 16)) ext = "afm";
3030 else ext = "txt";
3031 } else if (isZero && length >= MAGIC_BYTES_TO_READ && fileLength >= 526) {
3032 if (isFile) {
3033 if (lseek(fd, 512, SEEK_SET) == 512 && read(fd, buffer, MAGIC_BYTES_TO_READ) >= 14) {
3034 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(buffer + 10)))) ext = "pict";
3035 }
3036 } else {
3037 if (526 <= length && 0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 522)))) ext = "pict";
3038 }
3039 }
3040 }
3041 }
3042 if (extension && (!ext || 0 == strcmp(ext, "bz2")) && length >= MAGIC_BYTES_TO_READ && fileLength >= DMG_BYTES_TO_READ) {
3043 if (isFile) {
3044 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) {
3045 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";
3046 }
3047 } else {
3048 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";
3049 }
3050 }
3051 }
3052 if (extension) *extension = ext ? CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault, ext, kCFStringEncodingUTF8, kCFAllocatorNull) : NULL;
3053 if (machtype) *machtype = mt;
3054 if (fd >= 0) close(fd);
3055 return (ext ? true : false);
3056 }
3057
3058 CFStringRef _CFBundleCopyFileTypeForFileURL(CFURLRef url) {
3059 CFStringRef extension = NULL;
3060 (void)_CFBundleGrokFileType(url, NULL, &extension, NULL, NULL, NULL, NULL, NULL, NULL);
3061 return extension;
3062 }
3063
3064 CFStringRef _CFBundleCopyFileTypeForFileData(CFDataRef data) {
3065 CFStringRef extension = NULL;
3066 (void)_CFBundleGrokFileType(NULL, data, &extension, NULL, NULL, NULL, NULL, NULL, NULL);
3067 return extension;
3068 }
3069
3070 // returns zero-ref dictionary under GC
3071 __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url) {
3072 CFDictionaryRef result = NULL;
3073 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, &result, NULL, NULL, NULL);
3074 return result;
3075 }
3076
3077 __private_extern__ CFArrayRef _CFBundleCopyArchitecturesForExecutable(CFURLRef url) {
3078 CFArrayRef result = NULL;
3079 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, &result, NULL, NULL, NULL, NULL);
3080 return result;
3081 }
3082
3083 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3084 static Boolean _CFBundleGetObjCImageInfoForExecutable(CFURLRef url, uint32_t *objcVersion, uint32_t *objcFlags) {
3085 Boolean retval = false;
3086 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, NULL, &retval, objcVersion, objcFlags);
3087 return retval;
3088 }
3089 #endif
3090
3091 #if defined(BINARY_SUPPORT_DYLD)
3092
3093 __private_extern__ __CFPBinaryType _CFBundleGrokBinaryType(CFURLRef executableURL) {
3094 // 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.
3095 __CFPBinaryType result = executableURL ? __CFBundleUnreadableBinary : __CFBundleNoBinary;
3096 UInt32 machtype = UNKNOWN_FILETYPE;
3097 if (_CFBundleGrokFileType(executableURL, NULL, NULL, &machtype, NULL, NULL, NULL, NULL, NULL)) {
3098 switch (machtype) {
3099 case MH_EXECUTE:
3100 result = __CFBundleDYLDExecutableBinary;
3101 break;
3102 case MH_BUNDLE:
3103 result = __CFBundleDYLDBundleBinary;
3104 break;
3105 case MH_DYLIB:
3106 result = __CFBundleDYLDFrameworkBinary;
3107 break;
3108 case PEF_FILETYPE:
3109 result = __CFBundleCFMBinary;
3110 break;
3111 }
3112 }
3113 return result;
3114 }
3115
3116 #endif /* BINARY_SUPPORT_DYLD */
3117
3118 void _CFBundleSetCFMConnectionID(CFBundleRef bundle, void *connectionID) {
3119 bundle->_connectionCookie = connectionID;
3120 bundle->_isLoaded = true;
3121 }
3122
3123 static CFStringRef _CFBundleCopyLastPathComponent(CFBundleRef bundle) {
3124 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle);
3125 CFStringRef str = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
3126 UniChar buff[CFMaxPathSize];
3127 CFIndex buffLen = CFStringGetLength(str), startOfLastDir = 0;
3128
3129 CFRelease(bundleURL);
3130 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
3131 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
3132 CFRelease(str);
3133 if (buffLen > 0) startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen);
3134 return CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir);
3135 }
3136
3137 static CFErrorRef _CFBundleCreateErrorDebug(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code, CFStringRef debugString) {
3138 const void *userInfoKeys[6], *userInfoValues[6];
3139 CFIndex numKeys = 0;
3140 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle), absoluteURL = CFURLCopyAbsoluteURL(bundleURL), executableURL = CFBundleCopyExecutableURL(bundle);
3141 CFBundleRef bdl = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation"));
3142 CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE), executablePath = executableURL ? CFURLCopyFileSystemPath(executableURL, PLATFORM_PATH_STYLE) : NULL, descFormat = NULL, desc = NULL, reason = NULL, suggestion = NULL;
3143 CFErrorRef error;
3144 if (bdl) {
3145 CFStringRef name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey);
3146 name = name ? (CFStringRef)CFRetain(name) : _CFBundleCopyLastPathComponent(bundle);
3147 if (CFBundleExecutableNotFoundError == code) {
3148 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
3149 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable couldn\\U2019t be located."), "NSFileNoSuchFileError");
3150 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError");
3151 } else if (CFBundleExecutableNotLoadableError == code) {
3152 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
3153 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable isn\\U2019t loadable."), "NSExecutableNotLoadableError");
3154 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError");
3155 } else if (CFBundleExecutableArchitectureMismatchError == code) {
3156 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");
3157 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl, CFSTR("The bundle doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError");
3158 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError");
3159 } else if (CFBundleExecutableRuntimeMismatchError == code) {
3160 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");
3161 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl, CFSTR("The bundle isn\\U2019t compatible with this application."), "NSExecutableRuntimeMismatchError");
3162 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError");
3163 } else if (CFBundleExecutableLoadError == code) {
3164 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");
3165 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError");
3166 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError");
3167 } else if (CFBundleExecutableLinkError == code) {
3168 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded."), "NSExecutableLinkError");
3169 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl, CFSTR("The bundle couldn\\U2019t be loaded."), "NSExecutableLinkError");
3170 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError");
3171 }
3172 if (descFormat) {
3173 desc = CFStringCreateWithFormat(allocator, NULL, descFormat, name);
3174 CFRelease(descFormat);
3175 }
3176 CFRelease(name);
3177 }
3178 if (bundlePath) {
3179 userInfoKeys[numKeys] = CFSTR("NSBundlePath");
3180 userInfoValues[numKeys] = bundlePath;
3181 numKeys++;
3182 }
3183 if (executablePath) {
3184 userInfoKeys[numKeys] = CFSTR("NSFilePath");
3185 userInfoValues[numKeys] = executablePath;
3186 numKeys++;
3187 }
3188 if (desc) {
3189 userInfoKeys[numKeys] = kCFErrorLocalizedDescriptionKey;
3190 userInfoValues[numKeys] = desc;
3191 numKeys++;
3192 }
3193 if (reason) {
3194 userInfoKeys[numKeys] = kCFErrorLocalizedFailureReasonKey;
3195 userInfoValues[numKeys] = reason;
3196 numKeys++;
3197 }
3198 if (suggestion) {
3199 userInfoKeys[numKeys] = kCFErrorLocalizedRecoverySuggestionKey;
3200 userInfoValues[numKeys] = suggestion;
3201 numKeys++;
3202 }
3203 if (debugString) {
3204 userInfoKeys[numKeys] = CFSTR("NSDebugDescription");
3205 userInfoValues[numKeys] = debugString;
3206 numKeys++;
3207 }
3208 error = CFErrorCreateWithUserInfoKeysAndValues(allocator, kCFErrorDomainCocoa, code, userInfoKeys, userInfoValues, numKeys);
3209 if (bundleURL) CFRelease(bundleURL);
3210 if (absoluteURL) CFRelease(absoluteURL);
3211 if (executableURL) CFRelease(executableURL);
3212 if (bundlePath) CFRelease(bundlePath);
3213 if (executablePath) CFRelease(executablePath);
3214 if (desc) CFRelease(desc);
3215 if (reason) CFRelease(reason);
3216 if (suggestion) CFRelease(suggestion);
3217 return error;
3218 }
3219
3220 CFErrorRef _CFBundleCreateError(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code) {
3221 allocator = _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator);
3222 return _CFBundleCreateErrorDebug(allocator, bundle, code, NULL);
3223 }
3224
3225 Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) {
3226 Boolean result = false;
3227 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
3228 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
3229
3230 __CFSpinLock(&(bundle->_bundleLoadingLock));
3231 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
3232 // make sure we know whether bundle is already loaded or not
3233 #if defined(BINARY_SUPPORT_DLFCN)
3234 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
3235 #elif defined(BINARY_SUPPORT_DYLD)
3236 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
3237 #endif /* BINARY_SUPPORT_DLFCN */
3238 #if defined(BINARY_SUPPORT_DYLD)
3239 // We might need to figure out what it is
3240 if (bundle->_binaryType == __CFBundleUnknownBinary) {
3241 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
3242 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
3243 }
3244 #endif /* BINARY_SUPPORT_DYLD */
3245 if (executableURL) CFRelease(executableURL);
3246
3247 if (bundle->_isLoaded) {
3248 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3249 // Remove from the scheduled unload set if we are there.
3250 __CFSpinLock(&CFBundleGlobalDataLock);
3251 #if defined(AVOID_WEAK_COLLECTIONS)
3252 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle);
3253 #else /* AVOID_WEAK_COLLECTIONS */
3254 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle];
3255 #endif /* AVOID_WEAK_COLLECTIONS */
3256 __CFSpinUnlock(&CFBundleGlobalDataLock);
3257 return true;
3258 }
3259
3260 // Unload bundles scheduled for unloading
3261 if (!_scheduledBundlesAreUnloading) {
3262 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3263 _CFBundleUnloadScheduledBundles();
3264 __CFSpinLock(&(bundle->_bundleLoadingLock));
3265 }
3266
3267 if (bundle->_isLoaded) {
3268 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3269 // Remove from the scheduled unload set if we are there.
3270 __CFSpinLock(&CFBundleGlobalDataLock);
3271 #if defined(AVOID_WEAK_COLLECTIONS)
3272 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle);
3273 #else /* AVOID_WEAK_COLLECTIONS */
3274 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle];
3275 #endif /* AVOID_WEAK_COLLECTIONS */
3276 __CFSpinUnlock(&CFBundleGlobalDataLock);
3277 return true;
3278 }
3279 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3280
3281 switch (bundle->_binaryType) {
3282 #if defined(BINARY_SUPPORT_DLFCN)
3283 case __CFBundleUnreadableBinary:
3284 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
3285 break;
3286 #endif /* BINARY_SUPPORT_DLFCN */
3287 #if defined(BINARY_SUPPORT_DYLD)
3288 case __CFBundleDYLDBundleBinary:
3289 #if defined(BINARY_SUPPORT_DLFCN)
3290 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
3291 #else /* BINARY_SUPPORT_DLFCN */
3292 result = _CFBundleDYLDLoadBundle(bundle, forceGlobal, subError);
3293 #endif /* BINARY_SUPPORT_DLFCN */
3294 break;
3295 case __CFBundleDYLDFrameworkBinary:
3296 #if defined(BINARY_SUPPORT_DLFCN)
3297 result = _CFBundleDlfcnLoadFramework(bundle, subError);
3298 #else /* BINARY_SUPPORT_DLFCN */
3299 result = _CFBundleDYLDLoadFramework(bundle, subError);
3300 #endif /* BINARY_SUPPORT_DLFCN */
3301 break;
3302 case __CFBundleDYLDExecutableBinary:
3303 if (error) {
3304 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
3305 } else {
3306 CFLog(__kCFLogBundle, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle);
3307 }
3308 break;
3309 #endif /* BINARY_SUPPORT_DYLD */
3310 #if defined(BINARY_SUPPORT_DLFCN)
3311 case __CFBundleUnknownBinary:
3312 case __CFBundleELFBinary:
3313 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError);
3314 break;
3315 #endif /* BINARY_SUPPORT_DLFCN */
3316 #if defined(BINARY_SUPPORT_DLL)
3317 case __CFBundleDLLBinary:
3318 result = _CFBundleDLLLoad(bundle, subError);
3319 break;
3320 #endif /* BINARY_SUPPORT_DLL */
3321 case __CFBundleNoBinary:
3322 if (error) {
3323 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
3324 } else {
3325 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for %@"), bundle);
3326 }
3327 break;
3328 default:
3329 if (error) {
3330 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
3331 } else {
3332 CFLog(__kCFLogBundle, CFSTR("Cannot recognize type of executable for %@"), bundle);
3333 }
3334 break;
3335 }
3336 if (result && bundle->_plugInData._isPlugIn) _CFBundlePlugInLoaded(bundle);
3337 if (!result && error) *error = localError;
3338 return result;
3339 }
3340
3341 Boolean CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, CFErrorRef *error) {
3342 return _CFBundleLoadExecutableAndReturnError(bundle, false, error);
3343 }
3344
3345 Boolean CFBundleLoadExecutable(CFBundleRef bundle) {
3346 return _CFBundleLoadExecutableAndReturnError(bundle, false, NULL);
3347 }
3348
3349 Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) {
3350 Boolean result = false;
3351 CFErrorRef localError = NULL;
3352 #if defined(BINARY_SUPPORT_DLFCN)
3353 CFErrorRef *subError = (error ? &localError : NULL);
3354 #endif
3355 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
3356
3357 __CFSpinLock(&(bundle->_bundleLoadingLock));
3358 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
3359 // make sure we know whether bundle is already loaded or not
3360 #if defined(BINARY_SUPPORT_DLFCN)
3361 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
3362 #elif defined(BINARY_SUPPORT_DYLD)
3363 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
3364 #endif /* BINARY_SUPPORT_DLFCN */
3365 #if defined(BINARY_SUPPORT_DYLD)
3366 // We might need to figure out what it is
3367 if (bundle->_binaryType == __CFBundleUnknownBinary) {
3368 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
3369 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
3370 }
3371 #endif /* BINARY_SUPPORT_DYLD */
3372 if (executableURL) CFRelease(executableURL);
3373
3374 if (bundle->_isLoaded) {
3375 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3376 return true;
3377 }
3378 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3379
3380 switch (bundle->_binaryType) {
3381 #if defined(BINARY_SUPPORT_DLFCN)
3382 case __CFBundleUnreadableBinary:
3383 result = _CFBundleDlfcnPreflight(bundle, subError);
3384 break;
3385 #endif /* BINARY_SUPPORT_DLFCN */
3386 #if defined(BINARY_SUPPORT_DYLD)
3387 case __CFBundleDYLDBundleBinary:
3388 result = true;
3389 #if defined(BINARY_SUPPORT_DLFCN)
3390 result = _CFBundleDlfcnPreflight(bundle, subError);
3391 #endif /* BINARY_SUPPORT_DLFCN */
3392 break;
3393 case __CFBundleDYLDFrameworkBinary:
3394 result = true;
3395 #if defined(BINARY_SUPPORT_DLFCN)
3396 result = _CFBundleDlfcnPreflight(bundle, subError);
3397 #endif /* BINARY_SUPPORT_DLFCN */
3398 break;
3399 case __CFBundleDYLDExecutableBinary:
3400 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
3401 break;
3402 #endif /* BINARY_SUPPORT_DYLD */
3403 #if defined(BINARY_SUPPORT_DLFCN)
3404 case __CFBundleUnknownBinary:
3405 case __CFBundleELFBinary:
3406 result = _CFBundleDlfcnPreflight(bundle, subError);
3407 break;
3408 #endif /* BINARY_SUPPORT_DLFCN */
3409 #if defined(BINARY_SUPPORT_DLL)
3410 case __CFBundleDLLBinary:
3411 result = true;
3412 break;
3413 #endif /* BINARY_SUPPORT_DLL */
3414 case __CFBundleNoBinary:
3415 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
3416 break;
3417 default:
3418 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
3419 break;
3420 }
3421 if (!result && error) *error = localError;
3422 return result;
3423 }
3424
3425 CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) {
3426 CFArrayRef result = NULL;
3427 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
3428 if (executableURL) {
3429 result = _CFBundleCopyArchitecturesForExecutable(executableURL);
3430 CFRelease(executableURL);
3431 }
3432 return result;
3433 }
3434
3435 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3436 static Boolean _CFBundleGetObjCImageInfo(CFBundleRef bundle, uint32_t *objcVersion, uint32_t *objcFlags) {
3437 Boolean retval = false;
3438 uint32_t localVersion = 0, localFlags = 0;
3439 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
3440 if (executableURL) {
3441 retval = _CFBundleGetObjCImageInfoForExecutable(executableURL, &localVersion, &localFlags);
3442 CFRelease(executableURL);
3443 }
3444 if (objcVersion) *objcVersion = localVersion;
3445 if (objcFlags) *objcFlags = localFlags;
3446 return retval;
3447 }
3448 #endif
3449
3450 void CFBundleUnloadExecutable(CFBundleRef bundle) {
3451 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
3452 if (!_scheduledBundlesAreUnloading) _CFBundleUnloadScheduledBundles();
3453
3454 if (!bundle->_isLoaded) return;
3455
3456 // Remove from the scheduled unload set if we are there.
3457 if (!_scheduledBundlesAreUnloading) __CFSpinLock(&CFBundleGlobalDataLock);
3458 #if defined(AVOID_WEAK_COLLECTIONS)
3459 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle);
3460 #else /* AVOID_WEAK_COLLECTIONS */
3461 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle];
3462 #endif /* AVOID_WEAK_COLLECTIONS */
3463 if (!_scheduledBundlesAreUnloading) __CFSpinUnlock(&CFBundleGlobalDataLock);
3464
3465 // Give the plugIn code a chance to realize this...
3466 _CFPlugInWillUnload(bundle);
3467
3468 __CFSpinLock(&(bundle->_bundleLoadingLock));
3469 if (!bundle->_isLoaded) {
3470 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3471 return;
3472 }
3473 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3474
3475 switch (bundle->_binaryType) {
3476 #if defined(BINARY_SUPPORT_DYLD)
3477 case __CFBundleDYLDBundleBinary:
3478 #if defined(BINARY_SUPPORT_DLFCN)
3479 if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle);
3480 #else /* BINARY_SUPPORT_DLFCN */
3481 _CFBundleDYLDUnloadBundle(bundle);
3482 #endif /* BINARY_SUPPORT_DLFCN */
3483 break;
3484 case __CFBundleDYLDFrameworkBinary:
3485 #if defined(BINARY_SUPPORT_DLFCN)
3486 if (bundle->_handleCookie && _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) _CFBundleDlfcnUnload(bundle);
3487 #endif /* BINARY_SUPPORT_DLFCN */
3488 break;
3489 #endif /* BINARY_SUPPORT_DYLD */
3490 #if defined(BINARY_SUPPORT_DLL)
3491 case __CFBundleDLLBinary:
3492 _CFBundleDLLUnload(bundle);
3493 break;
3494 #endif /* BINARY_SUPPORT_DLL */
3495 default:
3496 #if defined(BINARY_SUPPORT_DLFCN)
3497 if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle);
3498 #endif /* BINARY_SUPPORT_DLFCN */
3499 break;
3500 }
3501 if (!bundle->_isLoaded && bundle->_glueDict) {
3502 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle));
3503 CFRelease(bundle->_glueDict);
3504 bundle->_glueDict = NULL;
3505 }
3506 }
3507
3508 #if defined(AVOID_WEAK_COLLECTIONS)
3509
3510 __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) {
3511 __CFSpinLock(&CFBundleGlobalDataLock);
3512 if (!_bundlesToUnload) {
3513 CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks;
3514 nonRetainingCallbacks.retain = NULL;
3515 nonRetainingCallbacks.release = NULL;
3516 _bundlesToUnload = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingCallbacks);
3517 }
3518 CFSetAddValue(_bundlesToUnload, bundle);
3519 __CFSpinUnlock(&CFBundleGlobalDataLock);
3520 }
3521
3522 __private_extern__ void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) {
3523 __CFSpinLock(&CFBundleGlobalDataLock);
3524 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle);
3525 __CFSpinUnlock(&CFBundleGlobalDataLock);
3526 }
3527
3528 __private_extern__ void _CFBundleUnloadScheduledBundles(void) {
3529 __CFSpinLock(&CFBundleGlobalDataLock);
3530 if (_bundlesToUnload) {
3531 CFIndex i, c = CFSetGetCount(_bundlesToUnload);
3532 if (c > 0) {
3533 CFBundleRef *unloadThese = (CFBundleRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFBundleRef) * c, 0);
3534 CFSetGetValues(_bundlesToUnload, (const void **)unloadThese);
3535 _scheduledBundlesAreUnloading = true;
3536 for (i = 0; i < c; i++) {
3537 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
3538 CFBundleUnloadExecutable(unloadThese[i]);
3539 }
3540 _scheduledBundlesAreUnloading = false;
3541 CFAllocatorDeallocate(kCFAllocatorSystemDefault, unloadThese);
3542 }
3543 }
3544 __CFSpinUnlock(&CFBundleGlobalDataLock);
3545 }
3546
3547 #else /* AVOID_WEAK_COLLECTIONS */
3548
3549 __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) {
3550 __CFSpinLock(&CFBundleGlobalDataLock);
3551 if (!_bundlesToUnload) _bundlesToUnload = [[__CFHashTable alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory capacity:0];
3552 [_bundlesToUnload addObject:(id)bundle];
3553 __CFSpinUnlock(&CFBundleGlobalDataLock);
3554 }
3555
3556 __private_extern__ void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) {
3557 __CFSpinLock(&CFBundleGlobalDataLock);
3558 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle];
3559 __CFSpinUnlock(&CFBundleGlobalDataLock);
3560 }
3561
3562 __private_extern__ void _CFBundleUnloadScheduledBundles(void) {
3563 __CFSpinLock(&CFBundleGlobalDataLock);
3564 if (_bundlesToUnload && [_bundlesToUnload count] > 0) {
3565 CFIndex i, c;
3566 CFMutableArrayRef unloadThese = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3567 for (id value in _bundlesToUnload) CFArrayAppendValue(unloadThese, value);
3568 c = CFArrayGetCount(unloadThese);
3569 if (c > 0) {
3570 _scheduledBundlesAreUnloading = true;
3571 for (i = 0; i < c; i++) {
3572 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
3573 CFBundleUnloadExecutable((CFBundleRef)CFArrayGetValueAtIndex(unloadThese, i));
3574 }
3575 _scheduledBundlesAreUnloading = false;
3576 }
3577 CFRelease(unloadThese);
3578 }
3579 __CFSpinUnlock(&CFBundleGlobalDataLock);
3580 }
3581
3582 #endif /* AVOID_WEAK_COLLECTIONS */
3583
3584 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) {
3585 void *tvp = NULL;
3586 // Load if necessary
3587 if (!bundle->_isLoaded) {
3588 if (!CFBundleLoadExecutable(bundle)) return NULL;
3589 }
3590
3591 switch (bundle->_binaryType) {
3592 #if defined(BINARY_SUPPORT_DYLD)
3593 case __CFBundleDYLDBundleBinary:
3594 case __CFBundleDYLDFrameworkBinary:
3595 case __CFBundleDYLDExecutableBinary:
3596 #if defined(BINARY_SUPPORT_DLFCN)
3597 if (bundle->_handleCookie) return _CFBundleDlfcnGetSymbolByName(bundle, funcName);
3598 #else /* BINARY_SUPPORT_DLFCN */
3599 return _CFBundleDYLDGetSymbolByName(bundle, funcName);
3600 #endif /* BINARY_SUPPORT_DLFCN */
3601 break;
3602 #endif /* BINARY_SUPPORT_DYLD */
3603 #if defined(BINARY_SUPPORT_DLL)
3604 case __CFBundleDLLBinary:
3605 tvp = _CFBundleDLLGetSymbolByName(bundle, funcName);
3606 break;
3607 #endif /* BINARY_SUPPORT_DLL */
3608 default:
3609 #if defined(BINARY_SUPPORT_DLFCN)
3610 if (bundle->_handleCookie) return _CFBundleDlfcnGetSymbolByName(bundle, funcName);
3611 #endif /* BINARY_SUPPORT_DLFCN */
3612 break;
3613 }
3614 return tvp;
3615 }
3616
3617 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) {
3618 void *fp = NULL;
3619 // Load if necessary
3620 if (!bundle->_isLoaded) {
3621 if (!CFBundleLoadExecutable(bundle)) return NULL;
3622 }
3623 #if defined (BINARY_SUPPORT_DYLD) || defined (BINARY_SUPPORT_DLFCN)
3624 switch (bundle->_binaryType) {
3625 #if defined(BINARY_SUPPORT_DYLD)
3626 case __CFBundleDYLDBundleBinary:
3627 case __CFBundleDYLDFrameworkBinary:
3628 case __CFBundleDYLDExecutableBinary:
3629 #if defined(BINARY_SUPPORT_DLFCN)
3630 if (bundle->_handleCookie) fp = _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, funcName, true);
3631 #else /* BINARY_SUPPORT_DLFCN */
3632 fp = _CFBundleDYLDGetSymbolByNameWithSearch(bundle, funcName, true);
3633 #endif /* BINARY_SUPPORT_DLFCN */
3634 break;
3635 #endif /* BINARY_SUPPORT_DYLD */
3636 default:
3637 #if defined(BINARY_SUPPORT_DLFCN)
3638 if (bundle->_handleCookie) fp = _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, funcName, true);
3639 #endif /* BINARY_SUPPORT_DLFCN */
3640 break;
3641 }
3642 #endif /* BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */
3643 return fp;
3644 }
3645
3646 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) {
3647 SInt32 i, c;
3648
3649 if (!ftbl) return;
3650
3651 c = CFArrayGetCount(functionNames);
3652 for (i = 0; i < c; i++) ftbl[i] = CFBundleGetFunctionPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(functionNames, i));
3653 }
3654
3655 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) {
3656 SInt32 i, c;
3657
3658 if (!ftbl) return;
3659
3660 c = CFArrayGetCount(functionNames);
3661 for (i = 0; i < c; i++) ftbl[i] = _CFBundleGetCFMFunctionPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(functionNames, i));
3662 }
3663
3664 void *CFBundleGetDataPointerForName(CFBundleRef bundle, CFStringRef symbolName) {
3665 void *dp = NULL;
3666 // Load if necessary
3667 if (!bundle->_isLoaded && !CFBundleLoadExecutable(bundle)) return NULL;
3668
3669 switch (bundle->_binaryType) {
3670 #if defined(BINARY_SUPPORT_DYLD)
3671 case __CFBundleDYLDBundleBinary:
3672 case __CFBundleDYLDFrameworkBinary:
3673 case __CFBundleDYLDExecutableBinary:
3674 #if defined(BINARY_SUPPORT_DLFCN)
3675 if (bundle->_handleCookie) dp = _CFBundleDlfcnGetSymbolByName(bundle, symbolName);
3676 #else /* BINARY_SUPPORT_DLFCN */
3677 dp = _CFBundleDYLDGetSymbolByName(bundle, symbolName);
3678 #endif /* BINARY_SUPPORT_DLFCN */
3679 break;
3680 #endif /* BINARY_SUPPORT_DYLD */
3681 #if defined(BINARY_SUPPORT_DLL)
3682 case __CFBundleDLLBinary:
3683 /* MF:!!! Handle this someday */
3684 break;
3685 #endif /* BINARY_SUPPORT_DLL */
3686 default:
3687 #if defined(BINARY_SUPPORT_DLFCN)
3688 if (bundle->_handleCookie) dp = _CFBundleDlfcnGetSymbolByName(bundle, symbolName);
3689 #endif /* BINARY_SUPPORT_DLFCN */
3690 break;
3691 }
3692 return dp;
3693 }
3694
3695 void CFBundleGetDataPointersForNames(CFBundleRef bundle, CFArrayRef symbolNames, void *stbl[]) {
3696 SInt32 i, c;
3697
3698 if (!stbl) return;
3699
3700 c = CFArrayGetCount(symbolNames);
3701 for (i = 0; i < c; i++) stbl[i] = CFBundleGetDataPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(symbolNames, i));
3702 }
3703
3704 __private_extern__ _CFResourceData *__CFBundleGetResourceData(CFBundleRef bundle) {
3705 return &(bundle->_resourceData);
3706 }
3707
3708 CFPlugInRef CFBundleGetPlugIn(CFBundleRef bundle) {
3709 return (bundle->_plugInData._isPlugIn) ? (CFPlugInRef)bundle : NULL;
3710 }
3711
3712 __private_extern__ _CFPlugInData *__CFBundleGetPlugInData(CFBundleRef bundle) {
3713 return &(bundle->_plugInData);
3714 }
3715
3716 __private_extern__ Boolean _CFBundleCouldBeBundle(CFURLRef url) {
3717 Boolean result = false;
3718 Boolean exists;
3719 SInt32 mode;
3720 if (_CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) result = (exists && (mode & S_IFMT) == S_IFDIR && (mode & 0444) != 0);
3721 return result;
3722 }
3723
3724 #define LENGTH_OF(A) (sizeof(A) / sizeof(A[0]))
3725
3726 //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/
3727 static CFURLRef __CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath, Boolean permissive) {
3728 // 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.
3729 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3730 #elif 0 && DEPLOYMENT_TARGET_WINDOWS
3731 UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3732 UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3733 UniChar executablesToSystemFrameworksPathBuff[MAX_PATH+1] = { 0 };
3734 SHGetFolderPathAndSubDirW(NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0 /* SHGFP_TYPE_CURRENT */, L"Apple\\Mobile Device Support\\Frameworks", executablesToSystemFrameworksPathBuff);
3735 UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
3736 #elif DEPLOYMENT_TARGET_WINDOWS
3737 UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3738 UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'};
3739 UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'};
3740 #else
3741 #error Unknown or unspecified DEPLOYMENT_TARGET
3742 #endif
3743 UniChar pathBuff[CFMaxPathSize] = {0};
3744 UniChar nameBuff[CFMaxPathSize] = {0};
3745 CFIndex length, nameStart, nameLength, savedLength;
3746 CFMutableStringRef cheapStr = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, NULL);
3747 CFURLRef bundleURL = NULL;
3748
3749 length = CFStringGetLength(executablePath);
3750 if (length > CFMaxPathSize) length = CFMaxPathSize;
3751 CFStringGetCharacters(executablePath, CFRangeMake(0, length), pathBuff);
3752
3753 // Save the name in nameBuff
3754 length = _CFLengthAfterDeletingPathExtension(pathBuff, length);
3755 nameStart = _CFStartOfLastPathComponent(pathBuff, length);
3756 nameLength = length - nameStart;
3757 memmove(nameBuff, &(pathBuff[nameStart]), nameLength * sizeof(UniChar));
3758
3759 // Strip the name from pathBuff
3760 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
3761 savedLength = length;
3762
3763 #if DEPLOYMENT_TARGET_WINDOWS
3764 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
3765 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, LENGTH_OF(executablesToFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
3766 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
3767 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
3768 if (!_CFBundleCouldBeBundle(bundleURL)) {
3769 CFRelease(bundleURL);
3770 bundleURL = NULL;
3771 }
3772 }
3773 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
3774 if (!bundleURL) {
3775 length = savedLength;
3776 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, LENGTH_OF(executablesToPrivateFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
3777 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
3778 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
3779 if (!_CFBundleCouldBeBundle(bundleURL)) {
3780 CFRelease(bundleURL);
3781 bundleURL = NULL;
3782 }
3783 }
3784 }
3785
3786 #elif 0 && DEPLOYMENT_TARGET_WINDOWS
3787 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
3788 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, LENGTH_OF(executablesToFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
3789 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
3790 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
3791 if (!_CFBundleCouldBeBundle(bundleURL)) {
3792 CFRelease(bundleURL);
3793 bundleURL = NULL;
3794 }
3795 }
3796 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
3797 if (!bundleURL) {
3798 length = savedLength;
3799 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, LENGTH_OF(executablesToPrivateFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
3800 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
3801 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
3802 if (!_CFBundleCouldBeBundle(bundleURL)) {
3803 CFRelease(bundleURL);
3804 bundleURL = NULL;
3805 }
3806 }
3807 }
3808 // * (Windows-only) Next check the \Program Files\Apple\Mobile Device Support\Frameworks directory
3809 if (!bundleURL) {
3810 length = 0;
3811 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToSystemFrameworksPathBuff, wcslen(executablesToSystemFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) {
3812 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
3813 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
3814 if (!_CFBundleCouldBeBundle(bundleURL)) {
3815 CFRelease(bundleURL);
3816 bundleURL = NULL;
3817 }
3818 }
3819 }
3820 #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
3821 #else
3822 #error Unknown or unspecified DEPLOYMENT_TARGET
3823 #endif
3824 // * Finally check the executable inside the framework case.
3825 if (!bundleURL) {
3826 length = savedLength;
3827 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
3828
3829 CFStringRef name = permissive ? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, (const char *)nameBuff);
3830
3831 while (length > 0) {
3832 CFIndex curStart = _CFStartOfLastPathComponent(pathBuff, length);
3833 if (curStart >= length) break;
3834 CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[curStart]), length - curStart, CFMaxPathSize - curStart);
3835 if (!permissive && CFEqual(cheapStr, _CFBundleResourcesDirectoryName)) break;
3836 if (CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName1) || CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName2)) {
3837 if (!permissive) {
3838 CFIndex fmwkStart = _CFStartOfLastPathComponent(pathBuff, length);
3839 CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[fmwkStart]), length - fmwkStart, CFMaxPathSize - fmwkStart);
3840 }
3841 if (permissive || CFStringHasPrefix(cheapStr, name)) {
3842 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
3843 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
3844
3845 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
3846 if (!_CFBundleCouldBeBundle(bundleURL)) {
3847 CFRelease(bundleURL);
3848 bundleURL = NULL;
3849 }
3850 break;
3851 }
3852 } else if (CFStringHasSuffix(cheapStr, CFSTR(".framework")) && (permissive || CFStringHasPrefix(cheapStr, name))) {
3853 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
3854 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true);
3855 if (!_CFBundleCouldBeBundle(bundleURL)) {
3856 CFRelease(bundleURL);
3857 bundleURL = NULL;
3858 }
3859 break;
3860 }
3861 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
3862 }
3863 if (!permissive) CFRelease(name);
3864 }
3865 CFStringSetExternalCharactersNoCopy(cheapStr, NULL, 0, 0);
3866 CFRelease(cheapStr);
3867
3868 return bundleURL;
3869 }
3870
3871 //SPI version; separated out to minimize linkage changes
3872 CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath) {
3873 return __CFBundleCopyFrameworkURLForExecutablePath(executablePath, false);
3874 }
3875
3876 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath) {
3877 // This finds the bundle for the given path.
3878 // If an image path corresponds to a bundle, we see if there is already a bundle instance. If there is and it is NOT in the _dynamicBundles array, it is added to the staticBundles. Do not add the main bundle to the list here.
3879 CFBundleRef bundle;
3880 CFURLRef curURL = __CFBundleCopyFrameworkURLForExecutablePath(imagePath, true);
3881 Boolean createdBundle = false;
3882
3883 if (curURL) {
3884 bundle = _CFBundleCopyBundleForURL(curURL, true);
3885 if (!bundle) {
3886 // Ensure bundle exists by creating it if necessary
3887 // NB doFinalProcessing must be false here, see below
3888 bundle = _CFBundleCreate(kCFAllocatorSystemDefault, curURL, true, false);
3889 createdBundle = true;
3890 }
3891 if (bundle) {
3892 __CFSpinLock(&(bundle->_bundleLoadingLock));
3893 if (!bundle->_isLoaded) {
3894 // 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)
3895 #if defined(BINARY_SUPPORT_DLFCN)
3896 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle);
3897 #elif defined(BINARY_SUPPORT_DYLD)
3898 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle);
3899 #endif /* BINARY_SUPPORT_DLFCN */
3900 #if defined(BINARY_SUPPORT_DYLD)
3901 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
3902 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true;
3903 #endif /* BINARY_SUPPORT_DYLD */
3904 #if LOG_BUNDLE_LOAD
3905 if (!bundle->_isLoaded) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle, bundle->_handleCookie, bundle->_imageCookie, bundle->_connectionCookie);
3906 #endif /* LOG_BUNDLE_LOAD */
3907 bundle->_isLoaded = true;
3908 }
3909 __CFSpinUnlock(&(bundle->_bundleLoadingLock));
3910 if (createdBundle) {
3911 // Perform delayed final processing steps.
3912 // This must be done after _isLoaded has been set, for security reasons (3624341).
3913 _CFBundleCheckWorkarounds(bundle);
3914 if (_CFBundleNeedsInitPlugIn(bundle)) {
3915 __CFSpinUnlock(&CFBundleGlobalDataLock);
3916 _CFBundleInitPlugIn(bundle);
3917 __CFSpinLock(&CFBundleGlobalDataLock);
3918 }
3919 } else {
3920 // Release the bundle if we did not create it here
3921 CFRelease(bundle);
3922 }
3923 }
3924 CFRelease(curURL);
3925 }
3926 }
3927
3928 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths) {
3929 // This finds the bundles for the given paths.
3930 // 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).
3931 CFIndex i, imagePathCount = CFArrayGetCount(imagePaths);
3932 for (i = 0; i < imagePathCount; i++) _CFBundleEnsureBundleExistsForImagePath((CFStringRef)CFArrayGetValueAtIndex(imagePaths, i));
3933 }
3934
3935 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint) {
3936 CFArrayRef imagePaths = NULL;
3937 // Tickle the main bundle into existence
3938 (void)_CFBundleGetMainBundleAlreadyLocked();
3939 #if defined(BINARY_SUPPORT_DYLD)
3940 imagePaths = _CFBundleDYLDCopyLoadedImagePathsForHint(hint);
3941 #endif /* BINARY_SUPPORT_DYLD */
3942 if (imagePaths) {
3943 _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
3944 CFRelease(imagePaths);
3945 }
3946 }
3947
3948 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
3949 // 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.
3950 CFArrayRef imagePaths = NULL;
3951 // Tickle the main bundle into existence
3952 (void)_CFBundleGetMainBundleAlreadyLocked();
3953
3954 #if defined(BINARY_SUPPORT_DLL)
3955 // Dont know how to find static bundles for DLLs
3956 #endif /* BINARY_SUPPORT_DLL */
3957
3958 #if defined(BINARY_SUPPORT_DYLD)
3959 imagePaths = _CFBundleDYLDCopyLoadedImagePathsIfChanged();
3960 #endif /* BINARY_SUPPORT_DYLD */
3961 if (imagePaths) {
3962 _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
3963 CFRelease(imagePaths);
3964 }
3965 }
3966
3967 CFArrayRef CFBundleGetAllBundles(void) {
3968 // To answer this properly, we have to have created the static bundles!
3969 #if !defined(AVOID_WEAK_COLLECTIONS)
3970 static CFMutableArrayRef externalAllBundles = NULL;
3971 #endif /* AVOID_WEAK_COLLECTIONS */
3972 CFArrayRef bundles;
3973 __CFSpinLock(&CFBundleGlobalDataLock);
3974 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
3975 #if defined(AVOID_WEAK_COLLECTIONS)
3976 bundles = _allBundles;
3977 #else /* AVOID_WEAK_COLLECTIONS */
3978 if (!externalAllBundles) {
3979 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
3980 nonRetainingArrayCallbacks.retain = NULL;
3981 nonRetainingArrayCallbacks.release = NULL;
3982 externalAllBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks);
3983 }
3984 CFArrayRemoveAllValues(externalAllBundles);
3985 for (id value in _allBundles) CFArrayAppendValue(externalAllBundles, value);
3986 bundles = externalAllBundles;
3987 #endif /* AVOID_WEAK_COLLECTIONS */
3988 __CFSpinUnlock(&CFBundleGlobalDataLock);
3989 return bundles;
3990 }
3991
3992 CF_EXPORT CFArrayRef _CFBundleCopyAllBundles(void) {
3993 // To answer this properly, we have to have created the static bundles!
3994 __CFSpinLock(&CFBundleGlobalDataLock);
3995 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
3996 #if defined(AVOID_WEAK_COLLECTIONS)
3997 CFArrayRef bundles = CFArrayCreateCopy(kCFAllocatorSystemDefault, _allBundles);
3998 #else /* AVOID_WEAK_COLLECTIONS */
3999 CFMutableArrayRef bundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
4000 for (id value in _allBundles) CFArrayAppendValue(bundles, value);
4001 #endif /* AVOID_WEAK_COLLECTIONS */
4002 __CFSpinUnlock(&CFBundleGlobalDataLock);
4003 return bundles;
4004 }
4005
4006 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle) {
4007 return bundle->_version;
4008 }
4009
4010 CF_EXPORT CFURLRef _CFBundleCopyInfoPlistURL(CFBundleRef bundle) {
4011 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
4012 CFURLRef url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey);
4013 if (!url) url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleRawInfoPlistURLKey);
4014 return (url ? (CFURLRef)CFRetain(url) : NULL);
4015 }
4016
4017 CF_EXPORT CFURLRef _CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {
4018 return CFBundleCopyPrivateFrameworksURL(bundle);
4019 }
4020
4021 CF_EXPORT CFURLRef CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {
4022 CFURLRef result = NULL;
4023
4024 if (1 == bundle->_version) {
4025 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase1, bundle->_url);
4026 } else if (2 == bundle->_version) {
4027 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase2, bundle->_url);
4028 } else {
4029 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase0, bundle->_url);
4030 }
4031 return result;
4032 }
4033
4034 CF_EXPORT CFURLRef _CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {
4035 return CFBundleCopySharedFrameworksURL(bundle);
4036 }
4037
4038 CF_EXPORT CFURLRef CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {
4039 CFURLRef result = NULL;
4040
4041 if (1 == bundle->_version) {
4042 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase1, bundle->_url);
4043 } else if (2 == bundle->_version) {
4044 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase2, bundle->_url);
4045 } else {
4046 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase0, bundle->_url);
4047 }
4048 return result;
4049 }
4050
4051 CF_EXPORT CFURLRef _CFBundleCopySharedSupportURL(CFBundleRef bundle) {
4052 return CFBundleCopySharedSupportURL(bundle);
4053 }
4054
4055 CF_EXPORT CFURLRef CFBundleCopySharedSupportURL(CFBundleRef bundle) {
4056 CFURLRef result = NULL;
4057
4058 if (1 == bundle->_version) {
4059 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase1, bundle->_url);
4060 } else if (2 == bundle->_version) {
4061 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase2, bundle->_url);
4062 } else {
4063 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase0, bundle->_url);
4064 }
4065 return result;
4066 }
4067
4068 __private_extern__ CFURLRef _CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {
4069 return CFBundleCopyBuiltInPlugInsURL(bundle);
4070 }
4071
4072 CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {
4073 CFURLRef result = NULL, alternateResult = NULL;
4074
4075 CFAllocatorRef alloc = CFGetAllocator(bundle);
4076 if (1 == bundle->_version) {
4077 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase1, bundle->_url);
4078 } else if (2 == bundle->_version) {
4079 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase2, bundle->_url);
4080 } else {
4081 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase0, bundle->_url);
4082 }
4083 if (!result || !_urlExists(result)) {
4084 if (1 == bundle->_version) {
4085 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase1, bundle->_url);
4086 } else if (2 == bundle->_version) {
4087 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase2, bundle->_url);
4088 } else {
4089 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase0, bundle->_url);
4090 }
4091 if (alternateResult && _urlExists(alternateResult)) {
4092 if (result) CFRelease(result);
4093 result = alternateResult;
4094 } else {
4095 if (alternateResult) CFRelease(alternateResult);
4096 }
4097 }
4098 return result;
4099 }
4100
4101 #if defined(BINARY_SUPPORT_DYLD)
4102
4103 __private_extern__ CFArrayRef _CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint) {
4104 uint32_t i, numImages = _dyld_image_count();
4105 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
4106 CFRange range = CFRangeMake(0, CFStringGetLength(hint)), altRange = CFRangeMake(0, 0), testRange = CFRangeMake(0, 0);
4107 const char *processPath = _CFProcessPath();
4108 const void *mhp = (const void *)_NSGetMachExecuteHeader();
4109
4110 if (range.length > 14) {
4111 // handle some common variations on framework bundle identifiers
4112 if (CFStringFindWithOptions(hint, CFSTR(".framework"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) {
4113 // identifier has .framework appended
4114 altRange.length = testRange.location;
4115 } else if (CFStringFindWithOptions(hint, CFSTR("framework"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) {
4116 // identifier has Framework appended
4117 altRange.length = testRange.location;
4118 } else if (CFStringFindWithOptions(hint, CFSTR("fw"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) {
4119 // identifier has FW appended
4120 altRange.length = testRange.location;
4121 }
4122 }
4123 for (i = 0; i < numImages; i++) {
4124 const char *curName = _dyld_get_image_name(i), *lastComponent = NULL;
4125 if (curName && (!processPath || 0 != strcmp(curName, processPath)) && mhp != (void *)_dyld_get_image_header(i)) lastComponent = strrchr(curName, '/');
4126 if (lastComponent) {
4127 CFStringRef str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, lastComponent + 1);
4128 if (str) {
4129 if (CFStringFindWithOptions(hint, str, range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL) || (altRange.length > 0 && CFStringFindWithOptions(hint, str, altRange, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL))) {
4130 CFStringRef curStr = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, curName);
4131 if (curStr) {
4132 CFArrayAppendValue(result, curStr);
4133 CFRelease(curStr);
4134 }
4135 }
4136 CFRelease(str);
4137 }
4138 }
4139 }
4140 return result;
4141 }
4142
4143 static char *_cleanedPathForPath(const char *curName) {
4144 char *thePath = strdup(curName);
4145 if (thePath) {
4146 // We are going to process the buffer replacing all "/./" and "//" with "/"
4147 CFIndex srcIndex = 0, dstIndex = 0;
4148 CFIndex len = strlen(thePath);
4149 for (srcIndex=0; srcIndex<len; srcIndex++) {
4150 thePath[dstIndex] = thePath[srcIndex];
4151 dstIndex++;
4152 while (srcIndex < len-1 && thePath[srcIndex] == '/' && (thePath[srcIndex+1] == '/' || (thePath[srcIndex+1] == '.' && srcIndex < len-2 && thePath[srcIndex+2] == '/'))) srcIndex += (thePath[srcIndex+1] == '/' ? 1 : 2);
4153 }
4154 thePath[dstIndex] = 0;
4155 }
4156 return thePath;
4157 }
4158
4159 __private_extern__ CFArrayRef _CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
4160 // 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.
4161 uint32_t i, numImages = _dyld_image_count();
4162 CFMutableArrayRef result = NULL;
4163 static uint32_t _cachedDYLDImageCount = -1;
4164
4165 if (numImages != _cachedDYLDImageCount) {
4166 const char *curName;
4167 char *cleanedCurName = NULL;
4168 CFStringRef curStr;
4169 const char *processPath = _CFProcessPath();
4170 const void *mhp = (const void *)_NSGetMachExecuteHeader();
4171
4172 result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks);
4173
4174 for (i = 0; i < numImages; i++) {
4175 curName = _dyld_get_image_name(i);
4176 if (curName && i == 0) cleanedCurName = _cleanedPathForPath(curName);
4177 if (curName && (!processPath || 0 != strcmp(curName, processPath)) && (!processPath || !cleanedCurName || 0 != strcmp(cleanedCurName, processPath)) && mhp != (void *)_dyld_get_image_header(i)) {
4178 curStr = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, curName);
4179 if (curStr) {
4180 CFArrayAppendValue(result, curStr);
4181 CFRelease(curStr);
4182 }
4183 }
4184 if (cleanedCurName) {
4185 free(cleanedCurName);
4186 cleanedCurName = NULL;
4187 }
4188 }
4189 _cachedDYLDImageCount = numImages;
4190 }
4191 return result;
4192 }
4193
4194 static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p) {
4195 CFStringRef result = NULL;
4196 #if defined(USE_DYLD_PRIV)
4197 const char *name = dyld_image_path_containing_address(p);
4198 if (name) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, name);
4199 #else /* USE_DYLD_PRIV */
4200 if (!result) {
4201 uint32_t i, j, n = _dyld_image_count();
4202 Boolean foundit = false;
4203 const char *name;
4204 #if __LP64__
4205 #define MACH_HEADER_TYPE struct mach_header_64
4206 #define MACH_SEGMENT_CMD_TYPE struct segment_command_64
4207 #define MACH_SEGMENT_FLAVOR LC_SEGMENT_64
4208 #else
4209 #define MACH_HEADER_TYPE struct mach_header
4210 #define MACH_SEGMENT_CMD_TYPE struct segment_command
4211 #define MACH_SEGMENT_FLAVOR LC_SEGMENT
4212 #endif
4213 for (i = 0; !foundit && i < n; i++) {
4214 const MACH_HEADER_TYPE *mh = (const MACH_HEADER_TYPE *)_dyld_get_image_header(i);
4215 uintptr_t addr = (uintptr_t)p - _dyld_get_image_vmaddr_slide(i);
4216 if (mh) {
4217 struct load_command *lc = (struct load_command *)((char *)mh + sizeof(MACH_HEADER_TYPE));
4218 for (j = 0; !foundit && j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) {
4219 if (MACH_SEGMENT_FLAVOR == lc->cmd && ((MACH_SEGMENT_CMD_TYPE *)lc)->vmaddr <= addr && addr < ((MACH_SEGMENT_CMD_TYPE *)lc)->vmaddr + ((MACH_SEGMENT_CMD_TYPE *)lc)->vmsize) {
4220 foundit = true;
4221 name = _dyld_get_image_name(i);
4222 if (name) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, name);
4223 }
4224 }
4225 }
4226 }
4227 #undef MACH_HEADER_TYPE
4228 #undef MACH_SEGMENT_CMD_TYPE
4229 #undef MACH_SEGMENT_FLAVOR
4230 }
4231 #endif /* USE_DYLD_PRIV */
4232 #if LOG_BUNDLE_LOAD
4233 printf("dyld image path for pointer %p is %p\n", p, result);
4234 #endif /* LOG_BUNDLE_LOAD */
4235 return result;
4236 }
4237
4238 #if !defined(BINARY_SUPPORT_DLFCN)
4239
4240 static const void *__CFBundleDYLDFindImage(char *buff) {
4241 const void *header = NULL;
4242 uint32_t i, numImages = _dyld_image_count(), numMatches = 0;
4243 const char *curName, *p, *q;
4244
4245 for (i = 0; !header && i < numImages; i++) {
4246 curName = _dyld_get_image_name(i);
4247 if (curName && 0 == strncmp(curName, buff, CFMaxPathSize)) {
4248 header = _dyld_get_image_header(i);
4249 numMatches = 1;
4250 }
4251 }
4252 if (!header) {
4253 for (i = 0; i < numImages; i++) {
4254 curName = _dyld_get_image_name(i);
4255 if (curName) {
4256 for (p = buff, q = curName; *p && *q && (q - curName < CFMaxPathSize); p++, q++) {
4257 if (*p != *q && (q - curName > 11) && 0 == strncmp(q - 11, ".framework/Versions/", 20) && *(q + 9) && '/' == *(q + 10)) q += 11;
4258 else if (*p != *q && (q - curName > 12) && 0 == strncmp(q - 12, ".framework/Versions/", 20) && *(q + 8) && '/' == *(q + 9)) q += 10;
4259 if (*p != *q) break;
4260 }
4261 if (*p == *q) {
4262 header = _dyld_get_image_header(i);
4263 numMatches++;
4264 }
4265 }
4266 }
4267 }
4268 return (numMatches == 1) ? header : NULL;
4269 }
4270
4271 __private_extern__ Boolean _CFBundleDYLDCheckLoaded(CFBundleRef bundle) {
4272 if (!bundle->_isLoaded) {
4273 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
4274 char buff[CFMaxPathSize];
4275
4276 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
4277 const void *header = __CFBundleDYLDFindImage(buff);
4278 if (header) {
4279 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
4280 if (!bundle->_imageCookie) {
4281 bundle->_imageCookie = header;
4282 #if LOG_BUNDLE_LOAD
4283 printf("dyld check load bundle %p, find %s getting image %p\n", bundle, buff, bundle->_imageCookie);
4284 #endif /* LOG_BUNDLE_LOAD */
4285 }
4286 bundle->_isLoaded = true;
4287 } else {
4288 #if LOG_BUNDLE_LOAD
4289 printf("dyld check load bundle %p, find %s no image\n", bundle, buff);
4290 #endif /* LOG_BUNDLE_LOAD */
4291 }
4292 }
4293 if (executableURL) CFRelease(executableURL);
4294 }
4295 return bundle->_isLoaded;
4296 }
4297
4298 __private_extern__ Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) {
4299 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
4300 NSLinkEditErrors c = NSLinkEditUndefinedError;
4301 int errorNumber = 0;
4302 const char *fileName = NULL;
4303 const char *errorString = NULL;
4304
4305 if (!bundle->_isLoaded) {
4306 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
4307 char buff[CFMaxPathSize];
4308
4309 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
4310 NSObjectFileImage image;
4311 NSObjectFileImageReturnCode retCode = NSCreateObjectFileImageFromFile(buff, &image);
4312 #if LOG_BUNDLE_LOAD
4313 printf("dyld load bundle %p, create image of %s returns image %p retcode %d\n", bundle, buff, image, retCode);
4314 #endif /* LOG_BUNDLE_LOAD */
4315 if (retCode == NSObjectFileImageSuccess) {
4316 uint32_t options = forceGlobal ? NSLINKMODULE_OPTION_RETURN_ON_ERROR : (NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
4317 NSModule module = NSLinkModule(image, buff, options);
4318 #if LOG_BUNDLE_LOAD
4319 printf("dyld load bundle %p, link module of %s options 0x%x returns module %p image %p\n", bundle, buff, options, module, image);
4320 #endif /* LOG_BUNDLE_LOAD */
4321 if (module) {
4322 bundle->_imageCookie = image;
4323 bundle->_moduleCookie = module;
4324 bundle->_isLoaded = true;
4325 } else {
4326 NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
4327 if (error) {
4328 #if defined(BINARY_SUPPORT_DLFCN)
4329 _CFBundleDlfcnPreflight(bundle, subError);
4330 #endif /* BINARY_SUPPORT_DLFCN */
4331 if (!localError) {
4332 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("error code %d, error number %d (%@)"), c, errorNumber, tempString);
4333 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString);
4334 if (tempString) CFRelease(tempString);
4335 if (debugString) CFRelease(debugString);
4336 }
4337 } else {
4338 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, fileName);
4339 CFLog(__kCFLogBundle, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString, c, errorNumber, tempString);
4340 if (tempString) CFRelease(tempString);
4341 if (executableString) CFRelease(executableString);
4342 }
4343 (void)NSDestroyObjectFileImage(image);
4344 }
4345 } else {
4346 if (error) {
4347 if (retCode == NSObjectFileImageArch) {
4348 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableArchitectureMismatchError);
4349 } else if (retCode == NSObjectFileImageInappropriateFile) {
4350 Boolean hasRuntimeMismatch = false;
4351 uint32_t mainFlags = 0, bundleFlags = 0;
4352 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) {
4353 if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true;
4354 }
4355 if (hasRuntimeMismatch) {
4356 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableRuntimeMismatchError);
4357 } else {
4358 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError);
4359 }
4360 } else {
4361 #if defined(BINARY_SUPPORT_DLFCN)
4362 _CFBundleDlfcnPreflight(bundle, subError);
4363 #endif /* BINARY_SUPPORT_DLFCN */
4364 if (!localError) {
4365 CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("dyld returns %d"), retCode);
4366 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString);
4367 CFRelease(debugString);
4368 }
4369 }
4370 } else {
4371 CFLog(__kCFLogBundle, CFSTR("dyld returns %d when trying to load %@"), retCode, executableURL);
4372 }
4373 }
4374 } else {
4375 if (error) {
4376 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
4377 } else {
4378 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
4379 }
4380 }
4381 if (executableURL) CFRelease(executableURL);
4382 }
4383 if (!bundle->_isLoaded && error) *error = localError;
4384 return bundle->_isLoaded;
4385 }
4386
4387 __private_extern__ Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle, CFErrorRef *error) {
4388 // !!! Framework loading should be better. Can't unload frameworks.
4389 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
4390 NSLinkEditErrors c = NSLinkEditUndefinedError;
4391 int errorNumber = 0;
4392 const char *fileName = NULL;
4393 const char *errorString = NULL;
4394
4395 if (!bundle->_isLoaded) {
4396 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
4397 char buff[CFMaxPathSize];
4398
4399 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
4400 void *image = (void *)NSAddImage(buff, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
4401 #if LOG_BUNDLE_LOAD
4402 printf("dyld load framework %p, add image of %s returns image %p\n", bundle, buff, image);
4403 #endif /* LOG_BUNDLE_LOAD */
4404 if (image) {
4405 bundle->_imageCookie = image;
4406 bundle->_isLoaded = true;
4407 } else {
4408 NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
4409 if (error) {
4410 #if defined(BINARY_SUPPORT_DLFCN)
4411 _CFBundleDlfcnPreflight(bundle, subError);
4412 #endif /* BINARY_SUPPORT_DLFCN */
4413 if (!localError) {
4414 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("error code %d, error number %d (%@)"), c, errorNumber, tempString);
4415 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString);
4416 if (tempString) CFRelease(tempString);
4417 if (debugString) CFRelease(debugString);
4418 }
4419 } else {
4420 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, fileName);
4421 CFLog(__kCFLogBundle, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString, c, errorNumber, tempString);
4422 if (tempString) CFRelease(tempString);
4423 if (executableString) CFRelease(executableString);
4424 }
4425 }
4426 } else {
4427 if (error) {
4428 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
4429 } else {
4430 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
4431 }
4432 }
4433 if (executableURL) CFRelease(executableURL);
4434 }
4435 if (!bundle->_isLoaded && error) *error = localError;
4436 return bundle->_isLoaded;
4437 }
4438
4439 __private_extern__ void _CFBundleDYLDUnloadBundle(CFBundleRef bundle) {
4440 if (bundle->_isLoaded) {
4441 #if LOG_BUNDLE_LOAD
4442 printf("dyld unload bundle %p, handle %p module %p image %p\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie);
4443 #endif /* LOG_BUNDLE_LOAD */
4444 if (bundle->_moduleCookie && !NSUnLinkModule((NSModule)(bundle->_moduleCookie), NSUNLINKMODULE_OPTION_NONE)) {
4445 CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle);
4446 } else {
4447 if (bundle->_moduleCookie && bundle->_imageCookie) (void)NSDestroyObjectFileImage((NSObjectFileImage)(bundle->_imageCookie));
4448 bundle->_connectionCookie = bundle->_handleCookie = NULL;
4449 bundle->_imageCookie = bundle->_moduleCookie = NULL;
4450 bundle->_isLoaded = false;
4451 }
4452 }
4453 }
4454
4455 __private_extern__ void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {
4456 return _CFBundleDYLDGetSymbolByNameWithSearch(bundle, symbolName, false);
4457 }
4458
4459 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) {
4460 void *result = NULL;
4461 char buff[1026];
4462 NSSymbol symbol = NULL;
4463
4464 buff[0] = '_';
4465 if (CFStringGetCString(symbolName, &(buff[1]), 1024, kCFStringEncodingUTF8)) {
4466 if (bundle->_moduleCookie) {
4467 symbol = NSLookupSymbolInModule((NSModule)(bundle->_moduleCookie), buff);
4468 } else if (bundle->_imageCookie) {
4469 symbol = NSLookupSymbolInImage(bundle->_imageCookie, buff, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
4470 }
4471 if (!symbol && !bundle->_moduleCookie && (!bundle->_imageCookie || globalSearch)) {
4472 char hintBuff[1026];
4473 CFStringRef executableName = _CFBundleCopyExecutableName(bundle, NULL, NULL);
4474 hintBuff[0] = '\0';
4475 if (executableName) {
4476 if (!CFStringGetCString(executableName, hintBuff, 1024, kCFStringEncodingUTF8)) hintBuff[0] = '\0';
4477 CFRelease(executableName);
4478 }
4479 // Nowdays, NSIsSymbolNameDefinedWithHint() and NSLookupAndBindSymbolWithHint()
4480 // are identical, except the first just returns a bool, so checking with the
4481 // Is function first just causes a redundant lookup.
4482 // This returns NULL on failure.
4483 symbol = NSLookupAndBindSymbolWithHint(buff, hintBuff);
4484 }
4485 if (symbol) result = NSAddressOfSymbol(symbol);
4486 #if defined(DEBUG)
4487 if (!result) CFLog(__kCFLogBundle, CFSTR("dyld cannot find symbol %@ in %@"), symbolName, bundle);
4488 #endif /* DEBUG */
4489 #if LOG_BUNDLE_LOAD
4490 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);
4491 #endif /* LOG_BUNDLE_LOAD */
4492 }
4493 return result;
4494 }
4495
4496 #endif /* !BINARY_SUPPORT_DLFCN */
4497 #endif /* BINARY_SUPPORT_DYLD */
4498
4499 #if defined(BINARY_SUPPORT_DLFCN)
4500
4501 __private_extern__ Boolean _CFBundleDlfcnCheckLoaded(CFBundleRef bundle) {
4502 if (!bundle->_isLoaded) {
4503 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
4504 char buff[CFMaxPathSize];
4505
4506 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
4507 int mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD | RTLD_FIRST;
4508 void *handle = dlopen(buff, mode);
4509 if (handle) {
4510 if (!bundle->_handleCookie) {
4511 bundle->_handleCookie = handle;
4512 #if LOG_BUNDLE_LOAD
4513 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x getting handle %p\n", bundle, buff, mode, bundle->_handleCookie);
4514 #endif /* LOG_BUNDLE_LOAD */
4515 }
4516 bundle->_isLoaded = true;
4517 } else {
4518 #if LOG_BUNDLE_LOAD
4519 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x no handle\n", bundle, buff, mode);
4520 #endif /* LOG_BUNDLE_LOAD */
4521 }
4522 }
4523 if (executableURL) CFRelease(executableURL);
4524 }
4525 return bundle->_isLoaded;
4526 }
4527
4528 CF_EXPORT Boolean _CFBundleDlfcnPreflight(CFBundleRef bundle, CFErrorRef *error) {
4529 Boolean retval = true;
4530 CFErrorRef localError = NULL;
4531 if (!bundle->_isLoaded) {
4532 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
4533 char buff[CFMaxPathSize];
4534
4535 retval = false;
4536 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
4537 retval = dlopen_preflight(buff);
4538 if (!retval && error) {
4539 CFArrayRef archs = CFBundleCopyExecutableArchitectures(bundle);
4540 CFStringRef debugString = NULL;
4541 const char *errorString = dlerror();
4542 if (errorString && strlen(errorString) > 0) debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString);
4543 if (archs) {
4544 Boolean hasSuitableArch = false, hasRuntimeMismatch = false;
4545 CFIndex i, count = CFArrayGetCount(archs);
4546 SInt32 arch, curArch = _CFBundleCurrentArchitecture();
4547 for (i = 0; !hasSuitableArch && i < count; i++) {
4548 if (CFNumberGetValue((CFNumberRef)CFArrayGetValueAtIndex(archs, i), kCFNumberSInt32Type, (void *)&arch) && arch == curArch) hasSuitableArch = true;
4549 }
4550 #if defined(BINARY_SUPPORT_DYLD)
4551 if (hasSuitableArch) {
4552 uint32_t mainFlags = 0, bundleFlags = 0;
4553 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) {
4554 if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true;
4555 }
4556 }
4557 #endif /* BINARY_SUPPORT_DYLD */
4558 if (hasRuntimeMismatch) {
4559 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableRuntimeMismatchError, debugString);
4560 } else if (!hasSuitableArch) {
4561 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableArchitectureMismatchError, debugString);
4562 } else {
4563 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLoadError, debugString);
4564 }
4565 CFRelease(archs);
4566 } else {
4567 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLoadError, debugString);
4568 }
4569 if (debugString) CFRelease(debugString);
4570 }
4571 } else {
4572 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
4573 }
4574 if (executableURL) CFRelease(executableURL);
4575 }
4576 if (!retval && error) *error = localError;
4577 return retval;
4578 }
4579
4580 __private_extern__ Boolean _CFBundleDlfcnLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) {
4581 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
4582 if (!bundle->_isLoaded) {
4583 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
4584 char buff[CFMaxPathSize];
4585 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
4586 int mode = forceGlobal ? (RTLD_LAZY | RTLD_GLOBAL | RTLD_FIRST) : (RTLD_NOW | RTLD_LOCAL | RTLD_FIRST);
4587 void *cookie = dlopen(buff, mode);
4588 #if LOG_BUNDLE_LOAD
4589 printf("dlfcn load bundle %p, dlopen of %s mode 0x%x returns handle %p\n", bundle, buff, mode, cookie);
4590 #endif /* LOG_BUNDLE_LOAD */
4591 if (cookie && cookie == bundle->_handleCookie) {
4592 // during the call to dlopen, arbitrary init routines may have run and caused bundle->_handleCookie to be set, in which case proper reference counting requires that reference to be released with dlclose
4593 #if LOG_BUNDLE_LOAD
4594 printf("dlfcn load bundle %p closing existing reference to handle %p\n", bundle, cookie);
4595 #endif /* LOG_BUNDLE_LOAD */
4596 dlclose(bundle->_handleCookie);
4597 }
4598 bundle->_handleCookie = cookie;
4599 if (bundle->_handleCookie) {
4600 bundle->_isLoaded = true;
4601 } else {
4602 const char *errorString = dlerror();
4603 if (error) {
4604 _CFBundleDlfcnPreflight(bundle, subError);
4605 if (!localError) {
4606 CFStringRef debugString = errorString ? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString) : NULL;
4607 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString);
4608 if (debugString) CFRelease(debugString);
4609 }
4610 } else {
4611 CFStringRef executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff);
4612 if (errorString) {
4613 CFStringRef debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString);
4614 CFLog(__kCFLogBundle, CFSTR("Error loading %@: %@"), executableString, debugString);
4615 if (debugString) CFRelease(debugString);
4616 } else {
4617 CFLog(__kCFLogBundle, CFSTR("Error loading %@"), executableString);
4618 }
4619 if (executableString) CFRelease(executableString);
4620 }
4621 }
4622 } else {
4623 if (error) {
4624 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
4625 } else {
4626 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
4627 }
4628 }
4629 if (executableURL) CFRelease(executableURL);
4630 }
4631 if (!bundle->_isLoaded && error) *error = localError;
4632 return bundle->_isLoaded;
4633 }
4634
4635 __private_extern__ Boolean _CFBundleDlfcnLoadFramework(CFBundleRef bundle, CFErrorRef *error) {
4636 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL);
4637 if (!bundle->_isLoaded) {
4638 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
4639 char buff[CFMaxPathSize];
4640 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) {
4641 int mode = RTLD_LAZY | RTLD_GLOBAL | RTLD_FIRST;
4642 void *cookie = dlopen(buff, mode);
4643 #if LOG_BUNDLE_LOAD
4644 printf("dlfcn load framework %p, dlopen of %s mode 0x%x returns handle %p\n", bundle, buff, mode, cookie);
4645 #endif /* LOG_BUNDLE_LOAD */
4646 if (cookie && cookie == bundle->_handleCookie) {
4647 // during the call to dlopen, arbitrary init routines may have run and caused bundle->_handleCookie to be set, in which case proper reference counting requires that reference to be released with dlclose
4648 #if LOG_BUNDLE_LOAD
4649 printf("dlfcn load framework %p closing existing reference to handle %p\n", bundle, cookie);
4650 #endif /* LOG_BUNDLE_LOAD */
4651 dlclose(bundle->_handleCookie);
4652 }
4653 bundle->_handleCookie = cookie;
4654 if (bundle->_handleCookie) {
4655 bundle->_isLoaded = true;
4656 } else {
4657 const char *errorString = dlerror();
4658 if (error) {
4659 _CFBundleDlfcnPreflight(bundle, subError);
4660 if (!localError) {
4661 CFStringRef debugString = errorString ? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString) : NULL;
4662 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString);
4663 if (debugString) CFRelease(debugString);
4664 }
4665 } else {
4666 CFStringRef executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff);
4667 if (errorString) {
4668 CFStringRef debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString);
4669 CFLog(__kCFLogBundle, CFSTR("Error loading %@: %@"), executableString, debugString);
4670 if (debugString) CFRelease(debugString);
4671 } else {
4672 CFLog(__kCFLogBundle, CFSTR("Error loading %@"), executableString);
4673 }
4674 if (executableString) CFRelease(executableString);
4675 }
4676 }
4677 } else {
4678 if (error) {
4679 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
4680 } else {
4681 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
4682 }
4683 }
4684 if (executableURL) CFRelease(executableURL);
4685 }
4686 if (!bundle->_isLoaded && error) *error = localError;
4687 return bundle->_isLoaded;
4688 }
4689
4690 __private_extern__ void _CFBundleDlfcnUnload(CFBundleRef bundle) {
4691 if (bundle->_isLoaded) {
4692 #if LOG_BUNDLE_LOAD
4693 printf("dlfcn unload bundle %p, handle %p module %p image %p\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie);
4694 #endif /* LOG_BUNDLE_LOAD */
4695 if (0 != dlclose(bundle->_handleCookie)) {
4696 CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle);
4697 } else {
4698 bundle->_connectionCookie = bundle->_handleCookie = NULL;
4699 bundle->_imageCookie = bundle->_moduleCookie = NULL;
4700 bundle->_isLoaded = false;
4701 }
4702 }
4703 }
4704
4705 __private_extern__ void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {
4706 return _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, symbolName, false);
4707 }
4708
4709 static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) {
4710 void *result = NULL;
4711 char buff[1026];
4712
4713 if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingUTF8)) {
4714 result = dlsym(bundle->_handleCookie, buff);
4715 if (!result && globalSearch) result = dlsym(RTLD_DEFAULT, buff);
4716 #if defined(DEBUG)
4717 if (!result) CFLog(__kCFLogBundle, CFSTR("dlsym cannot find symbol %@ in %@"), symbolName, bundle);
4718 #endif /* DEBUG */
4719 #if LOG_BUNDLE_LOAD
4720 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);
4721 #endif /* LOG_BUNDLE_LOAD */
4722 }
4723 return result;
4724 }
4725
4726 #if !defined(BINARY_SUPPORT_DYLD)
4727
4728 static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p) {
4729 CFStringRef result = NULL;
4730 Dl_info info;
4731 if (0 != dladdr(p, &info) && info.dli_fname) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, info.dli_fname);
4732 #if LOG_BUNDLE_LOAD
4733 printf("dlfcn image path for pointer %p is %p\n", p, result);
4734 #endif /* LOG_BUNDLE_LOAD */
4735 return result;
4736 }
4737
4738 #endif /* !BINARY_SUPPORT_DYLD */
4739 #endif /* BINARY_SUPPORT_DLFCN */
4740
4741 #if defined(BINARY_SUPPORT_DLL)
4742
4743 __private_extern__ Boolean _CFBundleDLLLoad(CFBundleRef bundle, CFErrorRef *error) {
4744 CFErrorRef localError = NULL;
4745 if (!bundle->_isLoaded) {
4746 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
4747 wchar_t buff[CFMaxPathSize];
4748
4749 if (executableURL && _CFURLGetWideFileSystemRepresentation(executableURL, true, (wchar_t *)buff, CFMaxPathSize)) {
4750 bundle->_hModule = LoadLibraryW(buff);
4751 if (bundle->_hModule) {
4752 bundle->_isLoaded = true;
4753 } else {
4754 if (error) {
4755 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError);
4756 } else {
4757 CFLog(__kCFLogBundle, CFSTR("Failed to load bundle %@"), bundle);
4758 }
4759 }
4760 } else {
4761 if (error) {
4762 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError);
4763 } else {
4764 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
4765 }
4766 }
4767 if (executableURL) CFRelease(executableURL);
4768 }
4769 if (!bundle->_isLoaded && error) *error = localError;
4770 return bundle->_isLoaded;
4771 }
4772
4773 __private_extern__ void _CFBundleDLLUnload(CFBundleRef bundle) {
4774 if (bundle->_isLoaded) {
4775 FreeLibrary(bundle->_hModule);
4776 bundle->_hModule = NULL;
4777 bundle->_isLoaded = false;
4778 }
4779 }
4780
4781 __private_extern__ void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {
4782 void *result = NULL;
4783 char buff[1024];
4784 if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingWindowsLatin1)) result = GetProcAddress(bundle->_hModule, buff);
4785 return result;
4786 }
4787
4788 #endif /* BINARY_SUPPORT_DLL */
4789
4790 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
4791 */
4792 CF_EXPORT void _CFStringSetCompatibility(CFOptionFlags);
4793
4794 static void _CFBundleCheckWorkarounds(CFBundleRef bundle) {
4795 }
4796