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