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