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