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
, Boolean doFinalProcessing
);
192 static CFStringRef
_CFBundleCopyExecutableName(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
);
193 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
);
194 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
);
195 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
);
196 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
);
197 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void);
198 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
);
199 #if defined(BINARY_SUPPORT_DYLD)
200 static CFDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable(void);
201 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
);
202 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
);
203 #endif /* BINARY_SUPPORT_DYLD */
204 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
205 static void *_CFBundleFunctionPointerForTVector(CFAllocatorRef allocator
, void *tvp
);
206 static void *_CFBundleTVectorForFunctionPointer(CFAllocatorRef allocator
, void *fp
);
207 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
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 // NB doFinalProcessing must be false here, see below
514 _mainBundle
= _CFBundleCreate(NULL
, bundleURL
, true, false);
515 if (_mainBundle
!= NULL
) {
516 CFBundleGetInfoDictionary(_mainBundle
);
517 // make sure that the main bundle is listed as loaded, and mark it as executable
518 _mainBundle
->_isLoaded
= true;
519 #if defined(BINARY_SUPPORT_DYLD)
520 if (_mainBundle
->_binaryType
== __CFBundleUnknownBinary
) {
521 if (!executableURL
) {
522 _mainBundle
->_binaryType
= __CFBundleNoBinary
;
524 _mainBundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
525 #if defined(BINARY_SUPPORT_CFM)
526 if (_mainBundle
->_binaryType
!= __CFBundleCFMBinary
&& _mainBundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
527 _mainBundle
->_resourceData
._executableLacksResourceFork
= true;
529 #endif /* BINARY_SUPPORT_CFM */
532 #endif /* BINARY_SUPPORT_DYLD */
533 if (_mainBundle
->_infoDict
== NULL
|| CFDictionaryGetCount(_mainBundle
->_infoDict
) == 0) {
534 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives
535 if (_mainBundle
->_version
== 3) _mainBundle
->_version
= 4;
536 if (_mainBundle
->_version
== 0) {
537 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives
538 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, _mainBundle
, NULL
, NULL
);
539 if (!executableName
|| !CFStringHasSuffix(str
, executableName
)) _mainBundle
->_version
= 4;
540 if (executableName
) CFRelease(executableName
);
542 #if defined(BINARY_SUPPORT_DYLD)
543 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
) {
544 if (_mainBundle
->_infoDict
!= NULL
) CFRelease(_mainBundle
->_infoDict
);
545 _mainBundle
->_infoDict
= _CFBundleGrokInfoDictFromMainExecutable();
547 #endif /* BINARY_SUPPORT_DYLD */
548 #if defined(BINARY_SUPPORT_CFM)
549 if (_mainBundle
->_binaryType
== __CFBundleCFMBinary
|| _mainBundle
->_binaryType
== __CFBundleUnreadableBinary
) {
550 // if type 0 bundle and CFM binary and no Info.plist, treat as unbundled, since this also gives too many false positives
551 if (_mainBundle
->_version
== 0) _mainBundle
->_version
= 4;
552 if (_mainBundle
->_infoDict
!= NULL
) CFRelease(_mainBundle
->_infoDict
);
553 _mainBundle
->_infoDict
= _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFGetAllocator(_mainBundle
), executableURL
);
554 if (_mainBundle
->_binaryType
== __CFBundleUnreadableBinary
&& _mainBundle
->_infoDict
!= NULL
&& CFDictionaryGetValue(_mainBundle
->_infoDict
, kCFBundleDevelopmentRegionKey
) != NULL
) versRegionOverrides
= true;
556 #endif /* BINARY_SUPPORT_CFM */
558 if (_mainBundle
->_infoDict
== NULL
) {
559 _mainBundle
->_infoDict
= CFDictionaryCreateMutable(CFGetAllocator(_mainBundle
), 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
561 if (NULL
== CFDictionaryGetValue(_mainBundle
->_infoDict
, _kCFBundleExecutablePathKey
)) {
562 CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), _kCFBundleExecutablePathKey
, str
);
564 #if defined(BINARY_SUPPORT_DYLD)
565 // get cookie for already-loaded main bundle
566 if (_mainBundle
->_binaryType
== __CFBundleDYLDExecutableBinary
&& !_mainBundle
->_imageCookie
) {
567 _mainBundle
->_imageCookie
= (void *)_dyld_get_image_header(0);
569 #endif /* BINARY_SUPPORT_DYLD */
570 #if defined(BINARY_SUPPORT_CFM)
571 if (versRegionOverrides
) {
572 // This is a hack to preserve backward compatibility for certain broken applications (2761067)
573 CFStringRef devLang
= _CFBundleCopyBundleDevelopmentRegionFromVersResource(_mainBundle
);
574 if (devLang
!= NULL
) {
575 CFDictionarySetValue((CFMutableDictionaryRef
)(_mainBundle
->_infoDict
), kCFBundleDevelopmentRegionKey
, devLang
);
579 #endif /* BINARY_SUPPORT_CFM */
580 // Perform delayed final processing steps.
581 // This must be done after _isLoaded has been set, for security reasons (3624341).
582 _CFBundleCheckWorkarounds(_mainBundle
);
583 _CFBundleInitPlugIn(_mainBundle
);
586 if (bundleURL
) CFRelease(bundleURL
);
587 if (str
) CFRelease(str
);
588 if (executableURL
) CFRelease(executableURL
);
593 CFBundleRef
CFBundleGetMainBundle(void) {
594 CFBundleRef mainBundle
;
595 __CFSpinLock(&CFBundleGlobalDataLock
);
596 mainBundle
= _CFBundleGetMainBundleAlreadyLocked();
597 __CFSpinUnlock(&CFBundleGlobalDataLock
);
601 #if defined(BINARY_SUPPORT_DYLD)
603 static void *_CFBundleReturnAddressFromFrameAddress(void *addr
)
607 __asm__
volatile("lwz %0,0x0008(%1)" : "=r" (ret
) : "b" (addr
));
608 #elif defined(__i386__)
609 __asm__
volatile("movl 0x4(%1),%0" : "=r" (ret
) : "r" (addr
));
611 __asm__
volatile("ldw 0x4(%1),%0" : "=r" (ret
) : "r" (addr
));
613 __asm__
volatile("ta 0x3");
614 __asm__
volatile("ld [%1 + 60],%0" : "=r" (ret
) : "r" (addr
));
616 #warning Do not know how to define _CFBundleReturnAddressFromFrameAddress on this architecture
624 CFBundleRef
CFBundleGetBundleWithIdentifier(CFStringRef bundleID
) {
625 CFBundleRef result
= NULL
;
627 __CFSpinLock(&CFBundleGlobalDataLock
);
628 (void)_CFBundleGetMainBundleAlreadyLocked();
629 if (_bundlesByIdentifier
!= NULL
) {
630 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
632 #if defined(BINARY_SUPPORT_DYLD)
633 if (result
== NULL
) {
634 // Try to create the bundle for the caller and try again
635 void *p
= _CFBundleReturnAddressFromFrameAddress(__builtin_frame_address(1));
636 CFStringRef imagePath
= _CFBundleDYLDCopyLoadedImagePathForPointer(p
);
637 if (imagePath
!= NULL
) {
638 _CFBundleEnsureBundleExistsForImagePath(imagePath
);
639 CFRelease(imagePath
);
641 if (_bundlesByIdentifier
!= NULL
) {
642 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
646 if (result
== NULL
) {
647 // Try to guess the bundle from the identifier and try again
648 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID
);
649 if (_bundlesByIdentifier
!= NULL
) {
650 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
653 if (result
== NULL
) {
654 // Make sure all bundles have been created and try again.
655 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
656 if (_bundlesByIdentifier
!= NULL
) {
657 result
= (CFBundleRef
)CFDictionaryGetValue(_bundlesByIdentifier
, bundleID
);
660 __CFSpinUnlock(&CFBundleGlobalDataLock
);
665 static CFStringRef
__CFBundleCopyDescription(CFTypeRef cf
) {
666 char buff
[CFMaxPathSize
];
667 CFStringRef path
= NULL
, binaryType
= NULL
, retval
= NULL
;
668 if (((CFBundleRef
)cf
)->_url
!= NULL
&& CFURLGetFileSystemRepresentation(((CFBundleRef
)cf
)->_url
, true, buff
, CFMaxPathSize
)) {
669 path
= CFStringCreateWithCString(NULL
, buff
, CFStringFileSystemEncoding());
671 switch (((CFBundleRef
)cf
)->_binaryType
) {
672 case __CFBundleCFMBinary
:
673 binaryType
= CFSTR("");
675 case __CFBundleDYLDExecutableBinary
:
676 binaryType
= CFSTR("executable, ");
678 case __CFBundleDYLDBundleBinary
:
679 binaryType
= CFSTR("bundle, ");
681 case __CFBundleDYLDFrameworkBinary
:
682 binaryType
= CFSTR("framework, ");
684 case __CFBundleDLLBinary
:
685 binaryType
= CFSTR("DLL, ");
687 case __CFBundleUnreadableBinary
:
688 binaryType
= CFSTR("");
691 binaryType
= CFSTR("");
694 if (((CFBundleRef
)cf
)->_plugInData
._isPlugIn
) {
695 retval
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFBundle/CFPlugIn 0x%x <%@> (%@%sloaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? "" : "not ");
697 retval
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("CFBundle 0x%x <%@> (%@%sloaded)"), cf
, path
, binaryType
, ((CFBundleRef
)cf
)->_isLoaded
? "" : "not ");
699 if (path
) CFRelease(path
);
703 static void _CFBundleDeallocateGlue(const void *key
, const void *value
, void *context
) {
704 CFAllocatorRef allocator
= (CFAllocatorRef
)context
;
706 CFAllocatorDeallocate(allocator
, (void *)value
);
710 static void __CFBundleDeallocate(CFTypeRef cf
) {
711 CFBundleRef bundle
= (CFBundleRef
)cf
;
712 CFAllocatorRef allocator
;
714 __CFGenericValidateType(cf
, __kCFBundleTypeID
);
716 allocator
= CFGetAllocator(bundle
);
719 CFBundleUnloadExecutable(bundle
);
721 // Clean up plugIn stuff
722 _CFBundleDeallocatePlugIn(bundle
);
724 _CFBundleRemoveFromTables(bundle
);
726 if (bundle
->_url
!= NULL
) {
727 CFRelease(bundle
->_url
);
729 if (bundle
->_infoDict
!= NULL
) {
730 CFRelease(bundle
->_infoDict
);
732 if (bundle
->_modDate
!= NULL
) {
733 CFRelease(bundle
->_modDate
);
735 if (bundle
->_localInfoDict
!= NULL
) {
736 CFRelease(bundle
->_localInfoDict
);
738 if (bundle
->_searchLanguages
!= NULL
) {
739 CFRelease(bundle
->_searchLanguages
);
741 if (bundle
->_glueDict
!= NULL
) {
742 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)allocator
);
743 CFRelease(bundle
->_glueDict
);
745 if (bundle
->_resourceData
._stringTableCache
!= NULL
) {
746 CFRelease(bundle
->_resourceData
._stringTableCache
);
750 static const CFRuntimeClass __CFBundleClass
= {
755 __CFBundleDeallocate
,
759 __CFBundleCopyDescription
762 __private_extern__
void __CFBundleInitialize(void) {
763 __kCFBundleTypeID
= _CFRuntimeRegisterClass(&__CFBundleClass
);
766 CFTypeID
CFBundleGetTypeID(void) {
767 return __kCFBundleTypeID
;
770 static CFBundleRef
_CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
, Boolean alreadyLocked
, Boolean doFinalProcessing
) {
771 CFBundleRef bundle
= NULL
;
772 char buff
[CFMaxPathSize
];
773 CFDateRef modDate
= NULL
;
774 Boolean exists
= false;
776 CFURLRef newURL
= NULL
;
777 uint8_t localVersion
= 0;
779 if (!CFURLGetFileSystemRepresentation(bundleURL
, true, buff
, CFMaxPathSize
)) return NULL
;
781 newURL
= CFURLCreateFromFileSystemRepresentation(allocator
, buff
, strlen(buff
), true);
782 if (NULL
== newURL
) {
783 newURL
= CFRetain(bundleURL
);
785 bundle
= _CFBundleFindByURL(newURL
, alreadyLocked
);
792 if (!_CFBundleURLLooksLikeBundleVersion(newURL
, &localVersion
)) {
794 if (_CFGetFileProperties(allocator
, newURL
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
795 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
796 if (NULL
!= modDate
) CFRelease(modDate
);
806 bundle
= (CFBundleRef
)_CFRuntimeCreateInstance(allocator
, __kCFBundleTypeID
, sizeof(struct __CFBundle
) - sizeof(CFRuntimeBase
), NULL
);
807 if (NULL
== bundle
) {
812 bundle
->_url
= newURL
;
814 bundle
->_modDate
= modDate
;
815 bundle
->_version
= localVersion
;
816 bundle
->_infoDict
= NULL
;
817 bundle
->_localInfoDict
= NULL
;
818 bundle
->_searchLanguages
= NULL
;
820 #if defined(BINARY_SUPPORT_DYLD)
821 /* We'll have to figure it out later */
822 bundle
->_binaryType
= __CFBundleUnknownBinary
;
823 #elif defined(BINARY_SUPPORT_CFM)
824 /* We support CFM only */
825 bundle
->_binaryType
= __CFBundleCFMBinary
;
826 #elif defined(BINARY_SUPPORT_DLL)
827 /* We support DLL only */
828 bundle
->_binaryType
= __CFBundleDLLBinary
;
829 bundle
->_hModule
= NULL
;
831 /* We'll have to figure it out later */
832 bundle
->_binaryType
= __CFBundleUnknownBinary
;
835 bundle
->_isLoaded
= false;
836 bundle
->_sharesStringsFiles
= false;
838 /* ??? For testing purposes? Or for good? */
839 if (!getenv("CFBundleDisableStringsSharing") &&
840 (strncmp(buff
, "/System/Library/Frameworks", 26) == 0) &&
841 (strncmp(buff
+ strlen(buff
) - 10, ".framework", 10) == 0)) bundle
->_sharesStringsFiles
= true;
843 bundle
->_connectionCookie
= NULL
;
844 bundle
->_imageCookie
= NULL
;
845 bundle
->_moduleCookie
= NULL
;
847 bundle
->_glueDict
= NULL
;
849 #if defined(BINARY_SUPPORT_CFM)
850 bundle
->_resourceData
._executableLacksResourceFork
= false;
852 bundle
->_resourceData
._executableLacksResourceFork
= true;
855 bundle
->_resourceData
._stringTableCache
= NULL
;
857 bundle
->_plugInData
._isPlugIn
= false;
858 bundle
->_plugInData
._loadOnDemand
= false;
859 bundle
->_plugInData
._isDoingDynamicRegistration
= false;
860 bundle
->_plugInData
._instanceCount
= 0;
861 bundle
->_plugInData
._factories
= NULL
;
863 CFBundleGetInfoDictionary(bundle
);
865 _CFBundleAddToTables(bundle
, alreadyLocked
);
867 if (doFinalProcessing
) {
868 _CFBundleCheckWorkarounds(bundle
);
869 _CFBundleInitPlugIn(bundle
);
875 CFBundleRef
CFBundleCreate(CFAllocatorRef allocator
, CFURLRef bundleURL
) {return _CFBundleCreate(allocator
, bundleURL
, false, true);}
877 CFArrayRef
CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc
, CFURLRef directoryURL
, CFStringRef bundleType
) {
878 CFMutableArrayRef bundles
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
);
879 CFArrayRef URLs
= _CFContentsOfDirectory(alloc
, NULL
, NULL
, directoryURL
, bundleType
);
881 CFIndex i
, c
= CFArrayGetCount(URLs
);
883 CFBundleRef curBundle
;
885 for (i
=0; i
<c
; i
++) {
886 curURL
= CFArrayGetValueAtIndex(URLs
, i
);
887 curBundle
= CFBundleCreate(alloc
, curURL
);
888 if (curBundle
!= NULL
) {
889 CFArrayAppendValue(bundles
, curBundle
);
898 CFURLRef
CFBundleCopyBundleURL(CFBundleRef bundle
) {
900 CFRetain(bundle
->_url
);
905 void _CFBundleSetDefaultLocalization(CFStringRef localizationName
) {
906 CFStringRef newLocalization
= localizationName
? CFStringCreateCopy(NULL
, localizationName
) : NULL
;
907 if (_defaultLocalization
) CFRelease(_defaultLocalization
);
908 _defaultLocalization
= newLocalization
;
911 __private_extern__ CFArrayRef
_CFBundleGetLanguageSearchList(CFBundleRef bundle
) {
912 if (bundle
->_searchLanguages
== NULL
) {
913 CFMutableArrayRef langs
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
914 CFStringRef devLang
= CFBundleGetDevelopmentRegion(bundle
);
916 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, devLang
);
918 if (CFArrayGetCount(langs
) == 0) {
919 // If the user does not prefer any of our languages, and devLang is not present, try English
920 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFSTR("en_US"));
922 if (CFArrayGetCount(langs
) == 0) {
923 // if none of the preferred localizations are present, fall back on a random localization that is present
924 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
926 if (CFArrayGetCount(localizations
) > 0) {
927 _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
, bundle
->_infoDict
, langs
, CFArrayGetValueAtIndex(localizations
, 0));
929 CFRelease(localizations
);
933 if (devLang
!= NULL
&& !CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), devLang
)) {
934 // Make sure that devLang is on the list as a fallback for individual resources that are not present
935 CFArrayAppendValue(langs
, devLang
);
936 } else if (devLang
== NULL
) {
937 // Or if there is no devLang, try some variation of English that is present
938 CFArrayRef localizations
= CFBundleCopyBundleLocalizations(bundle
);
940 CFStringRef en_US
= CFSTR("en_US"), en
= CFSTR("en"), English
= CFSTR("English");
941 CFRange range
= CFRangeMake(0, CFArrayGetCount(localizations
));
942 if (CFArrayContainsValue(localizations
, range
, en
)) {
943 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en
)) CFArrayAppendValue(langs
, en
);
944 } else if (CFArrayContainsValue(localizations
, range
, English
)) {
945 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), English
)) CFArrayAppendValue(langs
, English
);
946 } else if (CFArrayContainsValue(localizations
, range
, en_US
)) {
947 if (!CFArrayContainsValue(langs
, CFRangeMake(0, CFArrayGetCount(langs
)), en_US
)) CFArrayAppendValue(langs
, en_US
);
949 CFRelease(localizations
);
952 if (CFArrayGetCount(langs
) == 0) {
953 // Total backstop behavior to avoid having an empty array.
954 if (_defaultLocalization
!= NULL
) {
955 CFArrayAppendValue(langs
, _defaultLocalization
);
957 CFArrayAppendValue(langs
, CFSTR("en"));
960 bundle
->_searchLanguages
= langs
;
962 return bundle
->_searchLanguages
;
965 CFDictionaryRef
CFBundleCopyInfoDictionaryInDirectory(CFURLRef url
) {return _CFBundleCopyInfoDictionaryInDirectory(NULL
, url
, NULL
);}
967 CFDictionaryRef
CFBundleGetInfoDictionary(CFBundleRef bundle
) {
968 if (bundle
->_infoDict
== NULL
) {
969 bundle
->_infoDict
= _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);
971 return bundle
->_infoDict
;
974 CFDictionaryRef
_CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {return CFBundleGetLocalInfoDictionary(bundle
);}
976 CFDictionaryRef
CFBundleGetLocalInfoDictionary(CFBundleRef bundle
) {
977 if (bundle
->_localInfoDict
== NULL
) {
978 CFURLRef url
= CFBundleCopyResourceURL(bundle
, _CFBundleLocalInfoName
, _CFBundleStringTableType
, NULL
);
982 CFStringRef errStr
= NULL
;
984 if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle
), url
, &data
, NULL
, NULL
, &errCode
)) {
985 bundle
->_localInfoDict
= CFPropertyListCreateFromXMLData(CFGetAllocator(bundle
), data
, kCFPropertyListImmutable
, &errStr
);
994 return bundle
->_localInfoDict
;
997 CFPropertyListRef
_CFBundleGetValueForInfoKey(CFBundleRef bundle
, CFStringRef key
) {return (CFPropertyListRef
)CFBundleGetValueForInfoDictionaryKey(bundle
, key
);}
999 CFTypeRef
CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle
, CFStringRef key
) {
1000 // Look in InfoPlist.strings first. Then look in Info.plist
1001 CFTypeRef result
= NULL
;
1002 if ((bundle
!= NULL
) && (key
!= NULL
)) {
1003 CFDictionaryRef dict
= CFBundleGetLocalInfoDictionary(bundle
);
1005 result
= CFDictionaryGetValue(dict
, key
);
1007 if (result
== NULL
) {
1008 dict
= CFBundleGetInfoDictionary(bundle
);
1010 result
= CFDictionaryGetValue(dict
, key
);
1017 CFStringRef
CFBundleGetIdentifier(CFBundleRef bundle
) {
1018 CFStringRef bundleID
= NULL
;
1019 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1021 bundleID
= CFDictionaryGetValue(infoDict
, kCFBundleIdentifierKey
);
1026 #define DEVELOPMENT_STAGE 0x20
1027 #define ALPHA_STAGE 0x40
1028 #define BETA_STAGE 0x60
1029 #define RELEASE_STAGE 0x80
1031 #define MAX_VERS_LEN 10
1033 CF_INLINE Boolean
_isDigit(UniChar aChar
) {return (((aChar
>= (UniChar
)'0') && (aChar
<= (UniChar
)'9')) ? true : false);}
1035 __private_extern__ CFStringRef
_CFCreateStringFromVersionNumber(CFAllocatorRef alloc
, UInt32 vers
) {
1036 CFStringRef result
= NULL
;
1037 uint8_t major1
, major2
, minor1
, minor2
, stage
, build
;
1039 major1
= (vers
& 0xF0000000) >> 28;
1040 major2
= (vers
& 0x0F000000) >> 24;
1041 minor1
= (vers
& 0x00F00000) >> 20;
1042 minor2
= (vers
& 0x000F0000) >> 16;
1043 stage
= (vers
& 0x0000FF00) >> 8;
1044 build
= (vers
& 0x000000FF);
1046 if (stage
== RELEASE_STAGE
) {
1048 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d"), major1
, major2
, minor1
, minor2
);
1050 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d"), major2
, minor1
, minor2
);
1054 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d%d.%d.%d%s%d"), major1
, major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? "d" : ((stage
== ALPHA_STAGE
) ? "a" : "b")), build
);
1056 result
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%d.%d.%d%s%d"), major2
, minor1
, minor2
, ((stage
== DEVELOPMENT_STAGE
) ? "d" : ((stage
== ALPHA_STAGE
) ? "a" : "b")), build
);
1062 __private_extern__ UInt32
_CFVersionNumberFromString(CFStringRef versStr
) {
1063 // Parse version number from string.
1064 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped.
1065 UInt32 major1
= 0, major2
= 0, minor1
= 0, minor2
= 0, stage
= RELEASE_STAGE
, build
= 0;
1066 UniChar versChars
[MAX_VERS_LEN
];
1067 UniChar
*chars
= NULL
;
1070 Boolean digitsDone
= false;
1072 if (!versStr
) return 0;
1074 len
= CFStringGetLength(versStr
);
1076 if ((len
== 0) || (len
> MAX_VERS_LEN
)) return 0;
1078 CFStringGetCharacters(versStr
, CFRangeMake(0, len
), versChars
);
1081 // Get major version number.
1082 major1
= major2
= 0;
1083 if (_isDigit(*chars
)) {
1084 major2
= *chars
- (UniChar
)'0';
1088 if (_isDigit(*chars
)) {
1090 major2
= *chars
- (UniChar
)'0';
1094 if (*chars
== (UniChar
)'.') {
1101 } else if (*chars
== (UniChar
)'.') {
1108 } else if (*chars
== (UniChar
)'.') {
1115 // Now major1 and major2 contain first and second digit of the major version number as ints.
1116 // Now either len is 0 or chars points at the first char beyond the first decimal point.
1118 // Get the first minor version number.
1119 if (len
> 0 && !digitsDone
) {
1120 if (_isDigit(*chars
)) {
1121 minor1
= *chars
- (UniChar
)'0';
1125 if (*chars
== (UniChar
)'.') {
1137 // Now minor1 contains the first minor version number as an int.
1138 // Now either len is 0 or chars points at the first char beyond the second decimal point.
1140 // Get the second minor version number.
1141 if (len
> 0 && !digitsDone
) {
1142 if (_isDigit(*chars
)) {
1143 minor2
= *chars
- (UniChar
)'0';
1151 // Now minor2 contains the second minor version number as an int.
1152 // Now either len is 0 or chars points at the build stage letter.
1154 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next.
1156 if (*chars
== (UniChar
)'d') {
1157 stage
= DEVELOPMENT_STAGE
;
1158 } else if (*chars
== (UniChar
)'a') {
1159 stage
= ALPHA_STAGE
;
1160 } else if (*chars
== (UniChar
)'b') {
1162 } else if (*chars
== (UniChar
)'f') {
1163 stage
= RELEASE_STAGE
;
1171 // Now stage contains the release stage.
1172 // Now either len is 0 or chars points at the build number.
1174 // Get the first digit of the build number.
1176 if (_isDigit(*chars
)) {
1177 build
= *chars
- (UniChar
)'0';
1184 // Get the second digit of the build number.
1186 if (_isDigit(*chars
)) {
1188 build
+= *chars
- (UniChar
)'0';
1195 // Get the third digit of the build number.
1197 if (_isDigit(*chars
)) {
1199 build
+= *chars
- (UniChar
)'0';
1207 // Range check the build number and make sure we exhausted the string.
1208 if ((build
> 0xFF) || (len
> 0)) return 0;
1211 theVers
= major1
<< 28;
1212 theVers
+= major2
<< 24;
1213 theVers
+= minor1
<< 20;
1214 theVers
+= minor2
<< 16;
1215 theVers
+= stage
<< 8;
1221 UInt32
CFBundleGetVersionNumber(CFBundleRef bundle
) {
1222 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1223 CFTypeRef unknownVersionValue
= CFDictionaryGetValue(infoDict
, _kCFBundleNumericVersionKey
);
1224 CFNumberRef versNum
;
1227 if (unknownVersionValue
== NULL
) {
1228 unknownVersionValue
= CFDictionaryGetValue(infoDict
, kCFBundleVersionKey
);
1230 if (unknownVersionValue
!= NULL
) {
1231 if (CFGetTypeID(unknownVersionValue
) == CFStringGetTypeID()) {
1232 // Convert a string version number into a numeric one.
1233 vers
= _CFVersionNumberFromString((CFStringRef
)unknownVersionValue
);
1235 versNum
= CFNumberCreate(CFGetAllocator(bundle
), kCFNumberSInt32Type
, &vers
);
1236 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
, versNum
);
1238 } else if (CFGetTypeID(unknownVersionValue
) == CFNumberGetTypeID()) {
1239 CFNumberGetValue((CFNumberRef
)unknownVersionValue
, kCFNumberSInt32Type
, &vers
);
1241 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleNumericVersionKey
);
1247 CFStringRef
CFBundleGetDevelopmentRegion(CFBundleRef bundle
) {
1248 CFStringRef devLang
= NULL
;
1249 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
1251 devLang
= CFDictionaryGetValue(infoDict
, kCFBundleDevelopmentRegionKey
);
1252 if (devLang
!= NULL
&& (CFGetTypeID(devLang
) != CFStringGetTypeID() || CFStringGetLength(devLang
) == 0)) {
1254 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, kCFBundleDevelopmentRegionKey
);
1261 Boolean
_CFBundleGetHasChanged(CFBundleRef bundle
) {
1263 Boolean result
= false;
1264 Boolean exists
= false;
1267 if (_CFGetFileProperties(CFGetAllocator(bundle
), bundle
->_url
, &exists
, &mode
, NULL
, &modDate
, NULL
, NULL
) == 0) {
1268 // If the bundle no longer exists or is not a folder, it must have "changed"
1269 if (!exists
|| ((mode
& S_IFMT
) != S_IFDIR
)) {
1273 // Something is wrong. The stat failed.
1276 if (bundle
->_modDate
&& !CFEqual(bundle
->_modDate
, modDate
)) {
1277 // mod date is different from when we created.
1284 void _CFBundleSetStringsFilesShared(CFBundleRef bundle
, Boolean flag
) {
1285 bundle
->_sharesStringsFiles
= flag
;
1288 Boolean
_CFBundleGetStringsFilesShared(CFBundleRef bundle
) {
1289 return bundle
->_sharesStringsFiles
;
1292 static Boolean
_urlExists(CFAllocatorRef alloc
, CFURLRef url
) {
1294 return url
&& (0 == _CFGetFileProperties(alloc
, url
, &exists
, NULL
, NULL
, NULL
, NULL
, NULL
)) && exists
;
1297 __private_extern__ CFURLRef
_CFBundleCopySupportFilesDirectoryURLInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
) {
1298 CFURLRef result
= NULL
;
1301 result
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase1
, bundleURL
);
1302 } else if (2 == version
) {
1303 result
= CFURLCreateWithString(alloc
, _CFBundleSupportFilesURLFromBase2
, bundleURL
);
1305 result
= CFRetain(bundleURL
);
1311 CF_EXPORT CFURLRef
CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle
) {return _CFBundleCopySupportFilesDirectoryURLInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);}
1313 __private_extern__ CFURLRef
_CFBundleCopyResourcesDirectoryURLInDirectory(CFAllocatorRef alloc
, CFURLRef bundleURL
, uint8_t version
) {
1314 CFURLRef result
= NULL
;
1317 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase0
, bundleURL
);
1318 } else if (1 == version
) {
1319 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase1
, bundleURL
);
1320 } else if (2 == version
) {
1321 result
= CFURLCreateWithString(alloc
, _CFBundleResourcesURLFromBase2
, bundleURL
);
1323 result
= CFRetain(bundleURL
);
1329 CFURLRef
CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle
) {return _CFBundleCopyResourcesDirectoryURLInDirectory(CFGetAllocator(bundle
), bundle
->_url
, bundle
->_version
);}
1331 static CFURLRef
_CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc
, CFURLRef urlPath
, CFStringRef exeName
) {
1332 // Given an url to a folder and a name, this returns the url to the executable in that folder with that name, if it exists, and NULL otherwise. This function deals with appending the ".exe" or ".dll" on Windows.
1333 CFURLRef executableURL
= NULL
;
1334 #if defined(__MACH__)
1335 const uint8_t *image_suffix
= getenv("DYLD_IMAGE_SUFFIX");
1336 #endif /* __MACH__ */
1338 if (urlPath
== NULL
|| exeName
== NULL
) return NULL
;
1340 #if defined(__MACH__)
1341 if (image_suffix
!= NULL
) {
1342 CFStringRef newExeName
, imageSuffix
;
1343 imageSuffix
= CFStringCreateWithCString(NULL
, image_suffix
, kCFStringEncodingUTF8
);
1344 if (CFStringHasSuffix(exeName
, CFSTR(".dylib"))) {
1345 CFStringRef bareExeName
= CFStringCreateWithSubstring(alloc
, exeName
, CFRangeMake(0, CFStringGetLength(exeName
)-6));
1346 newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@.dylib"), exeName
, imageSuffix
);
1347 CFRelease(bareExeName
);
1349 newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, imageSuffix
);
1351 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, newExeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1352 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1353 CFRelease(executableURL
);
1354 executableURL
= NULL
;
1356 CFRelease(newExeName
);
1357 CFRelease(imageSuffix
);
1359 #endif /* __MACH__ */
1360 if (executableURL
== NULL
) {
1361 executableURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, exeName
, kCFURLPOSIXPathStyle
, false, urlPath
);
1362 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1363 CFRelease(executableURL
);
1364 executableURL
= NULL
;
1367 #if defined(__WIN32__)
1368 if (executableURL
== NULL
) {
1369 if (!CFStringHasSuffix(exeName
, CFSTR(".dll"))) {
1370 CFStringRef newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, CFSTR(".dll"));
1371 executableURL
= CFURLCreateWithString(alloc
, newExeName
, urlPath
);
1372 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1373 CFRelease(executableURL
);
1374 executableURL
= NULL
;
1376 CFRelease(newExeName
);
1379 if (executableURL
== NULL
) {
1380 if (!CFStringHasSuffix(exeName
, CFSTR(".exe"))) {
1381 CFStringRef newExeName
= CFStringCreateWithFormat(alloc
, NULL
, CFSTR("%@%@"), exeName
, CFSTR(".exe"));
1382 executableURL
= CFURLCreateWithString(alloc
, newExeName
, urlPath
);
1383 if (executableURL
!= NULL
&& !_urlExists(alloc
, executableURL
)) {
1384 CFRelease(executableURL
);
1385 executableURL
= NULL
;
1387 CFRelease(newExeName
);
1391 return executableURL
;
1394 static CFStringRef
_CFBundleCopyExecutableName(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFDictionaryRef infoDict
) {
1395 CFStringRef executableName
= NULL
;
1397 if (alloc
== NULL
&& bundle
!= NULL
) {
1398 alloc
= CFGetAllocator(bundle
);
1400 if (infoDict
== NULL
&& bundle
!= NULL
) {
1401 infoDict
= CFBundleGetInfoDictionary(bundle
);
1403 if (url
== NULL
&& bundle
!= NULL
) {
1407 if (infoDict
!= NULL
) {
1408 // Figure out the name of the executable.
1409 // First try for the new key in the plist.
1410 executableName
= CFDictionaryGetValue(infoDict
, kCFBundleExecutableKey
);
1411 if (executableName
== NULL
) {
1412 // Second try for the old key in the plist.
1413 executableName
= CFDictionaryGetValue(infoDict
, _kCFBundleOldExecutableKey
);
1415 if (executableName
!= NULL
&& CFGetTypeID(executableName
) == CFStringGetTypeID() && CFStringGetLength(executableName
) > 0) {
1416 CFRetain(executableName
);
1418 executableName
= NULL
;
1421 if (executableName
== NULL
&& url
!= NULL
) {
1422 // Third, take the name of the bundle itself (with path extension stripped)
1423 CFURLRef absoluteURL
= CFURLCopyAbsoluteURL(url
);
1424 CFStringRef bundlePath
= CFURLCopyFileSystemPath(absoluteURL
, PLATFORM_PATH_STYLE
);
1425 UniChar buff
[CFMaxPathSize
];
1426 CFIndex len
= CFStringGetLength(bundlePath
);
1427 CFIndex startOfBundleName
, endOfBundleName
;
1429 CFRelease(absoluteURL
);
1430 if (len
> CFMaxPathSize
) len
= CFMaxPathSize
;
1431 CFStringGetCharacters(bundlePath
, CFRangeMake(0, len
), buff
);
1432 startOfBundleName
= _CFStartOfLastPathComponent(buff
, len
);
1433 endOfBundleName
= _CFLengthAfterDeletingPathExtension(buff
, len
);
1435 if ((startOfBundleName
<= len
) && (endOfBundleName
<= len
) && (startOfBundleName
< endOfBundleName
)) {
1436 executableName
= CFStringCreateWithCharacters(alloc
, &(buff
[startOfBundleName
]), (endOfBundleName
- startOfBundleName
));
1438 CFRelease(bundlePath
);
1441 return executableName
;
1444 __private_extern__ CFURLRef
_CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle
, Boolean mayBeLocal
) {
1445 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, bundle
, NULL
, NULL
);
1446 CFURLRef resourceForkURL
= NULL
;
1447 if (executableName
!= NULL
) {
1449 resourceForkURL
= CFBundleCopyResourceURL(bundle
, executableName
, CFSTR("rsrc"), NULL
);
1451 resourceForkURL
= CFBundleCopyResourceURLForLocalization(bundle
, executableName
, CFSTR("rsrc"), NULL
, NULL
);
1453 CFRelease(executableName
);
1456 return resourceForkURL
;
1459 CFURLRef
_CFBundleCopyResourceForkURL(CFBundleRef bundle
) {return _CFBundleCopyResourceForkURLMayBeLocal(bundle
, true);}
1461 static CFURLRef
_CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRef alloc
, CFBundleRef bundle
, CFURLRef url
, CFStringRef executableName
, Boolean ignoreCache
, Boolean useOtherPlatform
) {
1462 uint8_t version
= 0;
1463 CFDictionaryRef infoDict
= NULL
;
1464 CFStringRef executablePath
= NULL
;
1465 CFURLRef executableURL
= NULL
;
1466 Boolean isDir
= false;
1467 Boolean foundIt
= false;
1468 Boolean lookupMainExe
= ((executableName
== NULL
) ? true : false);
1470 if (bundle
!= NULL
) {
1471 infoDict
= CFBundleGetInfoDictionary(bundle
);
1472 version
= bundle
->_version
;
1474 infoDict
= _CFBundleCopyInfoDictionaryInDirectory(alloc
, url
, &version
);
1477 // If we have a bundle instance and an info dict, see if we have already cached the path
1478 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& (bundle
!= NULL
) && (infoDict
!= NULL
)) {
1479 executablePath
= CFDictionaryGetValue(infoDict
, _kCFBundleExecutablePathKey
);
1480 if (executablePath
!= NULL
) {
1481 executableURL
= CFURLCreateWithFileSystemPath(alloc
, executablePath
, kCFURLPOSIXPathStyle
, false);
1482 if (executableURL
!= NULL
) foundIt
= true;
1484 executablePath
= NULL
;
1485 CFDictionaryRemoveValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
);
1491 if (lookupMainExe
) {
1492 executableName
= _CFBundleCopyExecutableName(alloc
, bundle
, url
, infoDict
);
1494 if (executableName
!= NULL
) {
1495 // Now, look for the executable inside the bundle.
1498 CFURLRef exeSubdirURL
;
1501 exeDirURL
= CFURLCreateWithString(alloc
, _CFBundleExecutablesURLFromBase1
, url
);
1502 } else if (2 == version
) {
1503 exeDirURL
= CFURLCreateWithString(alloc
, _CFBundleExecutablesURLFromBase2
, url
);
1505 exeDirURL
= CFRetain(url
);
1507 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1508 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1509 if (executableURL
== NULL
) {
1510 CFRelease(exeSubdirURL
);
1511 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1512 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1514 if (executableURL
== NULL
) {
1515 CFRelease(exeSubdirURL
);
1516 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1517 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1519 if (executableURL
== NULL
) {
1520 CFRelease(exeSubdirURL
);
1521 exeSubdirURL
= CFURLCreateWithFileSystemPathRelativeToBase(alloc
, useOtherPlatform
? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle
, true, exeDirURL
);
1522 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeSubdirURL
, executableName
);
1524 if (executableURL
== NULL
) {
1525 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeDirURL
, executableName
);
1528 CFRelease(exeDirURL
);
1529 CFRelease(exeSubdirURL
);
1532 // If this was an old bundle, or we did not find the executable in the Excutables subdirectory, look directly in the bundle wrapper.
1533 if (executableURL
== NULL
) {
1534 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, url
, executableName
);
1537 #if defined(__WIN32__)
1538 // Windows only: If we still haven't found the exe, look in the Executables folder.
1539 // But only for the main bundle exe
1540 if (lookupMainExe
&& (executableURL
== NULL
)) {
1543 exeDirURL
= CFURLCreateWithString(alloc
, CFSTR("../../Executables"), url
);
1545 executableURL
= _CFBundleCopyExecutableURLRaw(alloc
, exeDirURL
, executableName
);
1547 CFRelease(exeDirURL
);
1551 if (lookupMainExe
&& !ignoreCache
&& !useOtherPlatform
&& (bundle
!= NULL
) && (infoDict
!= NULL
) && (executableURL
!= NULL
)) {
1552 // We found it. Cache the path.
1553 CFURLRef absURL
= CFURLCopyAbsoluteURL(executableURL
);
1554 executablePath
= CFURLCopyFileSystemPath(absURL
, kCFURLPOSIXPathStyle
);
1556 CFDictionarySetValue((CFMutableDictionaryRef
)infoDict
, _kCFBundleExecutablePathKey
, executablePath
);
1557 CFRelease(executablePath
);
1559 if (lookupMainExe
&& !useOtherPlatform
&& (bundle
!= NULL
) && (executableURL
== NULL
)) {
1560 bundle
->_binaryType
= __CFBundleNoBinary
;
1562 if (lookupMainExe
) {
1563 CFRelease(executableName
);
1568 if ((bundle
== NULL
) && (infoDict
!= NULL
)) {
1569 CFRelease(infoDict
);
1572 return executableURL
;
1575 CFURLRef
_CFBundleCopyExecutableURLInDirectory(CFURLRef url
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL
, NULL
, url
, NULL
, true, false);}
1577 CFURLRef
_CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL
, NULL
, url
, NULL
, true, true);}
1579 CFURLRef
CFBundleCopyExecutableURL(CFBundleRef bundle
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, NULL
, false, false);}
1581 static CFURLRef
_CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, NULL
, true, false);}
1583 CFURLRef
CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle
, CFStringRef executableName
) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle
), bundle
, bundle
->_url
, executableName
, true, false);}
1585 Boolean
CFBundleIsExecutableLoaded(CFBundleRef bundle
) {return bundle
->_isLoaded
;}
1587 #define UNKNOWN_FILETYPE 0x0
1588 #define PEF_FILETYPE 0x1000
1589 #define XLS_FILETYPE 0x10001
1590 #define DOC_FILETYPE 0x10002
1591 #define PPT_FILETYPE 0x10003
1592 #define XLS_NAME "Workbook"
1593 #define DOC_NAME "WordDocument"
1594 #define PPT_NAME "PowerPoint Document"
1595 #define PEF_MAGIC 0x4a6f7921
1596 #define PEF_CIGAM 0x21796f4a
1597 #define PLIST_SEGMENT "__TEXT"
1598 #define PLIST_SECTION "__info_plist"
1599 #define LIB_X11 "/usr/X11R6/lib/libX"
1601 static const uint32_t __CFBundleMagicNumbersArray
[] = {
1602 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0x4a6f7921, 0x21796f4a, 0xffd8ffe0, 0x4d4d002a,
1603 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, 0x7b5c7274, 0x25504446, 0x2e7261fd,
1604 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864,
1605 0x504b0304, 0x53495421, 0x53495432, 0x53495435, 0x53495444, 0x53747566, 0x3c212d2d, 0x25215053,
1606 0xd0cf11e0, 0x62656769, 0x6b6f6c79, 0x3026b275, 0x0000000c
1609 // string, with groups of 5 characters being 1 element in the array
1610 static const char * __CFBundleExtensionsArray
=
1611 "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" "jpeg\0" "tiff\0"
1612 "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" "rtf\0\0" "pdf\0\0" "ra\0\0\0"
1613 "au\0\0\0""au\0\0\0""iff\0\0" "riff\0" "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0"
1614 "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "html\0" "ps\0\0\0"
1615 "ole\0\0" "uu\0\0\0""dmg\0\0" "wmv\0\0" "jp2\0\0";
1617 #define NUM_EXTENSIONS 37
1618 #define EXTENSION_LENGTH 5
1619 #define MAGIC_BYTES_TO_READ 512
1621 #if defined(BINARY_SUPPORT_DYLD)
1623 CF_INLINE
uint32_t _CFBundleSwapInt32Conditional(uint32_t arg
, Boolean swap
) {return swap
? CFSwapInt32(arg
) : arg
;}
1625 static CFDictionaryRef
_CFBundleGrokInfoDictFromData(char *bytes
, unsigned long length
) {
1626 CFMutableDictionaryRef result
= NULL
;
1627 CFDataRef infoData
= NULL
;
1628 if (NULL
!= bytes
&& 0 < length
) {
1629 infoData
= CFDataCreateWithBytesNoCopy(NULL
, bytes
, length
, kCFAllocatorNull
);
1632 __CFSetNastyFile(CFSTR("<plist section in main executable>"));
1634 result
= (CFMutableDictionaryRef
)CFPropertyListCreateFromXMLData(NULL
, infoData
, kCFPropertyListMutableContainers
, NULL
);
1635 if (result
&& CFDictionaryGetTypeID() != CFGetTypeID(result
)) {
1639 CFRelease(infoData
);
1642 result
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1648 static CFDictionaryRef
_CFBundleGrokInfoDictFromMainExecutable() {
1649 unsigned long length
= 0;
1650 char *bytes
= getsectdata(PLIST_SEGMENT
, PLIST_SECTION
, &length
);
1651 return _CFBundleGrokInfoDictFromData(bytes
, length
);
1654 static CFDictionaryRef
_CFBundleGrokInfoDictFromFile(int fd
, unsigned long offset
, Boolean swapped
) {
1655 struct stat statBuf
;
1658 CFDictionaryRef result
= NULL
;
1659 Boolean foundit
= false;
1660 if (fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
1661 unsigned long ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(maploc
+ offset
))->ncmds
, swapped
);
1662 unsigned long sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(maploc
+ offset
))->sizeofcmds
, swapped
);
1663 char *startofcmds
= maploc
+ offset
+ sizeof(struct mach_header
);
1664 char *endofcmds
= startofcmds
+ sizeofcmds
;
1665 struct segment_command
*sgp
= (struct segment_command
*)startofcmds
;
1666 if (endofcmds
> maploc
+ statBuf
.st_size
) endofcmds
= maploc
+ statBuf
.st_size
;
1667 for (i
= 0; !foundit
&& i
< ncmds
&& startofcmds
<= (char *)sgp
&& (char *)sgp
< endofcmds
; i
++) {
1668 if (LC_SEGMENT
== _CFBundleSwapInt32Conditional(sgp
->cmd
, swapped
)) {
1669 struct section
*sp
= (struct section
*)((char *)sgp
+ sizeof(struct segment_command
));
1670 unsigned long nsects
= _CFBundleSwapInt32Conditional(sgp
->nsects
, swapped
);
1671 for (j
= 0; !foundit
&& j
< nsects
&& startofcmds
<= (char *)sp
&& (char *)sp
< endofcmds
; j
++) {
1672 if (0 == strncmp(sp
->sectname
, PLIST_SECTION
, sizeof(sp
->sectname
)) && 0 == strncmp(sp
->segname
, PLIST_SEGMENT
, sizeof(sp
->segname
))) {
1673 unsigned long length
= _CFBundleSwapInt32Conditional(sp
->size
, swapped
);
1674 unsigned long sectoffset
= _CFBundleSwapInt32Conditional(sp
->offset
, swapped
);
1675 char *bytes
= maploc
+ offset
+ sectoffset
;
1676 if (maploc
<= bytes
&& bytes
+ length
<= maploc
+ statBuf
.st_size
) result
= _CFBundleGrokInfoDictFromData(bytes
, length
);
1679 sp
= (struct section
*)((char *)sp
+ sizeof(struct section
));
1682 sgp
= (struct segment_command
*)((char *)sgp
+ _CFBundleSwapInt32Conditional(sgp
->cmdsize
, swapped
));
1684 munmap(maploc
, statBuf
.st_size
);
1689 static Boolean
_CFBundleGrokX11(int fd
, unsigned long offset
, Boolean swapped
) {
1690 static const char libX11name
[] = LIB_X11
;
1691 struct stat statBuf
;
1694 Boolean result
= false;
1695 if (fstat(fd
, &statBuf
) == 0 && (maploc
= mmap(0, statBuf
.st_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0)) != (void *)-1) {
1696 unsigned long ncmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(maploc
+ offset
))->ncmds
, swapped
);
1697 unsigned long sizeofcmds
= _CFBundleSwapInt32Conditional(((struct mach_header
*)(maploc
+ offset
))->sizeofcmds
, swapped
);
1698 char *startofcmds
= maploc
+ offset
+ sizeof(struct mach_header
);
1699 char *endofcmds
= startofcmds
+ sizeofcmds
;
1700 struct dylib_command
*dlp
= (struct dylib_command
*)startofcmds
;
1701 if (endofcmds
> maploc
+ statBuf
.st_size
) endofcmds
= maploc
+ statBuf
.st_size
;
1702 for (i
= 0; !result
&& i
< ncmds
&& startofcmds
<= (char *)dlp
&& (char *)dlp
< endofcmds
; i
++) {
1703 if (LC_LOAD_DYLIB
== _CFBundleSwapInt32Conditional(dlp
->cmd
, swapped
)) {
1704 unsigned long nameoffset
= _CFBundleSwapInt32Conditional(dlp
->dylib
.name
.offset
, swapped
);
1705 if (0 == strncmp((char *)dlp
+ nameoffset
, libX11name
, sizeof(libX11name
) - 1)) result
= true;
1707 dlp
= (struct dylib_command
*)((char *)dlp
+ _CFBundleSwapInt32Conditional(dlp
->cmdsize
, swapped
));
1709 munmap(maploc
, statBuf
.st_size
);
1715 static UInt32
_CFBundleGrokMachTypeForFatFile(int fd
, void *bytes
, CFIndex length
, Boolean
*isX11
, CFDictionaryRef
*infodict
) {
1716 UInt32 machtype
= UNKNOWN_FILETYPE
, magic
, numFatHeaders
= ((struct fat_header
*)bytes
)->nfat_arch
, maxFatHeaders
= (length
- sizeof(struct fat_header
)) / sizeof(struct fat_arch
);
1717 unsigned char moreBytes
[sizeof(struct mach_header
)];
1718 const NXArchInfo
*archInfo
= NXGetLocalArchInfo();
1719 struct fat_arch
*fat
= NULL
;
1721 if (isX11
) *isX11
= false;
1722 if (infodict
) *infodict
= NULL
;
1723 if (numFatHeaders
> maxFatHeaders
) numFatHeaders
= maxFatHeaders
;
1724 if (numFatHeaders
> 0) {
1725 fat
= NXFindBestFatArch(archInfo
->cputype
, archInfo
->cpusubtype
, (struct fat_arch
*)(bytes
+ sizeof(struct fat_header
)), numFatHeaders
);
1726 if (!fat
) fat
= (struct fat_arch
*)(bytes
+ sizeof(struct fat_header
));
1729 if (lseek(fd
, fat
->offset
, SEEK_SET
) == (off_t
)fat
->offset
&& read(fd
, moreBytes
, sizeof(struct mach_header
)) >= (int)sizeof(struct mach_header
)) {
1730 magic
= *((UInt32
*)moreBytes
);
1731 if (MH_MAGIC
== magic
) {
1732 machtype
= ((struct mach_header
*)moreBytes
)->filetype
;
1733 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, fat
->offset
, false);
1734 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, fat
->offset
, false);
1735 } else if (MH_CIGAM
== magic
) {
1736 machtype
= CFSwapInt32(((struct mach_header
*)moreBytes
)->filetype
);
1737 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, fat
->offset
, true);
1738 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, fat
->offset
, true);
1745 static UInt32
_CFBundleGrokMachType(int fd
, void *bytes
, CFIndex length
, Boolean
*isX11
, CFDictionaryRef
*infodict
) {
1746 unsigned int magic
= *((UInt32
*)bytes
), machtype
= UNKNOWN_FILETYPE
;
1749 if (isX11
) *isX11
= false;
1750 if (infodict
) *infodict
= NULL
;
1751 if (MH_MAGIC
== magic
) {
1752 machtype
= ((struct mach_header
*)bytes
)->filetype
;
1753 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, 0, false);
1754 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, 0, false);
1755 } else if (MH_CIGAM
== magic
) {
1756 for (i
= 0; i
< length
; i
+= 4) *(UInt32
*)(bytes
+ i
) = CFSwapInt32(*(UInt32
*)(bytes
+ i
));
1757 machtype
= ((struct mach_header
*)bytes
)->filetype
;
1758 if (infodict
) *infodict
= _CFBundleGrokInfoDictFromFile(fd
, 0, true);
1759 if (isX11
) *isX11
= _CFBundleGrokX11(fd
, 0, true);
1760 } else if (FAT_MAGIC
== magic
) {
1761 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, isX11
, infodict
);
1762 } else if (FAT_CIGAM
== magic
) {
1763 for (i
= 0; i
< length
; i
+= 4) *(UInt32
*)(bytes
+ i
) = CFSwapInt32(*(UInt32
*)(bytes
+ i
));
1764 machtype
= _CFBundleGrokMachTypeForFatFile(fd
, bytes
, length
, isX11
, infodict
);
1765 } else if (PEF_MAGIC
== magic
|| PEF_CIGAM
== magic
) {
1766 machtype
= PEF_FILETYPE
;
1771 #endif /* BINARY_SUPPORT_DYLD */
1773 static UInt32
_CFBundleGrokFileTypeForOLEFile(int fd
, unsigned long offset
) {
1774 UInt32 filetype
= UNKNOWN_FILETYPE
;
1775 static const unsigned char xlsname
[] = XLS_NAME
, docname
[] = DOC_NAME
, pptname
[] = PPT_NAME
;
1776 unsigned char moreBytes
[512];
1778 if (lseek(fd
, offset
, SEEK_SET
) == (off_t
)offset
&& read(fd
, moreBytes
, sizeof(moreBytes
)) >= (int)sizeof(moreBytes
)) {
1780 Boolean foundit
= false;
1781 for (i
= 0; !foundit
&& i
< 4; i
++) {
1782 char namelength
= moreBytes
[128 * i
+ 64] / 2;
1783 if (sizeof(xlsname
) == namelength
) {
1784 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != xlsname
[j
]) foundit
= false;
1785 if (foundit
) filetype
= XLS_FILETYPE
;
1786 } else if (sizeof(docname
) == namelength
) {
1787 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != docname
[j
]) foundit
= false;
1788 if (foundit
) filetype
= DOC_FILETYPE
;
1789 } else if (sizeof(pptname
) == namelength
) {
1790 for (j
= 0, foundit
= true; j
+ 1 < namelength
; j
++) if (moreBytes
[128 * i
+ 2 * j
] != pptname
[j
]) foundit
= false;
1791 if (foundit
) filetype
= PPT_FILETYPE
;
1798 static Boolean
_CFBundleGrokFileType(CFURLRef url
, CFStringRef
*extension
, UInt32
*machtype
, CFDictionaryRef
*infodict
) {
1799 struct stat statBuf
;
1801 char path
[CFMaxPathSize
];
1802 unsigned char bytes
[MAGIC_BYTES_TO_READ
];
1803 CFIndex i
, length
= 0;
1804 const char *ext
= NULL
;
1805 UInt32 mt
= UNKNOWN_FILETYPE
;
1806 Boolean isX11
= false, isPlain
= true, isZero
= true;
1807 // extensions returned: o, tool, x11app, pef, core, dylib, bundle, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, pdf, ra, au, aiff, aifc, wav, avi, wmv, psd, mpeg, mid, zip, jar, sit, html, ps, mov, qtif, bmp, hqx, bin, class, tar, txt, gz, Z, uu, sh, pl, py, rb, dvi, sgi, mp3, xml, plist, xls, doc, ppt, mp4, m4a, m4b, m4p, dmg
1808 if (url
&& CFURLGetFileSystemRepresentation(url
, true, path
, CFMaxPathSize
) && (fd
= open(path
, O_RDONLY
, 0777)) >= 0 && fstat(fd
, &statBuf
) == 0 && (statBuf
.st_mode
& S_IFMT
) == S_IFREG
) {
1809 if ((length
= read(fd
, bytes
, MAGIC_BYTES_TO_READ
)) >= 4) {
1810 UInt32 magic
= CFSwapInt32HostToBig(*((UInt32
*)bytes
));
1811 for (i
= 0; !ext
&& i
< NUM_EXTENSIONS
; i
++) {
1812 if (__CFBundleMagicNumbersArray
[i
] == magic
) ext
= __CFBundleExtensionsArray
+ i
* EXTENSION_LENGTH
;
1815 if (0xcafebabe == magic
&& 8 <= length
&& 0 != *((UInt16
*)(bytes
+ 4))) {
1817 #if defined(BINARY_SUPPORT_DYLD)
1818 } else if ((int)sizeof(struct mach_header
) <= length
) {
1819 mt
= _CFBundleGrokMachType(fd
, bytes
, length
, extension
? &isX11
: NULL
, infodict
);
1820 #endif /* BINARY_SUPPORT_DYLD */
1822 #if defined(BINARY_SUPPORT_DYLD)
1823 if (MH_OBJECT
== mt
) {
1825 } else if (MH_EXECUTE
== mt
) {
1826 ext
= isX11
? "x11app" : "tool";
1827 } else if (PEF_FILETYPE
== mt
) {
1829 } else if (MH_CORE
== mt
) {
1831 } else if (MH_DYLIB
== mt
) {
1833 } else if (MH_BUNDLE
== mt
) {
1836 #endif /* BINARY_SUPPORT_DYLD */
1837 if (0x7b5c7274 == magic
&& (6 > length
|| 'f' != bytes
[4])) {
1839 } else if (0x47494638 == magic
&& (6 > length
|| (0x3761 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4)))))) {
1841 } else if (0x0000000c == magic
&& (6 > length
|| 0x6a50 != CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 4))))) {
1843 } else if (0x89504e47 == magic
&& (8 > length
|| 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) {
1845 } else if (0x53747566 == magic
&& (8 > length
|| 0x66497420 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) {
1847 } else if (0x3026b275 == magic
&& (8 > length
|| 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4))))) {
1848 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf
1850 } else if (0x504b0304 == magic
&& 38 <= length
&& 0x4d455441 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 30))) && 0x2d494e46 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34)))) {
1852 } else if (0x464f524d == magic
) {
1856 UInt32 iffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
1857 if (0x41494646 == iffMagic
) {
1859 } else if (0x414946 == iffMagic
) {
1863 } else if (0x52494646 == magic
) {
1867 UInt32 riffMagic
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)));
1868 if (0x57415645 == riffMagic
) {
1870 } else if (0x41564920 == riffMagic
) {
1874 } else if (0xd0cf11e0 == magic
) {
1878 UInt32 ft
= _CFBundleGrokFileTypeForOLEFile(fd
, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 48)))));
1879 if (XLS_FILETYPE
== ft
) {
1881 } else if (DOC_FILETYPE
== ft
) {
1883 } else if (PPT_FILETYPE
== ft
) {
1887 } else if (0x62656769 == magic
) {
1890 if (76 <= length
&& 'n' == bytes
[4] && ' ' == bytes
[5] && isdigit(bytes
[6]) && isdigit(bytes
[7]) && isdigit(bytes
[8]) && ' ' == bytes
[9]) {
1891 CFIndex endOfLine
= 0;
1892 for (i
= 10; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
1893 if (10 <= endOfLine
&& endOfLine
+ 62 < length
&& 'M' == bytes
[endOfLine
+ 1] && '\n' == bytes
[endOfLine
+ 62]) {
1895 for (i
= endOfLine
+ 1; ext
&& i
< endOfLine
+ 62; i
++) if (!isprint(bytes
[i
])) ext
= NULL
;
1900 if (extension
&& !ext
) {
1901 UInt16 shortMagic
= CFSwapInt16HostToBig(*((UInt16
*)bytes
));
1902 if (8 <= length
&& 0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
1904 } else if (8 <= length
&& 0x69647363 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
1906 } else if (12 <= length
&& 0x66747970 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 4)))) {
1907 // ??? list of ftyp values needs to be checked
1908 if (0x6d703432 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) {
1910 } else if (0x4d344120 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) {
1912 } else if (0x4d344220 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) {
1914 } else if (0x4d345020 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 8)))) {
1917 } else if (0x424d == shortMagic
&& 18 <= length
&& 40 == CFSwapInt32HostToLittle(*((UInt32
*)(bytes
+ 14)))) {
1919 } else if (40 <= length
&& 0x42696e48 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 38)))) {
1921 } else if (128 <= length
&& 0x6d42494e == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 102)))) {
1923 } else if (128 <= length
&& 0 == bytes
[0] && 0 < bytes
[1] && bytes
[1] < 64 && 0 == bytes
[74] && 0 == bytes
[82] && 0 == (statBuf
.st_size
% 128)) {
1924 unsigned df
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 83))), rf
= CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 87))), blocks
= 1 + (df
+ 127) / 128 + (rf
+ 127) / 128;
1925 if (df
< 0x00800000 && rf
< 0x00800000 && 1 < blocks
&& (off_t
)(128 * blocks
) == statBuf
.st_size
) {
1928 } else if (265 <= length
&& 0x75737461 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16
*)(bytes
+ 261))))) {
1930 } else if (0xfeff == shortMagic
|| 0xfffe == shortMagic
) {
1932 } else if (0x1f9d == shortMagic
) {
1934 } else if (0x1f8b == shortMagic
) {
1936 } else if (0xf702 == shortMagic
) {
1938 } else if (0x01da == shortMagic
&& (0 == bytes
[2] || 1 == bytes
[2]) && (0 < bytes
[3] && 16 > bytes
[3])) {
1940 } else if (0x2321 == shortMagic
) {
1941 CFIndex endOfLine
= 0, lastSlash
= 0;
1942 for (i
= 2; 0 == endOfLine
&& i
< length
; i
++) if ('\n' == bytes
[i
]) endOfLine
= i
;
1943 if (endOfLine
> 3) {
1944 for (i
= endOfLine
- 1; 0 == lastSlash
&& i
> 1; i
--) if ('/' == bytes
[i
]) lastSlash
= i
;
1945 if (lastSlash
> 0) {
1946 if (0 == strncmp(bytes
+ lastSlash
+ 1, "perl", 4)) {
1948 } else if (0 == strncmp(bytes
+ lastSlash
+ 1, "python", 6)) {
1950 } else if (0 == strncmp(bytes
+ lastSlash
+ 1, "ruby", 4)) {
1957 } else if (0xffd8 == shortMagic
&& 0xff == bytes
[2]) {
1959 } else if (0x4944 == shortMagic
&& '3' == bytes
[2] && 0x20 > bytes
[3]) {
1961 } else if ('<' == bytes
[0] && 14 <= length
) {
1962 if (0 == strncasecmp(bytes
+ 1, "!doctype html", 13) || 0 == strncasecmp(bytes
+ 1, "head", 4) || 0 == strncasecmp(bytes
+ 1, "title", 5) || 0 == strncasecmp(bytes
+ 1, "html", 4)) {
1964 } else if (0 == strncasecmp(bytes
+ 1, "?xml", 4)) {
1965 if (116 <= length
&& 0 == strncasecmp(bytes
+ 100, "PropertyList.dtd", 16)) {
1974 if (extension
&& !ext
) {
1975 //??? what about MacOSRoman?
1976 for (i
= 0; (isPlain
|| isZero
) && i
< length
&& i
< 512; i
++) {
1978 if (0x7f <= c
|| (0x20 > c
&& !isspace(c
))) isPlain
= false;
1979 if (0 != c
) isZero
= false;
1983 } else if (isZero
&& length
>= MAGIC_BYTES_TO_READ
&& statBuf
.st_size
>= 526) {
1984 if (lseek(fd
, 512, SEEK_SET
) == 512 && read(fd
, bytes
, 512) >= 14) {
1985 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 10)))) {
1991 if (extension
&& !ext
&& !isZero
&& length
>= MAGIC_BYTES_TO_READ
&& statBuf
.st_size
>= 1024) {
1992 off_t offset
= statBuf
.st_size
- 512;
1993 if (lseek(fd
, offset
, SEEK_SET
) == offset
&& read(fd
, bytes
, 512) >= 512) {
1994 if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32
*)bytes
)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 504))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32
*)(bytes
+ 508))))) {
2000 if (extension
) *extension
= ext
? CFStringCreateWithCStringNoCopy(NULL
, ext
, kCFStringEncodingASCII
, kCFAllocatorNull
) : NULL
;
2001 if (machtype
) *machtype
= mt
;
2003 return (ext
!= NULL
);
2006 CFStringRef
_CFBundleCopyFileTypeForFileURL(CFURLRef url
) {
2007 CFStringRef extension
= NULL
;
2008 (void)_CFBundleGrokFileType(url
, &extension
, NULL
, NULL
);
2012 __private_extern__ CFDictionaryRef
_CFBundleCopyInfoDictionaryInExecutable(CFURLRef url
) {
2013 CFDictionaryRef result
= NULL
;
2014 (void)_CFBundleGrokFileType(url
, NULL
, NULL
, &result
);
2018 #if defined(BINARY_SUPPORT_DYLD)
2020 __private_extern__ __CFPBinaryType
_CFBundleGrokBinaryType(CFURLRef executableURL
) {
2021 // Attempt to grok the type of the binary by looking for DYLD magic numbers. If one of the DYLD magic numbers is found, find out what type of Mach-o file it is. Otherwise, look for the PEF magic numbers to see if it is CFM (if we understand CFM).
2022 __CFPBinaryType result
= executableURL
? __CFBundleUnreadableBinary
: __CFBundleNoBinary
;
2023 UInt32 machtype
= UNKNOWN_FILETYPE
;
2024 if (_CFBundleGrokFileType(executableURL
, NULL
, &machtype
, NULL
)) {
2027 result
= __CFBundleDYLDExecutableBinary
;
2030 result
= __CFBundleDYLDBundleBinary
;
2033 result
= __CFBundleDYLDFrameworkBinary
;
2035 #if defined(BINARY_SUPPORT_CFM)
2037 result
= __CFBundleCFMBinary
;
2039 #endif /* BINARY_SUPPORT_CFM */
2045 #endif /* BINARY_SUPPORT_DYLD */
2047 void _CFBundleSetCFMConnectionID(CFBundleRef bundle
, void *connectionID
) {
2048 #if defined(BINARY_SUPPORT_CFM)
2049 if (bundle
->_binaryType
== __CFBundleUnknownBinary
|| bundle
->_binaryType
== __CFBundleUnreadableBinary
) {
2050 bundle
->_binaryType
= __CFBundleCFMBinary
;
2052 #endif /* BINARY_SUPPORT_CFM */
2053 bundle
->_connectionCookie
= connectionID
;
2054 bundle
->_isLoaded
= true;
2057 Boolean
CFBundleLoadExecutable(CFBundleRef bundle
) {
2058 Boolean result
= false;
2059 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2061 if (!executableURL
) {
2062 bundle
->_binaryType
= __CFBundleNoBinary
;
2064 #if defined(BINARY_SUPPORT_DYLD)
2065 // make sure we know whether bundle is already loaded or not
2066 if (!bundle
->_isLoaded
) {
2067 _CFBundleDYLDCheckLoaded(bundle
);
2069 // We might need to figure out what it is
2070 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2071 bundle
->_binaryType
= _CFBundleGrokBinaryType(executableURL
);
2072 #if defined(BINARY_SUPPORT_CFM)
2073 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
2074 bundle
->_resourceData
._executableLacksResourceFork
= true;
2076 #endif /* BINARY_SUPPORT_CFM */
2078 #endif /* BINARY_SUPPORT_DYLD */
2079 if (executableURL
) CFRelease(executableURL
);
2081 if (bundle
->_isLoaded
) {
2082 // Remove from the scheduled unload set if we are there.
2083 __CFSpinLock(&CFBundleGlobalDataLock
);
2084 if (_bundlesToUnload
) {
2085 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2087 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2091 // Unload bundles scheduled for unloading
2092 if (!_scheduledBundlesAreUnloading
) {
2093 _CFBundleUnloadScheduledBundles();
2097 switch (bundle
->_binaryType
) {
2098 #if defined(BINARY_SUPPORT_CFM)
2099 case __CFBundleCFMBinary
:
2100 case __CFBundleUnreadableBinary
:
2101 result
= _CFBundleCFMLoad(bundle
);
2103 #endif /* BINARY_SUPPORT_CFM */
2104 #if defined(BINARY_SUPPORT_DYLD)
2105 case __CFBundleDYLDBundleBinary
:
2106 result
= _CFBundleDYLDLoadBundle(bundle
);
2108 case __CFBundleDYLDFrameworkBinary
:
2109 result
= _CFBundleDYLDLoadFramework(bundle
);
2111 case __CFBundleDYLDExecutableBinary
:
2112 CFLog(__kCFLogBundle
, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle
);
2114 #endif /* BINARY_SUPPORT_DYLD */
2115 #if defined(BINARY_SUPPORT_DLL)
2116 case __CFBundleDLLBinary
:
2117 result
= _CFBundleDLLLoad(bundle
);
2119 #endif /* BINARY_SUPPORT_DLL */
2120 case __CFBundleNoBinary
:
2121 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for %@"), bundle
);
2124 CFLog(__kCFLogBundle
, CFSTR("Cannot recognize type of executable for %@"), bundle
);
2131 void CFBundleUnloadExecutable(CFBundleRef bundle
) {
2133 if (!_scheduledBundlesAreUnloading
) {
2134 // First unload bundles scheduled for unloading (if that's not what we are already doing.)
2135 _CFBundleUnloadScheduledBundles();
2138 if (!bundle
->_isLoaded
) return;
2140 // Remove from the scheduled unload set if we are there.
2141 if (!_scheduledBundlesAreUnloading
) {
2142 __CFSpinLock(&CFBundleGlobalDataLock
);
2144 if (_bundlesToUnload
) {
2145 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2147 if (!_scheduledBundlesAreUnloading
) {
2148 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2151 // Give the plugIn code a chance to realize this...
2152 _CFPlugInWillUnload(bundle
);
2154 switch (bundle
->_binaryType
) {
2155 #if defined(BINARY_SUPPORT_CFM)
2156 case __CFBundleCFMBinary
:
2157 _CFBundleCFMUnload(bundle
);
2159 #endif /* BINARY_SUPPORT_CFM */
2160 #if defined(BINARY_SUPPORT_DYLD)
2161 case __CFBundleDYLDBundleBinary
:
2162 _CFBundleDYLDUnloadBundle(bundle
);
2164 #endif /* BINARY_SUPPORT_DYLD */
2165 #if defined(BINARY_SUPPORT_DLL)
2166 case __CFBundleDLLBinary
:
2167 _CFBundleDLLUnload(bundle
);
2169 #endif /* BINARY_SUPPORT_DLL */
2173 if (!bundle
->_isLoaded
&& bundle
->_glueDict
!= NULL
) {
2174 CFDictionaryApplyFunction(bundle
->_glueDict
, _CFBundleDeallocateGlue
, (void *)CFGetAllocator(bundle
));
2175 CFRelease(bundle
->_glueDict
);
2176 bundle
->_glueDict
= NULL
;
2180 __private_extern__
void _CFBundleScheduleForUnloading(CFBundleRef bundle
) {
2181 __CFSpinLock(&CFBundleGlobalDataLock
);
2182 if (!_bundlesToUnload
) {
2183 // Create this from the default allocator
2184 CFSetCallBacks nonRetainingCallbacks
= kCFTypeSetCallBacks
;
2185 nonRetainingCallbacks
.retain
= NULL
;
2186 nonRetainingCallbacks
.release
= NULL
;
2187 _bundlesToUnload
= CFSetCreateMutable(NULL
, 0, &nonRetainingCallbacks
);
2189 CFSetAddValue(_bundlesToUnload
, bundle
);
2190 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2193 __private_extern__
void _CFBundleUnscheduleForUnloading(CFBundleRef bundle
) {
2194 __CFSpinLock(&CFBundleGlobalDataLock
);
2195 if (_bundlesToUnload
) {
2196 CFSetRemoveValue(_bundlesToUnload
, bundle
);
2198 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2201 __private_extern__
void _CFBundleUnloadScheduledBundles(void) {
2202 __CFSpinLock(&CFBundleGlobalDataLock
);
2203 if (_bundlesToUnload
) {
2204 CFIndex c
= CFSetGetCount(_bundlesToUnload
);
2207 CFBundleRef
*unloadThese
= CFAllocatorAllocate(NULL
, sizeof(CFBundleRef
) * c
, 0);
2208 CFSetGetValues(_bundlesToUnload
, (const void **)unloadThese
);
2209 _scheduledBundlesAreUnloading
= true;
2210 for (i
=0; i
<c
; i
++) {
2211 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.)
2212 CFBundleUnloadExecutable(unloadThese
[i
]);
2214 _scheduledBundlesAreUnloading
= false;
2215 CFAllocatorDeallocate(NULL
, unloadThese
);
2218 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2221 void *CFBundleGetFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
2223 // Load if necessary
2224 if (!bundle
->_isLoaded
) {
2225 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2228 switch (bundle
->_binaryType
) {
2229 #if defined(BINARY_SUPPORT_CFM)
2230 case __CFBundleCFMBinary
:
2231 tvp
= _CFBundleCFMGetSymbolByName(bundle
, funcName
, kTVectorCFragSymbol
);
2233 #endif /* BINARY_SUPPORT_CFM */
2234 #if defined(BINARY_SUPPORT_DYLD)
2235 case __CFBundleDYLDBundleBinary
:
2236 case __CFBundleDYLDFrameworkBinary
:
2237 case __CFBundleDYLDExecutableBinary
:
2238 return _CFBundleDYLDGetSymbolByName(bundle
, funcName
);
2240 #endif /* BINARY_SUPPORT_DYLD */
2241 #if defined(BINARY_SUPPORT_DLL)
2242 case __CFBundleDLLBinary
:
2243 tvp
= _CFBundleDLLGetSymbolByName(bundle
, funcName
);
2245 #endif /* BINARY_SUPPORT_DLL */
2249 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2251 if (bundle
->_glueDict
== NULL
) {
2252 bundle
->_glueDict
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, NULL
, NULL
);
2254 void *fp
= (void *)CFDictionaryGetValue(bundle
->_glueDict
, tvp
);
2256 fp
= _CFBundleFunctionPointerForTVector(CFGetAllocator(bundle
), tvp
);
2257 CFDictionarySetValue(bundle
->_glueDict
, tvp
, fp
);
2261 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2265 void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle
, CFStringRef funcName
) {
2267 // Load if necessary
2268 if (!bundle
->_isLoaded
) {
2269 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2272 switch (bundle
->_binaryType
) {
2273 #if defined(BINARY_SUPPORT_CFM)
2274 case __CFBundleCFMBinary
:
2275 return _CFBundleCFMGetSymbolByName(bundle
, funcName
, kTVectorCFragSymbol
);
2277 #endif /* BINARY_SUPPORT_CFM */
2278 #if defined(BINARY_SUPPORT_DYLD)
2279 case __CFBundleDYLDBundleBinary
:
2280 case __CFBundleDYLDFrameworkBinary
:
2281 case __CFBundleDYLDExecutableBinary
:
2282 fp
= _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, funcName
, true);
2284 #endif /* BINARY_SUPPORT_DYLD */
2288 #if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__)
2290 if (bundle
->_glueDict
== NULL
) {
2291 bundle
->_glueDict
= CFDictionaryCreateMutable(CFGetAllocator(bundle
), 0, NULL
, NULL
);
2293 void *tvp
= (void *)CFDictionaryGetValue(bundle
->_glueDict
, fp
);
2295 tvp
= _CFBundleTVectorForFunctionPointer(CFGetAllocator(bundle
), fp
);
2296 CFDictionarySetValue(bundle
->_glueDict
, fp
, tvp
);
2300 #endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */
2304 void CFBundleGetFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
2309 c
= CFArrayGetCount(functionNames
);
2310 for (i
= 0; i
< c
; i
++) {
2311 ftbl
[i
] = CFBundleGetFunctionPointerForName(bundle
, CFArrayGetValueAtIndex(functionNames
, i
));
2315 void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle
, CFArrayRef functionNames
, void *ftbl
[]) {
2320 c
= CFArrayGetCount(functionNames
);
2321 for (i
= 0; i
< c
; i
++) {
2322 ftbl
[i
] = _CFBundleGetCFMFunctionPointerForName(bundle
, CFArrayGetValueAtIndex(functionNames
, i
));
2326 void *CFBundleGetDataPointerForName(CFBundleRef bundle
, CFStringRef symbolName
) {
2328 // Load if necessary
2329 if (!bundle
->_isLoaded
) {
2330 if (!CFBundleLoadExecutable(bundle
)) return NULL
;
2333 switch (bundle
->_binaryType
) {
2334 #if defined(BINARY_SUPPORT_CFM)
2335 case __CFBundleCFMBinary
:
2336 dp
= _CFBundleCFMGetSymbolByName(bundle
, symbolName
, kDataCFragSymbol
);
2338 #endif /* BINARY_SUPPORT_CFM */
2339 #if defined(BINARY_SUPPORT_DYLD)
2340 case __CFBundleDYLDBundleBinary
:
2341 case __CFBundleDYLDFrameworkBinary
:
2342 case __CFBundleDYLDExecutableBinary
:
2343 dp
= _CFBundleDYLDGetSymbolByName(bundle
, symbolName
);
2345 #endif /* BINARY_SUPPORT_DYLD */
2346 #if defined(BINARY_SUPPORT_DLL)
2347 case __CFBundleDLLBinary
:
2348 /* MF:!!! Handle this someday */
2350 #endif /* BINARY_SUPPORT_DLL */
2357 void CFBundleGetDataPointersForNames(CFBundleRef bundle
, CFArrayRef symbolNames
, void *stbl
[]) {
2362 c
= CFArrayGetCount(symbolNames
);
2363 for (i
= 0; i
< c
; i
++) {
2364 stbl
[i
] = CFBundleGetDataPointerForName(bundle
, CFArrayGetValueAtIndex(symbolNames
, i
));
2368 __private_extern__ _CFResourceData
*__CFBundleGetResourceData(CFBundleRef bundle
) {
2369 return &(bundle
->_resourceData
);
2372 CFPlugInRef
CFBundleGetPlugIn(CFBundleRef bundle
) {
2373 if (bundle
->_plugInData
._isPlugIn
) {
2374 return (CFPlugInRef
)bundle
;
2380 __private_extern__ _CFPlugInData
*__CFBundleGetPlugInData(CFBundleRef bundle
) {
2381 return &(bundle
->_plugInData
);
2384 __private_extern__ Boolean
_CFBundleCouldBeBundle(CFURLRef url
) {
2385 Boolean result
= false;
2389 if (_CFGetFileProperties(NULL
, url
, &exists
, &mode
, NULL
, NULL
, NULL
, NULL
) == 0) {
2390 result
= (exists
&& ((mode
& S_IFMT
) == S_IFDIR
));
2391 #if !defined(__MACOS8__)
2392 result
= (result
&& ((mode
& 0444) != 0));
2398 __private_extern__ CFURLRef
_CFBundleCopyFrameworkURLForExecutablePath(CFAllocatorRef alloc
, CFStringRef executablePath
) {
2399 // MF:!!! Implement me. We need to be able to find the bundle from the exe, dealing with old vs. new as well as the Executables dir business on Windows.
2400 #if defined(__WIN32__)
2401 UniChar executablesToFrameworksPathBuff
[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 16
2402 UniChar executablesToPrivateFrameworksPathBuff
[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 23
2403 UniChar frameworksExtension
[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'}; // length 9
2406 UniChar pathBuff
[CFMaxPathSize
];
2407 UniChar nameBuff
[CFMaxPathSize
];
2408 CFIndex length
, nameStart
, nameLength
, savedLength
;
2409 CFMutableStringRef cheapStr
= CFStringCreateMutableWithExternalCharactersNoCopy(alloc
, NULL
, 0, 0, NULL
);
2410 CFURLRef bundleURL
= NULL
;
2412 length
= CFStringGetLength(executablePath
);
2413 if (length
> CFMaxPathSize
) length
= CFMaxPathSize
;
2414 CFStringGetCharacters(executablePath
, CFRangeMake(0, length
), pathBuff
);
2416 // Save the name in nameBuff
2417 length
= _CFLengthAfterDeletingPathExtension(pathBuff
, length
);
2418 nameStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2419 nameLength
= length
- nameStart
;
2420 memmove(nameBuff
, &(pathBuff
[nameStart
]), nameLength
* sizeof(UniChar
));
2422 // Strip the name from pathBuff
2423 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2424 savedLength
= length
;
2426 #if defined(__WIN32__)
2427 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case.
2428 _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToFrameworksPathBuff
, 16);
2429 _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
);
2430 _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, 9);
2432 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2433 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2434 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2435 CFRelease(bundleURL
);
2438 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case.
2439 if (bundleURL
== NULL
) {
2440 length
= savedLength
;
2441 _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, executablesToPrivateFrameworksPathBuff
, 23);
2442 _CFAppendPathComponent(pathBuff
, &length
, CFMaxPathSize
, nameBuff
, nameLength
);
2443 _CFAppendPathExtension(pathBuff
, &length
, CFMaxPathSize
, frameworksExtension
, 9);
2445 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2446 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2447 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2448 CFRelease(bundleURL
);
2453 // * Finally check the executable inside the framework case.
2454 if (bundleURL
== NULL
) {
2455 // MF:!!! This should ensure the framework name is the same as the library name!
2458 length
= savedLength
;
2459 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files".
2461 while (length
> 0) {
2462 curStart
= _CFStartOfLastPathComponent(pathBuff
, length
);
2463 if (curStart
>= length
) {
2466 CFStringSetExternalCharactersNoCopy(cheapStr
, &(pathBuff
[curStart
]), length
- curStart
, CFMaxPathSize
- curStart
);
2467 if (CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName1
) || CFEqual(cheapStr
, _CFBundleSupportFilesDirectoryName2
)) {
2468 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2469 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2470 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2471 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2472 CFRelease(bundleURL
);
2476 } else if (CFStringHasSuffix(cheapStr
, CFSTR(".framework"))) {
2477 CFStringSetExternalCharactersNoCopy(cheapStr
, pathBuff
, length
, CFMaxPathSize
);
2478 bundleURL
= CFURLCreateWithFileSystemPath(alloc
, cheapStr
, PLATFORM_PATH_STYLE
, true);
2479 if (!_CFBundleCouldBeBundle(bundleURL
)) {
2480 CFRelease(bundleURL
);
2485 length
= _CFLengthAfterDeletingLastPathComponent(pathBuff
, length
);
2489 CFStringSetExternalCharactersNoCopy(cheapStr
, NULL
, 0, 0);
2490 CFRelease(cheapStr
);
2495 static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath
) {
2496 // This finds the bundle for the given path.
2497 // If an image path corresponds to a bundle, we see if there is already a bundle instance. If there is and it is NOT in the _dynamicBundles array, it is added to the staticBundles. Do not add the main bundle to the list here.
2499 CFURLRef curURL
= _CFBundleCopyFrameworkURLForExecutablePath(NULL
, imagePath
);
2501 if (curURL
!= NULL
) {
2502 bundle
= _CFBundleFindByURL(curURL
, true);
2503 if (bundle
== NULL
) {
2504 bundle
= _CFBundleCreate(NULL
, curURL
, true, true);
2506 if (bundle
!= NULL
&& !bundle
->_isLoaded
) {
2507 // make sure that these bundles listed as loaded, and mark them frameworks (we probably can't see anything else here, and we cannot unload them)
2508 #if defined(BINARY_SUPPORT_DYLD)
2509 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2510 bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
2512 if (bundle
->_binaryType
!= __CFBundleCFMBinary
&& bundle
->_binaryType
!= __CFBundleUnreadableBinary
) {
2513 bundle
->_resourceData
._executableLacksResourceFork
= true;
2515 if (!bundle
->_imageCookie
) _CFBundleDYLDCheckLoaded(bundle
);
2516 #endif /* BINARY_SUPPORT_DYLD */
2517 bundle
->_isLoaded
= true;
2523 static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths
) {
2524 // This finds the bundles for the given paths.
2525 // If an image path corresponds to a bundle, we see if there is already a bundle instance. If there is and it is NOT in the _dynamicBundles array, it is added to the staticBundles. Do not add the main bundle to the list here (even if it appears in imagePaths).
2526 CFIndex i
, imagePathCount
= CFArrayGetCount(imagePaths
);
2528 for (i
=0; i
<imagePathCount
; i
++) {
2529 _CFBundleEnsureBundleExistsForImagePath(CFArrayGetValueAtIndex(imagePaths
, i
));
2533 static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint
) {
2534 CFArrayRef imagePaths
;
2535 // Tickle the main bundle into existence
2536 (void)_CFBundleGetMainBundleAlreadyLocked();
2537 #if defined(BINARY_SUPPORT_DYLD)
2538 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsForHint(hint
);
2539 if (imagePaths
!= NULL
) {
2540 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2541 CFRelease(imagePaths
);
2546 static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) {
2547 // This method returns all the statically linked bundles. This includes the main bundle as well as any frameworks that the process was linked against at launch time. It does not include frameworks or opther bundles that were loaded dynamically.
2549 CFArrayRef imagePaths
;
2551 // Tickle the main bundle into existence
2552 (void)_CFBundleGetMainBundleAlreadyLocked();
2554 #if defined(BINARY_SUPPORT_DLL)
2555 #warning (MF) Dont know how to find static bundles for DLLs
2558 #if defined(BINARY_SUPPORT_CFM)
2559 // CFM bundles are supplied to us by CFM, so we do not need to figure them out ourselves
2562 #if defined(BINARY_SUPPORT_DYLD)
2563 imagePaths
= _CFBundleDYLDCopyLoadedImagePathsIfChanged();
2564 if (imagePaths
!= NULL
) {
2565 _CFBundleEnsureBundlesExistForImagePaths(imagePaths
);
2566 CFRelease(imagePaths
);
2571 CFArrayRef
CFBundleGetAllBundles(void) {
2572 // To answer this properly, we have to have created the static bundles!
2573 __CFSpinLock(&CFBundleGlobalDataLock
);
2574 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked();
2575 __CFSpinUnlock(&CFBundleGlobalDataLock
);
2579 uint8_t _CFBundleLayoutVersion(CFBundleRef bundle
) {return bundle
->_version
;}
2581 CF_EXPORT CFURLRef
_CFBundleCopyInfoPlistURL(CFBundleRef bundle
) {
2582 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
);
2583 CFStringRef path
= CFDictionaryGetValue(infoDict
, _kCFBundleInfoPlistURLKey
);
2584 return (path
? CFRetain(path
) : NULL
);
2587 CF_EXPORT CFURLRef
_CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {return CFBundleCopyPrivateFrameworksURL(bundle
);}
2589 CF_EXPORT CFURLRef
CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle
) {
2590 CFURLRef result
= NULL
;
2592 if (1 == bundle
->_version
) {
2593 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase1
, bundle
->_url
);
2594 } else if (2 == bundle
->_version
) {
2595 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase2
, bundle
->_url
);
2597 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundlePrivateFrameworksURLFromBase0
, bundle
->_url
);
2602 CF_EXPORT CFURLRef
_CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {return CFBundleCopySharedFrameworksURL(bundle
);}
2604 CF_EXPORT CFURLRef
CFBundleCopySharedFrameworksURL(CFBundleRef bundle
) {
2605 CFURLRef result
= NULL
;
2607 if (1 == bundle
->_version
) {
2608 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase1
, bundle
->_url
);
2609 } else if (2 == bundle
->_version
) {
2610 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase2
, bundle
->_url
);
2612 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedFrameworksURLFromBase0
, bundle
->_url
);
2617 CF_EXPORT CFURLRef
_CFBundleCopySharedSupportURL(CFBundleRef bundle
) {return CFBundleCopySharedSupportURL(bundle
);}
2619 CF_EXPORT CFURLRef
CFBundleCopySharedSupportURL(CFBundleRef bundle
) {
2620 CFURLRef result
= NULL
;
2622 if (1 == bundle
->_version
) {
2623 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase1
, bundle
->_url
);
2624 } else if (2 == bundle
->_version
) {
2625 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase2
, bundle
->_url
);
2627 result
= CFURLCreateWithString(CFGetAllocator(bundle
), _CFBundleSharedSupportURLFromBase0
, bundle
->_url
);
2632 __private_extern__ CFURLRef
_CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {return CFBundleCopyBuiltInPlugInsURL(bundle
);}
2634 CF_EXPORT CFURLRef
CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle
) {
2635 CFURLRef result
= NULL
, alternateResult
= NULL
;
2637 CFAllocatorRef alloc
= CFGetAllocator(bundle
);
2638 if (1 == bundle
->_version
) {
2639 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase1
, bundle
->_url
);
2640 } else if (2 == bundle
->_version
) {
2641 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase2
, bundle
->_url
);
2643 result
= CFURLCreateWithString(alloc
, _CFBundleBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2645 if (!result
|| !_urlExists(alloc
, result
)) {
2646 if (1 == bundle
->_version
) {
2647 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase1
, bundle
->_url
);
2648 } else if (2 == bundle
->_version
) {
2649 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase2
, bundle
->_url
);
2651 alternateResult
= CFURLCreateWithString(alloc
, _CFBundleAlternateBuiltInPlugInsURLFromBase0
, bundle
->_url
);
2653 if (alternateResult
&& _urlExists(alloc
, alternateResult
)) {
2654 if (result
) CFRelease(result
);
2655 result
= alternateResult
;
2657 if (alternateResult
) CFRelease(alternateResult
);
2665 #if defined(BINARY_SUPPORT_DYLD)
2667 static void *__CFBundleDYLDFindImage(char *buff
) {
2668 void *header
= NULL
;
2669 unsigned long i
, numImages
= _dyld_image_count(), numMatches
= 0;
2670 char *curName
, *p
, *q
;
2672 for (i
= 0; !header
&& i
< numImages
; i
++) {
2673 curName
= _dyld_get_image_name(i
);
2674 if (curName
&& 0 == strncmp(curName
, buff
, CFMaxPathSize
)) {
2675 header
= _dyld_get_image_header(i
);
2680 for (i
= 0; i
< numImages
; i
++) {
2681 curName
= _dyld_get_image_name(i
);
2683 for (p
= buff
, q
= curName
; *p
&& *q
&& (q
- curName
< CFMaxPathSize
); p
++, q
++) {
2684 if (*p
!= *q
&& (q
- curName
> 11) && 0 == strncmp(q
- 11, ".framework/Versions/", 20) && *(q
+ 9) && '/' == *(q
+ 10)) q
+= 11;
2685 else if (*p
!= *q
&& (q
- curName
> 12) && 0 == strncmp(q
- 12, ".framework/Versions/", 20) && *(q
+ 8) && '/' == *(q
+ 9)) q
+= 10;
2686 if (*p
!= *q
) break;
2689 header
= _dyld_get_image_header(i
);
2695 return (numMatches
== 1) ? header
: NULL
;
2698 __private_extern__ Boolean
_CFBundleDYLDCheckLoaded(CFBundleRef bundle
) {
2699 if (!bundle
->_isLoaded
) {
2700 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2702 if (executableURL
!= NULL
) {
2703 char buff
[CFMaxPathSize
];
2705 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2706 void *header
= __CFBundleDYLDFindImage(buff
);
2708 if (bundle
->_binaryType
== __CFBundleUnknownBinary
) {
2709 bundle
->_binaryType
= __CFBundleDYLDFrameworkBinary
;
2711 if (!bundle
->_imageCookie
) bundle
->_imageCookie
= header
;
2712 bundle
->_isLoaded
= true;
2715 CFRelease(executableURL
);
2718 return bundle
->_isLoaded
;
2721 __private_extern__ Boolean
_CFBundleDYLDLoadBundle(CFBundleRef bundle
) {
2722 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
2723 int errorNumber
= 0;
2724 const char *fileName
= NULL
;
2725 const char *errorString
= NULL
;
2727 if (!bundle
->_isLoaded
) {
2728 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2730 if (executableURL
) {
2731 char buff
[CFMaxPathSize
];
2733 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2734 NSObjectFileImage image
;
2735 NSObjectFileImageReturnCode retCode
= NSCreateObjectFileImageFromFile(buff
, &image
);
2736 if (retCode
== NSObjectFileImageSuccess
) {
2737 NSModule
module = NSLinkModule(image
, buff
, (NSLINKMODULE_OPTION_BINDNOW
| NSLINKMODULE_OPTION_PRIVATE
| NSLINKMODULE_OPTION_RETURN_ON_ERROR
));
2739 bundle
->_imageCookie
= image
;
2740 bundle
->_moduleCookie
= module;
2741 bundle
->_isLoaded
= true;
2743 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
2744 CFLog(__kCFLogBundle
, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName
, c
, errorNumber
, errorString
);
2745 if (!NSDestroyObjectFileImage(image
)) {
2746 /* MF:!!! Error destroying object file image */
2750 CFLog(__kCFLogBundle
, CFSTR("dyld returns %d when trying to load %@"), retCode
, executableURL
);
2753 CFRelease(executableURL
);
2755 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2758 return bundle
->_isLoaded
;
2761 __private_extern__ Boolean
_CFBundleDYLDLoadFramework(CFBundleRef bundle
) {
2762 // !!! Framework loading should be better. Can't unload frameworks.
2763 NSLinkEditErrors c
= NSLinkEditUndefinedError
;
2764 int errorNumber
= 0;
2765 const char *fileName
= NULL
;
2766 const char *errorString
= NULL
;
2768 if (!bundle
->_isLoaded
) {
2769 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2771 if (executableURL
) {
2772 char buff
[CFMaxPathSize
];
2774 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2775 void *image
= (void *)NSAddImage(buff
, NSADDIMAGE_OPTION_RETURN_ON_ERROR
);
2777 bundle
->_imageCookie
= image
;
2778 bundle
->_isLoaded
= true;
2780 NSLinkEditError(&c
, &errorNumber
, &fileName
, &errorString
);
2781 CFLog(__kCFLogBundle
, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName
, c
, errorNumber
, errorString
);
2784 CFRelease(executableURL
);
2786 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2789 return bundle
->_isLoaded
;
2792 __private_extern__
void _CFBundleDYLDUnloadBundle(CFBundleRef bundle
) {
2793 if (bundle
->_isLoaded
) {
2794 if (bundle
->_moduleCookie
&& !NSUnLinkModule(bundle
->_moduleCookie
, NSUNLINKMODULE_OPTION_NONE
)) {
2795 CFLog(__kCFLogBundle
, CFSTR("Internal error unloading bundle %@"), bundle
);
2797 if (bundle
->_moduleCookie
&& bundle
->_imageCookie
&& !NSDestroyObjectFileImage(bundle
->_imageCookie
)) {
2798 /* MF:!!! Error destroying object file image */
2800 bundle
->_connectionCookie
= bundle
->_imageCookie
= bundle
->_moduleCookie
= NULL
;
2801 bundle
->_isLoaded
= false;
2806 __private_extern__
void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {return _CFBundleDYLDGetSymbolByNameWithSearch(bundle
, symbolName
, false);}
2808 static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle
, CFStringRef symbolName
, Boolean globalSearch
) {
2809 void *result
= NULL
;
2811 NSSymbol symbol
= NULL
;
2813 // MF:!!! What if the factory was in C++ code (and is therefore mangled differently)? Huh, answer me that!
2814 // MF: The current answer to the mangling question is that you cannot look up C++ functions with this API. Thus things like plugin factories must be extern "C" in plugin code.
2816 /* MF:??? ASCII appropriate here? */
2817 if (CFStringGetCString(symbolName
, &(buff
[1]), 1024, kCFStringEncodingASCII
)) {
2818 if (bundle
->_moduleCookie
) {
2819 symbol
= NSLookupSymbolInModule(bundle
->_moduleCookie
, buff
);
2820 } else if (bundle
->_imageCookie
) {
2821 symbol
= NSLookupSymbolInImage(bundle
->_imageCookie
, buff
, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND
|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR
);
2823 if (NULL
== symbol
&& NULL
== bundle
->_moduleCookie
&& (NULL
== bundle
->_imageCookie
|| globalSearch
)) {
2824 char hintBuff
[1026];
2825 CFStringRef executableName
= _CFBundleCopyExecutableName(NULL
, bundle
, NULL
, NULL
);
2827 if (executableName
) {
2828 if (!CFStringGetCString(executableName
, hintBuff
, 1024, kCFStringEncodingUTF8
)) hintBuff
[0] = '\0';
2829 CFRelease(executableName
);
2831 if (NSIsSymbolNameDefinedWithHint(buff
, hintBuff
)) {
2832 symbol
= NSLookupAndBindSymbolWithHint(buff
, hintBuff
);
2836 result
= NSAddressOfSymbol(symbol
);
2839 CFLog(__kCFLogBundle
, CFSTR("dyld cannot find symbol %s in %@"), buff
, bundle
);
2846 static CFStringRef
_CFBundleDYLDCopyLoadedImagePathForPointer(void *p
) {
2847 unsigned long i
, j
, n
= _dyld_image_count();
2848 Boolean foundit
= false;
2850 CFStringRef result
= NULL
;
2851 for (i
= 0; !foundit
&& i
< n
; i
++) {
2852 struct mach_header
*mh
= _dyld_get_image_header(i
);
2853 unsigned long addr
= (unsigned long)p
- _dyld_get_image_vmaddr_slide(i
);
2855 struct load_command
*lc
= (struct load_command
*)((char *)mh
+ sizeof(struct mach_header
));
2856 for (j
= 0; !foundit
&& j
< mh
->ncmds
; j
++, lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
)) {
2857 if (LC_SEGMENT
== lc
->cmd
&& addr
>= ((struct segment_command
*)lc
)->vmaddr
&& addr
< ((struct segment_command
*)lc
)->vmaddr
+ ((struct segment_command
*)lc
)->vmsize
) {
2859 name
= _dyld_get_image_name(i
);
2861 result
= CFStringCreateWithCString(NULL
, name
, CFStringFileSystemEncoding());
2870 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint
) {
2871 unsigned long i
, numImages
= _dyld_image_count();
2872 CFMutableArrayRef result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2873 CFRange range
= CFRangeMake(0, CFStringGetLength(hint
));
2875 for (i
=0; i
<numImages
; i
++) {
2876 char *curName
= _dyld_get_image_name(i
), *lastComponent
= NULL
;
2877 if (curName
!= NULL
) lastComponent
= strrchr(curName
, '/');
2878 if (lastComponent
!= NULL
) {
2879 CFStringRef str
= CFStringCreateWithCString(NULL
, lastComponent
+ 1, CFStringFileSystemEncoding());
2881 if (CFStringFindWithOptions(hint
, str
, range
, kCFCompareAnchored
|kCFCompareBackwards
|kCFCompareCaseInsensitive
, NULL
)) {
2882 CFStringRef curStr
= CFStringCreateWithCString(NULL
, curName
, CFStringFileSystemEncoding());
2883 if (curStr
!= NULL
) {
2884 CFArrayAppendValue(result
, curStr
);
2895 __private_extern__ CFArrayRef
_CFBundleDYLDCopyLoadedImagePathsIfChanged(void) {
2896 // This returns an array of the paths of all the dyld images in the process. These paths may not be absolute, they may point at things that are not bundles, they may be staticly linked bundles or dynamically loaded bundles, they may be NULL.
2897 static unsigned long _cachedDYLDImageCount
= -1;
2899 unsigned long i
, numImages
= _dyld_image_count();
2900 CFMutableArrayRef result
= NULL
;
2902 if (numImages
!= _cachedDYLDImageCount
) {
2906 result
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2908 for (i
=0; i
<numImages
; i
++) {
2909 curName
= _dyld_get_image_name(i
);
2910 if (curName
!= NULL
) {
2911 curStr
= CFStringCreateWithCString(NULL
, curName
, CFStringFileSystemEncoding());
2912 if (curStr
!= NULL
) {
2913 CFArrayAppendValue(result
, curStr
);
2918 _cachedDYLDImageCount
= numImages
;
2923 #endif /* BINARY_SUPPORT_DYLD */
2926 #if defined(BINARY_SUPPORT_DLL)
2928 __private_extern__ Boolean
_CFBundleDLLLoad(CFBundleRef bundle
) {
2930 if (!bundle
->_isLoaded
) {
2931 CFURLRef executableURL
= CFBundleCopyExecutableURL(bundle
);
2933 if (executableURL
) {
2934 char buff
[CFMaxPathSize
];
2936 if (CFURLGetFileSystemRepresentation(executableURL
, true, buff
, CFMaxPathSize
)) {
2937 bundle
->_hModule
= LoadLibrary(buff
);
2938 if (bundle
->_hModule
== NULL
) {
2940 bundle
->_isLoaded
= true;
2943 CFRelease(executableURL
);
2945 CFLog(__kCFLogBundle
, CFSTR("Cannot find executable for bundle %@"), bundle
);
2949 return bundle
->_isLoaded
;
2952 __private_extern__
void _CFBundleDLLUnload(CFBundleRef bundle
) {
2953 if (bundle
->_isLoaded
) {
2954 FreeLibrary(bundle
->_hModule
);
2955 bundle
->_hModule
= NULL
;
2956 bundle
->_isLoaded
= false;
2960 __private_extern__
void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle
, CFStringRef symbolName
) {
2961 void *result
= NULL
;
2964 if (CFStringGetCString(symbolName
, buff
, 1024, kCFStringEncodingWindowsLatin1
)) {
2965 result
= GetProcAddress(bundle
->_hModule
, buff
);
2970 #endif /* BINARY_SUPPORT_DLL */
2973 /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation.
2975 extern void _CFStringSetCompatibility(CFOptionFlags
);
2977 static void _CFBundleCheckWorkarounds(CFBundleRef bundle
) {