2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
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>
36 #include "CFInternal.h"
38 #include <CoreFoundation/CFByteOrder.h>
39 #include "CFBundle_BinaryTypes.h"
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>
55 #endif /* BINARY_SUPPORT_DYLD */
57 #if defined(__MACOS8__)
60 #include <Processes.h>
62 /* Unixy & Windows Headers */
66 #if defined(__LINUX__)
70 #if defined(__WIN32__)
76 // Public CFBundle Info plist keys
77 CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey
, "CFBundleInfoDictionaryVersion")
78 CONST_STRING_DECL(kCFBundleExecutableKey
, "CFBundleExecutable")
79 CONST_STRING_DECL(kCFBundleIdentifierKey
, "CFBundleIdentifier")
80 CONST_STRING_DECL(kCFBundleVersionKey
, "CFBundleVersion")
81 CONST_STRING_DECL(kCFBundleDevelopmentRegionKey
, "CFBundleDevelopmentRegion")
82 CONST_STRING_DECL(kCFBundleLocalizationsKey
, "CFBundleLocalizations")
85 CONST_STRING_DECL(_kCFBundlePackageTypeKey
, "CFBundlePackageType")
86 CONST_STRING_DECL(_kCFBundleSignatureKey
, "CFBundleSignature")
87 CONST_STRING_DECL(_kCFBundleIconFileKey
, "CFBundleIconFile")
88 CONST_STRING_DECL(_kCFBundleDocumentTypesKey
, "CFBundleDocumentTypes")
89 CONST_STRING_DECL(_kCFBundleURLTypesKey
, "CFBundleURLTypes")
91 // Keys that are usually localized in InfoPlist.strings
92 CONST_STRING_DECL(kCFBundleNameKey
, "CFBundleName")
93 CONST_STRING_DECL(_kCFBundleDisplayNameKey
, "CFBundleDisplayName")
94 CONST_STRING_DECL(_kCFBundleShortVersionStringKey
, "CFBundleShortVersionString")
95 CONST_STRING_DECL(_kCFBundleGetInfoStringKey
, "CFBundleGetInfoString")
96 CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey
, "CFBundleGetInfoHTML")
98 // Sub-keys for CFBundleDocumentTypes dictionaries
99 CONST_STRING_DECL(_kCFBundleTypeNameKey
, "CFBundleTypeName")
100 CONST_STRING_DECL(_kCFBundleTypeRoleKey
, "CFBundleTypeRole")
101 CONST_STRING_DECL(_kCFBundleTypeIconFileKey
, "CFBundleTypeIconFile")
102 CONST_STRING_DECL(_kCFBundleTypeOSTypesKey
, "CFBundleTypeOSTypes")
103 CONST_STRING_DECL(_kCFBundleTypeExtensionsKey
, "CFBundleTypeExtensions")
104 CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey
, "CFBundleTypeMIMETypes")
106 // Sub-keys for CFBundleURLTypes dictionaries
107 CONST_STRING_DECL(_kCFBundleURLNameKey
, "CFBundleURLName")
108 CONST_STRING_DECL(_kCFBundleURLIconFileKey
, "CFBundleURLIconFile")
109 CONST_STRING_DECL(_kCFBundleURLSchemesKey
, "CFBundleURLSchemes")
111 // Compatibility key names
112 CONST_STRING_DECL(_kCFBundleOldExecutableKey
, "NSExecutable")
113 CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey
, "NSInfoPlistVersion")
114 CONST_STRING_DECL(_kCFBundleOldNameKey
, "NSHumanReadableName")
115 CONST_STRING_DECL(_kCFBundleOldIconFileKey
, "NSIcon")
116 CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey
, "NSTypes")
117 CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey
, "NSAppVersion")
119 // Compatibility CFBundleDocumentTypes key names
120 CONST_STRING_DECL(_kCFBundleOldTypeNameKey
, "NSName")
121 CONST_STRING_DECL(_kCFBundleOldTypeRoleKey
, "NSRole")
122 CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey
, "NSIcon")
123 CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key
, "NSUnixExtensions")
124 CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key
, "NSDOSExtensions")
125 CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey
, "NSMacOSType")
127 // Internally used keys for loaded Info plists.
128 CONST_STRING_DECL(_kCFBundleInfoPlistURLKey
, "CFBundleInfoPlistURL")
129 CONST_STRING_DECL(_kCFBundleNumericVersionKey
, "CFBundleNumericVersion")
130 CONST_STRING_DECL(_kCFBundleExecutablePathKey
, "CFBundleExecutablePath")
131 CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey
, "CSResourcesFileMapped")
132 CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey
, "CFBundleCFMLoadAsBundle")
133 CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey
, "CFBundleAllowMixedLocalizations")
135 static CFTypeID __kCFBundleTypeID
= _kCFRuntimeNotATypeID
;
143 CFDictionaryRef _infoDict
;
144 CFDictionaryRef _localInfoDict
;
145 CFArrayRef _searchLanguages
;
147 __CFPBinaryType _binaryType
;
150 Boolean _sharesStringsFiles
;
154 void *_connectionCookie
;
160 /* CFM<->DYLD glue */
161 CFMutableDictionaryRef _glueDict
;
163 /* Resource fork goop */
164 _CFResourceData _resourceData
;
166 _CFPlugInData _plugInData
;
168 #if defined(BINARY_SUPPORT_DLL)
174 static CFSpinLock_t CFBundleGlobalDataLock
= 0;
176 static CFMutableDictionaryRef _bundlesByURL
= NULL
;
177 static CFMutableDictionaryRef _bundlesByIdentifier
= NULL
;
179 // For scheduled lazy unloading. Used by CFPlugIn.
180 static CFMutableSetRef _bundlesToUnload
= NULL
;
181 static Boolean _scheduledBundlesAreUnloading
= false;
183 // Various lists of all bundles.
184 static CFMutableArrayRef _allBundles
= NULL
;
186 static Boolean _initedMainBundle
= false;
187 static CFBundleRef _mainBundle
= NULL
;
188 static CFStringRef _defaultLocalization
= NULL
;
190 // Forward declares functions.
191 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
);
192 static CFStringRef
_CFBundleCopyExecutableName(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
);
193 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
);
194 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
);
195 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
);
196 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
);
197 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
198 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
);
199 #if defined(BINARY_SUPPORT_DYLD)
200 static CFDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable(void);
201 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
);
202 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
);
203 #endif /* BINARY_SUPPORT_DYLD */
204 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
205 static void *_CFBundleFunctionPointerForTVector(CFAllocatorRef allocator
, void *tvp
);
206 static void *_CFBundleTVectorForFunctionPointer(CFAllocatorRef allocator
, void *fp
);
207 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
209 static void _CFBundleAddToTables(CFBundleRef bundle
, Boolean alreadyLocked
) {
210 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
212 if (!alreadyLocked
) {
213 __CFSpinLock(&CFBundleGlobalDataLock
);
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
);
224 CFArrayAppendValue(_allBundles
, bundle
);
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
);
234 CFDictionarySetValue(_bundlesByURL
, bundle
->_url
, bundle
);
236 // Add to the table that maps identifiers to bundles
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
);
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.
258 CFDictionarySetValue(_bundlesByIdentifier
, bundleID
, bundle
);
261 if (!alreadyLocked
) {
262 __CFSpinUnlock(&CFBundleGlobalDataLock
);
266 static void _CFBundleRemoveFromTables(CFBundleRef bundle
) {
267 CFStringRef bundleID
= CFBundleGetIdentifier(bundle
);
269 __CFSpinLock(&CFBundleGlobalDataLock
);
271 // Remove from the various lists
272 if (_allBundles
!= NULL
) {
273 CFIndex i
= CFArrayGetFirstIndexOfValue(_allBundles
, CFRangeMake(0, CFArrayGetCount(_allBundles
)), bundle
);
275 CFArrayRemoveValueAtIndex(_allBundles
, i
);
279 // Remove from the table that maps urls to bundles
280 if (_bundlesByURL
!= NULL
) {
281 CFDictionaryRemoveValue(_bundlesByURL
, bundle
->_url
);
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
);
290 __CFSpinUnlock(&CFBundleGlobalDataLock
);
293 __private_extern__ CFBundleRef
_CFBundleFindByURL(CFURLRef url
, Boolean alreadyLocked
) {
294 CFBundleRef result
= NULL
;
295 if (!alreadyLocked
) {
296 __CFSpinLock(&CFBundleGlobalDataLock
);
298 if (_bundlesByURL
!= NULL
) {
299 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByURL
, url
);
301 if (!alreadyLocked
) {
302 __CFSpinUnlock(&CFBundleGlobalDataLock
);
307 static CFURLRef
_CFBundleCopyBundleURLForExecutablePath(CFStringRef str
) {
308 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd
309 UniChar buff
[CFMaxPathSize
];
314 buffLen
= CFStringGetLength(str
);
315 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
316 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
317 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
); // Remove exe name
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
);
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
328 // Remove platform folder
329 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
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
);
339 CFRelease(nextDirName
);
343 // Remove support files folder
344 buffLen
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
347 CFRelease(lastDirName
);
352 outstr
= CFStringCreateWithCharactersNoCopy(NULL
, buff
, buffLen
, kCFAllocatorNull
);
353 url
= CFURLCreateWithFileSystemPath(NULL
, outstr
, PLATFORM_PATH_STYLE
, true);
359 static CFURLRef
_CFBundleCopyResolvedURLForExecutableURL(CFURLRef url
) {
360 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL()
361 CFURLRef absoluteURL
, url1
, url2
, outURL
= NULL
;
362 CFStringRef str
, str1
, str2
;
363 absoluteURL
= CFURLCopyAbsoluteURL(url
);
364 str
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
366 UniChar buff
[CFMaxPathSize
];
367 CFIndex buffLen
= CFStringGetLength(str
), len1
;
368 if (buffLen
> CFMaxPathSize
) buffLen
= CFMaxPathSize
;
369 CFStringGetCharacters(str
, CFRangeMake(0, buffLen
), buff
);
370 len1
= _CFLengthAfterDeletingLastPathComponent(buff
, buffLen
);
371 if (len1
> 0 && len1
+ 1 < buffLen
) {
372 str1
= CFStringCreateWithCharacters(NULL
, buff
, len1
);
373 str2
= CFStringCreateWithCharacters(NULL
, buff
+ len1
+ 1, buffLen
- len1
- 1);
375 url1
= CFURLCreateWithFileSystemPath(NULL
, str1
, PLATFORM_PATH_STYLE
, true);
377 url2
= CFURLCreateWithFileSystemPathRelativeToBase(NULL
, str2
, PLATFORM_PATH_STYLE
, false, url1
);
379 outURL
= CFURLCopyAbsoluteURL(url2
);
385 if (str1
) CFRelease(str1
);
386 if (str2
) CFRelease(str2
);
391 outURL
= absoluteURL
;
393 CFRelease(absoluteURL
);
398 CFURLRef
_CFBundleCopyBundleURLForExecutableURL(CFURLRef url
) {
399 CFURLRef resolvedURL
, outurl
= NULL
;
401 resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
402 str
= CFURLCopyFileSystemPath(resolvedURL
, PLATFORM_PATH_STYLE
);
404 outurl
= _CFBundleCopyBundleURLForExecutablePath(str
);
407 CFRelease(resolvedURL
);
411 CFBundleRef
_CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
412 CFBundleRef bundle
= CFBundleCreate(allocator
, url
);
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
);
421 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
422 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
424 if (bundle
->_binaryType
== __CFBundleCFMBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
425 bundle
->_version
= 4;
427 bundle
->_resourceData
._executableLacksResourceFork
= true;
429 CFRelease(executableURL
);
431 bundle
->_version
= 4;
433 #elif defined(BINARY_SUPPORT_CFM)
434 bundle
->_version
= 4;
436 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
438 CFRelease(executableURL
);
440 bundle
->_version
= 4;
442 #endif /* BINARY_SUPPORT_CFM && BINARY_SUPPORT_DYLD */
445 if (bundle
&& (3 == bundle
->_version
|| 4 == bundle
->_version
)) {
452 CFBundleRef
_CFBundleGetMainBundleIfLooksLikeBundle(void) {
453 CFBundleRef mainBundle
= CFBundleGetMainBundle();
454 if (mainBundle
&& (3 == mainBundle
->_version
|| 4 == mainBundle
->_version
)) {
460 CFBundleRef
_CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator
, CFURLRef url
) {
461 CFBundleRef bundle
= NULL
;
462 CFURLRef bundleURL
= _CFBundleCopyBundleURLForExecutableURL(url
), resolvedURL
= _CFBundleCopyResolvedURLForExecutableURL(url
);
463 if (bundleURL
&& resolvedURL
) {
464 bundle
= _CFBundleCreateIfLooksLikeBundle(allocator
, bundleURL
);
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
)) {
472 if (executableURL
) CFRelease(executableURL
);
475 if (bundleURL
) CFRelease(bundleURL
);
476 if (resolvedURL
) CFRelease(resolvedURL
);
480 static CFBundleRef
_CFBundleGetMainBundleAlreadyLocked(void) {
481 if (!_initedMainBundle
) {
482 const char *processPath
;
483 CFStringRef str
= NULL
;
484 CFURLRef executableURL
= NULL
, bundleURL
= NULL
;
485 #if defined(BINARY_SUPPORT_CFM)
486 Boolean versRegionOverrides
= false;
487 #endif /* BINARY_SUPPORT_CFM */
488 #if defined(__MACOS8__)
489 // do not use Posix-styled _CFProcessPath()
490 ProcessSerialNumber gProcessID
;
491 ProcessInfoRec processInfo
;
492 FSSpec processAppSpec
;
494 processInfo
.processInfoLength
= sizeof(ProcessInfoRec
);
495 processInfo
.processAppSpec
= &processAppSpec
;
497 if ((GetCurrentProcess(&gProcessID
) == noErr
) && (GetProcessInformation(&gProcessID
, &processInfo
) == noErr
)) {
498 executableURL
= _CFCreateURLFromFSSpec(NULL
, (void *)(&processAppSpec
), false);
501 _initedMainBundle
= true;
502 processPath
= _CFProcessPath();
504 str
= CFStringCreateWithCString(NULL
, processPath
, CFStringFileSystemEncoding());
505 if (!executableURL
) executableURL
= CFURLCreateWithFileSystemPath(NULL
, str
, PLATFORM_PATH_STYLE
, false);
508 bundleURL
= _CFBundleCopyBundleURLForExecutableURL(executableURL
);
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
;
523 _mainBundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
524 #if defined(BINARY_SUPPORT_CFM)
525 if (_mainBundle
->_binaryType
!= __CFBundleCFMBinary
&& _mainBundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
526 _mainBundle
->_resourceData
._executableLacksResourceFork
= true;
528 #endif /* BINARY_SUPPORT_CFM */
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
);
541 #if defined(BINARY_SUPPORT_DYLD)
542 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
543 if (_mainBundle
->_infoDict
!= NULL
) CFRelease(_mainBundle
->_infoDict
);
544 _mainBundle
->_infoDict
= _CFBundleGrokInfoDictFromMainExecutable();
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;
555 #endif /* BINARY_SUPPORT_CFM */
557 if (_mainBundle
->_infoDict
== NULL
) {
558 _mainBundle
->_infoDict
= CFDictionaryCreateMutable(CFGetAllocator(_mainBundle
), 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
560 if (NULL
== CFDictionaryGetValue(_mainBundle
->_infoDict
, _kCFBundleExecutablePathKey
)) {
561 CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), _kCFBundleExecutablePathKey
, str
);
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);
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
);
578 #endif /* BINARY_SUPPORT_CFM */
581 if (bundleURL
) CFRelease(bundleURL
);
582 if (str
) CFRelease(str
);
583 if (executableURL
) CFRelease(executableURL
);
588 CFBundleRef
CFBundleGetMainBundle(void) {
589 CFBundleRef mainBundle
;
590 __CFSpinLock(&CFBundleGlobalDataLock
);
591 mainBundle
= _CFBundleGetMainBundleAlreadyLocked();
592 __CFSpinUnlock(&CFBundleGlobalDataLock
);
596 #if defined(BINARY_SUPPORT_DYLD)
598 static void *_CFBundleReturnAddressFromFrameAddress(void *addr
)
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
));
606 __asm__
volatile("ldw 0x4(%1),%0" : "=r" (ret
) : "r" (addr
));
608 __asm__
volatile("ta 0x3");
609 __asm__
volatile("ld [%1 + 60],%0" : "=r" (ret
) : "r" (addr
));
611 #warning Do not know how to define _CFBundleReturnAddressFromFrameAddress on this architecture
619 CFBundleRef
CFBundleGetBundleWithIdentifier(CFStringRef bundleID
) {
620 CFBundleRef result
= NULL
;
622 __CFSpinLock(&CFBundleGlobalDataLock
);
623 (void)_CFBundleGetMainBundleAlreadyLocked();
624 if (_bundlesByIdentifier
!= NULL
) {
625 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
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
);
636 if (_bundlesByIdentifier
!= NULL
) {
637 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
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
);
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
);
655 __CFSpinUnlock(&CFBundleGlobalDataLock
);
660 static 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());
666 switch (((CFBundleRef
)cf
)->_binaryType
) {
667 case __CFBundleCFMBinary
:
668 binaryType
= CFSTR("");
670 case __CFBundleDYLDExecutableBinary
:
671 binaryType
= CFSTR("executable, ");
673 case __CFBundleDYLDBundleBinary
:
674 binaryType
= CFSTR("bundle, ");
676 case __CFBundleDYLDFrameworkBinary
:
677 binaryType
= CFSTR("framework, ");
679 case __CFBundleDLLBinary
:
680 binaryType
= CFSTR("DLL, ");
682 case __CFBundleUnreadableBinary
:
683 binaryType
= CFSTR("");
686 binaryType
= CFSTR("");
689 if (((CFBundleRef
)cf
)->_plugInData
._isPlugIn
) {
690 retval
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFBundle/CFPlugIn 0x%x <%@> (%@%sloaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? "" : "not ");
692 retval
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFBundle 0x%x <%@> (%@%sloaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? "" : "not ");
694 if (path
) CFRelease(path
);
698 static void _CFBundleDeallocateGlue(const void *key
, const void *value
, void *context
) {
699 CFAllocatorRef allocator
= (CFAllocatorRef
)context
;
701 CFAllocatorDeallocate(allocator
, (void *)value
);
705 static void __CFBundleDeallocate(CFTypeRef cf
) {
706 CFBundleRef bundle
= (CFBundleRef
)cf
;
707 CFAllocatorRef allocator
;
709 __CFGenericValidateType(cf
, __kCFBundleTypeID
);
711 allocator
= CFGetAllocator(bundle
);
714 CFBundleUnloadExecutable(bundle
);
716 // Clean up plugIn stuff
717 _CFBundleDeallocatePlugIn(bundle
);
719 _CFBundleRemoveFromTables(bundle
);
721 if (bundle
->_url
!= NULL
) {
722 CFRelease(bundle
->_url
);
724 if (bundle
->_infoDict
!= NULL
) {
725 CFRelease(bundle
->_infoDict
);
727 if (bundle
->_modDate
!= NULL
) {
728 CFRelease(bundle
->_modDate
);
730 if (bundle
->_localInfoDict
!= NULL
) {
731 CFRelease(bundle
->_localInfoDict
);
733 if (bundle
->_searchLanguages
!= NULL
) {
734 CFRelease(bundle
->_searchLanguages
);
736 if (bundle
->_glueDict
!= NULL
) {
737 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)allocator
);
738 CFRelease(bundle
->_glueDict
);
740 if (bundle
->_resourceData
._stringTableCache
!= NULL
) {
741 CFRelease(bundle
->_resourceData
._stringTableCache
);
745 static const CFRuntimeClass __CFBundleClass
= {
750 __CFBundleDeallocate
,
754 __CFBundleCopyDescription
757 __private_extern__
void __CFBundleInitialize(void) {
758 __kCFBundleTypeID
= _CFRuntimeRegisterClass(&__CFBundleClass
);
761 CFTypeID
CFBundleGetTypeID(void) {
762 return __kCFBundleTypeID
;
765 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
) {
766 CFBundleRef bundle
= NULL
;
767 char buff
[CFMaxPathSize
];
768 CFDateRef modDate
= NULL
;
769 Boolean exists
= false;
771 CFURLRef newURL
= NULL
;
772 uint8_t localVersion
= 0;
774 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
776 newURL
= CFURLCreateFromFileSystemRepresentation(allocator
, buff
, strlen(buff
), true);
777 if (NULL
== newURL
) {
778 newURL
= CFRetain(bundleURL
);
780 bundle
= _CFBundleFindByURL(newURL
, alreadyLocked
);
787 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
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
);
801 bundle
= (CFBundleRef
)_CFRuntimeCreateInstance(allocator
, __kCFBundleTypeID
, sizeof(struct __CFBundle
) - sizeof(CFRuntimeBase
), NULL
);
802 if (NULL
== bundle
) {
807 bundle
->_url
= newURL
;
809 bundle
->_modDate
= modDate
;
810 bundle
->_version
= localVersion
;
811 bundle
->_infoDict
= NULL
;
812 bundle
->_localInfoDict
= NULL
;
813 bundle
->_searchLanguages
= NULL
;
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
;
826 /* We'll have to figure it out later */
827 bundle
->_binaryType
= __CFBundleUnknownBinary
;
830 bundle
->_isLoaded
= false;
831 bundle
->_sharesStringsFiles
= false;
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;
838 bundle
->_connectionCookie
= NULL
;
839 bundle
->_imageCookie
= NULL
;
840 bundle
->_moduleCookie
= NULL
;
842 bundle
->_glueDict
= NULL
;
844 #if defined(BINARY_SUPPORT_CFM)
845 bundle
->_resourceData
._executableLacksResourceFork
= false;
847 bundle
->_resourceData
._executableLacksResourceFork
= true;
850 bundle
->_resourceData
._stringTableCache
= NULL
;
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
;
858 CFBundleGetInfoDictionary(bundle
);
860 _CFBundleAddToTables(bundle
, alreadyLocked
);
862 _CFBundleInitPlugIn(bundle
);
864 _CFBundleCheckWorkarounds(bundle
);
869 CFBundleRef
CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
) {return _CFBundleCreate(allocator
, bundleURL
, false);}
871 CFArrayRef
CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc
, CFURLRef directoryURL
, CFStringRef bundleType
) {
872 CFMutableArrayRef bundles
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
873 CFArrayRef URLs
= _CFContentsOfDirectory(alloc
, NULL
, NULL
, directoryURL
, bundleType
);
875 CFIndex i
, c
= CFArrayGetCount(URLs
);
877 CFBundleRef curBundle
;
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
);
892 CFURLRef
CFBundleCopyBundleURL(CFBundleRef bundle
) {
894 CFRetain(bundle
->_url
);
899 void _CFBundleSetDefaultLocalization(CFStringRef localizationName
) {
900 CFStringRef newLocalization
= localizationName
? CFStringCreateCopy(NULL
, localizationName
) : NULL
;
901 if (_defaultLocalization
) CFRelease(_defaultLocalization
);
902 _defaultLocalization
= newLocalization
;
905 __private_extern__ CFArrayRef
_CFBundleGetLanguageSearchList(CFBundleRef bundle
) {
906 if (bundle
->_searchLanguages
== NULL
) {
907 CFMutableArrayRef langs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
908 CFStringRef devLang
= CFBundleGetDevelopmentRegion(bundle
);
910 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, devLang
);
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"));
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
);
920 if (CFArrayGetCount(localizations
) > 0) {
921 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFArrayGetValueAtIndex(localizations
, 0));
923 CFRelease(localizations
);
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
);
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
);
943 CFRelease(localizations
);
946 if (CFArrayGetCount(langs
) == 0) {
947 // Total backstop behavior to avoid having an empty array.
948 if (_defaultLocalization
!= NULL
) {
949 CFArrayAppendValue(langs
, _defaultLocalization
);
951 CFArrayAppendValue(langs
, CFSTR("en"));
954 bundle
->_searchLanguages
= langs
;
956 return bundle
->_searchLanguages
;
959 CFDictionaryRef
CFBundleCopyInfoDictionaryInDirectory(CFURLRef url
) {return _CFBundleCopyInfoDictionaryInDirectory(NULL
, url
, NULL
);}
961 CFDictionaryRef
CFBundleGetInfoDictionary(CFBundleRef bundle
) {
962 if (bundle
->_infoDict
== NULL
) {
963 bundle
->_infoDict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);
965 return bundle
->_infoDict
;
968 CFDictionaryRef
_CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {return CFBundleGetLocalInfoDictionary(bundle
);}
970 CFDictionaryRef
CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
971 if (bundle
->_localInfoDict
== NULL
) {
972 CFURLRef url
= CFBundleCopyResourceURL(bundle
, _CFBundleLocalInfoName
, _CFBundleStringTableType
, NULL
);
976 CFStringRef errStr
= NULL
;
978 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle
), url
, &data
, NULL
, NULL
, &errCode
)) {
979 bundle
->_localInfoDict
= CFPropertyListCreateFromXMLData(CFGetAllocator(bundle
), data
, kCFPropertyListImmutable
, &errStr
);
988 return bundle
->_localInfoDict
;
991 CFPropertyListRef
_CFBundleGetValueForInfoKey(CFBundleRef bundle
, CFStringRef key
) {return (CFPropertyListRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, key
);}
993 CFTypeRef
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
);
999 result
= CFDictionaryGetValue(dict
, key
);
1001 if (result
== NULL
) {
1002 dict
= CFBundleGetInfoDictionary(bundle
);
1004 result
= CFDictionaryGetValue(dict
, key
);
1011 CFStringRef
CFBundleGetIdentifier(CFBundleRef bundle
) {
1012 CFStringRef bundleID
= NULL
;
1013 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1015 bundleID
= CFDictionaryGetValue(infoDict
, kCFBundleIdentifierKey
);
1020 #define DEVELOPMENT_STAGE 0x20
1021 #define ALPHA_STAGE 0x40
1022 #define BETA_STAGE 0x60
1023 #define RELEASE_STAGE 0x80
1025 #define MAX_VERS_LEN 10
1027 CF_INLINE Boolean
_isDigit(UniChar aChar
) {return (((aChar
>= (UniChar
)'0') && (aChar
<= (UniChar
)'9')) ? true : false);}
1029 __private_extern__ CFStringRef
_CFCreateStringFromVersionNumber(CFAllocatorRef alloc
, UInt32 vers
) {
1030 CFStringRef result
= NULL
;
1031 uint8_t major1
, major2
, minor1
, minor2
, stage
, build
;
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);
1040 if (stage
== RELEASE_STAGE
) {
1042 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d"), major1
, major2
, minor1
, minor2
);
1044 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d"), major2
, minor1
, minor2
);
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
);
1050 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d%s%d"), major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? "d" : ((stage
== ALPHA_STAGE
) ? "a" : "b")), build
);
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
;
1064 Boolean digitsDone
= false;
1066 if (!versStr
) return 0;
1068 len
= CFStringGetLength(versStr
);
1070 if ((len
== 0) || (len
> MAX_VERS_LEN
)) return 0;
1072 CFStringGetCharacters(versStr
, CFRangeMake(0, len
), versChars
);
1075 // Get major version number.
1076 major1
= major2
= 0;
1077 if (_isDigit(*chars
)) {
1078 major2
= *chars
- (UniChar
)'0';
1082 if (_isDigit(*chars
)) {
1084 major2
= *chars
- (UniChar
)'0';
1088 if (*chars
== (UniChar
)'.') {
1095 } else if (*chars
== (UniChar
)'.') {
1102 } else if (*chars
== (UniChar
)'.') {
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.
1112 // Get the first minor version number.
1113 if (len
> 0 && !digitsDone
) {
1114 if (_isDigit(*chars
)) {
1115 minor1
= *chars
- (UniChar
)'0';
1119 if (*chars
== (UniChar
)'.') {
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.
1134 // Get the second minor version number.
1135 if (len
> 0 && !digitsDone
) {
1136 if (_isDigit(*chars
)) {
1137 minor2
= *chars
- (UniChar
)'0';
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.
1148 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
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') {
1156 } else if (*chars
== (UniChar
)'f') {
1157 stage
= RELEASE_STAGE
;
1165 // Now stage contains the release stage.
1166 // Now either len is 0 or chars points at the build number.
1168 // Get the first digit of the build number.
1170 if (_isDigit(*chars
)) {
1171 build
= *chars
- (UniChar
)'0';
1178 // Get the second digit of the build number.
1180 if (_isDigit(*chars
)) {
1182 build
+= *chars
- (UniChar
)'0';
1189 // Get the third digit of the build number.
1191 if (_isDigit(*chars
)) {
1193 build
+= *chars
- (UniChar
)'0';
1201 // Range check the build number and make sure we exhausted the string.
1202 if ((build
> 0xFF) || (len
> 0)) return 0;
1205 theVers
= major1
<< 28;
1206 theVers
+= major2
<< 24;
1207 theVers
+= minor1
<< 20;
1208 theVers
+= minor2
<< 16;
1209 theVers
+= stage
<< 8;
1215 UInt32
CFBundleGetVersionNumber(CFBundleRef bundle
) {
1216 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1217 CFTypeRef unknownVersionValue
= CFDictionaryGetValue(infoDict
, _kCFBundleNumericVersionKey
);
1218 CFNumberRef versNum
;
1221 if (unknownVersionValue
== NULL
) {
1222 unknownVersionValue
= CFDictionaryGetValue(infoDict
, kCFBundleVersionKey
);
1224 if (unknownVersionValue
!= NULL
) {
1225 if (CFGetTypeID(unknownVersionValue
) == CFStringGetTypeID()) {
1226 // Convert a string version number into a numeric one.
1227 vers
= _CFVersionNumberFromString((CFStringRef
)unknownVersionValue
);
1229 versNum
= CFNumberCreate(CFGetAllocator(bundle
), kCFNumberSInt32Type
, &vers
);
1230 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
, versNum
);
1232 } else if (CFGetTypeID(unknownVersionValue
) == CFNumberGetTypeID()) {
1233 CFNumberGetValue((CFNumberRef
)unknownVersionValue
, kCFNumberSInt32Type
, &vers
);
1235 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
);
1241 CFStringRef
CFBundleGetDevelopmentRegion(CFBundleRef bundle
) {
1242 CFStringRef devLang
= NULL
;
1243 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1245 devLang
= CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1246 if (devLang
!= NULL
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) {
1248 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleDevelopmentRegionKey
);
1255 Boolean
_CFBundleGetHasChanged(CFBundleRef bundle
) {
1257 Boolean result
= false;
1258 Boolean exists
= false;
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
)) {
1267 // Something is wrong. The stat failed.
1270 if (bundle
->_modDate
&& !CFEqual(bundle
->_modDate
, modDate
)) {
1271 // mod date is different from when we created.
1278 void _CFBundleSetStringsFilesShared(CFBundleRef bundle
, Boolean flag
) {
1279 bundle
->_sharesStringsFiles
= flag
;
1282 Boolean
_CFBundleGetStringsFilesShared(CFBundleRef bundle
) {
1283 return bundle
->_sharesStringsFiles
;
1286 static Boolean
_urlExists(CFAllocatorRef alloc
, CFURLRef url
) {
1288 return url
&& (0 == _CFGetFileProperties(alloc
, url
, &exists
, NULL
, NULL
, NULL
, NULL
, NULL
)) && exists
;
1291 __private_extern__ CFURLRef
_CFBundleCopySupportFilesDirectoryURLInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
) {
1292 CFURLRef result
= NULL
;
1295 result
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase1
, bundleURL
);
1296 } else if (2 == version
) {
1297 result
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase2
, bundleURL
);
1299 result
= CFRetain(bundleURL
);
1305 CF_EXPORT CFURLRef
CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle
) {return _CFBundleCopySupportFilesDirectoryURLInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);}
1307 __private_extern__ CFURLRef
_CFBundleCopyResourcesDirectoryURLInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
) {
1308 CFURLRef result
= NULL
;
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
);
1317 result
= CFRetain(bundleURL
);
1323 CFURLRef
CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle
) {return _CFBundleCopyResourcesDirectoryURLInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);}
1325 static 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__ */
1332 if (urlPath
== NULL
|| exeName
== NULL
) return NULL
;
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
);
1343 newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, imageSuffix
);
1345 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, newExeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1346 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1347 CFRelease(executableURL
);
1348 executableURL
= NULL
;
1350 CFRelease(newExeName
);
1351 CFRelease(imageSuffix
);
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
;
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
;
1370 CFRelease(newExeName
);
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
;
1381 CFRelease(newExeName
);
1385 return executableURL
;
1388 static CFStringRef
_CFBundleCopyExecutableName(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
) {
1389 CFStringRef executableName
= NULL
;
1391 if (alloc
== NULL
&& bundle
!= NULL
) {
1392 alloc
= CFGetAllocator(bundle
);
1394 if (infoDict
== NULL
&& bundle
!= NULL
) {
1395 infoDict
= CFBundleGetInfoDictionary(bundle
);
1397 if (url
== NULL
&& bundle
!= NULL
) {
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
);
1409 if (executableName
!= NULL
&& CFGetTypeID(executableName
) == CFStringGetTypeID() && CFStringGetLength(executableName
) > 0) {
1410 CFRetain(executableName
);
1412 executableName
= NULL
;
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
;
1423 CFRelease(absoluteURL
);
1424 if (len
> CFMaxPathSize
) len
= CFMaxPathSize
;
1425 CFStringGetCharacters(bundlePath
, CFRangeMake(0, len
), buff
);
1426 startOfBundleName
= _CFStartOfLastPathComponent(buff
, len
);
1427 endOfBundleName
= _CFLengthAfterDeletingPathExtension(buff
, len
);
1429 if ((startOfBundleName
<= len
) && (endOfBundleName
<= len
) && (startOfBundleName
< endOfBundleName
)) {
1430 executableName
= CFStringCreateWithCharacters(alloc
, &(buff
[startOfBundleName
]), (endOfBundleName
- startOfBundleName
));
1432 CFRelease(bundlePath
);
1435 return executableName
;
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
) {
1443 resourceForkURL
= CFBundleCopyResourceURL(bundle
, executableName
, CFSTR("rsrc"), NULL
);
1445 resourceForkURL
= CFBundleCopyResourceURLForLocalization(bundle
, executableName
, CFSTR("rsrc"), NULL
, NULL
);
1447 CFRelease(executableName
);
1450 return resourceForkURL
;
1453 CFURLRef
_CFBundleCopyResourceForkURL(CFBundleRef bundle
) {return _CFBundleCopyResourceForkURLMayBeLocal(bundle
, true);}
1455 static 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);
1464 if (bundle
!= NULL
) {
1465 infoDict
= CFBundleGetInfoDictionary(bundle
);
1466 version
= bundle
->_version
;
1468 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, &version
);
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;
1478 executablePath
= NULL
;
1479 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
);
1485 if (lookupMainExe
) {
1486 executableName
= _CFBundleCopyExecutableName(alloc
, bundle
, url
, infoDict
);
1488 if (executableName
!= NULL
) {
1489 // Now, look for the executable inside the bundle.
1492 CFURLRef exeSubdirURL
;
1495 exeDirURL
= CFURLCreateWithString(alloc
, _CFBundleExecutablesURLFromBase1
, url
);
1496 } else if (2 == version
) {
1497 exeDirURL
= CFURLCreateWithString(alloc
, _CFBundleExecutablesURLFromBase2
, url
);
1499 exeDirURL
= CFRetain(url
);
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
);
1508 if (executableURL
== NULL
) {
1509 CFRelease(exeSubdirURL
);
1510 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1511 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1513 if (executableURL
== NULL
) {
1514 CFRelease(exeSubdirURL
);
1515 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1516 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1518 if (executableURL
== NULL
) {
1519 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeDirURL
, executableName
);
1522 CFRelease(exeDirURL
);
1523 CFRelease(exeSubdirURL
);
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
);
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
)) {
1537 exeDirURL
= CFURLCreateWithString(alloc
, CFSTR("../../Executables"), url
);
1539 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeDirURL
, executableName
);
1541 CFRelease(exeDirURL
);
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
);
1550 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
, executablePath
);
1551 CFRelease(executablePath
);
1553 if (lookupMainExe
&& !useOtherPlatform
&& (bundle
!= NULL
) && (executableURL
== NULL
)) {
1554 bundle
->_binaryType
= __CFBundleNoBinary
;
1556 if (lookupMainExe
) {
1557 CFRelease(executableName
);
1562 if ((bundle
== NULL
) && (infoDict
!= NULL
)) {
1563 CFRelease(infoDict
);
1566 return executableURL
;
1569 CFURLRef
_CFBundleCopyExecutableURLInDirectory(CFURLRef url
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL
, NULL
, url
, NULL
, true, false);}
1571 CFURLRef
_CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL
, NULL
, url
, NULL
, true, true);}
1573 CFURLRef
CFBundleCopyExecutableURL(CFBundleRef bundle
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, NULL
, false, false);}
1575 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, NULL
, true, false);}
1577 CFURLRef
CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle
, CFStringRef executableName
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, executableName
, true, false);}
1579 Boolean
CFBundleIsExecutableLoaded(CFBundleRef bundle
) {return bundle
->_isLoaded
;}
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"
1595 static 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
1603 // string, with groups of 5 characters being 1 element in the array
1604 static 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";
1611 #define NUM_EXTENSIONS 37
1612 #define EXTENSION_LENGTH 5
1613 #define MAGIC_BYTES_TO_READ 512
1615 #if defined(BINARY_SUPPORT_DYLD)
1617 CF_INLINE
uint32_t _CFBundleSwapInt32Conditional(uint32_t arg
, Boolean swap
) {return swap
? CFSwapInt32(arg
) : arg
;}
1619 static 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
);
1626 __CFSetNastyFile(CFSTR("<plist section in main executable>"));
1628 result
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(NULL
, infoData
, kCFPropertyListMutableContainers
, NULL
);
1629 if (result
&& CFDictionaryGetTypeID() != CFGetTypeID(result
)) {
1633 CFRelease(infoData
);
1636 result
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1642 static CFDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable() {
1643 unsigned long length
= 0;
1644 char *bytes
= getsectdata(PLIST_SEGMENT
, PLIST_SECTION
, &length
);
1645 return _CFBundleGrokInfoDictFromData(bytes
, length
);
1648 static CFDictionaryRef
_CFBundleGrokInfoDictFromFile(int fd
, unsigned long offset
, Boolean swapped
) {
1649 struct stat statBuf
;
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
);
1673 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
1676 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
1678 munmap(maploc
, statBuf
.st_size
);
1683 static Boolean
_CFBundleGrokX11(int fd
, unsigned long offset
, Boolean swapped
) {
1684 static const char libX11name
[] = LIB_X11
;
1685 struct stat statBuf
;
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;
1701 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
1703 munmap(maploc
, statBuf
.st_size
);
1709 static 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
;
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
));
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);
1739 static UInt32
_CFBundleGrokMachType(int fd
, void *bytes
, CFIndex length
, Boolean
*isX11
, CFDictionaryRef
*infodict
) {
1740 unsigned int magic
= *((UInt32
*)bytes
), machtype
= UNKNOWN_FILETYPE
;
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
;
1765 #endif /* BINARY_SUPPORT_DYLD */
1767 static 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];
1772 if (lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
&& read(fd
, moreBytes
, sizeof(moreBytes
)) >= (int)sizeof(moreBytes
)) {
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
;
1792 static Boolean
_CFBundleGrokFileType(CFURLRef url
, CFStringRef
*extension
, UInt32
*machtype
, CFDictionaryRef
*infodict
) {
1793 struct stat statBuf
;
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
;
1809 if (0xcafebabe == magic
&& 8 <= length
&& 0 != *((UInt16
*)(bytes
+ 4))) {
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 */
1816 #if defined(BINARY_SUPPORT_DYLD)
1817 if (MH_OBJECT
== mt
) {
1819 } else if (MH_EXECUTE
== mt
) {
1820 ext
= isX11
? "x11app" : "tool";
1821 } else if (PEF_FILETYPE
== mt
) {
1823 } else if (MH_CORE
== mt
) {
1825 } else if (MH_DYLIB
== mt
) {
1827 } else if (MH_BUNDLE
== mt
) {
1830 #endif /* BINARY_SUPPORT_DYLD */
1831 if (0x7b5c7274 == magic
&& (6 > length
|| 'f' != bytes
[4])) {
1833 } else if (0x47494638 == magic
&& (6 > length
|| (0x3761 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4)))))) {
1835 } else if (0x0000000c == magic
&& (6 > length
|| 0x6a50 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) {
1837 } else if (0x89504e47 == magic
&& (8 > length
|| 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) {
1839 } else if (0x53747566 == magic
&& (8 > length
|| 0x66497420 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) {
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
1844 } else if (0x504b0304 == magic
&& 38 <= length
&& 0x4d455441 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 30))) && 0x2d494e46 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34)))) {
1846 } else if (0x464f524d == magic
) {
1850 UInt32 iffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
1851 if (0x41494646 == iffMagic
) {
1853 } else if (0x414946 == iffMagic
) {
1857 } else if (0x52494646 == magic
) {
1861 UInt32 riffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
1862 if (0x57415645 == riffMagic
) {
1864 } else if (0x41564920 == riffMagic
) {
1868 } else if (0xd0cf11e0 == magic
) {
1872 UInt32 ft
= _CFBundleGrokFileTypeForOLEFile(fd
, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 48)))));
1873 if (XLS_FILETYPE
== ft
) {
1875 } else if (DOC_FILETYPE
== ft
) {
1877 } else if (PPT_FILETYPE
== ft
) {
1881 } else if (0x62656769 == magic
) {
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]) {
1889 for (i
= endOfLine
+ 1; ext
&& i
< endOfLine
+ 62; i
++) if (!isprint(bytes
[i
])) ext
= NULL
;
1894 if (extension
&& !ext
) {
1895 UInt16 shortMagic
= CFSwapInt16HostToBig(*((UInt16
*)bytes
));
1896 if (8 <= length
&& 0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
1898 } else if (8 <= length
&& 0x69647363 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
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)))) {
1904 } else if (0x4d344120 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) {
1906 } else if (0x4d344220 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) {
1908 } else if (0x4d345020 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) {
1911 } else if (0x424d == shortMagic
&& 18 <= length
&& 40 == CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 14)))) {
1913 } else if (40 <= length
&& 0x42696e48 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 38)))) {
1915 } else if (128 <= length
&& 0x6d42494e == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 102)))) {
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
) {
1922 } else if (265 <= length
&& 0x75737461 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 261))))) {
1924 } else if (0xfeff == shortMagic
|| 0xfffe == shortMagic
) {
1926 } else if (0x1f9d == shortMagic
) {
1928 } else if (0x1f8b == shortMagic
) {
1930 } else if (0xf702 == shortMagic
) {
1932 } else if (0x01da == shortMagic
&& (0 == bytes
[2] || 1 == bytes
[2]) && (0 < bytes
[3] && 16 > bytes
[3])) {
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)) {
1942 } else if (0 == strncmp(bytes
+ lastSlash
+ 1, "python", 6)) {
1944 } else if (0 == strncmp(bytes
+ lastSlash
+ 1, "ruby", 4)) {
1951 } else if (0xffd8 == shortMagic
&& 0xff == bytes
[2]) {
1953 } else if (0x4944 == shortMagic
&& '3' == bytes
[2] && 0x20 > bytes
[3]) {
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)) {
1958 } else if (0 == strncasecmp(bytes
+ 1, "?xml", 4)) {
1959 if (116 <= length
&& 0 == strncasecmp(bytes
+ 100, "PropertyList.dtd", 16)) {
1968 if (extension
&& !ext
) {
1969 //??? what about MacOSRoman?
1970 for (i
= 0; (isPlain
|| isZero
) && i
< length
&& i
< 512; i
++) {
1972 if (0x7f <= c
|| (0x20 > c
&& !isspace(c
))) isPlain
= false;
1973 if (0 != c
) isZero
= false;
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)))) {
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))))) {
1994 if (extension
) *extension
= ext
? CFStringCreateWithCStringNoCopy(NULL
, ext
, kCFStringEncodingASCII
, kCFAllocatorNull
) : NULL
;
1995 if (machtype
) *machtype
= mt
;
1997 return (ext
!= NULL
);
2000 CFStringRef
_CFBundleCopyFileTypeForFileURL(CFURLRef url
) {
2001 CFStringRef extension
= NULL
;
2002 (void)_CFBundleGrokFileType(url
, &extension
, NULL
, NULL
);
2006 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInExecutable(CFURLRef url
) {
2007 CFDictionaryRef result
= NULL
;
2008 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, &result
);
2012 #if defined(BINARY_SUPPORT_DYLD)
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
)) {
2021 result
= __CFBundleDYLDExecutableBinary
;
2024 result
= __CFBundleDYLDBundleBinary
;
2027 result
= __CFBundleDYLDFrameworkBinary
;
2029 #if defined(BINARY_SUPPORT_CFM)
2031 result
= __CFBundleCFMBinary
;
2033 #endif /* BINARY_SUPPORT_CFM */
2039 #endif /* BINARY_SUPPORT_DYLD */
2041 void _CFBundleSetCFMConnectionID(CFBundleRef bundle
, void *connectionID
) {
2042 #if defined(BINARY_SUPPORT_CFM)
2043 if (bundle
->_binaryType
== __CFBundleUnknownBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
2044 bundle
->_binaryType
= __CFBundleCFMBinary
;
2046 #endif /* BINARY_SUPPORT_CFM */
2047 bundle
->_connectionCookie
= connectionID
;
2048 bundle
->_isLoaded
= true;
2051 Boolean
CFBundleLoadExecutable(CFBundleRef bundle
) {
2052 Boolean result
= false;
2053 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2055 if (!executableURL
) {
2056 bundle
->_binaryType
= __CFBundleNoBinary
;
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
);
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;
2070 #endif /* BINARY_SUPPORT_CFM */
2072 #endif /* BINARY_SUPPORT_DYLD */
2073 if (executableURL
) CFRelease(executableURL
);
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
);
2081 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2085 // Unload bundles scheduled for unloading
2086 if (!_scheduledBundlesAreUnloading
) {
2087 _CFBundleUnloadScheduledBundles();
2091 switch (bundle
->_binaryType
) {
2092 #if defined(BINARY_SUPPORT_CFM)
2093 case __CFBundleCFMBinary
:
2094 case __CFBundleUnreadableBinary
:
2095 result
= _CFBundleCFMLoad(bundle
);
2097 #endif /* BINARY_SUPPORT_CFM */
2098 #if defined(BINARY_SUPPORT_DYLD)
2099 case __CFBundleDYLDBundleBinary
:
2100 result
= _CFBundleDYLDLoadBundle(bundle
);
2102 case __CFBundleDYLDFrameworkBinary
:
2103 result
= _CFBundleDYLDLoadFramework(bundle
);
2105 case __CFBundleDYLDExecutableBinary
:
2106 CFLog(__kCFLogBundle
, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle
);
2108 #endif /* BINARY_SUPPORT_DYLD */
2109 #if defined(BINARY_SUPPORT_DLL)
2110 case __CFBundleDLLBinary
:
2111 result
= _CFBundleDLLLoad(bundle
);
2113 #endif /* BINARY_SUPPORT_DLL */
2114 case __CFBundleNoBinary
:
2115 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for %@"), bundle
);
2118 CFLog(__kCFLogBundle
, CFSTR("Cannot recognize type of executable for %@"), bundle
);
2125 void CFBundleUnloadExecutable(CFBundleRef bundle
) {
2127 if (!_scheduledBundlesAreUnloading
) {
2128 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
2129 _CFBundleUnloadScheduledBundles();
2132 if (!bundle
->_isLoaded
) return;
2134 // Remove from the scheduled unload set if we are there.
2135 if (!_scheduledBundlesAreUnloading
) {
2136 __CFSpinLock(&CFBundleGlobalDataLock
);
2138 if (_bundlesToUnload
) {
2139 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2141 if (!_scheduledBundlesAreUnloading
) {
2142 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2145 // Give the plugIn code a chance to realize this...
2146 _CFPlugInWillUnload(bundle
);
2148 switch (bundle
->_binaryType
) {
2149 #if defined(BINARY_SUPPORT_CFM)
2150 case __CFBundleCFMBinary
:
2151 _CFBundleCFMUnload(bundle
);
2153 #endif /* BINARY_SUPPORT_CFM */
2154 #if defined(BINARY_SUPPORT_DYLD)
2155 case __CFBundleDYLDBundleBinary
:
2156 _CFBundleDYLDUnloadBundle(bundle
);
2158 #endif /* BINARY_SUPPORT_DYLD */
2159 #if defined(BINARY_SUPPORT_DLL)
2160 case __CFBundleDLLBinary
:
2161 _CFBundleDLLUnload(bundle
);
2163 #endif /* BINARY_SUPPORT_DLL */
2167 if (!bundle
->_isLoaded
&& bundle
->_glueDict
!= NULL
) {
2168 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
2169 CFRelease(bundle
->_glueDict
);
2170 bundle
->_glueDict
= NULL
;
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
);
2183 CFSetAddValue(_bundlesToUnload
, bundle
);
2184 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2187 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
2188 __CFSpinLock(&CFBundleGlobalDataLock
);
2189 if (_bundlesToUnload
) {
2190 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2192 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2195 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
2196 __CFSpinLock(&CFBundleGlobalDataLock
);
2197 if (_bundlesToUnload
) {
2198 CFIndex c
= CFSetGetCount(_bundlesToUnload
);
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
]);
2208 _scheduledBundlesAreUnloading
= false;
2209 CFAllocatorDeallocate(NULL
, unloadThese
);
2212 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2215 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
2217 // Load if necessary
2218 if (!bundle
->_isLoaded
) {
2219 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2222 switch (bundle
->_binaryType
) {
2223 #if defined(BINARY_SUPPORT_CFM)
2224 case __CFBundleCFMBinary
:
2225 tvp
= _CFBundleCFMGetSymbolByName(bundle
, funcName
, kTVectorCFragSymbol
);
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
);
2234 #endif /* BINARY_SUPPORT_DYLD */
2235 #if defined(BINARY_SUPPORT_DLL)
2236 case __CFBundleDLLBinary
:
2237 tvp
= _CFBundleDLLGetSymbolByName(bundle
, funcName
);
2239 #endif /* BINARY_SUPPORT_DLL */
2243 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2245 if (bundle
->_glueDict
== NULL
) {
2246 bundle
->_glueDict
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, NULL
, NULL
);
2248 void *fp
= (void *)CFDictionaryGetValue(bundle
->_glueDict
, tvp
);
2250 fp
= _CFBundleFunctionPointerForTVector(CFGetAllocator(bundle
), tvp
);
2251 CFDictionarySetValue(bundle
->_glueDict
, tvp
, fp
);
2255 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2259 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
2261 // Load if necessary
2262 if (!bundle
->_isLoaded
) {
2263 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2266 switch (bundle
->_binaryType
) {
2267 #if defined(BINARY_SUPPORT_CFM)
2268 case __CFBundleCFMBinary
:
2269 return _CFBundleCFMGetSymbolByName(bundle
, funcName
, kTVectorCFragSymbol
);
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);
2278 #endif /* BINARY_SUPPORT_DYLD */
2282 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2284 if (bundle
->_glueDict
== NULL
) {
2285 bundle
->_glueDict
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, NULL
, NULL
);
2287 void *tvp
= (void *)CFDictionaryGetValue(bundle
->_glueDict
, fp
);
2289 tvp
= _CFBundleTVectorForFunctionPointer(CFGetAllocator(bundle
), fp
);
2290 CFDictionarySetValue(bundle
->_glueDict
, fp
, tvp
);
2294 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2298 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
2303 c
= CFArrayGetCount(functionNames
);
2304 for (i
= 0; i
< c
; i
++) {
2305 ftbl
[i
] = CFBundleGetFunctionPointerForName(bundle
, CFArrayGetValueAtIndex(functionNames
, i
));
2309 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
2314 c
= CFArrayGetCount(functionNames
);
2315 for (i
= 0; i
< c
; i
++) {
2316 ftbl
[i
] = _CFBundleGetCFMFunctionPointerForName(bundle
, CFArrayGetValueAtIndex(functionNames
, i
));
2320 void *CFBundleGetDataPointerForName(CFBundleRef bundle
, CFStringRef symbolName
) {
2322 // Load if necessary
2323 if (!bundle
->_isLoaded
) {
2324 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2327 switch (bundle
->_binaryType
) {
2328 #if defined(BINARY_SUPPORT_CFM)
2329 case __CFBundleCFMBinary
:
2330 dp
= _CFBundleCFMGetSymbolByName(bundle
, symbolName
, kDataCFragSymbol
);
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
);
2339 #endif /* BINARY_SUPPORT_DYLD */
2340 #if defined(BINARY_SUPPORT_DLL)
2341 case __CFBundleDLLBinary
:
2342 /* MF:!!! Handle this someday */
2344 #endif /* BINARY_SUPPORT_DLL */
2351 void CFBundleGetDataPointersForNames(CFBundleRef bundle
, CFArrayRef symbolNames
, void *stbl
[]) {
2356 c
= CFArrayGetCount(symbolNames
);
2357 for (i
= 0; i
< c
; i
++) {
2358 stbl
[i
] = CFBundleGetDataPointerForName(bundle
, CFArrayGetValueAtIndex(symbolNames
, i
));
2362 __private_extern__ _CFResourceData
*__CFBundleGetResourceData(CFBundleRef bundle
) {
2363 return &(bundle
->_resourceData
);
2366 CFPlugInRef
CFBundleGetPlugIn(CFBundleRef bundle
) {
2367 if (bundle
->_plugInData
._isPlugIn
) {
2368 return (CFPlugInRef
)bundle
;
2374 __private_extern__ _CFPlugInData
*__CFBundleGetPlugInData(CFBundleRef bundle
) {
2375 return &(bundle
->_plugInData
);
2378 __private_extern__ Boolean
_CFBundleCouldBeBundle(CFURLRef url
) {
2379 Boolean result
= false;
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));
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
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
;
2406 length
= CFStringGetLength(executablePath
);
2407 if (length
> CFMaxPathSize
) length
= CFMaxPathSize
;
2408 CFStringGetCharacters(executablePath
, CFRangeMake(0, length
), pathBuff
);
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
));
2416 // Strip the name from pathBuff
2417 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2418 savedLength
= length
;
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);
2426 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2427 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2428 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2429 CFRelease(bundleURL
);
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);
2439 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2440 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2441 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2442 CFRelease(bundleURL
);
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!
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".
2455 while (length
> 0) {
2456 curStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2457 if (curStart
>= length
) {
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
);
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
);
2479 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2483 CFStringSetExternalCharactersNoCopy(cheapStr
, NULL
, 0, 0);
2484 CFRelease(cheapStr
);
2489 static 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.
2493 CFURLRef curURL
= _CFBundleCopyFrameworkURLForExecutablePath(NULL
, imagePath
);
2495 if (curURL
!= NULL
) {
2496 bundle
= _CFBundleFindByURL(curURL
, true);
2497 if (bundle
== NULL
) {
2498 bundle
= _CFBundleCreate(NULL
, curURL
, true);
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
;
2506 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
2507 bundle
->_resourceData
._executableLacksResourceFork
= true;
2509 if (!bundle
->_imageCookie
) _CFBundleDYLDCheckLoaded(bundle
);
2510 #endif /* BINARY_SUPPORT_DYLD */
2511 bundle
->_isLoaded
= true;
2517 static 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
);
2522 for (i
=0; i
<imagePathCount
; i
++) {
2523 _CFBundleEnsureBundleExistsForImagePath(CFArrayGetValueAtIndex(imagePaths
, i
));
2527 static 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
);
2540 static 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.
2543 CFArrayRef imagePaths
;
2545 // Tickle the main bundle into existence
2546 (void)_CFBundleGetMainBundleAlreadyLocked();
2548 #if defined(BINARY_SUPPORT_DLL)
2549 #warning (MF) Dont know how to find static bundles for DLLs
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
2556 #if defined(BINARY_SUPPORT_DYLD)
2557 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsIfChanged();
2558 if (imagePaths
!= NULL
) {
2559 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2560 CFRelease(imagePaths
);
2565 CFArrayRef
CFBundleGetAllBundles(void) {
2566 // To answer this properly, we have to have created the static bundles!
2567 __CFSpinLock(&CFBundleGlobalDataLock
);
2568 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2569 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2573 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle
) {return bundle
->_version
;}
2575 CF_EXPORT CFURLRef
_CFBundleCopyInfoPlistURL(CFBundleRef bundle
) {
2576 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2577 CFStringRef path
= CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
);
2578 return (path
? CFRetain(path
) : NULL
);
2581 CF_EXPORT CFURLRef
_CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {return CFBundleCopyPrivateFrameworksURL(bundle
);}
2583 CF_EXPORT CFURLRef
CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
2584 CFURLRef result
= NULL
;
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
);
2591 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase0
, bundle
->_url
);
2596 CF_EXPORT CFURLRef
_CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {return CFBundleCopySharedFrameworksURL(bundle
);}
2598 CF_EXPORT CFURLRef
CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
2599 CFURLRef result
= NULL
;
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
);
2606 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase0
, bundle
->_url
);
2611 CF_EXPORT CFURLRef
_CFBundleCopySharedSupportURL(CFBundleRef bundle
) {return CFBundleCopySharedSupportURL(bundle
);}
2613 CF_EXPORT CFURLRef
CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
2614 CFURLRef result
= NULL
;
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
);
2621 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase0
, bundle
->_url
);
2626 __private_extern__ CFURLRef
_CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {return CFBundleCopyBuiltInPlugInsURL(bundle
);}
2628 CF_EXPORT CFURLRef
CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
2629 CFURLRef result
= NULL
, alternateResult
= NULL
;
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
);
2637 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase0
, bundle
->_url
);
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
);
2645 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2647 if (alternateResult
&& _urlExists(alloc
, alternateResult
)) {
2648 if (result
) CFRelease(result
);
2649 result
= alternateResult
;
2651 if (alternateResult
) CFRelease(alternateResult
);
2659 #if defined(BINARY_SUPPORT_DYLD)
2661 static void *__CFBundleDYLDFindImage(char *buff
) {
2662 void *header
= NULL
;
2663 unsigned long i
, numImages
= _dyld_image_count(), numMatches
= 0;
2664 char *curName
, *p
, *q
;
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
);
2674 for (i
= 0; i
< numImages
; i
++) {
2675 curName
= _dyld_get_image_name(i
);
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;
2683 header
= _dyld_get_image_header(i
);
2689 return (numMatches
== 1) ? header
: NULL
;
2692 __private_extern__ Boolean
_CFBundleDYLDCheckLoaded(CFBundleRef bundle
) {
2693 if (!bundle
->_isLoaded
) {
2694 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2696 if (executableURL
!= NULL
) {
2697 char buff
[CFMaxPathSize
];
2699 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2700 void *header
= __CFBundleDYLDFindImage(buff
);
2702 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2703 bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
2705 if (!bundle
->_imageCookie
) bundle
->_imageCookie
= header
;
2706 bundle
->_isLoaded
= true;
2709 CFRelease(executableURL
);
2712 return bundle
->_isLoaded
;
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
;
2721 if (!bundle
->_isLoaded
) {
2722 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2724 if (executableURL
) {
2725 char buff
[CFMaxPathSize
];
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
));
2733 bundle
->_imageCookie
= image
;
2734 bundle
->_moduleCookie
= module;
2735 bundle
->_isLoaded
= true;
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 */
2744 CFLog(__kCFLogBundle
, CFSTR("dyld returns %d when trying to load %@"), retCode
, executableURL
);
2747 CFRelease(executableURL
);
2749 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2752 return bundle
->_isLoaded
;
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
;
2762 if (!bundle
->_isLoaded
) {
2763 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2765 if (executableURL
) {
2766 char buff
[CFMaxPathSize
];
2768 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2769 void *image
= (void *)NSAddImage(buff
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
2771 bundle
->_imageCookie
= image
;
2772 bundle
->_isLoaded
= true;
2774 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
2775 CFLog(__kCFLogBundle
, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName
, c
, errorNumber
, errorString
);
2778 CFRelease(executableURL
);
2780 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2783 return bundle
->_isLoaded
;
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
);
2791 if (bundle
->_moduleCookie
&& bundle
->_imageCookie
&& !NSDestroyObjectFileImage(bundle
->_imageCookie
)) {
2792 /* MF:!!! Error destroying object file image */
2794 bundle
->_connectionCookie
= bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
2795 bundle
->_isLoaded
= false;
2800 __private_extern__
void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {return _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, symbolName
, false);}
2802 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
2803 void *result
= NULL
;
2805 NSSymbol symbol
= NULL
;
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.
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
);
2817 if (NULL
== symbol
&& NULL
== bundle
->_moduleCookie
&& (NULL
== bundle
->_imageCookie
|| globalSearch
)) {
2818 char hintBuff
[1026];
2819 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, bundle
, NULL
, NULL
);
2821 if (executableName
) {
2822 if (!CFStringGetCString(executableName
, hintBuff
, 1024, kCFStringEncodingUTF8
)) hintBuff
[0] = '\0';
2823 CFRelease(executableName
);
2825 if (NSIsSymbolNameDefinedWithHint(buff
, hintBuff
)) {
2826 symbol
= NSLookupAndBindSymbolWithHint(buff
, hintBuff
);
2830 result
= NSAddressOfSymbol(symbol
);
2833 CFLog(__kCFLogBundle
, CFSTR("dyld cannot find symbol %s in %@"), buff
, bundle
);
2840 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
) {
2841 unsigned long i
, j
, n
= _dyld_image_count();
2842 Boolean foundit
= false;
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
);
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
) {
2853 name
= _dyld_get_image_name(i
);
2855 result
= CFStringCreateWithCString(NULL
, name
, CFStringFileSystemEncoding());
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
));
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());
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
);
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;
2893 unsigned long i
, numImages
= _dyld_image_count();
2894 CFMutableArrayRef result
= NULL
;
2896 if (numImages
!= _cachedDYLDImageCount
) {
2900 result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
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
);
2912 _cachedDYLDImageCount
= numImages
;
2917 #endif /* BINARY_SUPPORT_DYLD */
2920 #if defined(BINARY_SUPPORT_DLL)
2922 __private_extern__ Boolean
_CFBundleDLLLoad(CFBundleRef bundle
) {
2924 if (!bundle
->_isLoaded
) {
2925 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2927 if (executableURL
) {
2928 char buff
[CFMaxPathSize
];
2930 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2931 bundle
->_hModule
= LoadLibrary(buff
);
2932 if (bundle
->_hModule
== NULL
) {
2934 bundle
->_isLoaded
= true;
2937 CFRelease(executableURL
);
2939 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2943 return bundle
->_isLoaded
;
2946 __private_extern__
void _CFBundleDLLUnload(CFBundleRef bundle
) {
2947 if (bundle
->_isLoaded
) {
2948 FreeLibrary(bundle
->_hModule
);
2949 bundle
->_hModule
= NULL
;
2950 bundle
->_isLoaded
= false;
2954 __private_extern__
void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
2955 void *result
= NULL
;
2958 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingWindowsLatin1
)) {
2959 result
= GetProcAddress(bundle
->_hModule
, buff
);
2964 #endif /* BINARY_SUPPORT_DLL */
2967 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
2969 extern void _CFStringSetCompatibility(CFOptionFlags
);
2971 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
) {