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