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