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