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