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