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