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