]> git.saurik.com Git - apple/cf.git/blob - PlugIn.subproj/CFBundle.c
CF-368.28.tar.gz
[apple/cf.git] / PlugIn.subproj / CFBundle.c
1 /*
2 * Copyright (c) 2005 Apple Computer, 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 1999-2002, 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 <string.h>
34 #include "CFInternal.h"
35 #include "CFPriv.h"
36 #include <CoreFoundation/CFByteOrder.h>
37 #include "CFBundle_BinaryTypes.h"
38 #include <ctype.h>
39
40 #if defined(BINARY_SUPPORT_DYLD)
41 // Import the mach-o headers that define the macho magic numbers
42 #include <mach-o/loader.h>
43 #include <mach-o/fat.h>
44 #include <mach-o/arch.h>
45 #include <mach-o/swap.h>
46 #include <mach-o/dyld.h>
47 #include <mach-o/getsect.h>
48
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <sys/mman.h>
52
53 #endif /* BINARY_SUPPORT_DYLD */
54
55 #if defined(__MACOS8__)
56 /* MacOS8 Headers */
57 #include <stat.h>
58 #include <Processes.h>
59 #else
60 /* Unixy & Windows Headers */
61 #include <sys/stat.h>
62 #include <stdlib.h>
63 #endif
64 #if defined(__LINUX__)
65 #include <fcntl.h>
66 #endif
67
68 #if defined(__WIN32__)
69 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
70 // With the MS headers, turning off Standard-C gets you macros for stat vs_stat.
71 // Strictly speaking, this is supposed to control traditional vs ANSI C features.
72 #undef __STDC__
73 #endif
74 #include <fcntl.h>
75 #include <io.h>
76 #if !defined(__MINGW32__) && !defined(__CYGWIN__)
77 #define __STDC__
78 #endif
79 #endif
80
81
82 // Public CFBundle Info plist keys
83 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey, "CFBundleInfoDictionaryVersion")
84 CONST_STRING_DECL(kCFBundleExecutableKey, "CFBundleExecutable")
85 CONST_STRING_DECL(kCFBundleIdentifierKey, "CFBundleIdentifier")
86 CONST_STRING_DECL(kCFBundleVersionKey, "CFBundleVersion")
87 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey, "CFBundleDevelopmentRegion")
88 CONST_STRING_DECL(kCFBundleLocalizationsKey, "CFBundleLocalizations")
89
90 // Finder stuff
91 CONST_STRING_DECL(_kCFBundlePackageTypeKey, "CFBundlePackageType")
92 CONST_STRING_DECL(_kCFBundleSignatureKey, "CFBundleSignature")
93 CONST_STRING_DECL(_kCFBundleIconFileKey, "CFBundleIconFile")
94 CONST_STRING_DECL(_kCFBundleDocumentTypesKey, "CFBundleDocumentTypes")
95 CONST_STRING_DECL(_kCFBundleURLTypesKey, "CFBundleURLTypes")
96
97 // Keys that are usually localized in InfoPlist.strings
98 CONST_STRING_DECL(kCFBundleNameKey, "CFBundleName")
99 CONST_STRING_DECL(_kCFBundleDisplayNameKey, "CFBundleDisplayName")
100 CONST_STRING_DECL(_kCFBundleShortVersionStringKey, "CFBundleShortVersionString")
101 CONST_STRING_DECL(_kCFBundleGetInfoStringKey, "CFBundleGetInfoString")
102 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey, "CFBundleGetInfoHTML")
103
104 // Sub-keys for CFBundleDocumentTypes dictionaries
105 CONST_STRING_DECL(_kCFBundleTypeNameKey, "CFBundleTypeName")
106 CONST_STRING_DECL(_kCFBundleTypeRoleKey, "CFBundleTypeRole")
107 CONST_STRING_DECL(_kCFBundleTypeIconFileKey, "CFBundleTypeIconFile")
108 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey, "CFBundleTypeOSTypes")
109 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey, "CFBundleTypeExtensions")
110 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey, "CFBundleTypeMIMETypes")
111
112 // Sub-keys for CFBundleURLTypes dictionaries
113 CONST_STRING_DECL(_kCFBundleURLNameKey, "CFBundleURLName")
114 CONST_STRING_DECL(_kCFBundleURLIconFileKey, "CFBundleURLIconFile")
115 CONST_STRING_DECL(_kCFBundleURLSchemesKey, "CFBundleURLSchemes")
116
117 // Compatibility key names
118 CONST_STRING_DECL(_kCFBundleOldExecutableKey, "NSExecutable")
119 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey, "NSInfoPlistVersion")
120 CONST_STRING_DECL(_kCFBundleOldNameKey, "NSHumanReadableName")
121 CONST_STRING_DECL(_kCFBundleOldIconFileKey, "NSIcon")
122 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey, "NSTypes")
123 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey, "NSAppVersion")
124
125 // Compatibility CFBundleDocumentTypes key names
126 CONST_STRING_DECL(_kCFBundleOldTypeNameKey, "NSName")
127 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey, "NSRole")
128 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey, "NSIcon")
129 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key, "NSUnixExtensions")
130 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key, "NSDOSExtensions")
131 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey, "NSMacOSType")
132
133 // Internally used keys for loaded Info plists.
134 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey, "CFBundleInfoPlistURL")
135 CONST_STRING_DECL(_kCFBundleNumericVersionKey, "CFBundleNumericVersion")
136 CONST_STRING_DECL(_kCFBundleExecutablePathKey, "CFBundleExecutablePath")
137 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey, "CSResourcesFileMapped")
138 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey, "CFBundleCFMLoadAsBundle")
139 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey, "CFBundleAllowMixedLocalizations")
140
141 static CFTypeID __kCFBundleTypeID = _kCFRuntimeNotATypeID;
142
143 struct __CFBundle {
144 CFRuntimeBase _base;
145
146 CFURLRef _url;
147 CFDateRef _modDate;
148
149 CFDictionaryRef _infoDict;
150 CFDictionaryRef _localInfoDict;
151 CFArrayRef _searchLanguages;
152
153 __CFPBinaryType _binaryType;
154 Boolean _isLoaded;
155 uint8_t _version;
156 Boolean _sharesStringsFiles;
157 char _padding[1];
158
159 /* CFM goop */
160 void *_connectionCookie;
161
162 /* DYLD goop */
163 const void *_imageCookie;
164 const void *_moduleCookie;
165
166 /* CFM<->DYLD glue */
167 CFMutableDictionaryRef _glueDict;
168
169 /* Resource fork goop */
170 _CFResourceData _resourceData;
171
172 _CFPlugInData _plugInData;
173
174 #if defined(BINARY_SUPPORT_DLL)
175 HMODULE _hModule;
176 #endif
177
178 };
179
180 static CFSpinLock_t CFBundleGlobalDataLock = 0;
181
182 static CFMutableDictionaryRef _bundlesByURL = NULL;
183 static CFMutableDictionaryRef _bundlesByIdentifier = NULL;
184
185 // For scheduled lazy unloading. Used by CFPlugIn.
186 static CFMutableSetRef _bundlesToUnload = NULL;
187 static Boolean _scheduledBundlesAreUnloading = false;
188
189 // Various lists of all bundles.
190 static CFMutableArrayRef _allBundles = NULL;
191
192 static Boolean _initedMainBundle = false;
193 static CFBundleRef _mainBundle = NULL;
194 static CFStringRef _defaultLocalization = NULL;
195
196 // Forward declares functions.
197 static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing);
198 static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict);
199 static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle);
200 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint);
201 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
202 static void _CFBundleCheckWorkarounds(CFBundleRef bundle);
203 #if defined(BINARY_SUPPORT_DYLD)
204 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath);
205 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths);
206 static CFDictionaryRef _CFBundleGrokInfoDictFromMainExecutable(void);
207 static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p);
208 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch);
209 #endif /* BINARY_SUPPORT_DYLD */
210 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
211 static void *_CFBundleFunctionPointerForTVector(CFAllocatorRef allocator, void *tvp);
212 static void *_CFBundleTVectorForFunctionPointer(CFAllocatorRef allocator, void *fp);
213 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
214
215 static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) {
216 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
217
218 if (!alreadyLocked) {
219 __CFSpinLock(&CFBundleGlobalDataLock);
220 }
221
222 // Add to the _allBundles list
223 if (_allBundles == NULL) {
224 // Create this from the default allocator
225 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks;
226 nonRetainingArrayCallbacks.retain = NULL;
227 nonRetainingArrayCallbacks.release = NULL;
228 _allBundles = CFArrayCreateMutable(NULL, 0, &nonRetainingArrayCallbacks);
229 }
230 CFArrayAppendValue(_allBundles, bundle);
231
232 // Add to the table that maps urls to bundles
233 if (_bundlesByURL == NULL) {
234 // Create this from the default allocator
235 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
236 nonRetainingDictionaryValueCallbacks.retain = NULL;
237 nonRetainingDictionaryValueCallbacks.release = NULL;
238 _bundlesByURL = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
239 }
240 CFDictionarySetValue(_bundlesByURL, bundle->_url, bundle);
241
242 // Add to the table that maps identifiers to bundles
243 if (bundleID) {
244 CFBundleRef existingBundle = NULL;
245 Boolean addIt = true;
246 if (_bundlesByIdentifier == NULL) {
247 // Create this from the default allocator
248 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks;
249 nonRetainingDictionaryValueCallbacks.retain = NULL;
250 nonRetainingDictionaryValueCallbacks.release = NULL;
251 _bundlesByIdentifier = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks);
252 }
253 existingBundle = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
254 if (existingBundle) {
255 UInt32 existingVersion, newVersion;
256 existingVersion = CFBundleGetVersionNumber(existingBundle);
257 newVersion = CFBundleGetVersionNumber(bundle);
258 if (newVersion < existingVersion) {
259 // Less than to means that if you load two bundles with the same identifier and the same version, the last one wins.
260 addIt = false;
261 }
262 }
263 if (addIt) {
264 CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundle);
265 }
266 }
267 if (!alreadyLocked) {
268 __CFSpinUnlock(&CFBundleGlobalDataLock);
269 }
270 }
271
272 static void _CFBundleRemoveFromTables(CFBundleRef bundle) {
273 CFStringRef bundleID = CFBundleGetIdentifier(bundle);
274
275 __CFSpinLock(&CFBundleGlobalDataLock);
276
277 // Remove from the various lists
278 if (_allBundles != NULL) {
279 CFIndex i = CFArrayGetFirstIndexOfValue(_allBundles, CFRangeMake(0, CFArrayGetCount(_allBundles)), bundle);
280 if (i>=0) {
281 CFArrayRemoveValueAtIndex(_allBundles, i);
282 }
283 }
284
285 // Remove from the table that maps urls to bundles
286 if (_bundlesByURL != NULL) {
287 CFDictionaryRemoveValue(_bundlesByURL, bundle->_url);
288 }
289
290 // Remove from the table that maps identifiers to bundles
291 if ((bundleID != NULL) && (_bundlesByIdentifier != NULL)) {
292 if (CFDictionaryGetValue(_bundlesByIdentifier, bundleID) == bundle) {
293 CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID);
294 }
295 }
296 __CFSpinUnlock(&CFBundleGlobalDataLock);
297 }
298
299 __private_extern__ CFBundleRef _CFBundleFindByURL(CFURLRef url, Boolean alreadyLocked) {
300 CFBundleRef result = NULL;
301 if (!alreadyLocked) {
302 __CFSpinLock(&CFBundleGlobalDataLock);
303 }
304 if (_bundlesByURL != NULL) {
305 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url);
306 }
307 if (!alreadyLocked) {
308 __CFSpinUnlock(&CFBundleGlobalDataLock);
309 }
310 return result;
311 }
312
313 static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) {
314 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
315 UniChar buff[CFMaxPathSize];
316 CFIndex buffLen;
317 CFURLRef url = NULL;
318 CFStringRef outstr;
319
320 buffLen = CFStringGetLength(str);
321 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize;
322 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff);
323 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); // Remove exe name
324
325 if (buffLen > 0) {
326 // See if this is a new bundle. If it is, we have to remove more path components.
327 CFIndex startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen);
328 if ((startOfLastDir > 0) && (startOfLastDir < buffLen)) {
329 CFStringRef lastDirName = CFStringCreateWithCharacters(NULL, &(buff[startOfLastDir]), buffLen - startOfLastDir);
330
331 if (CFEqual(lastDirName, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) {
332 // This is a new bundle. Back off a few more levels
333 if (buffLen > 0) {
334 // Remove platform folder
335 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
336 }
337 if (buffLen > 0) {
338 // Remove executables folder (if present)
339 CFIndex startOfNextDir = _CFStartOfLastPathComponent(buff, buffLen);
340 if ((startOfNextDir > 0) && (startOfNextDir < buffLen)) {
341 CFStringRef nextDirName = CFStringCreateWithCharacters(NULL, &(buff[startOfNextDir]), buffLen - startOfNextDir);
342 if (CFEqual(nextDirName, _CFBundleExecutablesDirectoryName)) {
343 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
344 }
345 CFRelease(nextDirName);
346 }
347 }
348 if (buffLen > 0) {
349 // Remove support files folder
350 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen);
351 }
352 }
353 CFRelease(lastDirName);
354 }
355 }
356
357 if (buffLen > 0) {
358 outstr = CFStringCreateWithCharactersNoCopy(NULL, buff, buffLen, kCFAllocatorNull);
359 url = CFURLCreateWithFileSystemPath(NULL, outstr, PLATFORM_PATH_STYLE, true);
360 CFRelease(outstr);
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(NULL, buff, len1);
379 str2 = CFStringCreateWithCharacters(NULL, buff + len1 + 1, buffLen - len1 - 1);
380 if (str1 && str2) {
381 url1 = CFURLCreateWithFileSystemPath(NULL, str1, PLATFORM_PATH_STYLE, true);
382 if (url1) {
383 url2 = CFURLCreateWithFileSystemPathRelativeToBase(NULL, 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 != NULL) {
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) {
428 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
429 }
430 if (bundle->_binaryType == __CFBundleCFMBinary || bundle->_binaryType == __CFBundleUnreadableBinary) {
431 bundle->_version = 4;
432 } else {
433 bundle->_resourceData._executableLacksResourceFork = true;
434 }
435 CFRelease(executableURL);
436 } else {
437 bundle->_version = 4;
438 }
439 #elif defined(BINARY_SUPPORT_CFM)
440 bundle->_version = 4;
441 #else
442 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
443 if (executableURL) {
444 CFRelease(executableURL);
445 } else {
446 bundle->_version = 4;
447 }
448 #endif /* BINARY_SUPPORT_CFM && BINARY_SUPPORT_DYLD */
449 }
450 }
451 if (bundle && (3 == bundle->_version || 4 == bundle->_version)) {
452 CFRelease(bundle);
453 bundle = NULL;
454 }
455 return bundle;
456 }
457
458 CFBundleRef _CFBundleGetMainBundleIfLooksLikeBundle(void) {
459 CFBundleRef mainBundle = CFBundleGetMainBundle();
460 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) {
461 mainBundle = NULL;
462 }
463 return mainBundle;
464 }
465
466 CFBundleRef _CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) {
467 CFBundleRef bundle = NULL;
468 CFURLRef bundleURL = _CFBundleCopyBundleURLForExecutableURL(url), resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url);
469 if (bundleURL && resolvedURL) {
470 bundle = _CFBundleCreateIfLooksLikeBundle(allocator, bundleURL);
471 if (bundle) {
472 CFURLRef executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle);
473 char buff1[CFMaxPathSize], buff2[CFMaxPathSize];
474 if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) {
475 CFRelease(bundle);
476 bundle = NULL;
477 }
478 if (executableURL) CFRelease(executableURL);
479 }
480 }
481 if (bundleURL) CFRelease(bundleURL);
482 if (resolvedURL) CFRelease(resolvedURL);
483 return bundle;
484 }
485
486 CFURLRef _CFBundleCopyMainBundleExecutableURL(Boolean *looksLikeBundle) {
487 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue
488 const char *processPath;
489 CFStringRef str = NULL;
490 CFURLRef executableURL = NULL;
491 processPath = _CFProcessPath();
492 if (processPath) {
493 str = CFStringCreateWithCString(NULL, processPath, CFStringFileSystemEncoding());
494 if (str) {
495 executableURL = CFURLCreateWithFileSystemPath(NULL, str, PLATFORM_PATH_STYLE, false);
496 CFRelease(str);
497 }
498 }
499 if (looksLikeBundle) {
500 CFBundleRef mainBundle = _mainBundle;
501 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL;
502 *looksLikeBundle = (mainBundle ? YES : NO);
503 }
504 return executableURL;
505 }
506
507 static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) {
508 if (!_initedMainBundle) {
509 const char *processPath;
510 CFStringRef str = NULL;
511 CFURLRef executableURL = NULL, bundleURL = NULL;
512 #if defined(BINARY_SUPPORT_CFM)
513 Boolean versRegionOverrides = false;
514 #endif /* BINARY_SUPPORT_CFM */
515 #if defined(__MACOS8__)
516 // do not use Posix-styled _CFProcessPath()
517 ProcessSerialNumber gProcessID;
518 ProcessInfoRec processInfo;
519 FSSpec processAppSpec;
520
521 processInfo.processInfoLength = sizeof(ProcessInfoRec);
522 processInfo.processAppSpec = &processAppSpec;
523
524 if ((GetCurrentProcess(&gProcessID) == noErr) && (GetProcessInformation(&gProcessID, &processInfo) == noErr)) {
525 executableURL = _CFCreateURLFromFSSpec(NULL, (void *)(&processAppSpec), false);
526 }
527 #endif
528 _initedMainBundle = true;
529 processPath = _CFProcessPath();
530 if (processPath) {
531 str = CFStringCreateWithCString(NULL, processPath, CFStringFileSystemEncoding());
532 if (!executableURL) executableURL = CFURLCreateWithFileSystemPath(NULL, str, PLATFORM_PATH_STYLE, false);
533 }
534 if (executableURL) {
535 bundleURL = _CFBundleCopyBundleURLForExecutableURL(executableURL);
536 }
537 if (bundleURL != NULL) {
538 // make sure that main bundle has executable path
539 //??? what if we are not the main executable in the bundle?
540 // NB doFinalProcessing must be false here, see below
541 _mainBundle = _CFBundleCreate(NULL, bundleURL, true, false);
542 if (_mainBundle != NULL) {
543 CFBundleGetInfoDictionary(_mainBundle);
544 // make sure that the main bundle is listed as loaded, and mark it as executable
545 _mainBundle->_isLoaded = true;
546 #if defined(BINARY_SUPPORT_DYLD)
547 if (_mainBundle->_binaryType == __CFBundleUnknownBinary) {
548 if (!executableURL) {
549 _mainBundle->_binaryType = __CFBundleNoBinary;
550 } else {
551 _mainBundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
552 #if defined(BINARY_SUPPORT_CFM)
553 if (_mainBundle->_binaryType != __CFBundleCFMBinary && _mainBundle->_binaryType != __CFBundleUnreadableBinary) {
554 _mainBundle->_resourceData._executableLacksResourceFork = true;
555 }
556 #endif /* BINARY_SUPPORT_CFM */
557 }
558 }
559 #endif /* BINARY_SUPPORT_DYLD */
560 if (_mainBundle->_infoDict == NULL || CFDictionaryGetCount(_mainBundle->_infoDict) == 0) {
561 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
562 if (_mainBundle->_version == 3) _mainBundle->_version = 4;
563 if (_mainBundle->_version == 0) {
564 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
565 CFStringRef executableName = _CFBundleCopyExecutableName(NULL, _mainBundle, NULL, NULL);
566 if (!executableName || !CFStringHasSuffix(str, executableName)) _mainBundle->_version = 4;
567 if (executableName) CFRelease(executableName);
568 }
569 #if defined(BINARY_SUPPORT_DYLD)
570 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) {
571 if (_mainBundle->_infoDict != NULL) CFRelease(_mainBundle->_infoDict);
572 _mainBundle->_infoDict = _CFBundleGrokInfoDictFromMainExecutable();
573 }
574 #endif /* BINARY_SUPPORT_DYLD */
575 #if defined(BINARY_SUPPORT_CFM)
576 if (_mainBundle->_binaryType == __CFBundleCFMBinary || _mainBundle->_binaryType == __CFBundleUnreadableBinary) {
577 // if type 0 bundle and CFM binary and no Info.plist, treat as unbundled, since this also gives too many false positives
578 if (_mainBundle->_version == 0) _mainBundle->_version = 4;
579 if (_mainBundle->_version != 4) {
580 // if CFM binary and no Info.plist and not main executable for bundle, treat as unbundled, since this also gives too many false positives
581 // except for Macromedia Director MX, which is unbundled but wants to be treated as bundled
582 CFStringRef executableName = _CFBundleCopyExecutableName(NULL, _mainBundle, NULL, NULL);
583 Boolean treatAsBundled = false;
584 if (str) {
585 CFIndex strLength = CFStringGetLength(str);
586 if (strLength > 10) treatAsBundled = CFStringFindWithOptions(str, CFSTR(" MX"), CFRangeMake(strLength - 10, 10), 0, NULL);
587 }
588 if (!treatAsBundled && (!executableName || !CFStringHasSuffix(str, executableName))) _mainBundle->_version = 4;
589 if (executableName) CFRelease(executableName);
590 }
591 if (_mainBundle->_infoDict != NULL) CFRelease(_mainBundle->_infoDict);
592 _mainBundle->_infoDict = _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFGetAllocator(_mainBundle), executableURL);
593 if (_mainBundle->_binaryType == __CFBundleUnreadableBinary && _mainBundle->_infoDict != NULL && CFDictionaryGetValue(_mainBundle->_infoDict, kCFBundleDevelopmentRegionKey) != NULL) versRegionOverrides = true;
594 }
595 #endif /* BINARY_SUPPORT_CFM */
596 }
597 if (_mainBundle->_infoDict == NULL) {
598 _mainBundle->_infoDict = CFDictionaryCreateMutable(CFGetAllocator(_mainBundle), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
599 }
600 if (NULL == CFDictionaryGetValue(_mainBundle->_infoDict, _kCFBundleExecutablePathKey)) {
601 CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), _kCFBundleExecutablePathKey, str);
602 }
603 #if defined(BINARY_SUPPORT_DYLD)
604 // get cookie for already-loaded main bundle
605 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary && !_mainBundle->_imageCookie) {
606 _mainBundle->_imageCookie = (void *)_dyld_get_image_header(0);
607 }
608 #endif /* BINARY_SUPPORT_DYLD */
609 #if defined(BINARY_SUPPORT_CFM)
610 if (versRegionOverrides) {
611 // This is a hack to preserve backward compatibility for certain broken applications (2761067)
612 CFStringRef devLang = _CFBundleCopyBundleDevelopmentRegionFromVersResource(_mainBundle);
613 if (devLang != NULL) {
614 CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), kCFBundleDevelopmentRegionKey, devLang);
615 CFRelease(devLang);
616 }
617 }
618 #endif /* BINARY_SUPPORT_CFM */
619 // Perform delayed final processing steps.
620 // This must be done after _isLoaded has been set, for security reasons (3624341).
621 _CFBundleCheckWorkarounds(_mainBundle);
622 if (_CFBundleNeedsInitPlugIn(_mainBundle)) {
623 __CFSpinUnlock(&CFBundleGlobalDataLock);
624 _CFBundleInitPlugIn(_mainBundle);
625 __CFSpinLock(&CFBundleGlobalDataLock);
626 }
627 }
628 }
629 if (bundleURL) CFRelease(bundleURL);
630 if (str) CFRelease(str);
631 if (executableURL) CFRelease(executableURL);
632 }
633 return _mainBundle;
634 }
635
636 CFBundleRef CFBundleGetMainBundle(void) {
637 CFBundleRef mainBundle;
638 __CFSpinLock(&CFBundleGlobalDataLock);
639 mainBundle = _CFBundleGetMainBundleAlreadyLocked();
640 __CFSpinUnlock(&CFBundleGlobalDataLock);
641 return mainBundle;
642 }
643
644 #if defined(BINARY_SUPPORT_DYLD)
645
646 static void *_CFBundleReturnAddressFromFrameAddress(void *addr)
647 {
648 void *ret;
649 #if defined(__ppc__)
650 __asm__ volatile("lwz %0,0x0008(%1)" : "=r" (ret) : "b" (addr));
651 #elif defined(__i386__)
652 __asm__ volatile("movl 0x4(%1),%0" : "=r" (ret) : "r" (addr));
653 #elif defined(hppa)
654 __asm__ volatile("ldw 0x4(%1),%0" : "=r" (ret) : "r" (addr));
655 #elif defined(sparc)
656 __asm__ volatile("ta 0x3");
657 __asm__ volatile("ld [%1 + 60],%0" : "=r" (ret) : "r" (addr));
658 #else
659 #warning Do not know how to define _CFBundleReturnAddressFromFrameAddress on this architecture
660 ret = NULL;
661 #endif
662 return ret;
663 }
664
665 #endif
666
667 CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) {
668 CFBundleRef result = NULL;
669 if (bundleID) {
670 __CFSpinLock(&CFBundleGlobalDataLock);
671 (void)_CFBundleGetMainBundleAlreadyLocked();
672 if (_bundlesByIdentifier != NULL) {
673 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
674 }
675 #if defined(BINARY_SUPPORT_DYLD)
676 if (result == NULL) {
677 // Try to create the bundle for the caller and try again
678 void *p = _CFBundleReturnAddressFromFrameAddress(__builtin_frame_address(1));
679 CFStringRef imagePath = _CFBundleDYLDCopyLoadedImagePathForPointer(p);
680 if (imagePath != NULL) {
681 _CFBundleEnsureBundleExistsForImagePath(imagePath);
682 CFRelease(imagePath);
683 }
684 if (_bundlesByIdentifier != NULL) {
685 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
686 }
687 }
688 #endif
689 if (result == NULL) {
690 // Try to guess the bundle from the identifier and try again
691 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID);
692 if (_bundlesByIdentifier != NULL) {
693 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
694 }
695 }
696 if (result == NULL) {
697 // Make sure all bundles have been created and try again.
698 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
699 if (_bundlesByIdentifier != NULL) {
700 result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID);
701 }
702 }
703 __CFSpinUnlock(&CFBundleGlobalDataLock);
704 }
705 return result;
706 }
707
708 static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) {
709 char buff[CFMaxPathSize];
710 CFStringRef path = NULL, binaryType = NULL, retval = NULL;
711 if (((CFBundleRef)cf)->_url != NULL && CFURLGetFileSystemRepresentation(((CFBundleRef)cf)->_url, true, buff, CFMaxPathSize)) {
712 path = CFStringCreateWithCString(NULL, buff, CFStringFileSystemEncoding());
713 }
714 switch (((CFBundleRef)cf)->_binaryType) {
715 case __CFBundleCFMBinary:
716 binaryType = CFSTR("");
717 break;
718 case __CFBundleDYLDExecutableBinary:
719 binaryType = CFSTR("executable, ");
720 break;
721 case __CFBundleDYLDBundleBinary:
722 binaryType = CFSTR("bundle, ");
723 break;
724 case __CFBundleDYLDFrameworkBinary:
725 binaryType = CFSTR("framework, ");
726 break;
727 case __CFBundleDLLBinary:
728 binaryType = CFSTR("DLL, ");
729 break;
730 case __CFBundleUnreadableBinary:
731 binaryType = CFSTR("");
732 break;
733 default:
734 binaryType = CFSTR("");
735 break;
736 }
737 if (((CFBundleRef)cf)->_plugInData._isPlugIn) {
738 retval = CFStringCreateWithFormat(NULL, NULL, CFSTR("CFBundle/CFPlugIn 0x%x <%@> (%@%sloaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? "" : "not ");
739 } else {
740 retval = CFStringCreateWithFormat(NULL, NULL, CFSTR("CFBundle 0x%x <%@> (%@%sloaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? "" : "not ");
741 }
742 if (path) CFRelease(path);
743 return retval;
744 }
745
746 static void _CFBundleDeallocateGlue(const void *key, const void *value, void *context) {
747 CFAllocatorRef allocator = (CFAllocatorRef)context;
748 if (value != NULL) {
749 CFAllocatorDeallocate(allocator, (void *)value);
750 }
751 }
752
753 static void __CFBundleDeallocate(CFTypeRef cf) {
754 CFBundleRef bundle = (CFBundleRef)cf;
755 CFAllocatorRef allocator;
756
757 __CFGenericValidateType(cf, __kCFBundleTypeID);
758
759 allocator = CFGetAllocator(bundle);
760
761 /* Unload it */
762 CFBundleUnloadExecutable(bundle);
763
764 // Clean up plugIn stuff
765 _CFBundleDeallocatePlugIn(bundle);
766
767 _CFBundleRemoveFromTables(bundle);
768
769 if (bundle->_url != NULL) {
770 _CFBundleFlushCachesForURL(bundle->_url);
771 CFRelease(bundle->_url);
772 }
773 if (bundle->_infoDict != NULL) {
774 CFRelease(bundle->_infoDict);
775 }
776 if (bundle->_modDate != NULL) {
777 CFRelease(bundle->_modDate);
778 }
779 if (bundle->_localInfoDict != NULL) {
780 CFRelease(bundle->_localInfoDict);
781 }
782 if (bundle->_searchLanguages != NULL) {
783 CFRelease(bundle->_searchLanguages);
784 }
785 if (bundle->_glueDict != NULL) {
786 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)allocator);
787 CFRelease(bundle->_glueDict);
788 }
789 if (bundle->_resourceData._stringTableCache != NULL) {
790 CFRelease(bundle->_resourceData._stringTableCache);
791 }
792 }
793
794 static const CFRuntimeClass __CFBundleClass = {
795 0,
796 "CFBundle",
797 NULL, // init
798 NULL, // copy
799 __CFBundleDeallocate,
800 NULL, // equal
801 NULL, // hash
802 NULL, //
803 __CFBundleCopyDescription
804 };
805
806 __private_extern__ void __CFBundleInitialize(void) {
807 __kCFBundleTypeID = _CFRuntimeRegisterClass(&__CFBundleClass);
808 }
809
810 CFTypeID CFBundleGetTypeID(void) {
811 return __kCFBundleTypeID;
812 }
813
814 static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing) {
815 CFBundleRef bundle = NULL;
816 char buff[CFMaxPathSize];
817 CFDateRef modDate = NULL;
818 Boolean exists = false;
819 SInt32 mode = 0;
820 CFURLRef newURL = NULL;
821 uint8_t localVersion = 0;
822
823 if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL;
824
825 newURL = CFURLCreateFromFileSystemRepresentation(allocator, buff, strlen(buff), true);
826 if (NULL == newURL) {
827 newURL = CFRetain(bundleURL);
828 }
829 bundle = _CFBundleFindByURL(newURL, alreadyLocked);
830 if (bundle) {
831 CFRetain(bundle);
832 CFRelease(newURL);
833 return bundle;
834 }
835
836 if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) {
837 localVersion = 3;
838 if (_CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) {
839 if (!exists || ((mode & S_IFMT) != S_IFDIR)) {
840 if (NULL != modDate) CFRelease(modDate);
841 CFRelease(newURL);
842 return NULL;
843 }
844 } else {
845 CFRelease(newURL);
846 return NULL;
847 }
848 }
849
850 bundle = (CFBundleRef)_CFRuntimeCreateInstance(allocator, __kCFBundleTypeID, sizeof(struct __CFBundle) - sizeof(CFRuntimeBase), NULL);
851 if (NULL == bundle) {
852 CFRelease(newURL);
853 return NULL;
854 }
855
856 bundle->_url = newURL;
857
858 bundle->_modDate = modDate;
859 bundle->_version = localVersion;
860 bundle->_infoDict = NULL;
861 bundle->_localInfoDict = NULL;
862 bundle->_searchLanguages = NULL;
863
864 #if defined(BINARY_SUPPORT_DYLD)
865 /* We'll have to figure it out later */
866 bundle->_binaryType = __CFBundleUnknownBinary;
867 #elif defined(BINARY_SUPPORT_CFM)
868 /* We support CFM only */
869 bundle->_binaryType = __CFBundleCFMBinary;
870 #elif defined(BINARY_SUPPORT_DLL)
871 /* We support DLL only */
872 bundle->_binaryType = __CFBundleDLLBinary;
873 bundle->_hModule = NULL;
874 #else
875 /* We'll have to figure it out later */
876 bundle->_binaryType = __CFBundleUnknownBinary;
877 #endif
878
879 bundle->_isLoaded = false;
880 bundle->_sharesStringsFiles = false;
881
882 /* ??? For testing purposes? Or for good? */
883 #warning Ali or Doug: Decide how to finalize strings sharing
884 if (!getenv("CFBundleDisableStringsSharing") &&
885 (strncmp(buff, "/System/Library/Frameworks", 26) == 0) &&
886 (strncmp(buff + strlen(buff) - 10, ".framework", 10) == 0)) bundle->_sharesStringsFiles = true;
887
888 bundle->_connectionCookie = NULL;
889 bundle->_imageCookie = NULL;
890 bundle->_moduleCookie = NULL;
891
892 bundle->_glueDict = NULL;
893
894 #if defined(BINARY_SUPPORT_CFM)
895 bundle->_resourceData._executableLacksResourceFork = false;
896 #else
897 bundle->_resourceData._executableLacksResourceFork = true;
898 #endif
899
900 bundle->_resourceData._stringTableCache = NULL;
901
902 bundle->_plugInData._isPlugIn = false;
903 bundle->_plugInData._loadOnDemand = false;
904 bundle->_plugInData._isDoingDynamicRegistration = false;
905 bundle->_plugInData._instanceCount = 0;
906 bundle->_plugInData._factories = NULL;
907
908 CFBundleGetInfoDictionary(bundle);
909
910 _CFBundleAddToTables(bundle, alreadyLocked);
911
912 if (doFinalProcessing) {
913 _CFBundleCheckWorkarounds(bundle);
914 if (_CFBundleNeedsInitPlugIn(bundle)) {
915 if (alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock);
916 _CFBundleInitPlugIn(bundle);
917 if (alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock);
918 }
919 }
920
921 return bundle;
922 }
923
924 CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL) {return _CFBundleCreate(allocator, bundleURL, false, true);}
925
926 CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc, CFURLRef directoryURL, CFStringRef bundleType) {
927 CFMutableArrayRef bundles = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
928 CFArrayRef URLs = _CFContentsOfDirectory(alloc, NULL, NULL, directoryURL, bundleType);
929 if (URLs != NULL) {
930 CFIndex i, c = CFArrayGetCount(URLs);
931 CFURLRef curURL;
932 CFBundleRef curBundle;
933
934 for (i=0; i<c; i++) {
935 curURL = CFArrayGetValueAtIndex(URLs, i);
936 curBundle = CFBundleCreate(alloc, curURL);
937 if (curBundle != NULL) {
938 CFArrayAppendValue(bundles, curBundle);
939 }
940 }
941 CFRelease(URLs);
942 }
943
944 return bundles;
945 }
946
947 CFURLRef CFBundleCopyBundleURL(CFBundleRef bundle) {
948 if (bundle->_url) {
949 CFRetain(bundle->_url);
950 }
951 return bundle->_url;
952 }
953
954 void _CFBundleSetDefaultLocalization(CFStringRef localizationName) {
955 CFStringRef newLocalization = localizationName ? CFStringCreateCopy(NULL, localizationName) : NULL;
956 if (_defaultLocalization) CFRelease(_defaultLocalization);
957 _defaultLocalization = newLocalization;
958 }
959
960 CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle) {
961 if (bundle->_searchLanguages == NULL) {
962 CFMutableArrayRef langs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
963 CFStringRef devLang = CFBundleGetDevelopmentRegion(bundle);
964
965 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, devLang);
966
967 if (CFArrayGetCount(langs) == 0) {
968 // If the user does not prefer any of our languages, and devLang is not present, try English
969 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, CFSTR("en_US"));
970 }
971 if (CFArrayGetCount(langs) == 0) {
972 // if none of the preferred localizations are present, fall back on a random localization that is present
973 CFArrayRef localizations = CFBundleCopyBundleLocalizations(bundle);
974 if (localizations) {
975 if (CFArrayGetCount(localizations) > 0) {
976 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, CFArrayGetValueAtIndex(localizations, 0));
977 }
978 CFRelease(localizations);
979 }
980 }
981
982 if (devLang != NULL && !CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang)) {
983 // Make sure that devLang is on the list as a fallback for individual resources that are not present
984 CFArrayAppendValue(langs, devLang);
985 } else if (devLang == NULL) {
986 // Or if there is no devLang, try some variation of English that is present
987 CFArrayRef localizations = CFBundleCopyBundleLocalizations(bundle);
988 if (localizations) {
989 CFStringRef en_US = CFSTR("en_US"), en = CFSTR("en"), English = CFSTR("English");
990 CFRange range = CFRangeMake(0, CFArrayGetCount(localizations));
991 if (CFArrayContainsValue(localizations, range, en)) {
992 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), en)) CFArrayAppendValue(langs, en);
993 } else if (CFArrayContainsValue(localizations, range, English)) {
994 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), English)) CFArrayAppendValue(langs, English);
995 } else if (CFArrayContainsValue(localizations, range, en_US)) {
996 if (!CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), en_US)) CFArrayAppendValue(langs, en_US);
997 }
998 CFRelease(localizations);
999 }
1000 }
1001 if (CFArrayGetCount(langs) == 0) {
1002 // Total backstop behavior to avoid having an empty array.
1003 if (_defaultLocalization != NULL) {
1004 CFArrayAppendValue(langs, _defaultLocalization);
1005 } else {
1006 CFArrayAppendValue(langs, CFSTR("en"));
1007 }
1008 }
1009 bundle->_searchLanguages = langs;
1010 }
1011 return bundle->_searchLanguages;
1012 }
1013
1014 CFDictionaryRef CFBundleCopyInfoDictionaryInDirectory(CFURLRef url) {return _CFBundleCopyInfoDictionaryInDirectory(NULL, url, NULL);}
1015
1016 CFDictionaryRef CFBundleGetInfoDictionary(CFBundleRef bundle) {
1017 if (bundle->_infoDict == NULL) {
1018 bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle), bundle->_url, bundle->_version);
1019 }
1020 return bundle->_infoDict;
1021 }
1022
1023 CFDictionaryRef _CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {return CFBundleGetLocalInfoDictionary(bundle);}
1024
1025 CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {
1026 if (bundle->_localInfoDict == NULL) {
1027 CFURLRef url = CFBundleCopyResourceURL(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL);
1028 if (url) {
1029 CFDataRef data;
1030 SInt32 errCode;
1031 CFStringRef errStr = NULL;
1032
1033 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), url, &data, NULL, NULL, &errCode)) {
1034 bundle->_localInfoDict = CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), data, kCFPropertyListImmutable, &errStr);
1035 if (errStr) {
1036 CFRelease(errStr);
1037 }
1038 if (bundle->_localInfoDict && CFDictionaryGetTypeID() != CFGetTypeID(bundle->_localInfoDict)) {
1039 CFRelease(bundle->_localInfoDict);
1040 bundle->_localInfoDict = NULL;
1041 }
1042 CFRelease(data);
1043 }
1044 CFRelease(url);
1045 }
1046 }
1047 return bundle->_localInfoDict;
1048 }
1049
1050 CFPropertyListRef _CFBundleGetValueForInfoKey(CFBundleRef bundle, CFStringRef key) {return (CFPropertyListRef)CFBundleGetValueForInfoDictionaryKey(bundle, key);}
1051
1052 CFTypeRef CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle, CFStringRef key) {
1053 // Look in InfoPlist.strings first. Then look in Info.plist
1054 CFTypeRef result = NULL;
1055 if ((bundle!= NULL) && (key != NULL)) {
1056 CFDictionaryRef dict = CFBundleGetLocalInfoDictionary(bundle);
1057 if (dict != NULL) {
1058 result = CFDictionaryGetValue(dict, key);
1059 }
1060 if (result == NULL) {
1061 dict = CFBundleGetInfoDictionary(bundle);
1062 if (dict != NULL) {
1063 result = CFDictionaryGetValue(dict, key);
1064 }
1065 }
1066 }
1067 return result;
1068 }
1069
1070 CFStringRef CFBundleGetIdentifier(CFBundleRef bundle) {
1071 CFStringRef bundleID = NULL;
1072 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1073 if (infoDict) {
1074 bundleID = CFDictionaryGetValue(infoDict, kCFBundleIdentifierKey);
1075 }
1076 return bundleID;
1077 }
1078
1079 #define DEVELOPMENT_STAGE 0x20
1080 #define ALPHA_STAGE 0x40
1081 #define BETA_STAGE 0x60
1082 #define RELEASE_STAGE 0x80
1083
1084 #define MAX_VERS_LEN 10
1085
1086 CF_INLINE Boolean _isDigit(UniChar aChar) {return (((aChar >= (UniChar)'0') && (aChar <= (UniChar)'9')) ? true : false);}
1087
1088 __private_extern__ CFStringRef _CFCreateStringFromVersionNumber(CFAllocatorRef alloc, UInt32 vers) {
1089 CFStringRef result = NULL;
1090 uint8_t major1, major2, minor1, minor2, stage, build;
1091
1092 major1 = (vers & 0xF0000000) >> 28;
1093 major2 = (vers & 0x0F000000) >> 24;
1094 minor1 = (vers & 0x00F00000) >> 20;
1095 minor2 = (vers & 0x000F0000) >> 16;
1096 stage = (vers & 0x0000FF00) >> 8;
1097 build = (vers & 0x000000FF);
1098
1099 if (stage == RELEASE_STAGE) {
1100 if (major1 > 0) {
1101 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d"), major1, major2, minor1, minor2);
1102 } else {
1103 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d"), major2, minor1, minor2);
1104 }
1105 } else {
1106 if (major1 > 0) {
1107 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);
1108 } else {
1109 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d%s%d"), major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? "d" : ((stage == ALPHA_STAGE) ? "a" : "b")), build);
1110 }
1111 }
1112 return result;
1113 }
1114
1115 __private_extern__ UInt32 _CFVersionNumberFromString(CFStringRef versStr) {
1116 // Parse version number from string.
1117 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1118 UInt32 major1 = 0, major2 = 0, minor1 = 0, minor2 = 0, stage = RELEASE_STAGE, build = 0;
1119 UniChar versChars[MAX_VERS_LEN];
1120 UniChar *chars = NULL;
1121 CFIndex len;
1122 UInt32 theVers;
1123 Boolean digitsDone = false;
1124
1125 if (!versStr) return 0;
1126
1127 len = CFStringGetLength(versStr);
1128
1129 if ((len == 0) || (len > MAX_VERS_LEN)) return 0;
1130
1131 CFStringGetCharacters(versStr, CFRangeMake(0, len), versChars);
1132 chars = versChars;
1133
1134 // Get major version number.
1135 major1 = major2 = 0;
1136 if (_isDigit(*chars)) {
1137 major2 = *chars - (UniChar)'0';
1138 chars++;
1139 len--;
1140 if (len > 0) {
1141 if (_isDigit(*chars)) {
1142 major1 = major2;
1143 major2 = *chars - (UniChar)'0';
1144 chars++;
1145 len--;
1146 if (len > 0) {
1147 if (*chars == (UniChar)'.') {
1148 chars++;
1149 len--;
1150 } else {
1151 digitsDone = true;
1152 }
1153 }
1154 } else if (*chars == (UniChar)'.') {
1155 chars++;
1156 len--;
1157 } else {
1158 digitsDone = true;
1159 }
1160 }
1161 } else if (*chars == (UniChar)'.') {
1162 chars++;
1163 len--;
1164 } else {
1165 digitsDone = true;
1166 }
1167
1168 // Now major1 and major2 contain first and second digit of the major version number as ints.
1169 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1170
1171 // Get the first minor version number.
1172 if (len > 0 && !digitsDone) {
1173 if (_isDigit(*chars)) {
1174 minor1 = *chars - (UniChar)'0';
1175 chars++;
1176 len--;
1177 if (len > 0) {
1178 if (*chars == (UniChar)'.') {
1179 chars++;
1180 len--;
1181 } else {
1182 digitsDone = true;
1183 }
1184 }
1185 } else {
1186 digitsDone = true;
1187 }
1188 }
1189
1190 // Now minor1 contains the first minor version number as an int.
1191 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1192
1193 // Get the second minor version number.
1194 if (len > 0 && !digitsDone) {
1195 if (_isDigit(*chars)) {
1196 minor2 = *chars - (UniChar)'0';
1197 chars++;
1198 len--;
1199 } else {
1200 digitsDone = true;
1201 }
1202 }
1203
1204 // Now minor2 contains the second minor version number as an int.
1205 // Now either len is 0 or chars points at the build stage letter.
1206
1207 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1208 if (len > 0) {
1209 if (*chars == (UniChar)'d') {
1210 stage = DEVELOPMENT_STAGE;
1211 } else if (*chars == (UniChar)'a') {
1212 stage = ALPHA_STAGE;
1213 } else if (*chars == (UniChar)'b') {
1214 stage = BETA_STAGE;
1215 } else if (*chars == (UniChar)'f') {
1216 stage = RELEASE_STAGE;
1217 } else {
1218 return 0;
1219 }
1220 chars++;
1221 len--;
1222 }
1223
1224 // Now stage contains the release stage.
1225 // Now either len is 0 or chars points at the build number.
1226
1227 // Get the first digit of the build number.
1228 if (len > 0) {
1229 if (_isDigit(*chars)) {
1230 build = *chars - (UniChar)'0';
1231 chars++;
1232 len--;
1233 } else {
1234 return 0;
1235 }
1236 }
1237 // Get the second digit of the build number.
1238 if (len > 0) {
1239 if (_isDigit(*chars)) {
1240 build *= 10;
1241 build += *chars - (UniChar)'0';
1242 chars++;
1243 len--;
1244 } else {
1245 return 0;
1246 }
1247 }
1248 // Get the third digit of the build number.
1249 if (len > 0) {
1250 if (_isDigit(*chars)) {
1251 build *= 10;
1252 build += *chars - (UniChar)'0';
1253 chars++;
1254 len--;
1255 } else {
1256 return 0;
1257 }
1258 }
1259
1260 // Range check the build number and make sure we exhausted the string.
1261 if ((build > 0xFF) || (len > 0)) return 0;
1262
1263 // Build the number
1264 theVers = major1 << 28;
1265 theVers += major2 << 24;
1266 theVers += minor1 << 20;
1267 theVers += minor2 << 16;
1268 theVers += stage << 8;
1269 theVers += build;
1270
1271 return theVers;
1272 }
1273
1274 UInt32 CFBundleGetVersionNumber(CFBundleRef bundle) {
1275 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1276 CFTypeRef unknownVersionValue = CFDictionaryGetValue(infoDict, _kCFBundleNumericVersionKey);
1277 CFNumberRef versNum;
1278 UInt32 vers = 0;
1279
1280 if (unknownVersionValue == NULL) {
1281 unknownVersionValue = CFDictionaryGetValue(infoDict, kCFBundleVersionKey);
1282 }
1283 if (unknownVersionValue != NULL) {
1284 if (CFGetTypeID(unknownVersionValue) == CFStringGetTypeID()) {
1285 // Convert a string version number into a numeric one.
1286 vers = _CFVersionNumberFromString((CFStringRef)unknownVersionValue);
1287
1288 versNum = CFNumberCreate(CFGetAllocator(bundle), kCFNumberSInt32Type, &vers);
1289 CFDictionarySetValue((CFMutableDictionaryRef)infoDict, _kCFBundleNumericVersionKey, versNum);
1290 CFRelease(versNum);
1291 } else if (CFGetTypeID(unknownVersionValue) == CFNumberGetTypeID()) {
1292 CFNumberGetValue((CFNumberRef)unknownVersionValue, kCFNumberSInt32Type, &vers);
1293 } else {
1294 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleNumericVersionKey);
1295 }
1296 }
1297 return vers;
1298 }
1299
1300 CFStringRef CFBundleGetDevelopmentRegion(CFBundleRef bundle) {
1301 CFStringRef devLang = NULL;
1302 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
1303 if (infoDict) {
1304 devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey);
1305 if (devLang != NULL && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) {
1306 devLang = NULL;
1307 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleDevelopmentRegionKey);
1308 }
1309 }
1310
1311 return devLang;
1312 }
1313
1314 Boolean _CFBundleGetHasChanged(CFBundleRef bundle) {
1315 CFDateRef modDate;
1316 Boolean result = false;
1317 Boolean exists = false;
1318 SInt32 mode = 0;
1319
1320 if (_CFGetFileProperties(CFGetAllocator(bundle), bundle->_url, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) {
1321 // If the bundle no longer exists or is not a folder, it must have "changed"
1322 if (!exists || ((mode & S_IFMT) != S_IFDIR)) {
1323 result = true;
1324 }
1325 } else {
1326 // Something is wrong. The stat failed.
1327 result = true;
1328 }
1329 if (bundle->_modDate && !CFEqual(bundle->_modDate, modDate)) {
1330 // mod date is different from when we created.
1331 result = true;
1332 }
1333 CFRelease(modDate);
1334 return result;
1335 }
1336
1337 void _CFBundleSetStringsFilesShared(CFBundleRef bundle, Boolean flag) {
1338 bundle->_sharesStringsFiles = flag;
1339 }
1340
1341 Boolean _CFBundleGetStringsFilesShared(CFBundleRef bundle) {
1342 return bundle->_sharesStringsFiles;
1343 }
1344
1345 static Boolean _urlExists(CFAllocatorRef alloc, CFURLRef url) {
1346 Boolean exists;
1347 return url && (0 == _CFGetFileProperties(alloc, url, &exists, NULL, NULL, NULL, NULL, NULL)) && exists;
1348 }
1349
1350 __private_extern__ CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version) {
1351 CFURLRef result = NULL;
1352 if (bundleURL) {
1353 if (1 == version) {
1354 result = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase1, bundleURL);
1355 } else if (2 == version) {
1356 result = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase2, bundleURL);
1357 } else {
1358 result = CFRetain(bundleURL);
1359 }
1360 }
1361 return result;
1362 }
1363
1364 CF_EXPORT CFURLRef CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle) {return _CFBundleCopySupportFilesDirectoryURLInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version);}
1365
1366 __private_extern__ CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version) {
1367 CFURLRef result = NULL;
1368 if (bundleURL) {
1369 if (0 == version) {
1370 result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase0, bundleURL);
1371 } else if (1 == version) {
1372 result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase1, bundleURL);
1373 } else if (2 == version) {
1374 result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase2, bundleURL);
1375 } else {
1376 result = CFRetain(bundleURL);
1377 }
1378 }
1379 return result;
1380 }
1381
1382 CFURLRef CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) {return _CFBundleCopyResourcesDirectoryURLInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version);}
1383
1384 static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, CFURLRef urlPath, CFStringRef exeName) {
1385 // 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.
1386 CFURLRef executableURL = NULL;
1387 #if defined(__MACH__)
1388 const uint8_t *image_suffix = getenv("DYLD_IMAGE_SUFFIX");
1389 #endif /* __MACH__ */
1390
1391 if (urlPath == NULL || exeName == NULL) return NULL;
1392
1393 #if defined(__MACH__)
1394 if (image_suffix != NULL) {
1395 CFStringRef newExeName, imageSuffix;
1396 imageSuffix = CFStringCreateWithCString(NULL, image_suffix, kCFStringEncodingUTF8);
1397 if (CFStringHasSuffix(exeName, CFSTR(".dylib"))) {
1398 CFStringRef bareExeName = CFStringCreateWithSubstring(alloc, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6));
1399 newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix);
1400 CFRelease(bareExeName);
1401 } else {
1402 newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, imageSuffix);
1403 }
1404 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, newExeName, kCFURLPOSIXPathStyle, false, urlPath);
1405 if (executableURL != NULL && !_urlExists(alloc, executableURL)) {
1406 CFRelease(executableURL);
1407 executableURL = NULL;
1408 }
1409 CFRelease(newExeName);
1410 CFRelease(imageSuffix);
1411 }
1412 #endif /* __MACH__ */
1413 if (executableURL == NULL) {
1414 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, exeName, kCFURLPOSIXPathStyle, false, urlPath);
1415 if (executableURL != NULL && !_urlExists(alloc, executableURL)) {
1416 CFRelease(executableURL);
1417 executableURL = NULL;
1418 }
1419 }
1420 #if defined(__WIN32__)
1421 if (executableURL == NULL) {
1422 if (!CFStringHasSuffix(exeName, CFSTR(".dll"))) {
1423 CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR(".dll"));
1424 executableURL = CFURLCreateWithString(alloc, newExeName, urlPath);
1425 if (executableURL != NULL && !_urlExists(alloc, executableURL)) {
1426 CFRelease(executableURL);
1427 executableURL = NULL;
1428 }
1429 CFRelease(newExeName);
1430 }
1431 }
1432 if (executableURL == NULL) {
1433 if (!CFStringHasSuffix(exeName, CFSTR(".exe"))) {
1434 CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR(".exe"));
1435 executableURL = CFURLCreateWithString(alloc, newExeName, urlPath);
1436 if (executableURL != NULL && !_urlExists(alloc, executableURL)) {
1437 CFRelease(executableURL);
1438 executableURL = NULL;
1439 }
1440 CFRelease(newExeName);
1441 }
1442 }
1443 #endif
1444 return executableURL;
1445 }
1446
1447 static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) {
1448 CFStringRef executableName = NULL;
1449
1450 if (alloc == NULL && bundle != NULL) {
1451 alloc = CFGetAllocator(bundle);
1452 }
1453 if (infoDict == NULL && bundle != NULL) {
1454 infoDict = CFBundleGetInfoDictionary(bundle);
1455 }
1456 if (url == NULL && bundle != NULL) {
1457 url = bundle->_url;
1458 }
1459
1460 if (infoDict != NULL) {
1461 // Figure out the name of the executable.
1462 // First try for the new key in the plist.
1463 executableName = CFDictionaryGetValue(infoDict, kCFBundleExecutableKey);
1464 if (executableName == NULL) {
1465 // Second try for the old key in the plist.
1466 executableName = CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey);
1467 }
1468 if (executableName != NULL && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) {
1469 CFRetain(executableName);
1470 } else {
1471 executableName = NULL;
1472 }
1473 }
1474 if (executableName == NULL && url != NULL) {
1475 // Third, take the name of the bundle itself (with path extension stripped)
1476 CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url);
1477 CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE);
1478 UniChar buff[CFMaxPathSize];
1479 CFIndex len = CFStringGetLength(bundlePath);
1480 CFIndex startOfBundleName, endOfBundleName;
1481
1482 CFRelease(absoluteURL);
1483 if (len > CFMaxPathSize) len = CFMaxPathSize;
1484 CFStringGetCharacters(bundlePath, CFRangeMake(0, len), buff);
1485 startOfBundleName = _CFStartOfLastPathComponent(buff, len);
1486 endOfBundleName = _CFLengthAfterDeletingPathExtension(buff, len);
1487
1488 if ((startOfBundleName <= len) && (endOfBundleName <= len) && (startOfBundleName < endOfBundleName)) {
1489 executableName = CFStringCreateWithCharacters(alloc, &(buff[startOfBundleName]), (endOfBundleName - startOfBundleName));
1490 }
1491 CFRelease(bundlePath);
1492 }
1493
1494 return executableName;
1495 }
1496
1497 __private_extern__ CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boolean mayBeLocal) {
1498 CFStringRef executableName = _CFBundleCopyExecutableName(NULL, bundle, NULL, NULL);
1499 CFURLRef resourceForkURL = NULL;
1500 if (executableName != NULL) {
1501 if (mayBeLocal) {
1502 resourceForkURL = CFBundleCopyResourceURL(bundle, executableName, CFSTR("rsrc"), NULL);
1503 } else {
1504 resourceForkURL = CFBundleCopyResourceURLForLocalization(bundle, executableName, CFSTR("rsrc"), NULL, NULL);
1505 }
1506 CFRelease(executableName);
1507 }
1508
1509 return resourceForkURL;
1510 }
1511
1512 CFURLRef _CFBundleCopyResourceForkURL(CFBundleRef bundle) {return _CFBundleCopyResourceForkURLMayBeLocal(bundle, true);}
1513
1514 static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFStringRef executableName, Boolean ignoreCache, Boolean useOtherPlatform) {
1515 uint8_t version = 0;
1516 CFDictionaryRef infoDict = NULL;
1517 CFStringRef executablePath = NULL;
1518 CFURLRef executableURL = NULL;
1519 Boolean foundIt = false;
1520 Boolean lookupMainExe = ((executableName == NULL) ? true : false);
1521
1522 if (bundle != NULL) {
1523 infoDict = CFBundleGetInfoDictionary(bundle);
1524 version = bundle->_version;
1525 } else {
1526 infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, &version);
1527 }
1528
1529 // If we have a bundle instance and an info dict, see if we have already cached the path
1530 if (lookupMainExe && !ignoreCache && !useOtherPlatform && (bundle != NULL) && (infoDict != NULL)) {
1531 executablePath = CFDictionaryGetValue(infoDict, _kCFBundleExecutablePathKey);
1532 if (executablePath != NULL) {
1533 executableURL = CFURLCreateWithFileSystemPath(alloc, executablePath, kCFURLPOSIXPathStyle, false);
1534 if (executableURL != NULL) foundIt = true;
1535 if (!foundIt) {
1536 executablePath = NULL;
1537 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleExecutablePathKey);
1538 }
1539 }
1540 }
1541
1542 if (!foundIt) {
1543 if (lookupMainExe) {
1544 executableName = _CFBundleCopyExecutableName(alloc, bundle, url, infoDict);
1545 }
1546 if (executableName != NULL) {
1547 // Now, look for the executable inside the bundle.
1548 if (0 != version) {
1549 CFURLRef exeDirURL;
1550 CFURLRef exeSubdirURL;
1551
1552 if (1 == version) {
1553 exeDirURL = CFURLCreateWithString(alloc, _CFBundleExecutablesURLFromBase1, url);
1554 } else if (2 == version) {
1555 exeDirURL = CFURLCreateWithString(alloc, _CFBundleExecutablesURLFromBase2, url);
1556 } else {
1557 exeDirURL = CFRetain(url);
1558 }
1559 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL);
1560 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName);
1561 if (executableURL == NULL) {
1562 CFRelease(exeSubdirURL);
1563 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL);
1564 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName);
1565 }
1566 if (executableURL == NULL) {
1567 CFRelease(exeSubdirURL);
1568 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL);
1569 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName);
1570 }
1571 if (executableURL == NULL) {
1572 CFRelease(exeSubdirURL);
1573 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL);
1574 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName);
1575 }
1576 if (executableURL == NULL) {
1577 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeDirURL, executableName);
1578 }
1579
1580 CFRelease(exeDirURL);
1581 CFRelease(exeSubdirURL);
1582 }
1583
1584 // If this was an old bundle, or we did not find the executable in the Excutables subdirectory, look directly in the bundle wrapper.
1585 if (executableURL == NULL) {
1586 executableURL = _CFBundleCopyExecutableURLRaw(alloc, url, executableName);
1587 }
1588
1589 #if defined(__WIN32__)
1590 // Windows only: If we still haven't found the exe, look in the Executables folder.
1591 // But only for the main bundle exe
1592 if (lookupMainExe && (executableURL == NULL)) {
1593 CFURLRef exeDirURL;
1594
1595 exeDirURL = CFURLCreateWithString(alloc, CFSTR("../../Executables"), url);
1596
1597 executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeDirURL, executableName);
1598
1599 CFRelease(exeDirURL);
1600 }
1601 #endif
1602
1603 if (lookupMainExe && !ignoreCache && !useOtherPlatform && (bundle != NULL) && (infoDict != NULL) && (executableURL != NULL)) {
1604 // We found it. Cache the path.
1605 CFURLRef absURL = CFURLCopyAbsoluteURL(executableURL);
1606 executablePath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
1607 CFRelease(absURL);
1608 CFDictionarySetValue((CFMutableDictionaryRef)infoDict, _kCFBundleExecutablePathKey, executablePath);
1609 CFRelease(executablePath);
1610 }
1611 if (lookupMainExe && !useOtherPlatform && (bundle != NULL) && (executableURL == NULL)) {
1612 bundle->_binaryType = __CFBundleNoBinary;
1613 }
1614 if (lookupMainExe) {
1615 CFRelease(executableName);
1616 }
1617 }
1618 }
1619
1620 if ((bundle == NULL) && (infoDict != NULL)) {
1621 CFRelease(infoDict);
1622 }
1623
1624 return executableURL;
1625 }
1626
1627 CFURLRef _CFBundleCopyExecutableURLInDirectory(CFURLRef url) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL, NULL, url, NULL, true, false);}
1628
1629 CFURLRef _CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL, NULL, url, NULL, true, true);}
1630
1631 CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, NULL, false, false);}
1632
1633 static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, NULL, true, false);}
1634
1635 CFURLRef CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle, CFStringRef executableName) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, executableName, true, false);}
1636
1637 Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle) {return bundle->_isLoaded;}
1638
1639 CFBundleExecutableType CFBundleGetExecutableType(CFBundleRef bundle) {
1640 CFBundleExecutableType result = kCFBundleOtherExecutableType;
1641 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
1642
1643 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary;
1644 #if defined(BINARY_SUPPORT_DYLD)
1645 if (bundle->_binaryType == __CFBundleUnknownBinary) {
1646 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
1647 #if defined(BINARY_SUPPORT_CFM)
1648 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) {
1649 bundle->_resourceData._executableLacksResourceFork = true;
1650 }
1651 #endif /* BINARY_SUPPORT_CFM */
1652 }
1653 #endif /* BINARY_SUPPORT_DYLD */
1654 if (executableURL) CFRelease(executableURL);
1655
1656 if (bundle->_binaryType == __CFBundleCFMBinary) {
1657 result = kCFBundlePEFExecutableType;
1658 } else if (bundle->_binaryType == __CFBundleDYLDExecutableBinary || bundle->_binaryType == __CFBundleDYLDBundleBinary || bundle->_binaryType == __CFBundleDYLDFrameworkBinary) {
1659 result = kCFBundleMachOExecutableType;
1660 } else if (bundle->_binaryType == __CFBundleDLLBinary) {
1661 result = kCFBundleDLLExecutableType;
1662 } else if (bundle->_binaryType == __CFBundleELFBinary) {
1663 result = kCFBundleELFExecutableType;
1664 }
1665 return result;
1666 }
1667
1668 #define UNKNOWN_FILETYPE 0x0
1669 #define PEF_FILETYPE 0x1000
1670 #define XLS_FILETYPE 0x10001
1671 #define DOC_FILETYPE 0x10002
1672 #define PPT_FILETYPE 0x10003
1673 #define XLS_NAME "Workbook"
1674 #define XLS_NAME2 "Book"
1675 #define DOC_NAME "WordDocument"
1676 #define PPT_NAME "PowerPoint Document"
1677 #define PEF_MAGIC 0x4a6f7921
1678 #define PEF_CIGAM 0x21796f4a
1679 #define PLIST_SEGMENT "__TEXT"
1680 #define PLIST_SECTION "__info_plist"
1681 #define LIB_X11 "/usr/X11R6/lib/libX"
1682
1683 static const uint32_t __CFBundleMagicNumbersArray[] = {
1684 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0x4a6f7921, 0x21796f4a, 0x7f454c46, 0xffd8ffe0,
1685 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, 0x7b5c7274, 0x25504446,
1686 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, 0x38425053, 0x000001b3,
1687 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435, 0x53495444, 0x53747566,
1688 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x6b6f6c79, 0x3026b275, 0x0000000c,
1689 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143, 0x00010000, 0x74727565, 0x4f54544f,
1690 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70, 0x3c435058, 0x28445746, 0x424f4d53
1691 };
1692
1693 // string, with groups of 5 characters being 1 element in the array
1694 static const char * __CFBundleExtensionsArray =
1695 "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" "elf\0\0" "jpeg\0"
1696 "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" "rtf\0\0" "pdf\0\0"
1697 "ra\0\0\0""rm\0\0\0""au\0\0\0""au\0\0\0""iff\0\0" "riff\0" "psd\0\0" "mpeg\0"
1698 "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0"
1699 "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""dmg\0\0" "wmv\0\0" "jp2\0\0"
1700 "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0" "ttf\0\0" "ttf\0\0" "otf\0\0"
1701 "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0" "cpx\0\0" "dwf\0\0" "bom\0\0";
1702
1703 #define NUM_EXTENSIONS 56
1704 #define EXTENSION_LENGTH 5
1705 #define MAGIC_BYTES_TO_READ 512
1706
1707 #if defined(BINARY_SUPPORT_DYLD)
1708
1709 CF_INLINE uint32_t _CFBundleSwapInt32Conditional(uint32_t arg, Boolean swap) {return swap ? CFSwapInt32(arg) : arg;}
1710 CF_INLINE uint32_t _CFBundleSwapInt64Conditional(uint64_t arg, Boolean swap) {return swap ? CFSwapInt64(arg) : arg;}
1711
1712 static CFDictionaryRef _CFBundleGrokInfoDictFromData(const char *bytes, uint32_t length) {
1713 CFMutableDictionaryRef result = NULL;
1714 CFDataRef infoData = NULL;
1715 if (NULL != bytes && 0 < length) {
1716 infoData = CFDataCreateWithBytesNoCopy(NULL, bytes, length, kCFAllocatorNull);
1717 if (infoData) {
1718
1719 __CFSetNastyFile(CFSTR("<plist section in main executable>"));
1720
1721 result = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(NULL, infoData, kCFPropertyListMutableContainers, NULL);
1722 if (result && CFDictionaryGetTypeID() != CFGetTypeID(result)) {
1723 CFRelease(result);
1724 result = NULL;
1725 }
1726 CFRelease(infoData);
1727 }
1728 if (!result) {
1729 result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1730 }
1731 }
1732 return result;
1733 }
1734
1735 static CFDictionaryRef _CFBundleGrokInfoDictFromMainExecutable() {
1736 unsigned long length = 0;
1737 char *bytes = getsectdata(PLIST_SEGMENT, PLIST_SECTION, &length);
1738 return _CFBundleGrokInfoDictFromData(bytes, length);
1739 }
1740
1741 static CFDictionaryRef _CFBundleGrokInfoDictFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) {
1742 struct stat statBuf;
1743 off_t fileLength = 0;
1744 char *maploc = NULL;
1745 const char *loc;
1746 unsigned i, j;
1747 CFDictionaryRef result = NULL;
1748 Boolean foundit = false;
1749 if (fd >= 0 && fstat(fd, &statBuf) == 0 && (maploc = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != (void *)-1) {
1750 loc = maploc;
1751 fileLength = statBuf.st_size;
1752 } else {
1753 loc = bytes;
1754 fileLength = length;
1755 }
1756 if (fileLength > offset + sizeof(struct mach_header_64)) {
1757 if (sixtyFour) {
1758 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->ncmds, swapped);
1759 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->sizeofcmds, swapped);
1760 const char *startofcmds = loc + offset + sizeof(struct mach_header_64);
1761 const char *endofcmds = startofcmds + sizeofcmds;
1762 struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds;
1763 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength;
1764 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) {
1765 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) {
1766 struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64));
1767 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped);
1768 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) {
1769 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, PLIST_SEGMENT, sizeof(sp->segname))) {
1770 uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped);
1771 uint32_t sectlength = (uint32_t)(sectlength64 & 0xffffffff);
1772 uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped);
1773 const char *sectbytes = loc + offset + sectoffset;
1774 // we don't support huge-sized plists
1775 if (sectlength64 <= 0xffffffff && loc <= sectbytes && sectbytes + sectlength <= loc + fileLength) result = _CFBundleGrokInfoDictFromData(sectbytes, sectlength);
1776 foundit = true;
1777 }
1778 sp = (struct section_64 *)((char *)sp + sizeof(struct section_64));
1779 }
1780 }
1781 sgp = (struct segment_command_64 *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped));
1782 }
1783 } else {
1784 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->ncmds, swapped);
1785 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->sizeofcmds, swapped);
1786 const char *startofcmds = loc + offset + sizeof(struct mach_header);
1787 const char *endofcmds = startofcmds + sizeofcmds;
1788 struct segment_command *sgp = (struct segment_command *)startofcmds;
1789 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength;
1790 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) {
1791 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) {
1792 struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command));
1793 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped);
1794 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) {
1795 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, PLIST_SEGMENT, sizeof(sp->segname))) {
1796 uint32_t sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped);
1797 uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped);
1798 const char *sectbytes = loc + offset + sectoffset;
1799 if (loc <= sectbytes && sectbytes + sectlength <= loc + fileLength) result = _CFBundleGrokInfoDictFromData(sectbytes, sectlength);
1800 foundit = true;
1801 }
1802 sp = (struct section *)((char *)sp + sizeof(struct section));
1803 }
1804 }
1805 sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped));
1806 }
1807 }
1808 }
1809 if (maploc) munmap(maploc, statBuf.st_size);
1810 return result;
1811 }
1812
1813 static Boolean _CFBundleGrokX11(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) {
1814 static const char libX11name[] = LIB_X11;
1815 struct stat statBuf;
1816 off_t fileLength = 0;
1817 char *maploc = NULL;
1818 const char *loc;
1819 unsigned i;
1820 Boolean result = false;
1821 if (fd >= 0 && fstat(fd, &statBuf) == 0 && (maploc = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != (void *)-1) {
1822 loc = maploc;
1823 fileLength = statBuf.st_size;
1824 } else {
1825 loc = bytes;
1826 fileLength = length;
1827 }
1828 if (fileLength > offset + sizeof(struct mach_header_64)) {
1829 if (sixtyFour) {
1830 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->ncmds, swapped);
1831 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->sizeofcmds, swapped);
1832 const char *startofcmds = loc + offset + sizeof(struct mach_header_64);
1833 const char *endofcmds = startofcmds + sizeofcmds;
1834 struct dylib_command *dlp = (struct dylib_command *)startofcmds;
1835 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength;
1836 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) {
1837 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) {
1838 uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped);
1839 if (0 == strncmp((char *)dlp + nameoffset, libX11name, sizeof(libX11name) - 1)) result = true;
1840 }
1841 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped));
1842 }
1843 } else {
1844 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->ncmds, swapped);
1845 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->sizeofcmds, swapped);
1846 const char *startofcmds = loc + offset + sizeof(struct mach_header);
1847 const char *endofcmds = startofcmds + sizeofcmds;
1848 struct dylib_command *dlp = (struct dylib_command *)startofcmds;
1849 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength;
1850 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) {
1851 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) {
1852 uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped);
1853 if (0 == strncmp((char *)dlp + nameoffset, libX11name, sizeof(libX11name) - 1)) result = true;
1854 }
1855 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped));
1856 }
1857 }
1858 }
1859 if (maploc) munmap(maploc, statBuf.st_size);
1860 return result;
1861 }
1862
1863 static UInt32 _CFBundleGrokMachTypeForFatFile(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFDictionaryRef *infodict) {
1864 UInt32 machtype = UNKNOWN_FILETYPE, magic, numFatHeaders = ((struct fat_header *)bytes)->nfat_arch, maxFatHeaders = (length - sizeof(struct fat_header)) / sizeof(struct fat_arch);
1865 unsigned char buffer[sizeof(struct mach_header_64)];
1866 const unsigned char *moreBytes = NULL;
1867 const NXArchInfo *archInfo = NXGetLocalArchInfo();
1868 struct fat_arch *fat = NULL;
1869
1870 if (isX11) *isX11 = false;
1871 if (infodict) *infodict = NULL;
1872 if (numFatHeaders > maxFatHeaders) numFatHeaders = maxFatHeaders;
1873 if (numFatHeaders > 0) {
1874 fat = NXFindBestFatArch(archInfo->cputype, archInfo->cpusubtype, (struct fat_arch *)(bytes + sizeof(struct fat_header)), numFatHeaders);
1875 if (!fat) fat = (struct fat_arch *)(bytes + sizeof(struct fat_header));
1876 }
1877 if (fat) {
1878 if (fd >= 0 && lseek(fd, fat->offset, SEEK_SET) == (off_t)fat->offset && read(fd, buffer, sizeof(buffer)) >= (int)sizeof(buffer)) {
1879 moreBytes = buffer;
1880 } else if (bytes && (uint32_t)length >= fat->offset + 512) {
1881 moreBytes = bytes + fat->offset;
1882 }
1883 if (moreBytes) {
1884 magic = *((UInt32 *)moreBytes);
1885 if (MH_MAGIC == magic) {
1886 machtype = ((struct mach_header *)moreBytes)->filetype;
1887 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, false, false);
1888 if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, fat->offset, false, false);
1889 } else if (MH_CIGAM == magic) {
1890 machtype = CFSwapInt32(((struct mach_header *)moreBytes)->filetype);
1891 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, true, false);
1892 if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, fat->offset, true, false);
1893 } else if (MH_MAGIC_64 == magic) {
1894 machtype = ((struct mach_header_64 *)moreBytes)->filetype;
1895 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, false, true);
1896 if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, fat->offset, false, true);
1897 } else if (MH_CIGAM_64 == magic) {
1898 machtype = CFSwapInt32(((struct mach_header_64 *)moreBytes)->filetype);
1899 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, true, true);
1900 if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, fat->offset, true, true);
1901 }
1902 }
1903 }
1904 return machtype;
1905 }
1906
1907 static UInt32 _CFBundleGrokMachType(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFDictionaryRef *infodict) {
1908 unsigned int magic = *((UInt32 *)bytes), machtype = UNKNOWN_FILETYPE;
1909 CFIndex i;
1910
1911 if (isX11) *isX11 = false;
1912 if (infodict) *infodict = NULL;
1913 if (MH_MAGIC == magic) {
1914 machtype = ((struct mach_header *)bytes)->filetype;
1915 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, false, false);
1916 if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, 0, false, false);
1917 } else if (MH_CIGAM == magic) {
1918 for (i = 0; i < length; i += 4) *(UInt32 *)(bytes + i) = CFSwapInt32(*(UInt32 *)(bytes + i));
1919 machtype = ((struct mach_header *)bytes)->filetype;
1920 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, true, false);
1921 if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, 0, true, false);
1922 } else if (MH_MAGIC_64 == magic) {
1923 machtype = ((struct mach_header_64 *)bytes)->filetype;
1924 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, false, true);
1925 if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, 0, false, true);
1926 } else if (MH_CIGAM_64 == magic) {
1927 for (i = 0; i < length; i += 4) *(UInt32 *)(bytes + i) = CFSwapInt32(*(UInt32 *)(bytes + i));
1928 machtype = ((struct mach_header_64 *)bytes)->filetype;
1929 if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, true, true);
1930 if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, 0, true, true);
1931 } else if (FAT_MAGIC == magic) {
1932 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, isX11, infodict);
1933 } else if (FAT_CIGAM == magic) {
1934 for (i = 0; i < length; i += 4) *(UInt32 *)(bytes + i) = CFSwapInt32(*(UInt32 *)(bytes + i));
1935 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, isX11, infodict);
1936 } else if (PEF_MAGIC == magic || PEF_CIGAM == magic) {
1937 machtype = PEF_FILETYPE;
1938 }
1939 return machtype;
1940 }
1941
1942 #endif /* BINARY_SUPPORT_DYLD */
1943
1944 static UInt32 _CFBundleGrokFileTypeForOLEFile(int fd, const void *bytes, CFIndex length, off_t offset) {
1945 UInt32 filetype = UNKNOWN_FILETYPE;
1946 static const unsigned char xlsname[] = XLS_NAME, xlsname2[] = XLS_NAME2, docname[] = DOC_NAME, pptname[] = PPT_NAME;
1947 const unsigned char *moreBytes = NULL;
1948 unsigned char buffer[512];
1949
1950 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset && read(fd, buffer, sizeof(buffer)) >= (int)sizeof(buffer)) {
1951 moreBytes = buffer;
1952 } else if (bytes && length >= offset + 512) {
1953 moreBytes = bytes + offset;
1954 }
1955 if (moreBytes) {
1956 CFIndex i, j;
1957 Boolean foundit = false;
1958 for (i = 0; !foundit && i < 4; i++) {
1959 char namelength = moreBytes[128 * i + 64] / 2;
1960 if (sizeof(xlsname) == namelength) {
1961 for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != xlsname[j]) foundit = false;
1962 if (foundit) filetype = XLS_FILETYPE;
1963 } else if (sizeof(xlsname2) == namelength) {
1964 for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != xlsname2[j]) foundit = false;
1965 if (foundit) filetype = XLS_FILETYPE;
1966 } else if (sizeof(docname) == namelength) {
1967 for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != docname[j]) foundit = false;
1968 if (foundit) filetype = DOC_FILETYPE;
1969 } else if (sizeof(pptname) == namelength) {
1970 for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != pptname[j]) foundit = false;
1971 if (foundit) filetype = PPT_FILETYPE;
1972 }
1973 }
1974 }
1975 return filetype;
1976 }
1977
1978 static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef *extension, UInt32 *machtype, CFDictionaryRef *infodict) {
1979 struct stat statBuf;
1980 int fd = -1;
1981 char path[CFMaxPathSize];
1982 const unsigned char *bytes = NULL;
1983 unsigned char buffer[MAGIC_BYTES_TO_READ];
1984 CFIndex i, length = 0;
1985 off_t fileLength = 0;
1986 const char *ext = NULL;
1987 UInt32 mt = UNKNOWN_FILETYPE;
1988 #if defined(BINARY_SUPPORT_DYLD)
1989 Boolean isX11 = false;
1990 #endif /* BINARY_SUPPORT_DYLD */
1991 Boolean isFile = false, isPlain = true, isZero = true, isHTML = false;
1992 // extensions returned: o, tool, x11app, pef, core, dylib, bundle, elf, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, 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, 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
1993 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
1994 if (url && CFURLGetFileSystemRepresentation(url, true, path, CFMaxPathSize) && stat(path, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG && (fd = open(path, O_RDONLY, 0777)) >= 0) {
1995 // cjk: It is not at clear that not caching would be a win here, since
1996 // in most cases the sniffing of the executable is only done lazily,
1997 // the executable is likely to be immediately used again; say, the
1998 // bundle executable loaded. CFBundle does not need the data again,
1999 // but for the system as a whole not caching could be a net win or lose.
2000 // So, this is where the cache disablement would go, but I am not going
2001 // to turn it on at this point.
2002 // fcntl(fd, F_NOCACHE, 1);
2003 length = read(fd, buffer, MAGIC_BYTES_TO_READ);
2004 fileLength = statBuf.st_size;
2005 bytes = buffer;
2006 isFile = true;
2007 } else if (data) {
2008 length = CFDataGetLength(data);
2009 fileLength = (off_t)length;
2010 bytes = CFDataGetBytePtr(data);
2011 if (length == 0) ext = "txt";
2012 }
2013 if (bytes) {
2014 if (length >= 4) {
2015 UInt32 magic = CFSwapInt32HostToBig(*((UInt32 *)bytes));
2016 for (i = 0; !ext && i < NUM_EXTENSIONS; i++) {
2017 if (__CFBundleMagicNumbersArray[i] == magic) ext = __CFBundleExtensionsArray + i * EXTENSION_LENGTH;
2018 }
2019 if (ext) {
2020 if (0xcafebabe == magic && 8 <= length && 0 != *((UInt16 *)(bytes + 4))) ext = "class";
2021 #if defined(BINARY_SUPPORT_DYLD)
2022 else if ((int)sizeof(struct mach_header_64) <= length) mt = _CFBundleGrokMachType(fd, bytes, length, extension ? &isX11 : NULL, infodict);
2023
2024 if (MH_OBJECT == mt) ext = "o";
2025 else if (MH_EXECUTE == mt) ext = isX11 ? "x11app" : "tool";
2026 else if (PEF_FILETYPE == mt) ext = "pef";
2027 else if (MH_CORE == mt) ext = "core";
2028 else if (MH_DYLIB == mt) ext = "dylib";
2029 else if (MH_BUNDLE == mt) ext = "bundle";
2030 #endif /* BINARY_SUPPORT_DYLD */
2031 else if (0x7b5c7274 == magic && (6 > length || 'f' != bytes[4])) ext = NULL;
2032 else if (0x00010000 == magic && (6 > length || 0 != bytes[4])) ext = NULL;
2033 else if (0x47494638 == magic && (6 > length || (0x3761 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4)))))) ext = NULL;
2034 else if (0x0000000c == magic && (6 > length || 0x6a50 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL;
2035 else if (0x2356524d == magic && (6 > length || 0x4c20 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL;
2036 else if (0x28445746 == magic && (6 > length || 0x2056 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL;
2037 else if (0x30373037 == magic && (6 > length || 0x30 != bytes[4] || !isdigit(bytes[5]))) ext = NULL;
2038 else if (0x41433130 == magic && (6 > length || 0x31 != bytes[4] || !isdigit(bytes[5]))) ext = NULL;
2039 else if (0x89504e47 == magic && (8 > length || 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2040 else if (0x53747566 == magic && (8 > length || 0x66497420 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2041 else if (0x3026b275 == magic && (8 > length || 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2042 else if (0x67696d70 == magic && (8 > length || 0x20786366 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2043 else if (0x424f4d53 == magic && (8 > length || 0x746f7265 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL;
2044 else if (0x25215053 == magic && 14 <= length && 0 == strncmp(bytes + 4, "-AdobeFont", 10)) ext = "pfa";
2045 else if (0x504b0304 == magic && 38 <= length && 0x4d455441 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 30))) && 0x2d494e46 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34)))) ext = "jar";
2046 else if (0x464f524d == magic) {
2047 // IFF
2048 ext = NULL;
2049 if (12 <= length) {
2050 UInt32 iffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)));
2051 if (0x41494646 == iffMagic) ext = "aiff";
2052 else if (0x414946 == iffMagic) ext = "aifc";
2053 }
2054 } else if (0x52494646 == magic) {
2055 // RIFF
2056 ext = NULL;
2057 if (12 <= length) {
2058 UInt32 riffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)));
2059 if (0x57415645 == riffMagic) ext = "wav";
2060 else if (0x41564920 == riffMagic) ext = "avi";
2061 }
2062 } else if (0xd0cf11e0 == magic) {
2063 // OLE
2064 if (52 <= length) {
2065 UInt32 ft = _CFBundleGrokFileTypeForOLEFile(fd, bytes, length, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 48)))));
2066 if (XLS_FILETYPE == ft) ext = "xls";
2067 else if (DOC_FILETYPE == ft) ext = "doc";
2068 else if (PPT_FILETYPE == ft) ext = "ppt";
2069 }
2070 } else if (0x62656769 == magic) {
2071 // uu
2072 ext = NULL;
2073 if (76 <= length && 'n' == bytes[4] && ' ' == bytes[5] && isdigit(bytes[6]) && isdigit(bytes[7]) && isdigit(bytes[8]) && ' ' == bytes[9]) {
2074 CFIndex endOfLine = 0;
2075 for (i = 10; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i;
2076 if (10 <= endOfLine && endOfLine + 62 < length && 'M' == bytes[endOfLine + 1] && '\n' == bytes[endOfLine + 62]) {
2077 ext = "uu";
2078 for (i = endOfLine + 1; ext && i < endOfLine + 62; i++) if (!isprint(bytes[i])) ext = NULL;
2079 }
2080 }
2081 }
2082 }
2083 if (extension && !ext) {
2084 UInt16 shortMagic = CFSwapInt16HostToBig(*((UInt16 *)bytes));
2085 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";
2086 else if (8 <= length && (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "mov";
2087 else if (8 <= length && (0x69647363 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "qtif";
2088 else if (8 <= length && 0x424f424f == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) ext = "cwk";
2089 else if (8 <= length && 0x62706c69 == magic && 0x7374 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && isdigit(bytes[6]) && isdigit(bytes[7])) {
2090 for (i = 8; !ext && i < 128 && i + 16 <= length; i++) {
2091 if (0 == strncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive";
2092 }
2093 if (!ext) ext = "plist";
2094 } else if (12 <= length && 0x66747970 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) {
2095 // ??? list of ftyp values needs to be checked
2096 if (0x6d703432 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) ext = "mp4";
2097 else if (0x4d344120 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) ext = "m4a";
2098 else if (0x4d344220 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) ext = "m4b";
2099 else if (0x4d345020 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) ext = "m4p";
2100 } else if (0x424d == shortMagic && 18 <= length && 40 == CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 14)))) ext = "bmp";
2101 else if (20 <= length && 0 == strncmp(bytes + 6, "%!PS-AdobeFont", 14)) ext = "pfb";
2102 else if (40 <= length && 0x42696e48 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 38)))) ext = "hqx";
2103 else if (128 <= length && 0x6d42494e == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 102)))) ext = "bin";
2104 else if (128 <= length && 0 == bytes[0] && 0 < bytes[1] && bytes[1] < 64 && 0 == bytes[74] && 0 == bytes[82] && 0 == (fileLength % 128)) {
2105 unsigned df = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 83))), rf = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 87))), blocks = 1 + (df + 127) / 128 + (rf + 127) / 128;
2106 if (df < 0x00800000 && rf < 0x00800000 && 1 < blocks && (off_t)(128 * blocks) == fileLength) ext = "bin";
2107 } else if (265 <= length && 0x75737461 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 261))))) ext = "tar";
2108 else if (0xfeff == shortMagic || 0xfffe == shortMagic) ext = "txt";
2109 else if (0x1f9d == shortMagic) ext = "Z";
2110 else if (0x1f8b == shortMagic) ext = "gz";
2111 else if (0x71c7 == shortMagic || 0xc771 == shortMagic) ext = "cpio";
2112 else if (0xf702 == shortMagic) ext = "dvi";
2113 else if (0x01da == shortMagic && (0 == bytes[2] || 1 == bytes[2]) && (0 < bytes[3] && 16 > bytes[3])) ext = "sgi";
2114 else if (0x2321 == shortMagic) {
2115 CFIndex endOfLine = 0, lastSlash = 0;
2116 for (i = 2; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i;
2117 if (endOfLine > 3) {
2118 for (i = endOfLine - 1; 0 == lastSlash && i > 1; i--) if ('/' == bytes[i]) lastSlash = i;
2119 if (lastSlash > 0) {
2120 if (0 == strncmp(bytes + lastSlash + 1, "perl", 4)) ext = "pl";
2121 else if (0 == strncmp(bytes + lastSlash + 1, "python", 6)) ext = "py";
2122 else if (0 == strncmp(bytes + lastSlash + 1, "ruby", 4)) ext = "rb";
2123 else ext = "sh";
2124 }
2125 }
2126 } else if (0xffd8 == shortMagic && 0xff == bytes[2]) ext = "jpeg";
2127 else if (0x4657 == shortMagic && 0x53 == bytes[2]) ext = "swf";
2128 else if (0x4357 == shortMagic && 0x53 == bytes[2]) ext = "swc";
2129 else if (0x4944 == shortMagic && '3' == bytes[2] && 0x20 > bytes[3]) ext = "mp3";
2130 else if (0x425a == shortMagic && isdigit(bytes[2]) && isdigit(bytes[3])) ext = "bz";
2131 else if (0x425a == shortMagic && 'h' == bytes[2] && isdigit(bytes[3]) && 8 <= length && (0x31415926 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "bz2";
2132 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2)))) ext = "tfm";
2133 else if ('<' == bytes[0] && 14 <= length) {
2134 if (0 == strncasecmp(bytes + 1, "!doctype html", 13) || 0 == strncasecmp(bytes + 1, "head", 4) || 0 == strncasecmp(bytes + 1, "title", 5) || 0 == strncasecmp(bytes + 1, "html", 4)) {
2135 ext = "html";
2136 } else if (0 == strncasecmp(bytes + 1, "?xml", 4)) {
2137 for (i = 4; !ext && i < 128 && i + 20 <= length; i++) {
2138 if ('<' == bytes[i]) {
2139 if (0 == strncasecmp(bytes + i + 1, "abiword", 7)) ext = "abw";
2140 else if (0 == strncasecmp(bytes + i + 1, "!doctype svg", 12)) ext = "svg";
2141 else if (0 == strncasecmp(bytes + i + 1, "!doctype x3d", 12)) ext = "x3d";
2142 else if (0 == strncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html";
2143 else if (0 == strncasecmp(bytes + i + 1, "!doctype plist", 14)) ext = "plist";
2144 else if (0 == strncasecmp(bytes + i + 1, "!doctype posingfont", 19)) ext = "sfont";
2145 }
2146 }
2147 if (!ext) ext = "xml";
2148 }
2149 }
2150 }
2151 }
2152 if (extension && !ext) {
2153 //??? what about MacOSRoman?
2154 for (i = 0; (isPlain || isZero) && !isHTML && i < length && i < 512; i++) {
2155 char c = bytes[i];
2156 if (0x7f <= c || (0x20 > c && !isspace(c))) isPlain = false;
2157 if (0 != c) isZero = false;
2158 if (isPlain && '<' == c && i + 14 <= length && 0 == strncasecmp(bytes + i + 1, "!doctype html", 13)) isHTML = true;
2159 }
2160 if (isHTML) {
2161 ext = "html";
2162 } else if (isPlain) {
2163 if (16 <= length && 0 == strncmp(bytes, "StartFontMetrics", 16)) ext = "afm";
2164 else ext = "txt";
2165 } else if (isZero && length >= MAGIC_BYTES_TO_READ && fileLength >= 526) {
2166 if (isFile) {
2167 if (lseek(fd, 512, SEEK_SET) == 512 && read(fd, buffer, MAGIC_BYTES_TO_READ) >= 14) {
2168 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(buffer + 10)))) ext = "pict";
2169 }
2170 } else {
2171 if (526 <= length && 0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 522)))) ext = "pict";
2172 }
2173 }
2174 }
2175 if (extension && !ext && !isZero && length >= MAGIC_BYTES_TO_READ && fileLength >= 1024) {
2176 if (isFile) {
2177 off_t offset = fileLength - 512;
2178 if (lseek(fd, offset, SEEK_SET) == offset && read(fd, buffer, 512) >= 512) {
2179 if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)buffer)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + 504))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + 508))))) ext = "dmg";
2180 }
2181 } else {
2182 if (512 <= length && (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 512))) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 4)))))) ext = "dmg";
2183 }
2184 }
2185 }
2186 if (extension) *extension = ext ? CFStringCreateWithCStringNoCopy(NULL, ext, kCFStringEncodingASCII, kCFAllocatorNull) : NULL;
2187 if (machtype) *machtype = mt;
2188 if (fd >= 0) close(fd);
2189 return (ext != NULL);
2190 }
2191
2192 CFStringRef _CFBundleCopyFileTypeForFileURL(CFURLRef url) {
2193 CFStringRef extension = NULL;
2194 (void)_CFBundleGrokFileType(url, NULL, &extension, NULL, NULL);
2195 return extension;
2196 }
2197
2198 CFStringRef _CFBundleCopyFileTypeForFileData(CFDataRef data) {
2199 CFStringRef extension = NULL;
2200 (void)_CFBundleGrokFileType(NULL, data, &extension, NULL, NULL);
2201 return extension;
2202 }
2203
2204 __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url) {
2205 CFDictionaryRef result = NULL;
2206 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, &result);
2207 return result;
2208 }
2209
2210 #if defined(BINARY_SUPPORT_DYLD)
2211
2212 __private_extern__ __CFPBinaryType _CFBundleGrokBinaryType(CFURLRef executableURL) {
2213 // 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).
2214 __CFPBinaryType result = executableURL ? __CFBundleUnreadableBinary : __CFBundleNoBinary;
2215 UInt32 machtype = UNKNOWN_FILETYPE;
2216 if (_CFBundleGrokFileType(executableURL, NULL, NULL, &machtype, NULL)) {
2217 switch (machtype) {
2218 case MH_EXECUTE:
2219 result = __CFBundleDYLDExecutableBinary;
2220 break;
2221 case MH_BUNDLE:
2222 result = __CFBundleDYLDBundleBinary;
2223 break;
2224 case MH_DYLIB:
2225 result = __CFBundleDYLDFrameworkBinary;
2226 break;
2227 #if defined(BINARY_SUPPORT_CFM)
2228 case PEF_FILETYPE:
2229 result = __CFBundleCFMBinary;
2230 break;
2231 #endif /* BINARY_SUPPORT_CFM */
2232 }
2233 }
2234 return result;
2235 }
2236
2237 #endif /* BINARY_SUPPORT_DYLD */
2238
2239 void _CFBundleSetCFMConnectionID(CFBundleRef bundle, void *connectionID) {
2240 #if defined(BINARY_SUPPORT_CFM)
2241 if (bundle->_binaryType == __CFBundleUnknownBinary || bundle->_binaryType == __CFBundleUnreadableBinary) {
2242 bundle->_binaryType = __CFBundleCFMBinary;
2243 }
2244 #endif /* BINARY_SUPPORT_CFM */
2245 bundle->_connectionCookie = connectionID;
2246 bundle->_isLoaded = true;
2247 }
2248
2249 Boolean CFBundleLoadExecutable(CFBundleRef bundle) {
2250 Boolean result = false;
2251 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2252
2253 if (!executableURL) {
2254 bundle->_binaryType = __CFBundleNoBinary;
2255 }
2256 #if defined(BINARY_SUPPORT_DYLD)
2257 // make sure we know whether bundle is already loaded or not
2258 if (!bundle->_isLoaded) {
2259 _CFBundleDYLDCheckLoaded(bundle);
2260 }
2261 // We might need to figure out what it is
2262 if (bundle->_binaryType == __CFBundleUnknownBinary) {
2263 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL);
2264 #if defined(BINARY_SUPPORT_CFM)
2265 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) {
2266 bundle->_resourceData._executableLacksResourceFork = true;
2267 }
2268 #endif /* BINARY_SUPPORT_CFM */
2269 }
2270 #endif /* BINARY_SUPPORT_DYLD */
2271 if (executableURL) CFRelease(executableURL);
2272
2273 if (bundle->_isLoaded) {
2274 // Remove from the scheduled unload set if we are there.
2275 __CFSpinLock(&CFBundleGlobalDataLock);
2276 if (_bundlesToUnload) {
2277 CFSetRemoveValue(_bundlesToUnload, bundle);
2278 }
2279 __CFSpinUnlock(&CFBundleGlobalDataLock);
2280 return true;
2281 }
2282
2283 // Unload bundles scheduled for unloading
2284 if (!_scheduledBundlesAreUnloading) {
2285 _CFBundleUnloadScheduledBundles();
2286 }
2287
2288
2289 switch (bundle->_binaryType) {
2290 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2291 case __CFBundleCFMBinary:
2292 case __CFBundleUnreadableBinary:
2293 result = _CFBundleCFMLoad(bundle);
2294 break;
2295 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2296 #if defined(BINARY_SUPPORT_DYLD)
2297 case __CFBundleDYLDBundleBinary:
2298 result = _CFBundleDYLDLoadBundle(bundle);
2299 break;
2300 case __CFBundleDYLDFrameworkBinary:
2301 result = _CFBundleDYLDLoadFramework(bundle);
2302 break;
2303 case __CFBundleDYLDExecutableBinary:
2304 CFLog(__kCFLogBundle, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle);
2305 break;
2306 #endif /* BINARY_SUPPORT_DYLD */
2307 #if defined(BINARY_SUPPORT_DLL)
2308 case __CFBundleDLLBinary:
2309 result = _CFBundleDLLLoad(bundle);
2310 break;
2311 #endif /* BINARY_SUPPORT_DLL */
2312 case __CFBundleNoBinary:
2313 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for %@"), bundle);
2314 break;
2315 default:
2316 CFLog(__kCFLogBundle, CFSTR("Cannot recognize type of executable for %@"), bundle);
2317 break;
2318 }
2319 if (result && bundle->_plugInData._isPlugIn) _CFBundlePlugInLoaded(bundle);
2320
2321 return result;
2322 }
2323
2324 void CFBundleUnloadExecutable(CFBundleRef bundle) {
2325
2326 if (!_scheduledBundlesAreUnloading) {
2327 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
2328 _CFBundleUnloadScheduledBundles();
2329 }
2330
2331 if (!bundle->_isLoaded) return;
2332
2333 // Remove from the scheduled unload set if we are there.
2334 if (!_scheduledBundlesAreUnloading) {
2335 __CFSpinLock(&CFBundleGlobalDataLock);
2336 }
2337 if (_bundlesToUnload) {
2338 CFSetRemoveValue(_bundlesToUnload, bundle);
2339 }
2340 if (!_scheduledBundlesAreUnloading) {
2341 __CFSpinUnlock(&CFBundleGlobalDataLock);
2342 }
2343
2344 // Give the plugIn code a chance to realize this...
2345 _CFPlugInWillUnload(bundle);
2346
2347 switch (bundle->_binaryType) {
2348 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2349 case __CFBundleCFMBinary:
2350 _CFBundleCFMUnload(bundle);
2351 break;
2352 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2353 #if defined(BINARY_SUPPORT_DYLD)
2354 case __CFBundleDYLDBundleBinary:
2355 _CFBundleDYLDUnloadBundle(bundle);
2356 break;
2357 #endif /* BINARY_SUPPORT_DYLD */
2358 #if defined(BINARY_SUPPORT_DLL)
2359 case __CFBundleDLLBinary:
2360 _CFBundleDLLUnload(bundle);
2361 break;
2362 #endif /* BINARY_SUPPORT_DLL */
2363 default:
2364 break;
2365 }
2366 if (!bundle->_isLoaded && bundle->_glueDict != NULL) {
2367 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle));
2368 CFRelease(bundle->_glueDict);
2369 bundle->_glueDict = NULL;
2370 }
2371 }
2372
2373 __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) {
2374 __CFSpinLock(&CFBundleGlobalDataLock);
2375 if (!_bundlesToUnload) {
2376 // Create this from the default allocator
2377 CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks;
2378 nonRetainingCallbacks.retain = NULL;
2379 nonRetainingCallbacks.release = NULL;
2380 _bundlesToUnload = CFSetCreateMutable(NULL, 0, &nonRetainingCallbacks);
2381 }
2382 CFSetAddValue(_bundlesToUnload, bundle);
2383 __CFSpinUnlock(&CFBundleGlobalDataLock);
2384 }
2385
2386 __private_extern__ void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) {
2387 __CFSpinLock(&CFBundleGlobalDataLock);
2388 if (_bundlesToUnload) {
2389 CFSetRemoveValue(_bundlesToUnload, bundle);
2390 }
2391 __CFSpinUnlock(&CFBundleGlobalDataLock);
2392 }
2393
2394 __private_extern__ void _CFBundleUnloadScheduledBundles(void) {
2395 __CFSpinLock(&CFBundleGlobalDataLock);
2396 if (_bundlesToUnload) {
2397 CFIndex c = CFSetGetCount(_bundlesToUnload);
2398 if (c > 0) {
2399 CFIndex i;
2400 CFBundleRef *unloadThese = CFAllocatorAllocate(NULL, sizeof(CFBundleRef) * c, 0);
2401 CFSetGetValues(_bundlesToUnload, (const void **)unloadThese);
2402 _scheduledBundlesAreUnloading = true;
2403 for (i=0; i<c; i++) {
2404 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2405 CFBundleUnloadExecutable(unloadThese[i]);
2406 }
2407 _scheduledBundlesAreUnloading = false;
2408 CFAllocatorDeallocate(NULL, unloadThese);
2409 }
2410 }
2411 __CFSpinUnlock(&CFBundleGlobalDataLock);
2412 }
2413
2414 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) {
2415 void *tvp = NULL;
2416 // Load if necessary
2417 if (!bundle->_isLoaded) {
2418 if (!CFBundleLoadExecutable(bundle)) return NULL;
2419 }
2420
2421 switch (bundle->_binaryType) {
2422 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2423 case __CFBundleCFMBinary:
2424 tvp = _CFBundleCFMGetSymbolByName(bundle, funcName, kTVectorCFragSymbol);
2425 break;
2426 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2427 #if defined(BINARY_SUPPORT_DYLD)
2428 case __CFBundleDYLDBundleBinary:
2429 case __CFBundleDYLDFrameworkBinary:
2430 case __CFBundleDYLDExecutableBinary:
2431 return _CFBundleDYLDGetSymbolByName(bundle, funcName);
2432 break;
2433 #endif /* BINARY_SUPPORT_DYLD */
2434 #if defined(BINARY_SUPPORT_DLL)
2435 case __CFBundleDLLBinary:
2436 tvp = _CFBundleDLLGetSymbolByName(bundle, funcName);
2437 break;
2438 #endif /* BINARY_SUPPORT_DLL */
2439 default:
2440 break;
2441 }
2442 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2443 if (tvp != NULL) {
2444 if (bundle->_glueDict == NULL) {
2445 bundle->_glueDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, NULL, NULL);
2446 }
2447 void *fp = (void *)CFDictionaryGetValue(bundle->_glueDict, tvp);
2448 if (fp == NULL) {
2449 fp = _CFBundleFunctionPointerForTVector(CFGetAllocator(bundle), tvp);
2450 CFDictionarySetValue(bundle->_glueDict, tvp, fp);
2451 }
2452 return fp;
2453 }
2454 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2455 return tvp;
2456 }
2457
2458 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) {
2459 void *fp = NULL;
2460 // Load if necessary
2461 if (!bundle->_isLoaded) {
2462 if (!CFBundleLoadExecutable(bundle)) return NULL;
2463 }
2464
2465 switch (bundle->_binaryType) {
2466 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2467 case __CFBundleCFMBinary:
2468 return _CFBundleCFMGetSymbolByName(bundle, funcName, kTVectorCFragSymbol);
2469 break;
2470 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2471 #if defined(BINARY_SUPPORT_DYLD)
2472 case __CFBundleDYLDBundleBinary:
2473 case __CFBundleDYLDFrameworkBinary:
2474 case __CFBundleDYLDExecutableBinary:
2475 fp = _CFBundleDYLDGetSymbolByNameWithSearch(bundle, funcName, true);
2476 break;
2477 #endif /* BINARY_SUPPORT_DYLD */
2478 default:
2479 break;
2480 }
2481 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2482 if (fp != NULL) {
2483 if (bundle->_glueDict == NULL) {
2484 bundle->_glueDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, NULL, NULL);
2485 }
2486 void *tvp = (void *)CFDictionaryGetValue(bundle->_glueDict, fp);
2487 if (tvp == NULL) {
2488 tvp = _CFBundleTVectorForFunctionPointer(CFGetAllocator(bundle), fp);
2489 CFDictionarySetValue(bundle->_glueDict, fp, tvp);
2490 }
2491 return tvp;
2492 }
2493 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2494 return fp;
2495 }
2496
2497 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) {
2498 SInt32 i, c;
2499
2500 if (!ftbl) return;
2501
2502 c = CFArrayGetCount(functionNames);
2503 for (i = 0; i < c; i++) {
2504 ftbl[i] = CFBundleGetFunctionPointerForName(bundle, CFArrayGetValueAtIndex(functionNames, i));
2505 }
2506 }
2507
2508 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) {
2509 SInt32 i, c;
2510
2511 if (!ftbl) return;
2512
2513 c = CFArrayGetCount(functionNames);
2514 for (i = 0; i < c; i++) {
2515 ftbl[i] = _CFBundleGetCFMFunctionPointerForName(bundle, CFArrayGetValueAtIndex(functionNames, i));
2516 }
2517 }
2518
2519 void *CFBundleGetDataPointerForName(CFBundleRef bundle, CFStringRef symbolName) {
2520 void *dp = NULL;
2521 // Load if necessary
2522 if (!bundle->_isLoaded) {
2523 if (!CFBundleLoadExecutable(bundle)) return NULL;
2524 }
2525
2526 switch (bundle->_binaryType) {
2527 #if defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2528 case __CFBundleCFMBinary:
2529 dp = _CFBundleCFMGetSymbolByName(bundle, symbolName, kDataCFragSymbol);
2530 break;
2531 #endif /* BINARY_SUPPORT_CFM && __ppc__ */
2532 #if defined(BINARY_SUPPORT_DYLD)
2533 case __CFBundleDYLDBundleBinary:
2534 case __CFBundleDYLDFrameworkBinary:
2535 case __CFBundleDYLDExecutableBinary:
2536 dp = _CFBundleDYLDGetSymbolByName(bundle, symbolName);
2537 break;
2538 #endif /* BINARY_SUPPORT_DYLD */
2539 #if defined(BINARY_SUPPORT_DLL)
2540 case __CFBundleDLLBinary:
2541 /* MF:!!! Handle this someday */
2542 break;
2543 #endif /* BINARY_SUPPORT_DLL */
2544 default:
2545 break;
2546 }
2547 return dp;
2548 }
2549
2550 void CFBundleGetDataPointersForNames(CFBundleRef bundle, CFArrayRef symbolNames, void *stbl[]) {
2551 SInt32 i, c;
2552
2553 if (!stbl) return;
2554
2555 c = CFArrayGetCount(symbolNames);
2556 for (i = 0; i < c; i++) {
2557 stbl[i] = CFBundleGetDataPointerForName(bundle, CFArrayGetValueAtIndex(symbolNames, i));
2558 }
2559 }
2560
2561 __private_extern__ _CFResourceData *__CFBundleGetResourceData(CFBundleRef bundle) {
2562 return &(bundle->_resourceData);
2563 }
2564
2565 CFPlugInRef CFBundleGetPlugIn(CFBundleRef bundle) {
2566 if (bundle->_plugInData._isPlugIn) {
2567 return (CFPlugInRef)bundle;
2568 } else {
2569 return NULL;
2570 }
2571 }
2572
2573 __private_extern__ _CFPlugInData *__CFBundleGetPlugInData(CFBundleRef bundle) {
2574 return &(bundle->_plugInData);
2575 }
2576
2577 __private_extern__ Boolean _CFBundleCouldBeBundle(CFURLRef url) {
2578 Boolean result = false;
2579 Boolean exists;
2580 SInt32 mode;
2581
2582 if (_CFGetFileProperties(NULL, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) {
2583 result = (exists && ((mode & S_IFMT) == S_IFDIR));
2584 #if !defined(__MACOS8__)
2585 result = (result && ((mode & 0444) != 0));
2586 #endif
2587 }
2588 return result;
2589 }
2590
2591 __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocatorRef alloc, CFStringRef executablePath) {
2592 // 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.
2593 #if defined(__WIN32__)
2594 UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 16
2595 UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 23
2596 UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'}; // length 9
2597 #endif
2598
2599 UniChar pathBuff[CFMaxPathSize];
2600 UniChar nameBuff[CFMaxPathSize];
2601 CFIndex length, nameStart, nameLength, savedLength;
2602 CFMutableStringRef cheapStr = CFStringCreateMutableWithExternalCharactersNoCopy(alloc, NULL, 0, 0, NULL);
2603 CFURLRef bundleURL = NULL;
2604
2605 length = CFStringGetLength(executablePath);
2606 if (length > CFMaxPathSize) length = CFMaxPathSize;
2607 CFStringGetCharacters(executablePath, CFRangeMake(0, length), pathBuff);
2608
2609 // Save the name in nameBuff
2610 length = _CFLengthAfterDeletingPathExtension(pathBuff, length);
2611 nameStart = _CFStartOfLastPathComponent(pathBuff, length);
2612 nameLength = length - nameStart;
2613 memmove(nameBuff, &(pathBuff[nameStart]), nameLength * sizeof(UniChar));
2614
2615 // Strip the name from pathBuff
2616 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2617 savedLength = length;
2618
2619 #if defined(__WIN32__)
2620 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
2621 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, 16) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, 9)) {
2622 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2623 bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true);
2624 if (!_CFBundleCouldBeBundle(bundleURL)) {
2625 CFRelease(bundleURL);
2626 bundleURL = NULL;
2627 }
2628 }
2629 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
2630 if (bundleURL == NULL) {
2631 length = savedLength;
2632 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, 23) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, 9)) {
2633 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2634 bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true);
2635 if (!_CFBundleCouldBeBundle(bundleURL)) {
2636 CFRelease(bundleURL);
2637 bundleURL = NULL;
2638 }
2639 }
2640 }
2641 #endif
2642 // * Finally check the executable inside the framework case.
2643 if (bundleURL == NULL) {
2644 // MF:!!! This should ensure the framework name is the same as the library name!
2645 CFIndex curStart;
2646
2647 length = savedLength;
2648 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
2649
2650 while (length > 0) {
2651 curStart = _CFStartOfLastPathComponent(pathBuff, length);
2652 if (curStart >= length) {
2653 break;
2654 }
2655 CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[curStart]), length - curStart, CFMaxPathSize - curStart);
2656 if (CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName1) || CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName2)) {
2657 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2658 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2659 bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true);
2660 if (!_CFBundleCouldBeBundle(bundleURL)) {
2661 CFRelease(bundleURL);
2662 bundleURL = NULL;
2663 }
2664 break;
2665 } else if (CFStringHasSuffix(cheapStr, CFSTR(".framework"))) {
2666 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize);
2667 bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true);
2668 if (!_CFBundleCouldBeBundle(bundleURL)) {
2669 CFRelease(bundleURL);
2670 bundleURL = NULL;
2671 }
2672 break;
2673 }
2674 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length);
2675 }
2676 }
2677
2678 CFStringSetExternalCharactersNoCopy(cheapStr, NULL, 0, 0);
2679 CFRelease(cheapStr);
2680
2681 return bundleURL;
2682 }
2683
2684 #if defined(BINARY_SUPPORT_DYLD)
2685 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath) {
2686 // This finds the bundle for the given path.
2687 // 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.
2688 CFBundleRef bundle;
2689 CFURLRef curURL = _CFBundleCopyFrameworkURLForExecutablePath(NULL, imagePath);
2690 Boolean doFinalProcessing = false;
2691
2692 if (curURL != NULL) {
2693 bundle = _CFBundleFindByURL(curURL, true);
2694 if (bundle == NULL) {
2695 bundle = _CFBundleCreate(NULL, curURL, true, false);
2696 doFinalProcessing = true;
2697 }
2698 if (bundle != NULL && !bundle->_isLoaded) {
2699 // 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)
2700 #if defined(BINARY_SUPPORT_DYLD)
2701 if (bundle->_binaryType == __CFBundleUnknownBinary) {
2702 bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
2703 }
2704 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) {
2705 bundle->_resourceData._executableLacksResourceFork = true;
2706 }
2707 if (!bundle->_imageCookie) _CFBundleDYLDCheckLoaded(bundle);
2708 #endif /* BINARY_SUPPORT_DYLD */
2709 bundle->_isLoaded = true;
2710 }
2711 // Perform delayed final processing steps.
2712 // This must be done after _isLoaded has been set.
2713 if (bundle && doFinalProcessing) {
2714 _CFBundleCheckWorkarounds(bundle);
2715 if (_CFBundleNeedsInitPlugIn(bundle)) {
2716 __CFSpinUnlock(&CFBundleGlobalDataLock);
2717 _CFBundleInitPlugIn(bundle);
2718 __CFSpinLock(&CFBundleGlobalDataLock);
2719 }
2720 }
2721 CFRelease(curURL);
2722 }
2723 }
2724
2725 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths) {
2726 // This finds the bundles for the given paths.
2727 // 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).
2728 CFIndex i, imagePathCount = CFArrayGetCount(imagePaths);
2729
2730 for (i=0; i<imagePathCount; i++) {
2731 _CFBundleEnsureBundleExistsForImagePath(CFArrayGetValueAtIndex(imagePaths, i));
2732 }
2733 }
2734 #endif /* BINARY_SUPPORT_DYLD */
2735
2736 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint) {
2737 // Tickle the main bundle into existence
2738 (void)_CFBundleGetMainBundleAlreadyLocked();
2739 #if defined(BINARY_SUPPORT_DYLD)
2740 CFArrayRef imagePaths = _CFBundleDYLDCopyLoadedImagePathsForHint(hint);
2741 if (imagePaths != NULL) {
2742 _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
2743 CFRelease(imagePaths);
2744 }
2745 #endif
2746 }
2747
2748 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
2749 // 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.
2750
2751 // Tickle the main bundle into existence
2752 (void)_CFBundleGetMainBundleAlreadyLocked();
2753
2754 #if defined(BINARY_SUPPORT_DLL)
2755 #warning (MF) Dont know how to find static bundles for DLLs
2756 #endif
2757
2758 #if defined(BINARY_SUPPORT_CFM)
2759 // CFM bundles are supplied to us by CFM, so we do not need to figure them out ourselves
2760 #endif
2761
2762 #if defined(BINARY_SUPPORT_DYLD)
2763 CFArrayRef imagePaths = _CFBundleDYLDCopyLoadedImagePathsIfChanged();
2764 if (imagePaths != NULL) {
2765 _CFBundleEnsureBundlesExistForImagePaths(imagePaths);
2766 CFRelease(imagePaths);
2767 }
2768 #endif
2769 }
2770
2771 CFArrayRef CFBundleGetAllBundles(void) {
2772 // To answer this properly, we have to have created the static bundles!
2773 __CFSpinLock(&CFBundleGlobalDataLock);
2774 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2775 __CFSpinUnlock(&CFBundleGlobalDataLock);
2776 return _allBundles;
2777 }
2778
2779 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle) {return bundle->_version;}
2780
2781 CF_EXPORT CFURLRef _CFBundleCopyInfoPlistURL(CFBundleRef bundle) {
2782 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
2783 CFStringRef path = CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey);
2784 return (path ? CFRetain(path) : NULL);
2785 }
2786
2787 CF_EXPORT CFURLRef _CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {return CFBundleCopyPrivateFrameworksURL(bundle);}
2788
2789 CF_EXPORT CFURLRef CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {
2790 CFURLRef result = NULL;
2791
2792 if (1 == bundle->_version) {
2793 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase1, bundle->_url);
2794 } else if (2 == bundle->_version) {
2795 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase2, bundle->_url);
2796 } else {
2797 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase0, bundle->_url);
2798 }
2799 return result;
2800 }
2801
2802 CF_EXPORT CFURLRef _CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {return CFBundleCopySharedFrameworksURL(bundle);}
2803
2804 CF_EXPORT CFURLRef CFBundleCopySharedFrameworksURL(CFBundleRef bundle) {
2805 CFURLRef result = NULL;
2806
2807 if (1 == bundle->_version) {
2808 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase1, bundle->_url);
2809 } else if (2 == bundle->_version) {
2810 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase2, bundle->_url);
2811 } else {
2812 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase0, bundle->_url);
2813 }
2814 return result;
2815 }
2816
2817 CF_EXPORT CFURLRef _CFBundleCopySharedSupportURL(CFBundleRef bundle) {return CFBundleCopySharedSupportURL(bundle);}
2818
2819 CF_EXPORT CFURLRef CFBundleCopySharedSupportURL(CFBundleRef bundle) {
2820 CFURLRef result = NULL;
2821
2822 if (1 == bundle->_version) {
2823 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase1, bundle->_url);
2824 } else if (2 == bundle->_version) {
2825 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase2, bundle->_url);
2826 } else {
2827 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase0, bundle->_url);
2828 }
2829 return result;
2830 }
2831
2832 __private_extern__ CFURLRef _CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {return CFBundleCopyBuiltInPlugInsURL(bundle);}
2833
2834 CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) {
2835 CFURLRef result = NULL, alternateResult = NULL;
2836
2837 CFAllocatorRef alloc = CFGetAllocator(bundle);
2838 if (1 == bundle->_version) {
2839 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase1, bundle->_url);
2840 } else if (2 == bundle->_version) {
2841 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase2, bundle->_url);
2842 } else {
2843 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase0, bundle->_url);
2844 }
2845 if (!result || !_urlExists(alloc, result)) {
2846 if (1 == bundle->_version) {
2847 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase1, bundle->_url);
2848 } else if (2 == bundle->_version) {
2849 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase2, bundle->_url);
2850 } else {
2851 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase0, bundle->_url);
2852 }
2853 if (alternateResult && _urlExists(alloc, alternateResult)) {
2854 if (result) CFRelease(result);
2855 result = alternateResult;
2856 } else {
2857 if (alternateResult) CFRelease(alternateResult);
2858 }
2859 }
2860 return result;
2861 }
2862
2863
2864
2865 #if defined(BINARY_SUPPORT_DYLD)
2866
2867 static const void *__CFBundleDYLDFindImage(char *buff) {
2868 const void *header = NULL;
2869 uint32_t i, numImages = _dyld_image_count(), numMatches = 0;
2870 const char *curName, *p, *q;
2871
2872 for (i = 0; !header && i < numImages; i++) {
2873 curName = _dyld_get_image_name(i);
2874 if (curName && 0 == strncmp(curName, buff, CFMaxPathSize)) {
2875 header = _dyld_get_image_header(i);
2876 numMatches = 1;
2877 }
2878 }
2879 if (!header) {
2880 for (i = 0; i < numImages; i++) {
2881 curName = _dyld_get_image_name(i);
2882 if (curName) {
2883 for (p = buff, q = curName; *p && *q && (q - curName < CFMaxPathSize); p++, q++) {
2884 if (*p != *q && (q - curName > 11) && 0 == strncmp(q - 11, ".framework/Versions/", 20) && *(q + 9) && '/' == *(q + 10)) q += 11;
2885 else if (*p != *q && (q - curName > 12) && 0 == strncmp(q - 12, ".framework/Versions/", 20) && *(q + 8) && '/' == *(q + 9)) q += 10;
2886 if (*p != *q) break;
2887 }
2888 if (*p == *q) {
2889 header = _dyld_get_image_header(i);
2890 numMatches++;
2891 }
2892 }
2893 }
2894 }
2895 return (numMatches == 1) ? header : NULL;
2896 }
2897
2898 __private_extern__ Boolean _CFBundleDYLDCheckLoaded(CFBundleRef bundle) {
2899 if (!bundle->_isLoaded) {
2900 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2901
2902 if (executableURL != NULL) {
2903 char buff[CFMaxPathSize];
2904
2905 if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) {
2906 const void *header = __CFBundleDYLDFindImage(buff);
2907 if (header) {
2908 if (bundle->_binaryType == __CFBundleUnknownBinary) {
2909 bundle->_binaryType = __CFBundleDYLDFrameworkBinary;
2910 }
2911 if (!bundle->_imageCookie) bundle->_imageCookie = header;
2912 bundle->_isLoaded = true;
2913 }
2914 }
2915 CFRelease(executableURL);
2916 }
2917 }
2918 return bundle->_isLoaded;
2919 }
2920
2921 __private_extern__ Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle) {
2922 NSLinkEditErrors c = NSLinkEditUndefinedError;
2923 int errorNumber = 0;
2924 const char *fileName = NULL;
2925 const char *errorString = NULL;
2926
2927 if (!bundle->_isLoaded) {
2928 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2929
2930 if (executableURL) {
2931 char buff[CFMaxPathSize];
2932
2933 if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) {
2934 NSObjectFileImage image;
2935 NSObjectFileImageReturnCode retCode = NSCreateObjectFileImageFromFile(buff, &image);
2936 if (retCode == NSObjectFileImageSuccess) {
2937 NSModule module = NSLinkModule(image, buff, (NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR));
2938 if (module) {
2939 bundle->_imageCookie = image;
2940 bundle->_moduleCookie = module;
2941 bundle->_isLoaded = true;
2942 } else {
2943 NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
2944 CFLog(__kCFLogBundle, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName, c, errorNumber, errorString);
2945 if (!NSDestroyObjectFileImage(image)) {
2946 /* MF:!!! Error destroying object file image */
2947 }
2948 }
2949 } else {
2950 CFLog(__kCFLogBundle, CFSTR("dyld returns %d when trying to load %@"), retCode, executableURL);
2951 }
2952 }
2953 CFRelease(executableURL);
2954 } else {
2955 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
2956 }
2957 }
2958 return bundle->_isLoaded;
2959 }
2960
2961 __private_extern__ Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle) {
2962 // !!! Framework loading should be better. Can't unload frameworks.
2963 NSLinkEditErrors c = NSLinkEditUndefinedError;
2964 int errorNumber = 0;
2965 const char *fileName = NULL;
2966 const char *errorString = NULL;
2967
2968 if (!bundle->_isLoaded) {
2969 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
2970
2971 if (executableURL) {
2972 char buff[CFMaxPathSize];
2973
2974 if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) {
2975 void *image = (void *)NSAddImage(buff, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
2976 if (image) {
2977 bundle->_imageCookie = image;
2978 bundle->_isLoaded = true;
2979 } else {
2980 NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
2981 CFLog(__kCFLogBundle, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName, c, errorNumber, errorString);
2982 }
2983 }
2984 CFRelease(executableURL);
2985 } else {
2986 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
2987 }
2988 }
2989 return bundle->_isLoaded;
2990 }
2991
2992 __private_extern__ void _CFBundleDYLDUnloadBundle(CFBundleRef bundle) {
2993 if (bundle->_isLoaded) {
2994 if (bundle->_moduleCookie && !NSUnLinkModule((NSModule)(bundle->_moduleCookie), NSUNLINKMODULE_OPTION_NONE)) {
2995 CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle);
2996 } else {
2997 if (bundle->_moduleCookie && bundle->_imageCookie && !NSDestroyObjectFileImage((NSObjectFileImage)(bundle->_imageCookie))) {
2998 /* MF:!!! Error destroying object file image */
2999 }
3000 bundle->_connectionCookie = NULL;
3001 bundle->_imageCookie = bundle->_moduleCookie = NULL;
3002 bundle->_isLoaded = false;
3003 }
3004 }
3005 }
3006
3007 __private_extern__ void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {return _CFBundleDYLDGetSymbolByNameWithSearch(bundle, symbolName, false);}
3008
3009 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) {
3010 void *result = NULL;
3011 char buff[1026];
3012 NSSymbol symbol = NULL;
3013
3014 // MF:!!! What if the factory was in C++ code (and is therefore mangled differently)? Huh, answer me that!
3015 // MF: The current answer to the mangling question is that you cannot look up C++ functions with this API. Thus things like plugin factories must be extern "C" in plugin code.
3016 buff[0] = '_';
3017 /* MF:??? ASCII appropriate here? */
3018 if (CFStringGetCString(symbolName, &(buff[1]), 1024, kCFStringEncodingASCII)) {
3019 if (bundle->_moduleCookie) {
3020 symbol = NSLookupSymbolInModule((NSModule)(bundle->_moduleCookie), buff);
3021 } else if (bundle->_imageCookie) {
3022 symbol = NSLookupSymbolInImage(bundle->_imageCookie, buff, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
3023 }
3024 if (NULL == symbol && NULL == bundle->_moduleCookie && (NULL == bundle->_imageCookie || globalSearch)) {
3025 char hintBuff[1026];
3026 CFStringRef executableName = _CFBundleCopyExecutableName(NULL, bundle, NULL, NULL);
3027 hintBuff[0] = '\0';
3028 if (executableName) {
3029 if (!CFStringGetCString(executableName, hintBuff, 1024, kCFStringEncodingUTF8)) hintBuff[0] = '\0';
3030 CFRelease(executableName);
3031 }
3032 if (NSIsSymbolNameDefinedWithHint(buff, hintBuff)) {
3033 symbol = NSLookupAndBindSymbolWithHint(buff, hintBuff);
3034 }
3035 }
3036 if (symbol) {
3037 result = NSAddressOfSymbol(symbol);
3038 } else {
3039 #if defined(DEBUG)
3040 CFLog(__kCFLogBundle, CFSTR("dyld cannot find symbol %s in %@"), buff, bundle);
3041 #endif
3042 }
3043 }
3044 return result;
3045 }
3046
3047 static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p) {
3048 uint32_t i, j, n = _dyld_image_count();
3049 Boolean foundit = false;
3050 const char *name;
3051 CFStringRef result = NULL;
3052 for (i = 0; !foundit && i < n; i++) {
3053 // will need modification for 64-bit
3054 const struct mach_header *mh = _dyld_get_image_header(i);
3055 uint32_t addr = (uint32_t)p - _dyld_get_image_vmaddr_slide(i);
3056 if (mh) {
3057 struct load_command *lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
3058 for (j = 0; !foundit && j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) {
3059 if (LC_SEGMENT == lc->cmd && addr >= ((struct segment_command *)lc)->vmaddr && addr < ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) {
3060 foundit = true;
3061 name = _dyld_get_image_name(i);
3062 if (name != NULL) {
3063 result = CFStringCreateWithCString(NULL, name, CFStringFileSystemEncoding());
3064 }
3065 }
3066 }
3067 }
3068 }
3069 return result;
3070 }
3071
3072 __private_extern__ CFArrayRef _CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint) {
3073 uint32_t i, numImages = _dyld_image_count();
3074 CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3075 CFRange range = CFRangeMake(0, CFStringGetLength(hint));
3076
3077 for (i=0; i<numImages; i++) {
3078 const char *curName = _dyld_get_image_name(i), *lastComponent = NULL;
3079 if (curName != NULL) lastComponent = strrchr(curName, '/');
3080 if (lastComponent != NULL) {
3081 CFStringRef str = CFStringCreateWithCString(NULL, lastComponent + 1, CFStringFileSystemEncoding());
3082 if (str) {
3083 if (CFStringFindWithOptions(hint, str, range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) {
3084 CFStringRef curStr = CFStringCreateWithCString(NULL, curName, CFStringFileSystemEncoding());
3085 if (curStr != NULL) {
3086 CFArrayAppendValue(result, curStr);
3087 CFRelease(curStr);
3088 }
3089 }
3090 CFRelease(str);
3091 }
3092 }
3093 }
3094 return result;
3095 }
3096
3097 __private_extern__ CFArrayRef _CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
3098 // 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.
3099 static uint32_t _cachedDYLDImageCount = -1;
3100
3101 uint32_t i, numImages = _dyld_image_count();
3102 CFMutableArrayRef result = NULL;
3103
3104 if (numImages != _cachedDYLDImageCount) {
3105 const char *curName;
3106 CFStringRef curStr;
3107
3108 result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
3109
3110 for (i=0; i<numImages; i++) {
3111 curName = _dyld_get_image_name(i);
3112 if (curName != NULL) {
3113 curStr = CFStringCreateWithCString(NULL, curName, CFStringFileSystemEncoding());
3114 if (curStr != NULL) {
3115 CFArrayAppendValue(result, curStr);
3116 CFRelease(curStr);
3117 }
3118 }
3119 }
3120 _cachedDYLDImageCount = numImages;
3121 }
3122 return result;
3123 }
3124
3125 #endif /* BINARY_SUPPORT_DYLD */
3126
3127
3128 #if defined(BINARY_SUPPORT_DLL)
3129
3130 __private_extern__ Boolean _CFBundleDLLLoad(CFBundleRef bundle) {
3131
3132 if (!bundle->_isLoaded) {
3133 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle);
3134
3135 if (executableURL) {
3136 char buff[CFMaxPathSize];
3137
3138 if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) {
3139 bundle->_hModule = LoadLibrary(buff);
3140 if (bundle->_hModule == NULL) {
3141 } else {
3142 bundle->_isLoaded = true;
3143 }
3144 }
3145 CFRelease(executableURL);
3146 } else {
3147 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle);
3148 }
3149 }
3150
3151 return bundle->_isLoaded;
3152 }
3153
3154 __private_extern__ void _CFBundleDLLUnload(CFBundleRef bundle) {
3155 if (bundle->_isLoaded) {
3156 FreeLibrary(bundle->_hModule);
3157 bundle->_hModule = NULL;
3158 bundle->_isLoaded = false;
3159 }
3160 }
3161
3162 __private_extern__ void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {
3163 void *result = NULL;
3164 char buff[1024];
3165
3166 if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingWindowsLatin1)) {
3167 result = GetProcAddress(bundle->_hModule, buff);
3168 }
3169 return result;
3170 }
3171
3172 #endif /* BINARY_SUPPORT_DLL */
3173
3174
3175 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
3176 */
3177 extern void _CFStringSetCompatibility(CFOptionFlags);
3178
3179 static void _CFBundleCheckWorkarounds(CFBundleRef bundle) {
3180 }
3181