1/* 2 * Copyright (c) 2014 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* CFBundle.c 25 Copyright (c) 1999-2013, Apple Inc. All rights reserved. 26 Responsibility: Tony Parker 27*/ 28 29#include "CFBundle_Internal.h" 30#include <CoreFoundation/CFPropertyList.h> 31#include <CoreFoundation/CFNumber.h> 32#include <CoreFoundation/CFSet.h> 33#include <CoreFoundation/CFURLAccess.h> 34#include <CoreFoundation/CFError.h> 35#include <string.h> 36#include <CoreFoundation/CFPriv.h> 37#include "CFInternal.h" 38#include <CoreFoundation/CFByteOrder.h> 39#include "CFBundle_BinaryTypes.h" 40#include <ctype.h> 41#include <sys/stat.h> 42#include <stdlib.h> 43 44#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS 45#else 46#error Unknown deployment target 47#endif 48 49#define AVOID_WEAK_COLLECTIONS 1 50 51#if !AVOID_WEAK_COLLECTIONS 52#include "CFHashTable.h" 53#include "CFMapTable.h" 54#include "CFPointerArray.h" 55#endif /* !AVOID_WEAK_COLLECTIONS */ 56 57#if defined(BINARY_SUPPORT_DYLD) 58// Import the mach-o headers that define the macho magic numbers 59#include <mach-o/loader.h> 60#include <mach-o/fat.h> 61#include <mach-o/arch.h> 62#include <mach-o/dyld.h> 63#include <mach-o/getsect.h> 64#include <unistd.h> 65#include <fcntl.h> 66#include <sys/mman.h> 67#include <crt_externs.h> 68#if defined(USE_DYLD_PRIV) 69#include <mach-o/dyld_priv.h> 70#endif /* USE_DYLD_PRIV */ 71#endif /* BINARY_SUPPORT_DYLD */ 72 73#if defined(BINARY_SUPPORT_DLFCN) 74#include <dlfcn.h> 75#endif /* BINARY_SUPPORT_DLFCN */ 76 77#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 78#include <fcntl.h> 79#elif DEPLOYMENT_TARGET_WINDOWS 80#include <fcntl.h> 81#include <io.h> 82 83#define open _NS_open 84#define stat(x,y) _NS_stat(x,y) 85#endif 86 87 88#if DEPLOYMENT_TARGET_WINDOWS 89#define statinfo _stat 90 91// Windows isspace implementation limits the input chars to < 256 in the ASCII range. It will 92// assert in debug builds. This is annoying. We merrily grok chars > 256. 93static inline BOOL isspace(char c) { 94 return (c == ' ' || c == '\t' || c == '\n' || c == '\r'|| c == '\v' || c == '\f'); 95} 96 97#else 98#define statinfo stat 99#endif 100 101static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked); 102 103#define LOG_BUNDLE_LOAD 0 104 105// Public CFBundle Info plist keys 106CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey, "CFBundleInfoDictionaryVersion") 107CONST_STRING_DECL(kCFBundleExecutableKey, "CFBundleExecutable") 108CONST_STRING_DECL(kCFBundleIdentifierKey, "CFBundleIdentifier") 109CONST_STRING_DECL(kCFBundleVersionKey, "CFBundleVersion") 110CONST_STRING_DECL(kCFBundleDevelopmentRegionKey, "CFBundleDevelopmentRegion") 111CONST_STRING_DECL(kCFBundleLocalizationsKey, "CFBundleLocalizations") 112 113// Private CFBundle Info plist keys, possible candidates for public constants 114CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey, "CFBundleAllowMixedLocalizations") 115CONST_STRING_DECL(_kCFBundleSupportedPlatformsKey, "CFBundleSupportedPlatforms") 116CONST_STRING_DECL(_kCFBundleResourceSpecificationKey, "CFBundleResourceSpecification") 117 118// Finder stuff 119CONST_STRING_DECL(_kCFBundlePackageTypeKey, "CFBundlePackageType") 120CONST_STRING_DECL(_kCFBundleSignatureKey, "CFBundleSignature") 121CONST_STRING_DECL(_kCFBundleIconFileKey, "CFBundleIconFile") 122CONST_STRING_DECL(_kCFBundleDocumentTypesKey, "CFBundleDocumentTypes") 123CONST_STRING_DECL(_kCFBundleURLTypesKey, "CFBundleURLTypes") 124 125// Keys that are usually localized in InfoPlist.strings 126CONST_STRING_DECL(kCFBundleNameKey, "CFBundleName") 127CONST_STRING_DECL(_kCFBundleDisplayNameKey, "CFBundleDisplayName") 128CONST_STRING_DECL(_kCFBundleShortVersionStringKey, "CFBundleShortVersionString") 129CONST_STRING_DECL(_kCFBundleGetInfoStringKey, "CFBundleGetInfoString") 130CONST_STRING_DECL(_kCFBundleGetInfoHTMLKey, "CFBundleGetInfoHTML") 131 132// Sub-keys for CFBundleDocumentTypes dictionaries 133CONST_STRING_DECL(_kCFBundleTypeNameKey, "CFBundleTypeName") 134CONST_STRING_DECL(_kCFBundleTypeRoleKey, "CFBundleTypeRole") 135CONST_STRING_DECL(_kCFBundleTypeIconFileKey, "CFBundleTypeIconFile") 136CONST_STRING_DECL(_kCFBundleTypeOSTypesKey, "CFBundleTypeOSTypes") 137CONST_STRING_DECL(_kCFBundleTypeExtensionsKey, "CFBundleTypeExtensions") 138CONST_STRING_DECL(_kCFBundleTypeMIMETypesKey, "CFBundleTypeMIMETypes") 139 140// Sub-keys for CFBundleURLTypes dictionaries 141CONST_STRING_DECL(_kCFBundleURLNameKey, "CFBundleURLName") 142CONST_STRING_DECL(_kCFBundleURLIconFileKey, "CFBundleURLIconFile") 143CONST_STRING_DECL(_kCFBundleURLSchemesKey, "CFBundleURLSchemes") 144 145// Compatibility key names 146CONST_STRING_DECL(_kCFBundleOldExecutableKey, "NSExecutable") 147CONST_STRING_DECL(_kCFBundleOldInfoDictionaryVersionKey, "NSInfoPlistVersion") 148CONST_STRING_DECL(_kCFBundleOldNameKey, "NSHumanReadableName") 149CONST_STRING_DECL(_kCFBundleOldIconFileKey, "NSIcon") 150CONST_STRING_DECL(_kCFBundleOldDocumentTypesKey, "NSTypes") 151CONST_STRING_DECL(_kCFBundleOldShortVersionStringKey, "NSAppVersion") 152 153// Compatibility CFBundleDocumentTypes key names 154CONST_STRING_DECL(_kCFBundleOldTypeNameKey, "NSName") 155CONST_STRING_DECL(_kCFBundleOldTypeRoleKey, "NSRole") 156CONST_STRING_DECL(_kCFBundleOldTypeIconFileKey, "NSIcon") 157CONST_STRING_DECL(_kCFBundleOldTypeExtensions1Key, "NSUnixExtensions") 158CONST_STRING_DECL(_kCFBundleOldTypeExtensions2Key, "NSDOSExtensions") 159CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey, "NSMacOSType") 160 161// Internally used keys for loaded Info plists. 162CONST_STRING_DECL(_kCFBundleInfoPlistURLKey, "CFBundleInfoPlistURL") 163CONST_STRING_DECL(_kCFBundleRawInfoPlistURLKey, "CFBundleRawInfoPlistURL") 164CONST_STRING_DECL(_kCFBundleNumericVersionKey, "CFBundleNumericVersion") 165CONST_STRING_DECL(_kCFBundleExecutablePathKey, "CFBundleExecutablePath") 166CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey, "CSResourcesFileMapped") 167CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey, "CFBundleCFMLoadAsBundle") 168 169// Keys used by NSBundle for loaded Info plists. 170CONST_STRING_DECL(_kCFBundlePrincipalClassKey, "NSPrincipalClass") 171 172static char __CFBundleMainID__[1026] = {0}; 173CF_PRIVATE char *__CFBundleMainID = __CFBundleMainID__; 174 175static CFTypeID __kCFBundleTypeID = _kCFRuntimeNotATypeID; 176 177static pthread_mutex_t CFBundleGlobalDataLock = PTHREAD_MUTEX_INITIALIZER; 178 179static CFMutableDictionaryRef _bundlesByIdentifier = NULL; 180#if AVOID_WEAK_COLLECTIONS 181static CFMutableDictionaryRef _bundlesByURL = NULL; 182static CFMutableArrayRef _allBundles = NULL; 183static CFMutableSetRef _bundlesToUnload = NULL; 184#else /* AVOID_WEAK_COLLECTIONS */ 185static __CFHashTable *_allBundles = nil; 186static __CFHashTable *_bundlesToUnload = nil; 187#endif /* AVOID_WEAK_COLLECTIONS */ 188static Boolean _scheduledBundlesAreUnloading = false; 189 190static Boolean _initedMainBundle = false; 191static CFBundleRef _mainBundle = NULL; 192 193// Forward declares functions. 194static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing); 195static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle); 196static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint); 197static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void); 198static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath); 199static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths); 200#if defined(BINARY_SUPPORT_DYLD) 201static CFMutableDictionaryRef _CFBundleCreateInfoDictFromMainExecutable(void); 202static Boolean _CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion, uint32_t *objcFlags); 203static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p); 204#if !defined(BINARY_SUPPORT_DLFCN) 205static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch); 206#endif /* !BINARY_SUPPORT_DLFCN */ 207#endif /* BINARY_SUPPORT_DYLD */ 208#if defined(BINARY_SUPPORT_DLFCN) 209static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch); 210#if !defined(BINARY_SUPPORT_DYLD) 211static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p); 212#endif /* !BINARY_SUPPORT_DYLD */ 213#endif /* BINARY_SUPPORT_DLFCN */ 214 215 216#if AVOID_WEAK_COLLECTIONS 217 218static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { 219 CFStringRef bundleID = CFBundleGetIdentifier(bundle); 220 221 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); 222 223 // Add to the _allBundles list 224 if (!_allBundles) { 225 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks; 226 nonRetainingArrayCallbacks.retain = NULL; 227 nonRetainingArrayCallbacks.release = NULL; 228 _allBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks); 229 } 230 CFArrayAppendValue(_allBundles, bundle); 231 232 // Add to the table that maps urls to bundles 233 if (!_bundlesByURL) { 234 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks; 235 nonRetainingDictionaryValueCallbacks.retain = NULL; 236 nonRetainingDictionaryValueCallbacks.release = NULL; 237 _bundlesByURL = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks); 238 } 239 CFDictionarySetValue(_bundlesByURL, bundle->_url, bundle); 240 241 // Add to the table that maps identifiers to bundles 242 if (bundleID) { 243 CFMutableArrayRef bundlesWithThisID = NULL; 244 CFBundleRef existingBundle = NULL; 245 if (!_bundlesByIdentifier) { 246 _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 247 } 248 bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); 249 if (bundlesWithThisID) { 250 CFIndex i, count = CFArrayGetCount(bundlesWithThisID); 251 UInt32 existingVersion, newVersion = CFBundleGetVersionNumber(bundle); 252 for (i = 0; i < count; i++) { 253 existingBundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i); 254 existingVersion = CFBundleGetVersionNumber(existingBundle); 255 // If you load two bundles with the same identifier and the same version, the last one wins. 256 if (newVersion >= existingVersion) break; 257 } 258 CFArrayInsertValueAtIndex(bundlesWithThisID, i, bundle); 259 } else { 260 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks; 261 nonRetainingArrayCallbacks.retain = NULL; 262 nonRetainingArrayCallbacks.release = NULL; 263 bundlesWithThisID = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks); 264 CFArrayAppendValue(bundlesWithThisID, bundle); 265 CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundlesWithThisID); 266 CFRelease(bundlesWithThisID); 267 } 268 } 269 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); 270} 271 272static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) { 273 pthread_mutex_lock(&CFBundleGlobalDataLock); 274 // Remove from the various lists 275 if (_allBundles) { 276 CFIndex i = CFArrayGetFirstIndexOfValue(_allBundles, CFRangeMake(0, CFArrayGetCount(_allBundles)), bundle); 277 if (i >= 0) CFArrayRemoveValueAtIndex(_allBundles, i); 278 } 279 280 // Remove from the table that maps urls to bundles 281 if (bundleURL && _bundlesByURL) { 282 CFBundleRef bundleForURL = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, bundleURL); 283 if (bundleForURL == bundle) CFDictionaryRemoveValue(_bundlesByURL, bundleURL); 284 } 285 286 // Remove from the table that maps identifiers to bundles 287 if (bundleID && _bundlesByIdentifier) { 288 CFMutableArrayRef bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); 289 if (bundlesWithThisID) { 290 CFIndex count = CFArrayGetCount(bundlesWithThisID); 291 while (count-- > 0) if (bundle == (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, count)) CFArrayRemoveValueAtIndex(bundlesWithThisID, count); 292 if (0 == CFArrayGetCount(bundlesWithThisID)) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID); 293 } 294 } 295 pthread_mutex_unlock(&CFBundleGlobalDataLock); 296} 297 298static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) { 299 CFBundleRef result = NULL; 300 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); 301 if (_bundlesByURL) result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url); 302 if (result && !result->_url) { 303 result = NULL; 304 CFDictionaryRemoveValue(_bundlesByURL, url); 305 } 306 if (result) CFRetain(result); 307 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); 308 return result; 309} 310 311static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID) { 312 CFBundleRef result = NULL, bundle; 313 if (_bundlesByIdentifier && bundleID) { 314 // Note that this array is maintained in descending order by version number 315 CFArrayRef bundlesWithThisID = (CFArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); 316 if (bundlesWithThisID) { 317 CFIndex i, count = CFArrayGetCount(bundlesWithThisID); 318 if (count > 0) { 319 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle 320 for (i = 0; !result && i < count; i++) { 321 bundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i); 322 if (CFBundleIsExecutableLoaded(bundle)) result = bundle; 323 } 324 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number 325 if (!result) result = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, 0); 326 } 327 } 328 } 329 return result; 330} 331 332#else /* AVOID_WEAK_COLLECTIONS */ 333 334/* 335 An explanation of what I'm doing here is probably in order. 336 8029300 has cast suspicion on the correctness of __CFMapTable with strong keys and weak values, at least under non-GC. 337 An early attempt to work around it by inserting dummy values instead of removing things succeeded, as did turning on the AVOID_WEAK_COLLECTIONS #ifdef 338 This indicates that it's not an overrelease in securityd, since AVOID_WEAK_COLLECTIONS wouldn't help in that case. 339 Therefore, these functions following this comment allow us to have _bundlesByURL be a CFDictionary on non-GC and keep __CFMapTable to GC where it's needed. 340 */ 341static inline id _getBundlesByURL() { 342 static id _bundles = nil; 343 static dispatch_once_t onceToken; 344 dispatch_once(&onceToken, ^{ 345 if (CF_USING_COLLECTABLE_MEMORY) { 346 _bundles = [[__CFMapTable alloc] initWithKeyOptions:CFPointerFunctionsStrongMemory valueOptions:CFPointerFunctionsZeroingWeakMemory capacity:0]; 347 } else { 348 CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks; 349 nonRetainingDictionaryValueCallbacks.retain = NULL; 350 nonRetainingDictionaryValueCallbacks.release = NULL; 351 _bundles = (id)CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks); 352 } 353 }); 354 return _bundles; 355} 356 357#define _bundlesByURL _getBundlesByURL() 358 359static void _setInBundlesByURL(CFURLRef key, CFBundleRef bundle) { 360 if (CF_USING_COLLECTABLE_MEMORY) { 361 [(__CFMapTable *)_bundlesByURL setObject:(id)bundle forKey:(id)key]; 362 } else { 363 CFDictionarySetValue((CFMutableDictionaryRef)_bundlesByURL, key, bundle); 364 } 365} 366 367static void _removeFromBundlesByURL(CFURLRef key) { 368 if (CF_USING_COLLECTABLE_MEMORY) { 369 [(__CFMapTable *)_bundlesByURL removeObjectForKey:(id)key]; 370 } else { 371 CFDictionaryRemoveValue((CFMutableDictionaryRef)_bundlesByURL, key); 372 } 373} 374 375static CFBundleRef _getFromBundlesByURL(CFURLRef key) { 376 if (CF_USING_COLLECTABLE_MEMORY) { 377 return (CFBundleRef)[(__CFMapTable *)_bundlesByURL objectForKey:(id)key]; 378 } else { 379 return (CFBundleRef)CFDictionaryGetValue((CFMutableDictionaryRef)_bundlesByURL, key); 380 } 381} 382 383static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { 384 CFStringRef bundleID = CFBundleGetIdentifier(bundle); 385 386 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); 387 388 // Add to the _allBundles list 389 if (!_allBundles) _allBundles = [[__CFHashTable alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory capacity:0]; 390 [_allBundles addObject:(id)bundle]; 391 392 // Add to the table that maps urls to bundles 393 _setInBundlesByURL(bundle->_url, bundle); 394 395 // Add to the table that maps identifiers to bundles 396 if (bundleID) { 397 __CFPointerArray *bundlesWithThisID = nil; 398 CFBundleRef existingBundle = NULL; 399 if (!_bundlesByIdentifier) { 400 _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 401 } 402 bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); 403 if (bundlesWithThisID) { 404 CFIndex i, count = (CFIndex)[bundlesWithThisID count]; 405 UInt32 existingVersion, newVersion = CFBundleGetVersionNumber(bundle); 406 for (i = 0; i < count; i++) { 407 existingBundle = (CFBundleRef)[bundlesWithThisID pointerAtIndex:i]; 408 if (!existingBundle) continue; 409 existingVersion = CFBundleGetVersionNumber(existingBundle); 410 // If you load two bundles with the same identifier and the same version, the last one wins. 411 if (newVersion >= existingVersion) break; 412 } 413 if (i < count) { 414 [bundlesWithThisID insertPointer:bundle atIndex:i]; 415 } else { 416 [bundlesWithThisID addPointer:bundle]; 417 } 418 } else { 419 bundlesWithThisID = [[__CFPointerArray alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory]; 420 [bundlesWithThisID addPointer:bundle]; 421 CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundlesWithThisID); 422 [bundlesWithThisID release]; 423 } 424 } 425 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); 426} 427 428static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) { 429 pthread_mutex_lock(&CFBundleGlobalDataLock); 430 // Remove from the various lists 431 if (_allBundles && [_allBundles member:(id)bundle]) [_allBundles removeObject:(id)bundle]; 432 433 // Remove from the table that maps urls to bundles 434 if (bundleURL) { 435 _removeFromBundlesByURL(bundleURL); 436 } 437 438 // Remove from the table that maps identifiers to bundles 439 if (bundleID && _bundlesByIdentifier) { 440 __CFPointerArray *bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); 441 if (bundlesWithThisID) { 442 CFIndex count = (CFIndex)[bundlesWithThisID count]; 443 while (count-- > 0) if (bundle == (CFBundleRef)[bundlesWithThisID pointerAtIndex:count]) [bundlesWithThisID removePointerAtIndex:count]; 444 [bundlesWithThisID compact]; 445 if (0 == [bundlesWithThisID count]) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID); 446 } 447 } 448 pthread_mutex_unlock(&CFBundleGlobalDataLock); 449} 450 451static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) { 452 CFBundleRef result = NULL; 453 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); 454 result = _getFromBundlesByURL(url); 455 if (result && !result->_url) { 456 result = NULL; 457 _removeFromBundlesByURL(url); 458 } 459 if (result) CFRetain(result); 460 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); 461 return result; 462} 463 464static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStringRef bundleID) { 465 CFBundleRef result = NULL; 466 if (_bundlesByIdentifier && bundleID) { 467 // Note that this array is maintained in descending order by version number 468 __CFPointerArray *bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); 469 if (bundlesWithThisID && [bundlesWithThisID count] > 0) { 470 // First check for loaded bundles so we will always prefer a loaded to an unloaded bundle 471 for (id bundle in bundlesWithThisID) { 472 if (bundle && CFBundleIsExecutableLoaded((CFBundleRef)bundle)) { 473 result = (CFBundleRef)bundle; 474 break; 475 } 476 } 477 // If no loaded bundle, simply take the first item in the array, i.e. the one with the latest version number 478 if (!result) { 479 for (id bundle in bundlesWithThisID) { 480 if (bundle) { 481 result = (CFBundleRef)bundle; 482 break; 483 } 484 } 485 } 486 } 487 } 488 return result; 489} 490 491#endif /* AVOID_WEAK_COLLECTIONS */ 492 493static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { 494 //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd 495 UniChar buff[CFMaxPathSize]; 496 CFIndex buffLen; 497 CFURLRef url = NULL; 498 CFStringRef outstr; 499 500 buffLen = CFStringGetLength(str); 501 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize; 502 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff); 503 504#if DEPLOYMENT_TARGET_WINDOWS 505 // Is this a .dll or .exe? 506 if (buffLen >= 5 && (_wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".exe", 4) == 0)) { 507 CFIndex extensionLength = CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension); 508 buffLen -= 4; 509 // If this is an _debug, we should strip that before looking for the bundle 510 if (buffLen >= 7 && (_wcsnicmp((wchar_t *)&buff[buffLen-6], L"_debug", 6) == 0)) buffLen -= 6; 511 512 if (buffLen + 1 + extensionLength < CFMaxPathSize) { 513 buff[buffLen] = '.'; 514 buffLen ++; 515 CFStringGetCharacters(_CFBundleWindowsResourceDirectoryExtension, CFRangeMake(0, extensionLength), buff + buffLen); 516 buffLen += extensionLength; 517 outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull); 518 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true); 519 CFRelease(outstr); 520 } 521 } 522#endif 523 524 if (!url) { 525 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); // Remove exe name 526 527 if (buffLen > 0) { 528 // See if this is a new bundle. If it is, we have to remove more path components. 529 CFIndex startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen); 530 if (startOfLastDir > 0 && startOfLastDir < buffLen) { 531 CFStringRef lastDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir); 532 533 if (CFEqual(lastDirName, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) { 534 // This is a new bundle. Back off a few more levels 535 if (buffLen > 0) { 536 // Remove platform folder 537 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); 538 } 539 if (buffLen > 0) { 540 // Remove executables folder (if present) 541 CFIndex startOfNextDir = _CFStartOfLastPathComponent(buff, buffLen); 542 if (startOfNextDir > 0 && startOfNextDir < buffLen) { 543 CFStringRef nextDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfNextDir]), buffLen - startOfNextDir); 544 if (CFEqual(nextDirName, _CFBundleExecutablesDirectoryName)) buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); 545 CFRelease(nextDirName); 546 } 547 } 548 if (buffLen > 0) { 549 // Remove support files folder 550 buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); 551 } 552 } 553 CFRelease(lastDirName); 554 } 555 } 556 557 if (buffLen > 0) { 558 outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull); 559 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true); 560 CFRelease(outstr); 561 } 562 } 563 return url; 564} 565 566static CFURLRef _CFBundleCopyResolvedURLForExecutableURL(CFURLRef url) { 567 // this is necessary so that we match any sanitization CFURL may perform on the result of _CFBundleCopyBundleURLForExecutableURL() 568 CFURLRef absoluteURL, url1, url2, outURL = NULL; 569 CFStringRef str, str1, str2; 570 absoluteURL = CFURLCopyAbsoluteURL(url); 571 str = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); 572 if (str) { 573 UniChar buff[CFMaxPathSize]; 574 CFIndex buffLen = CFStringGetLength(str), len1; 575 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize; 576 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff); 577 len1 = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); 578 if (len1 > 0 && len1 + 1 < buffLen) { 579 str1 = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buff, len1); 580 CFIndex skipSlashCount = 1; 581#if DEPLOYMENT_TARGET_WINDOWS 582 // On Windows, _CFLengthAfterDeletingLastPathComponent will return a value of 3 if the path is at the root (e.g. C:\). This includes the \, which is not the case for URLs with subdirectories 583 if (len1 == 3 && buff[1] == ':' && buff[2] == '\\') { 584 skipSlashCount = 0; 585 } 586#endif 587 str2 = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buff + len1 + skipSlashCount, buffLen - len1 - skipSlashCount); 588 if (str1 && str2) { 589 url1 = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str1, PLATFORM_PATH_STYLE, true); 590 if (url1) { 591 url2 = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, str2, PLATFORM_PATH_STYLE, false, url1); 592 if (url2) { 593 outURL = CFURLCopyAbsoluteURL(url2); 594 CFRelease(url2); 595 } 596 CFRelease(url1); 597 } 598 } 599 if (str1) CFRelease(str1); 600 if (str2) CFRelease(str2); 601 } 602 CFRelease(str); 603 } 604 if (!outURL) { 605 outURL = absoluteURL; 606 } else { 607 CFRelease(absoluteURL); 608 } 609 return outURL; 610} 611 612CFURLRef _CFBundleCopyBundleURLForExecutableURL(CFURLRef url) { 613 CFURLRef resolvedURL, outurl = NULL; 614 CFStringRef str; 615 resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url); 616 str = CFURLCopyFileSystemPath(resolvedURL, PLATFORM_PATH_STYLE); 617 if (str) { 618 outurl = _CFBundleCopyBundleURLForExecutablePath(str); 619 CFRelease(str); 620 } 621 CFRelease(resolvedURL); 622 return outurl; 623} 624 625static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle) { 626 uint8_t localVersion = bundle->_version; 627 // exclude type 0 bundles with no binary (or CFM binary) and no Info.plist, since they give too many false positives 628 if (0 == localVersion) { 629 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); 630 if (!infoDict || 0 == CFDictionaryGetCount(infoDict)) { 631#if defined(BINARY_SUPPORT_DYLD) 632 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 633 if (executableURL) { 634 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); 635 if (bundle->_binaryType == __CFBundleCFMBinary || bundle->_binaryType == __CFBundleUnreadableBinary) { 636 localVersion = 4; 637 } else { 638 bundle->_resourceData._executableLacksResourceFork = true; 639 } 640 CFRelease(executableURL); 641 } else { 642 localVersion = 4; 643 } 644#else 645 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 646 if (executableURL) { 647 CFRelease(executableURL); 648 } else { 649 localVersion = 4; 650 } 651#endif /* BINARY_SUPPORT_DYLD */ 652 } 653 } 654 return localVersion; 655} 656 657CFBundleRef _CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) { 658 CFBundleRef bundle = CFBundleCreate(allocator, url); 659 if (bundle) { 660 uint8_t localVersion = _CFBundleEffectiveLayoutVersion(bundle); 661 if (3 == localVersion || 4 == localVersion) { 662 CFRelease(bundle); 663 bundle = NULL; 664 } 665 } 666 return bundle; 667} 668 669CFBundleRef _CFBundleGetMainBundleIfLooksLikeBundle(void) { 670 CFBundleRef mainBundle = CFBundleGetMainBundle(); 671 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL; 672 return mainBundle; 673} 674 675Boolean _CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) { 676 CFBundleRef mainBundle = CFBundleGetMainBundle(); 677 return (mainBundle && mainBundle->_resourceData._infoDictionaryFromResourceFork); 678} 679 680CFBundleRef _CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) { 681 CFBundleRef bundle = NULL; 682 CFURLRef bundleURL = _CFBundleCopyBundleURLForExecutableURL(url), resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url); 683 if (bundleURL && resolvedURL) { 684 bundle = _CFBundleCreateIfLooksLikeBundle(allocator, bundleURL); 685 if (bundle) { 686 CFURLRef executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle); 687 char buff1[CFMaxPathSize], buff2[CFMaxPathSize]; 688 if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, (uint8_t *)buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) { 689 CFRelease(bundle); 690 bundle = NULL; 691 } 692 if (executableURL) CFRelease(executableURL); 693 } 694 } 695 if (bundleURL) CFRelease(bundleURL); 696 if (resolvedURL) CFRelease(resolvedURL); 697 return bundle; 698} 699 700CFBundleRef _CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator, CFURLRef url) { 701 CFBundleRef bundle = CFBundleCreate(allocator, url); 702 if (bundle) { 703 Boolean mightBeBundle = true, isDir = false; 704 uint8_t localVersion = _CFBundleEffectiveLayoutVersion(bundle); 705 if (3 == localVersion) { 706 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); 707 CFURLRef executableURL, supportFilesURL, resourceSpecificationFileURL; 708 CFArrayRef supportedPlatforms; 709 CFStringRef resourceSpecificationFile; 710 711 mightBeBundle = false; 712 if (infoDict && CFDictionaryGetValue(infoDict, kCFBundleExecutableKey) && (executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle))) { 713 supportedPlatforms = _CFBundleGetSupportedPlatforms(bundle); 714 resourceSpecificationFile = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleResourceSpecificationKey); 715 if (supportedPlatforms && CFArrayGetCount(supportedPlatforms) > 0 && CFArrayGetFirstIndexOfValue(supportedPlatforms, CFRangeMake(0, CFArrayGetCount(supportedPlatforms)), CFSTR("iPhoneOS")) >= 0) { 716 mightBeBundle = true; 717 } else if (resourceSpecificationFile && CFGetTypeID(resourceSpecificationFile) == CFStringGetTypeID() && (supportFilesURL = CFBundleCopySupportFilesDirectoryURL(bundle))) { 718 resourceSpecificationFileURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, resourceSpecificationFile, kCFURLPOSIXPathStyle, false, supportFilesURL); 719 if (resourceSpecificationFileURL) { 720 if (_CFIsResourceAtURL(resourceSpecificationFileURL, &isDir) && !isDir) mightBeBundle = true; 721 CFRelease(resourceSpecificationFileURL); 722 } 723 CFRelease(supportFilesURL); 724 } 725 CFRelease(executableURL); 726 } 727 } else if (4 == localVersion) { 728 mightBeBundle = false; 729 } 730 if (!mightBeBundle) { 731 CFRelease(bundle); 732 bundle = NULL; 733 } 734 } 735 return bundle; 736} 737 738CFBundleRef _CFBundleCreateWithExecutableURLIfMightBeBundle(CFAllocatorRef allocator, CFURLRef url) { 739 CFBundleRef bundle = NULL; 740 CFURLRef bundleURL = _CFBundleCopyBundleURLForExecutableURL(url), resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url); 741 if (bundleURL && resolvedURL) { 742 bundle = _CFBundleCreateIfMightBeBundle(allocator, bundleURL); 743 if (bundle) { 744 CFURLRef executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle); 745 char buff1[CFMaxPathSize], buff2[CFMaxPathSize]; 746 if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, (uint8_t *)buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) { 747 CFRelease(bundle); 748 bundle = NULL; 749 } 750 if (executableURL) CFRelease(executableURL); 751 } 752 } 753 if (bundleURL) CFRelease(bundleURL); 754 if (resolvedURL) CFRelease(resolvedURL); 755 return bundle; 756} 757 758CFURLRef _CFBundleCopyMainBundleExecutableURL(Boolean *looksLikeBundle) { 759 // This function is for internal use only; _mainBundle is deliberately accessed outside of the lock to get around a reentrancy issue 760 const char *processPath; 761 CFStringRef str = NULL; 762 CFURLRef executableURL = NULL; 763 processPath = _CFProcessPath(); 764 if (processPath) { 765 str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, processPath); 766 if (str) { 767 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false); 768 CFRelease(str); 769 } 770 } 771 if (looksLikeBundle) { 772 CFBundleRef mainBundle = _mainBundle; 773 if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL; 774 *looksLikeBundle = (mainBundle ? true : false); 775 } 776 return executableURL; 777} 778 779static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef executablePath) { 780 CFBundleGetInfoDictionary(_mainBundle); 781 if (!_mainBundle->_infoDict || CFDictionaryGetCount(_mainBundle->_infoDict) == 0) { 782 // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives 783 if (_mainBundle->_version == 3) _mainBundle->_version = 4; 784 if (_mainBundle->_version == 0) { 785 // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives 786 CFStringRef executableName = _CFBundleCopyExecutableName(_mainBundle, NULL, NULL); 787 if (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName)) _mainBundle->_version = 4; 788 if (executableName) CFRelease(executableName); 789 } 790#if defined(BINARY_SUPPORT_DYLD) 791 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) { 792 if (_mainBundle->_infoDict && !(0)) CFRelease(_mainBundle->_infoDict); 793 _mainBundle->_infoDict = (CFDictionaryRef)_CFBundleCreateInfoDictFromMainExecutable(); 794 } 795#endif /* BINARY_SUPPORT_DYLD */ 796 } else { 797#if defined(BINARY_SUPPORT_DYLD) 798 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) { 799 // if dyld and not main executable for bundle, prefer info dictionary from executable 800 CFStringRef executableName = _CFBundleCopyExecutableName(_mainBundle, NULL, NULL); 801 if (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName)) { 802 CFDictionaryRef infoDictFromExecutable = (CFDictionaryRef)_CFBundleCreateInfoDictFromMainExecutable(); 803 if (infoDictFromExecutable && CFDictionaryGetCount(infoDictFromExecutable) > 0) { 804 if (_mainBundle->_infoDict) CFRelease(_mainBundle->_infoDict); 805 _mainBundle->_infoDict = infoDictFromExecutable; 806 } else if (infoDictFromExecutable) { 807 CFRelease(infoDictFromExecutable); 808 } 809 } 810 if (executableName) CFRelease(executableName); 811 } 812#endif /* BINARY_SUPPORT_DYLD */ 813 } 814 if (!_mainBundle->_infoDict) _mainBundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 815 if (!_mainBundle->_executablePath && executablePath) _mainBundle->_executablePath = (CFStringRef)CFRetain(executablePath); 816 CFStringRef bundleID = (CFStringRef)CFDictionaryGetValue(_mainBundle->_infoDict, kCFBundleIdentifierKey); 817 if (bundleID) { 818 if (!CFStringGetCString(bundleID, __CFBundleMainID__, sizeof(__CFBundleMainID__) - 2, kCFStringEncodingUTF8)) { 819 __CFBundleMainID__[0] = '\0'; 820 } 821 } 822} 823 824static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked) { 825 CFDictionaryRef oldInfoDict = bundle->_infoDict; 826 CFTypeRef val; 827 828 bundle->_infoDict = NULL; 829 if (bundle->_localInfoDict) { 830 CFRelease(bundle->_localInfoDict); 831 bundle->_localInfoDict = NULL; 832 } 833 if (bundle->_developmentRegion) { 834 CFRelease(bundle->_developmentRegion); 835 bundle->_developmentRegion = NULL; 836 } 837 if (bundle->_executablePath) { 838 CFRelease(bundle->_executablePath); 839 bundle->_executablePath = NULL; 840 } 841 if (bundle->_searchLanguages) { 842 CFRelease(bundle->_searchLanguages); 843 bundle->_searchLanguages = NULL; 844 } 845 if (bundle->_resourceData._stringTableCache) { 846 CFRelease(bundle->_resourceData._stringTableCache); 847 bundle->_resourceData._stringTableCache = NULL; 848 } 849 if (bundle == _mainBundle) { 850 CFStringRef executablePath = bundle->_executablePath; 851 if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); 852 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath); 853 if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); 854 } else { 855 CFBundleGetInfoDictionary(bundle); 856 } 857 if (oldInfoDict) { 858 if (!bundle->_infoDict) bundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 859 val = CFDictionaryGetValue(oldInfoDict, _kCFBundlePrincipalClassKey); 860 if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundlePrincipalClassKey, val); 861 CFRelease(oldInfoDict); 862 } 863 __CFSpinLock(&bundle->_queryLock); 864 if (bundle->_queryTable) { 865 CFDictionaryRemoveAllValues(bundle->_queryTable); 866 } 867 __CFSpinUnlock(&bundle->_queryLock); 868} 869 870CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle) { 871 _CFBundleFlushBundleCachesAlreadyLocked(bundle, false); 872} 873 874static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) { 875 if (!_initedMainBundle) { 876 const char *processPath; 877 CFStringRef str = NULL; 878 CFURLRef executableURL = NULL, bundleURL = NULL; 879 _initedMainBundle = true; 880 processPath = _CFProcessPath(); 881 if (processPath) { 882 str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, processPath); 883 if (!executableURL) executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false); 884 } 885 if (executableURL) bundleURL = _CFBundleCopyBundleURLForExecutableURL(executableURL); 886 if (bundleURL) { 887 // make sure that main bundle has executable path 888 //??? what if we are not the main executable in the bundle? 889 // NB doFinalProcessing must be false here, see below 890 _mainBundle = _CFBundleCreate(kCFAllocatorSystemDefault, bundleURL, true, false); 891 if (_mainBundle) { 892 // make sure that the main bundle is listed as loaded, and mark it as executable 893 _mainBundle->_isLoaded = true; 894#if defined(BINARY_SUPPORT_DYLD) 895 if (_mainBundle->_binaryType == __CFBundleUnknownBinary) { 896 if (!executableURL) { 897 _mainBundle->_binaryType = __CFBundleNoBinary; 898 } else { 899 _mainBundle->_binaryType = _CFBundleGrokBinaryType(executableURL); 900 if (_mainBundle->_binaryType != __CFBundleCFMBinary && _mainBundle->_binaryType != __CFBundleUnreadableBinary) _mainBundle->_resourceData._executableLacksResourceFork = true; 901 } 902 } 903#endif /* BINARY_SUPPORT_DYLD */ 904 // get cookie for already-loaded main bundle 905#if defined(BINARY_SUPPORT_DLFCN) 906 if (!_mainBundle->_handleCookie) { 907 _mainBundle->_handleCookie = dlopen(NULL, RTLD_NOLOAD | RTLD_FIRST); 908#if LOG_BUNDLE_LOAD 909 printf("main bundle %p getting handle %p\n", _mainBundle, _mainBundle->_handleCookie); 910#endif /* LOG_BUNDLE_LOAD */ 911 } 912#elif defined(BINARY_SUPPORT_DYLD) 913 if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary && !_mainBundle->_imageCookie) { 914 _mainBundle->_imageCookie = (void *)_dyld_get_image_header(0); 915#if LOG_BUNDLE_LOAD 916 printf("main bundle %p getting image %p\n", _mainBundle, _mainBundle->_imageCookie); 917#endif /* LOG_BUNDLE_LOAD */ 918 } 919#endif /* BINARY_SUPPORT_DLFCN */ 920 _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str); 921 // Perform delayed final processing steps. 922 // This must be done after _isLoaded has been set, for security reasons (3624341). 923 if (_CFBundleNeedsInitPlugIn(_mainBundle)) { 924 pthread_mutex_unlock(&CFBundleGlobalDataLock); 925 _CFBundleInitPlugIn(_mainBundle); 926 pthread_mutex_lock(&CFBundleGlobalDataLock); 927 } 928 } 929 } 930 if (bundleURL) CFRelease(bundleURL); 931 if (str) CFRelease(str); 932 if (executableURL) CFRelease(executableURL); 933 } 934 return _mainBundle; 935} 936 937CFBundleRef CFBundleGetMainBundle(void) { 938 CFBundleRef mainBundle; 939 pthread_mutex_lock(&CFBundleGlobalDataLock); 940 mainBundle = _CFBundleGetMainBundleAlreadyLocked(); 941 pthread_mutex_unlock(&CFBundleGlobalDataLock); 942 return mainBundle; 943} 944 945CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) { 946 CFBundleRef result = NULL; 947 if (bundleID) { 948 pthread_mutex_lock(&CFBundleGlobalDataLock); 949 (void)_CFBundleGetMainBundleAlreadyLocked(); 950 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID); 951#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 952 if (!result) { 953 // Try to create the bundle for the caller and try again 954 void *p = __builtin_return_address(0); 955 if (p) { 956 CFStringRef imagePath = NULL; 957#if defined(BINARY_SUPPORT_DYLD) 958 if (!imagePath) imagePath = _CFBundleDYLDCopyLoadedImagePathForPointer(p); 959#elif defined(BINARY_SUPPORT_DLFCN) 960 if (!imagePath) imagePath = _CFBundleDlfcnCopyLoadedImagePathForPointer(p); 961#endif /* BINARY_SUPPORT_DYLD */ 962 if (imagePath) { 963 _CFBundleEnsureBundleExistsForImagePath(imagePath); 964 CFRelease(imagePath); 965 } 966 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID); 967 } 968 } 969#endif 970 if (!result) { 971 // Try to guess the bundle from the identifier and try again 972 _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID); 973 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID); 974 } 975 if (!result) { 976 // Make sure all bundles have been created and try again. 977 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(); 978 result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID); 979 } 980 pthread_mutex_unlock(&CFBundleGlobalDataLock); 981 } 982 return result; 983} 984 985static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) { 986 char buff[CFMaxPathSize]; 987 CFStringRef path = NULL, binaryType = NULL, retval = NULL; 988 if (((CFBundleRef)cf)->_url && CFURLGetFileSystemRepresentation(((CFBundleRef)cf)->_url, true, (uint8_t *)buff, CFMaxPathSize)) path = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff); 989 switch (((CFBundleRef)cf)->_binaryType) { 990 case __CFBundleCFMBinary: 991 binaryType = CFSTR(""); 992 break; 993 case __CFBundleDYLDExecutableBinary: 994 binaryType = CFSTR("executable, "); 995 break; 996 case __CFBundleDYLDBundleBinary: 997 binaryType = CFSTR("bundle, "); 998 break; 999 case __CFBundleDYLDFrameworkBinary: 1000 binaryType = CFSTR("framework, "); 1001 break; 1002 case __CFBundleDLLBinary: 1003 binaryType = CFSTR("DLL, "); 1004 break; 1005 case __CFBundleUnreadableBinary: 1006 binaryType = CFSTR(""); 1007 break; 1008 default: 1009 binaryType = CFSTR(""); 1010 break; 1011 } 1012 if (((CFBundleRef)cf)->_plugInData._isPlugIn) { 1013 retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle/CFPlugIn %p <%@> (%@%@loaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? CFSTR("") : CFSTR("not ")); 1014 } else { 1015 retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle %p <%@> (%@%@loaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? CFSTR("") : CFSTR("not ")); 1016 } 1017 if (path) CFRelease(path); 1018 return retval; 1019} 1020 1021static void _CFBundleDeallocateGlue(const void *key, const void *value, void *context) { 1022 CFAllocatorRef allocator = (CFAllocatorRef)context; 1023 if (value) CFAllocatorDeallocate(allocator, (void *)value); 1024} 1025 1026static void __CFBundleDeallocate(CFTypeRef cf) { 1027 CFBundleRef bundle = (CFBundleRef)cf; 1028 CFURLRef bundleURL; 1029 CFStringRef bundleID = NULL; 1030 1031 __CFGenericValidateType(cf, __kCFBundleTypeID); 1032 bundleURL = bundle->_url; 1033 bundle->_url = NULL; 1034 if (bundle->_infoDict) bundleID = (CFStringRef)CFDictionaryGetValue(bundle->_infoDict, kCFBundleIdentifierKey); 1035 _CFBundleRemoveFromTables(bundle, bundleURL, bundleID); 1036 CFBundleUnloadExecutable(bundle); 1037 _CFBundleDeallocatePlugIn(bundle); 1038 if (bundleURL) { 1039 CFRelease(bundleURL); 1040 } 1041 if (bundle->_infoDict && !(0)) CFRelease(bundle->_infoDict); 1042 if (bundle->_modDate) CFRelease(bundle->_modDate); 1043 if (bundle->_localInfoDict && !(0)) CFRelease(bundle->_localInfoDict); 1044 if (bundle->_searchLanguages) CFRelease(bundle->_searchLanguages); 1045 if (bundle->_executablePath) CFRelease(bundle->_executablePath); 1046 if (bundle->_developmentRegion) CFRelease(bundle->_developmentRegion); 1047 if (bundle->_glueDict) { 1048 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle)); 1049 CFRelease(bundle->_glueDict); 1050 } 1051 if (bundle->_resourceData._stringTableCache) CFRelease(bundle->_resourceData._stringTableCache); 1052 1053 if (bundle->_bundleBasePath) CFRelease(bundle->_bundleBasePath); 1054 if (bundle->_queryTable) CFRelease(bundle->_queryTable); 1055 1056 if (bundle->_localizations) CFRelease(bundle->_localizations); 1057 if (bundle->_resourceDirectoryContents) CFRelease(bundle->_resourceDirectoryContents); 1058 1059 pthread_mutex_destroy(&(bundle->_bundleLoadingLock)); 1060} 1061 1062static const CFRuntimeClass __CFBundleClass = { 1063 _kCFRuntimeScannedObject, 1064 "CFBundle", 1065 NULL, // init 1066 NULL, // copy 1067 __CFBundleDeallocate, 1068 NULL, // equal 1069 NULL, // hash 1070 NULL, // 1071 __CFBundleCopyDescription 1072}; 1073 1074// From CFBundle_Resources.c 1075CF_PRIVATE void _CFBundleResourcesInitialize(); 1076 1077CF_PRIVATE void __CFBundleInitialize(void) { 1078 __kCFBundleTypeID = _CFRuntimeRegisterClass(&__CFBundleClass); 1079 _CFBundleResourcesInitialize(); 1080} 1081 1082CFTypeID CFBundleGetTypeID(void) { 1083 return __kCFBundleTypeID; 1084} 1085 1086CFBundleRef _CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL) { 1087 CFBundleRef bundle = NULL; 1088 char buff[CFMaxPathSize]; 1089 CFURLRef newURL = NULL; 1090 1091 if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL; 1092 1093 newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)buff, strlen(buff), true); 1094 if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL); 1095 bundle = _CFBundleCopyBundleForURL(newURL, false); 1096 if (bundle) CFRelease(bundle); 1097 CFRelease(newURL); 1098 return bundle; 1099} 1100 1101static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing) { 1102 CFBundleRef bundle = NULL; 1103 char buff[CFMaxPathSize]; 1104 CFDateRef modDate = NULL; // do not actually fetch the modDate, since that can cause something like 7609956, unless absolutely found to be necessary in the future 1105 Boolean exists = false; 1106 SInt32 mode = 0; 1107 CFURLRef newURL = NULL; 1108 uint8_t localVersion = 0; 1109 1110 if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL; 1111 1112 newURL = CFURLCreateFromFileSystemRepresentation(allocator, (uint8_t *)buff, strlen(buff), true); 1113 if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL); 1114 bundle = _CFBundleCopyBundleForURL(newURL, alreadyLocked); 1115 if (bundle) { 1116 CFRelease(newURL); 1117 return bundle; 1118 } 1119 1120 localVersion = _CFBundleGetBundleVersionForURL(newURL); 1121 if (localVersion == 3) { 1122 SInt32 res = _CFGetPathProperties(allocator, (char *)buff, &exists, &mode, NULL, NULL, NULL, NULL); 1123#if DEPLOYMENT_TARGET_WINDOWS 1124 if (!(res == 0 && exists && ((mode & S_IFMT) == S_IFDIR))) { 1125 // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again 1126 if (modDate) { 1127 CFRelease(modDate); 1128 modDate = NULL; 1129 } 1130 CFURLRef shorterPath = CFURLCreateCopyDeletingLastPathComponent(allocator, newURL); 1131 CFRelease(newURL); 1132 newURL = shorterPath; 1133 res = _CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, NULL, NULL, NULL); 1134 } 1135#endif 1136 if (res == 0) { 1137 if (!exists || ((mode & S_IFMT) != S_IFDIR)) { 1138 if (modDate) CFRelease(modDate); 1139 CFRelease(newURL); 1140 return NULL; 1141 } 1142 } else { 1143 CFRelease(newURL); 1144 return NULL; 1145 } 1146 } 1147 1148 bundle = (CFBundleRef)_CFRuntimeCreateInstance(allocator, __kCFBundleTypeID, sizeof(struct __CFBundle) - sizeof(CFRuntimeBase), NULL); 1149 if (!bundle) { 1150 CFRelease(newURL); 1151 return NULL; 1152 } 1153 1154 bundle->_url = newURL; 1155 1156 bundle->_modDate = modDate; 1157 bundle->_version = localVersion; 1158 bundle->_infoDict = NULL; 1159 bundle->_localInfoDict = NULL; 1160 bundle->_searchLanguages = NULL; 1161 bundle->_executablePath = NULL; 1162 bundle->_developmentRegion = NULL; 1163 bundle->_developmentRegionCalculated = false; 1164#if defined(BINARY_SUPPORT_DYLD) 1165 /* We'll have to figure it out later */ 1166 bundle->_binaryType = __CFBundleUnknownBinary; 1167#elif defined(BINARY_SUPPORT_DLL) 1168 /* We support DLL only */ 1169 bundle->_binaryType = __CFBundleDLLBinary; 1170 bundle->_hModule = NULL; 1171#else 1172 /* We'll have to figure it out later */ 1173 bundle->_binaryType = __CFBundleUnknownBinary; 1174#endif /* BINARY_SUPPORT_DYLD */ 1175 1176 bundle->_isLoaded = false; 1177 bundle->_sharesStringsFiles = false; 1178 1179#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 1180 if (!__CFgetenv("CFBundleDisableStringsSharing") && 1181 (strncmp(buff, "/System/Library/Frameworks", 26) == 0) && 1182 (strncmp(buff + strlen(buff) - 10, ".framework", 10) == 0)) bundle->_sharesStringsFiles = true; 1183#endif 1184 1185 bundle->_connectionCookie = NULL; 1186 bundle->_handleCookie = NULL; 1187 bundle->_imageCookie = NULL; 1188 bundle->_moduleCookie = NULL; 1189 1190 bundle->_glueDict = NULL; 1191 1192 bundle->_resourceData._executableLacksResourceFork = false; 1193 bundle->_resourceData._infoDictionaryFromResourceFork = false; 1194 bundle->_resourceData._stringTableCache = NULL; 1195 1196 bundle->_plugInData._isPlugIn = false; 1197 bundle->_plugInData._loadOnDemand = false; 1198 bundle->_plugInData._isDoingDynamicRegistration = false; 1199 bundle->_plugInData._instanceCount = 0; 1200 bundle->_plugInData._factories = NULL; 1201 1202 pthread_mutexattr_t mattr; 1203 pthread_mutexattr_init(&mattr); 1204 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_DEFAULT); 1205 int32_t mret = pthread_mutex_init(&(bundle->_bundleLoadingLock), &mattr); 1206 pthread_mutexattr_destroy(&mattr); 1207 if (0 != mret) { 1208 CFLog(4, CFSTR("%s: failed to initialize bundle loading lock for bundle %@."), __PRETTY_FUNCTION__, bundle); 1209 } 1210 1211 bundle->_lock = CFSpinLockInit; 1212 bundle->_resourceDirectoryContents = NULL; 1213 1214 bundle->_localizations = NULL; 1215 bundle->_lookedForLocalizations = false; 1216 1217 bundle->_queryLock = CFSpinLockInit; 1218 bundle->_queryTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1219 CFURLRef absoURL = CFURLCopyAbsoluteURL(bundle->_url); 1220 bundle->_bundleBasePath = CFURLCopyFileSystemPath(absoURL, PLATFORM_PATH_STYLE); 1221 CFRelease(absoURL); 1222 1223 CFBundleGetInfoDictionary(bundle); 1224 1225 _CFBundleAddToTables(bundle, alreadyLocked); 1226 1227 if (doFinalProcessing) { 1228 if (_CFBundleNeedsInitPlugIn(bundle)) { 1229 if (alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); 1230 _CFBundleInitPlugIn(bundle); 1231 if (alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); 1232 } 1233 } 1234 1235 return bundle; 1236} 1237 1238CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL) { 1239 return _CFBundleCreate(allocator, bundleURL, false, true); 1240} 1241 1242CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc, CFURLRef directoryURL, CFStringRef bundleType) { 1243 CFMutableArrayRef bundles = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); 1244 CFArrayRef URLs = _CFCreateContentsOfDirectory(alloc, NULL, NULL, directoryURL, bundleType); 1245 if (URLs) { 1246 CFIndex i, c = CFArrayGetCount(URLs); 1247 CFURLRef curURL; 1248 CFBundleRef curBundle; 1249 1250 for (i = 0; i < c; i++) { 1251 curURL = (CFURLRef)CFArrayGetValueAtIndex(URLs, i); 1252 curBundle = CFBundleCreate(alloc, curURL); 1253 if (curBundle) CFArrayAppendValue(bundles, curBundle); 1254 } 1255 CFRelease(URLs); 1256 } 1257 1258 return bundles; 1259} 1260 1261CFURLRef CFBundleCopyBundleURL(CFBundleRef bundle) { 1262 if (bundle->_url) CFRetain(bundle->_url); 1263 return bundle->_url; 1264} 1265 1266#define DEVELOPMENT_STAGE 0x20 1267#define ALPHA_STAGE 0x40 1268#define BETA_STAGE 0x60 1269#define RELEASE_STAGE 0x80 1270 1271#define MAX_VERS_LEN 10 1272 1273CF_INLINE Boolean _isDigit(UniChar aChar) {return ((aChar >= (UniChar)'0' && aChar <= (UniChar)'9') ? true : false);} 1274 1275CF_PRIVATE CFStringRef _CFCreateStringFromVersionNumber(CFAllocatorRef alloc, UInt32 vers) { 1276 CFStringRef result = NULL; 1277 uint8_t major1, major2, minor1, minor2, stage, build; 1278 1279 major1 = (vers & 0xF0000000) >> 28; 1280 major2 = (vers & 0x0F000000) >> 24; 1281 minor1 = (vers & 0x00F00000) >> 20; 1282 minor2 = (vers & 0x000F0000) >> 16; 1283 stage = (vers & 0x0000FF00) >> 8; 1284 build = (vers & 0x000000FF); 1285 1286 if (stage == RELEASE_STAGE) { 1287 if (major1 > 0) { 1288 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d"), major1, major2, minor1, minor2); 1289 } else { 1290 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d"), major2, minor1, minor2); 1291 } 1292 } else { 1293 if (major1 > 0) { 1294 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d%d.%d.%d%c%d"), major1, major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? 'd' : ((stage == ALPHA_STAGE) ? 'a' : 'b')), build); 1295 } else { 1296 result = CFStringCreateWithFormat(alloc, NULL, CFSTR("%d.%d.%d%c%d"), major2, minor1, minor2, ((stage == DEVELOPMENT_STAGE) ? 'd' : ((stage == ALPHA_STAGE) ? 'a' : 'b')), build); 1297 } 1298 } 1299 return result; 1300} 1301 1302CF_PRIVATE UInt32 _CFVersionNumberFromString(CFStringRef versStr) { 1303 // Parse version number from string. 1304 // String can begin with "." for major version number 0. String can end at any point, but elements within the string cannot be skipped. 1305 UInt32 major1 = 0, major2 = 0, minor1 = 0, minor2 = 0, stage = RELEASE_STAGE, build = 0; 1306 UniChar versChars[MAX_VERS_LEN]; 1307 UniChar *chars = NULL; 1308 CFIndex len; 1309 UInt32 theVers; 1310 Boolean digitsDone = false; 1311 1312 if (!versStr) return 0; 1313 len = CFStringGetLength(versStr); 1314 if (len <= 0 || len > MAX_VERS_LEN) return 0; 1315 1316 CFStringGetCharacters(versStr, CFRangeMake(0, len), versChars); 1317 chars = versChars; 1318 1319 // Get major version number. 1320 major1 = major2 = 0; 1321 if (_isDigit(*chars)) { 1322 major2 = *chars - (UniChar)'0'; 1323 chars++; 1324 len--; 1325 if (len > 0) { 1326 if (_isDigit(*chars)) { 1327 major1 = major2; 1328 major2 = *chars - (UniChar)'0'; 1329 chars++; 1330 len--; 1331 if (len > 0) { 1332 if (*chars == (UniChar)'.') { 1333 chars++; 1334 len--; 1335 } else { 1336 digitsDone = true; 1337 } 1338 } 1339 } else if (*chars == (UniChar)'.') { 1340 chars++; 1341 len--; 1342 } else { 1343 digitsDone = true; 1344 } 1345 } 1346 } else if (*chars == (UniChar)'.') { 1347 chars++; 1348 len--; 1349 } else { 1350 digitsDone = true; 1351 } 1352 1353 // Now major1 and major2 contain first and second digit of the major version number as ints. 1354 // Now either len is 0 or chars points at the first char beyond the first decimal point. 1355 1356 // Get the first minor version number. 1357 if (len > 0 && !digitsDone) { 1358 if (_isDigit(*chars)) { 1359 minor1 = *chars - (UniChar)'0'; 1360 chars++; 1361 len--; 1362 if (len > 0) { 1363 if (*chars == (UniChar)'.') { 1364 chars++; 1365 len--; 1366 } else { 1367 digitsDone = true; 1368 } 1369 } 1370 } else { 1371 digitsDone = true; 1372 } 1373 } 1374 1375 // Now minor1 contains the first minor version number as an int. 1376 // Now either len is 0 or chars points at the first char beyond the second decimal point. 1377 1378 // Get the second minor version number. 1379 if (len > 0 && !digitsDone) { 1380 if (_isDigit(*chars)) { 1381 minor2 = *chars - (UniChar)'0'; 1382 chars++; 1383 len--; 1384 } else { 1385 digitsDone = true; 1386 } 1387 } 1388 1389 // Now minor2 contains the second minor version number as an int. 1390 // Now either len is 0 or chars points at the build stage letter. 1391 1392 // Get the build stage letter. We must find 'd', 'a', 'b', or 'f' next, if there is anything next. 1393 if (len > 0) { 1394 if (*chars == (UniChar)'d') { 1395 stage = DEVELOPMENT_STAGE; 1396 } else if (*chars == (UniChar)'a') { 1397 stage = ALPHA_STAGE; 1398 } else if (*chars == (UniChar)'b') { 1399 stage = BETA_STAGE; 1400 } else if (*chars == (UniChar)'f') { 1401 stage = RELEASE_STAGE; 1402 } else { 1403 return 0; 1404 } 1405 chars++; 1406 len--; 1407 } 1408 1409 // Now stage contains the release stage. 1410 // Now either len is 0 or chars points at the build number. 1411 1412 // Get the first digit of the build number. 1413 if (len > 0) { 1414 if (_isDigit(*chars)) { 1415 build = *chars - (UniChar)'0'; 1416 chars++; 1417 len--; 1418 } else { 1419 return 0; 1420 } 1421 } 1422 // Get the second digit of the build number. 1423 if (len > 0) { 1424 if (_isDigit(*chars)) { 1425 build *= 10; 1426 build += *chars - (UniChar)'0'; 1427 chars++; 1428 len--; 1429 } else { 1430 return 0; 1431 } 1432 } 1433 // Get the third digit of the build number. 1434 if (len > 0) { 1435 if (_isDigit(*chars)) { 1436 build *= 10; 1437 build += *chars - (UniChar)'0'; 1438 chars++; 1439 len--; 1440 } else { 1441 return 0; 1442 } 1443 } 1444 1445 // Range check the build number and make sure we exhausted the string. 1446 if (build > 0xFF || len > 0) return 0; 1447 1448 // Build the number 1449 theVers = major1 << 28; 1450 theVers += major2 << 24; 1451 theVers += minor1 << 20; 1452 theVers += minor2 << 16; 1453 theVers += stage << 8; 1454 theVers += build; 1455 1456 return theVers; 1457} 1458 1459UInt32 CFBundleGetVersionNumber(CFBundleRef bundle) { 1460 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); 1461 CFNumberRef versionValue = (CFNumberRef)CFDictionaryGetValue(infoDict, _kCFBundleNumericVersionKey); 1462 if (!versionValue || CFGetTypeID(versionValue) != CFNumberGetTypeID()) return 0; 1463 1464 UInt32 vers = 0; 1465 CFNumberGetValue(versionValue, kCFNumberSInt32Type, &vers); 1466 return vers; 1467} 1468 1469CFStringRef CFBundleGetDevelopmentRegion(CFBundleRef bundle) { 1470 CFStringRef devRegion = NULL; 1471 devRegion = bundle->_developmentRegion; 1472 1473 if (!devRegion && !bundle->_developmentRegionCalculated) { 1474 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); 1475 if (infoDict) { 1476 devRegion = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); 1477 if (devRegion && (CFGetTypeID(devRegion) != CFStringGetTypeID() || CFStringGetLength(devRegion) == 0)) { 1478 devRegion = NULL; 1479 } 1480 } 1481 1482 if (devRegion) bundle->_developmentRegion = (CFStringRef)CFRetain(devRegion); 1483 bundle->_developmentRegionCalculated = true; 1484 } 1485 1486 return devRegion; 1487} 1488 1489Boolean _CFBundleGetHasChanged(CFBundleRef bundle) { 1490 CFDateRef modDate; 1491 Boolean result = false; 1492 Boolean exists = false; 1493 SInt32 mode = 0; 1494 1495 if (_CFGetFileProperties(CFGetAllocator(bundle), bundle->_url, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) { 1496 // If the bundle no longer exists or is not a folder, it must have "changed" 1497 if (!exists || ((mode & S_IFMT) != S_IFDIR)) result = true; 1498 } else { 1499 // Something is wrong. The stat failed. 1500 result = true; 1501 } 1502 if (bundle->_modDate && !CFEqual(bundle->_modDate, modDate)) { 1503 // mod date is different from when we created. 1504 result = true; 1505 } 1506 CFRelease(modDate); 1507 return result; 1508} 1509 1510void _CFBundleSetStringsFilesShared(CFBundleRef bundle, Boolean flag) { 1511 bundle->_sharesStringsFiles = flag; 1512} 1513 1514Boolean _CFBundleGetStringsFilesShared(CFBundleRef bundle) { 1515 return bundle->_sharesStringsFiles; 1516} 1517 1518static Boolean _urlExists(CFURLRef url) { 1519 Boolean exists; 1520 return url && (0 == _CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, NULL, NULL, NULL, NULL, NULL)) && exists; 1521} 1522 1523// This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their 1524// original locations on disk, so checking whether a binary's path exists is no longer sufficient. 1525// For performance reasons, we only call dlopen_preflight() after we've verified that the binary 1526// does not exist at its original path with _urlExists(). 1527// See <rdar://problem/6956670> 1528static Boolean _binaryLoadable(CFURLRef url) { 1529 Boolean loadable = _urlExists(url); 1530#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 1531 if (!loadable) { 1532 uint8_t path[PATH_MAX]; 1533 if (url && CFURLGetFileSystemRepresentation(url, true, path, sizeof(path))) { 1534 loadable = dlopen_preflight((char *)path); 1535 } 1536 } 1537#endif 1538 return loadable; 1539} 1540 1541CF_PRIVATE CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL, uint8_t version) { 1542 CFURLRef result = NULL; 1543 if (bundleURL) { 1544 if (1 == version) { 1545 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase1, bundleURL); 1546 } else if (2 == version) { 1547 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase2, bundleURL); 1548 } else { 1549 result = (CFURLRef)CFRetain(bundleURL); 1550 } 1551 } 1552 return result; 1553} 1554 1555CF_EXPORT CFURLRef CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle) { 1556 return _CFBundleCopySupportFilesDirectoryURLInDirectory(bundle->_url, bundle->_version); 1557} 1558 1559CF_PRIVATE CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL, uint8_t version) { 1560 CFURLRef result = NULL; 1561 if (bundleURL) { 1562 if (0 == version) { 1563 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase0, bundleURL); 1564 } else if (1 == version) { 1565 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase1, bundleURL); 1566 } else if (2 == version) { 1567 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase2, bundleURL); 1568 } else { 1569 result = (CFURLRef)CFRetain(bundleURL); 1570 } 1571 } 1572 return result; 1573} 1574 1575CFURLRef CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) { 1576 return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle->_url, bundle->_version); 1577} 1578 1579CF_PRIVATE CFURLRef _CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL, uint8_t version) { 1580 CFURLRef result = NULL; 1581 if (bundleURL) { 1582 if (0 == version) { 1583 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase0, bundleURL); 1584 } else if (1 == version) { 1585 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase1, bundleURL); 1586 } else if (2 == version) { 1587 result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase2, bundleURL); 1588 } 1589 } 1590 return result; 1591} 1592 1593CFURLRef _CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle) { 1594 return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle->_url, bundle->_version); 1595} 1596 1597static CFURLRef _CFBundleCopyExecutableURLRaw(CFURLRef urlPath, CFStringRef exeName) { 1598 // 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. 1599 CFURLRef executableURL = NULL; 1600 if (!urlPath || !exeName) return NULL; 1601 1602#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 1603 const uint8_t *image_suffix = (uint8_t *)__CFgetenv("DYLD_IMAGE_SUFFIX"); 1604 if (image_suffix) { 1605 CFStringRef newExeName, imageSuffix; 1606 imageSuffix = CFStringCreateWithCString(kCFAllocatorSystemDefault, (char *)image_suffix, kCFStringEncodingUTF8); 1607 if (CFStringHasSuffix(exeName, CFSTR(".dylib"))) { 1608 CFStringRef bareExeName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6)); 1609 newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix); 1610 CFRelease(bareExeName); 1611 } else { 1612 newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, imageSuffix); 1613 } 1614 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, newExeName, kCFURLPOSIXPathStyle, false, urlPath); 1615 if (executableURL && !_binaryLoadable(executableURL)) { 1616 CFRelease(executableURL); 1617 executableURL = NULL; 1618 } 1619 CFRelease(newExeName); 1620 CFRelease(imageSuffix); 1621 } 1622 if (!executableURL) { 1623 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLPOSIXPathStyle, false, urlPath); 1624 if (executableURL && !_binaryLoadable(executableURL)) { 1625 CFRelease(executableURL); 1626 executableURL = NULL; 1627 } 1628 } 1629#elif DEPLOYMENT_TARGET_WINDOWS 1630 if (!executableURL) { 1631 executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLWindowsPathStyle, false, urlPath); 1632 if (executableURL && !_urlExists(executableURL)) { 1633 CFRelease(executableURL); 1634 executableURL = NULL; 1635 } 1636 } 1637 if (!executableURL) { 1638 if (!CFStringFindWithOptions(exeName, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) { 1639#if defined(DEBUG) 1640 CFStringRef extension = CFSTR("_debug.dll"); 1641#else 1642 CFStringRef extension = CFSTR(".dll"); 1643#endif 1644 CFStringRef newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, extension); 1645 executableURL = CFURLCreateWithString(kCFAllocatorSystemDefault, newExeName, urlPath); 1646 if (executableURL && !_binaryLoadable(executableURL)) { 1647 CFRelease(executableURL); 1648 executableURL = NULL; 1649 } 1650 CFRelease(newExeName); 1651 } 1652 } 1653 if (!executableURL) { 1654 if (!CFStringFindWithOptions(exeName, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) { 1655#if defined(DEBUG) 1656 CFStringRef extension = CFSTR("_debug.exe"); 1657#else 1658 CFStringRef extension = CFSTR(".exe"); 1659#endif 1660 CFStringRef newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, extension); 1661 executableURL = CFURLCreateWithString(kCFAllocatorSystemDefault, newExeName, urlPath); 1662 if (executableURL && !_binaryLoadable(executableURL)) { 1663 CFRelease(executableURL); 1664 executableURL = NULL; 1665 } 1666 CFRelease(newExeName); 1667 } 1668 } 1669#endif 1670 return executableURL; 1671} 1672 1673CF_PRIVATE CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) { 1674 CFStringRef executableName = NULL; 1675 1676 if (!infoDict && bundle) infoDict = CFBundleGetInfoDictionary(bundle); 1677 if (!url && bundle) url = bundle->_url; 1678 1679 if (infoDict) { 1680 // Figure out the name of the executable. 1681 // First try for the new key in the plist. 1682 executableName = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleExecutableKey); 1683 // Second try for the old key in the plist. 1684 if (!executableName) executableName = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey); 1685 if (executableName && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) { 1686 CFRetain(executableName); 1687 } else { 1688 executableName = NULL; 1689 } 1690 } 1691 if (!executableName && url) { 1692 // Third, take the name of the bundle itself (with path extension stripped) 1693 CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); 1694 CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); 1695 CFRelease(absoluteURL); 1696 if (bundlePath) { 1697 CFIndex len = CFStringGetLength(bundlePath); 1698 CFIndex startOfBundleName = _CFStartOfLastPathComponent2(bundlePath); 1699 CFIndex endOfBundleName = _CFLengthAfterDeletingPathExtension2(bundlePath); 1700 1701 if (startOfBundleName <= len && endOfBundleName <= len && startOfBundleName < endOfBundleName) { 1702 executableName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, bundlePath, CFRangeMake(startOfBundleName, endOfBundleName - startOfBundleName)); 1703 } 1704 CFRelease(bundlePath); 1705 } 1706 } 1707 1708 return executableName; 1709} 1710 1711static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURLRef url, CFStringRef executableName, Boolean ignoreCache, Boolean useOtherPlatform) { 1712 uint8_t version = 0; 1713 CFDictionaryRef infoDict = NULL; 1714 CFStringRef executablePath = NULL; 1715 CFURLRef executableURL = NULL; 1716 Boolean foundIt = false; 1717 Boolean lookupMainExe = (executableName ? false : true); 1718 1719 if (bundle) { 1720 infoDict = CFBundleGetInfoDictionary(bundle); 1721 version = bundle->_version; 1722 } else { 1723 infoDict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, &version); 1724 } 1725 1726 // If we have a bundle instance and an info dict, see if we have already cached the path 1727 if (lookupMainExe && !ignoreCache && !useOtherPlatform && bundle && bundle->_executablePath) { 1728 __CFSpinLock(&bundle->_lock); 1729 executablePath = bundle->_executablePath; 1730 if (executablePath) CFRetain(executablePath); 1731 __CFSpinUnlock(&bundle->_lock); 1732 if (executablePath) { 1733#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 1734 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLPOSIXPathStyle, false); 1735#elif DEPLOYMENT_TARGET_WINDOWS 1736 executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLWindowsPathStyle, false); 1737#endif 1738 if (executableURL) { 1739 foundIt = true; 1740 } 1741 CFRelease(executablePath); 1742 } 1743 } 1744 1745 if (!foundIt) { 1746 if (lookupMainExe) executableName = _CFBundleCopyExecutableName(bundle, url, infoDict); 1747 if (executableName) { 1748#if (DEPLOYMENT_TARGET_EMBEDDED && !TARGET_IPHONE_SIMULATOR) 1749 Boolean doExecSearch = false; 1750#else 1751 Boolean doExecSearch = true; 1752#endif 1753 // Now, look for the executable inside the bundle. 1754 if (doExecSearch && 0 != version) { 1755 CFURLRef exeDirURL = NULL; 1756 CFURLRef exeSubdirURL; 1757 1758 if (1 == version) { 1759 exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase1, url); 1760 } else if (2 == version) { 1761 exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase2, url); 1762 } else { 1763#if DEPLOYMENT_TARGET_WINDOWS 1764 // On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory 1765 CFStringRef extension = CFURLCopyPathExtension(url); 1766 if (extension && CFEqual(extension, _CFBundleWindowsResourceDirectoryExtension)) { 1767 exeDirURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, url); 1768 } else { 1769 exeDirURL = (CFURLRef)CFRetain(url); 1770 } 1771#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 1772 exeDirURL = (CFURLRef)CFRetain(url); 1773#endif 1774 } 1775 CFStringRef platformSubDir = useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(); 1776 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); 1777 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName); 1778 if (!executableURL) { 1779 CFRelease(exeSubdirURL); 1780 platformSubDir = useOtherPlatform ? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(); 1781 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); 1782 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName); 1783 } 1784 if (!executableURL) { 1785 CFRelease(exeSubdirURL); 1786 platformSubDir = useOtherPlatform ? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(); 1787 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); 1788 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName); 1789 } 1790 if (!executableURL) { 1791 CFRelease(exeSubdirURL); 1792 platformSubDir = useOtherPlatform ? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(); 1793 exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); 1794 executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName); 1795 } 1796 if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName); 1797 CFRelease(exeDirURL); 1798 CFRelease(exeSubdirURL); 1799 } 1800 1801 // If this was an old bundle, or we did not find the executable in the Executables subdirectory, look directly in the bundle wrapper. 1802 if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(url, executableName); 1803 1804#if DEPLOYMENT_TARGET_WINDOWS 1805 // Windows only: If we still haven't found the exe, look in the Executables folder. 1806 // But only for the main bundle exe 1807 if (lookupMainExe && !executableURL) { 1808 CFURLRef exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, CFSTR("../../Executables"), url); 1809 executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName); 1810 CFRelease(exeDirURL); 1811 } 1812#endif 1813 1814 if (lookupMainExe && !ignoreCache && !useOtherPlatform && bundle && executableURL) { 1815 // We found it. Cache the path. 1816 CFURLRef absURL = CFURLCopyAbsoluteURL(executableURL); 1817#if DEPLOYMENT_TARGET_WINDOWS 1818 executablePath = CFURLCopyFileSystemPath(absURL, kCFURLWindowsPathStyle); 1819#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 1820 executablePath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle); 1821#endif 1822 CFRelease(absURL); 1823 __CFSpinLock(&bundle->_lock); 1824 bundle->_executablePath = (CFStringRef)CFRetain(executablePath); 1825 __CFSpinUnlock(&bundle->_lock); 1826 CFRelease(executablePath); 1827 } 1828 if (lookupMainExe && !useOtherPlatform && bundle && !executableURL) bundle->_binaryType = __CFBundleNoBinary; 1829 if (lookupMainExe) CFRelease(executableName); 1830 } 1831 } 1832 if (!bundle && infoDict && !(0)) CFRelease(infoDict); 1833 return executableURL; 1834} 1835 1836 1837CFURLRef _CFBundleCopyExecutableURLInDirectory(CFURLRef url) { 1838 return _CFBundleCopyExecutableURLInDirectory2(NULL, url, NULL, true, false); 1839} 1840 1841CFURLRef _CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url) { 1842 return _CFBundleCopyExecutableURLInDirectory2(NULL, url, NULL, true, true); 1843} 1844 1845CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle) { 1846 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, NULL, false, false); 1847} 1848 1849static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle) { 1850 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, NULL, true, false); 1851} 1852 1853CFURLRef CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle, CFStringRef executableName) { 1854 return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, executableName, true, false); 1855} 1856 1857Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle) { 1858 return bundle->_isLoaded; 1859} 1860 1861CFBundleExecutableType CFBundleGetExecutableType(CFBundleRef bundle) { 1862 CFBundleExecutableType result = kCFBundleOtherExecutableType; 1863 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 1864 1865 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary; 1866#if defined(BINARY_SUPPORT_DYLD) 1867 if (bundle->_binaryType == __CFBundleUnknownBinary) { 1868 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); 1869 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true; 1870 } 1871#endif /* BINARY_SUPPORT_DYLD */ 1872 if (executableURL) CFRelease(executableURL); 1873 1874 if (bundle->_binaryType == __CFBundleCFMBinary) { 1875 result = kCFBundlePEFExecutableType; 1876 } else if (bundle->_binaryType == __CFBundleDYLDExecutableBinary || bundle->_binaryType == __CFBundleDYLDBundleBinary || bundle->_binaryType == __CFBundleDYLDFrameworkBinary) { 1877 result = kCFBundleMachOExecutableType; 1878 } else if (bundle->_binaryType == __CFBundleDLLBinary) { 1879 result = kCFBundleDLLExecutableType; 1880 } else if (bundle->_binaryType == __CFBundleELFBinary) { 1881 result = kCFBundleELFExecutableType; 1882 } 1883 return result; 1884} 1885 1886static SInt32 _CFBundleCurrentArchitecture(void) { 1887 SInt32 arch = 0; 1888#if defined(__ppc__) 1889 arch = kCFBundleExecutableArchitecturePPC; 1890#elif defined(__ppc64__) 1891 arch = kCFBundleExecutableArchitecturePPC64; 1892#elif defined(__i386__) 1893 arch = kCFBundleExecutableArchitectureI386; 1894#elif defined(__x86_64__) 1895 arch = kCFBundleExecutableArchitectureX86_64; 1896#elif defined(BINARY_SUPPORT_DYLD) 1897 const NXArchInfo *archInfo = NXGetLocalArchInfo(); 1898 if (archInfo) arch = archInfo->cputype; 1899#endif 1900 return arch; 1901} 1902 1903#define UNKNOWN_FILETYPE 0x0 1904#define PEF_FILETYPE 0x1000 1905#define PEF_MAGIC 0x4a6f7921 1906#define PEF_CIGAM 0x21796f4a 1907#define TEXT_SEGMENT "__TEXT" 1908#define PLIST_SECTION "__info_plist" 1909#define OBJC_SEGMENT "__OBJC" 1910#define IMAGE_INFO_SECTION "__image_info" 1911#define OBJC_SEGMENT_64 "__DATA" 1912#define IMAGE_INFO_SECTION_64 "__objc_imageinfo" 1913#define LIB_X11 "/usr/X11R6/lib/libX" 1914 1915#define XLS_NAME "Book" 1916#define XLS_NAME2 "Workbook" 1917#define DOC_NAME "WordDocument" 1918#define PPT_NAME "PowerPoint Document" 1919 1920#define ustrncmp(x, y, z) strncmp((char *)(x), (char *)(y), (z)) 1921#define ustrncasecmp(x, y, z) strncasecmp_l((char *)(x), (char *)(y), (z), NULL) 1922 1923static const uint32_t __CFBundleMagicNumbersArray[] = { 1924 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0xfeedfacf, 0xcffaedfe, 0x4a6f7921, 0x21796f4a, 1925 0x7f454c46, 0xffd8ffe0, 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, 1926 0x7b5c7274, 0x25504446, 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, 1927 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435, 1928 0x53495444, 0x53747566, 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x3d796265, 1929 0x6b6f6c79, 0x3026b275, 0x0000000c, 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143, 1930 0x00010000, 0x74727565, 0x4f54544f, 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70, 1931 0x3c435058, 0x28445746, 0x424f4d53, 0x49544f4c, 0x72746664, 0x63616666, 0x802a5fd7, 0x762f3101 1932}; 1933 1934// string, with groups of 5 characters being 1 element in the array 1935static const char * __CFBundleExtensionsArray = 1936 "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" 1937 "elf\0\0" "jpeg\0" "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" 1938 "rtf\0\0" "pdf\0\0" "ra\0\0\0""rm\0\0\0""au\0\0\0""au\0\0\0""iff\0\0" "riff\0" 1939 "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" 1940 "sit\0\0" "sit\0\0" "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""ync\0\0" 1941 "dmg\0\0" "wmv\0\0" "jp2\0\0" "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0" 1942 "ttf\0\0" "ttf\0\0" "otf\0\0" "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0" 1943 "cpx\0\0" "dwf\0\0" "bom\0\0" "lit\0\0" "rtfd\0" "caf\0\0" "cin\0\0" "exr\0\0"; 1944 1945static const char * __CFBundleOOExtensionsArray = "sxc\0\0" "sxd\0\0" "sxg\0\0" "sxi\0\0" "sxm\0\0" "sxw\0\0"; 1946static const char * __CFBundleODExtensionsArray = "odc\0\0" "odf\0\0" "odg\0\0" "oth\0\0" "odi\0\0" "odm\0\0" "odp\0\0" "ods\0\0" "odt\0\0"; 1947 1948#define EXTENSION_LENGTH 5 1949#define NUM_EXTENSIONS 64 1950#define MAGIC_BYTES_TO_READ 512 1951#define DMG_BYTES_TO_READ 512 1952#define ZIP_BYTES_TO_READ 1024 1953#define OLE_BYTES_TO_READ 512 1954#define X11_BYTES_TO_READ 4096 1955#define IMAGE_INFO_BYTES_TO_READ 4096 1956 1957#if defined(BINARY_SUPPORT_DYLD) 1958 1959CF_INLINE uint32_t _CFBundleSwapInt32Conditional(uint32_t arg, Boolean swap) {return swap ? CFSwapInt32(arg) : arg;} 1960CF_INLINE uint32_t _CFBundleSwapInt64Conditional(uint64_t arg, Boolean swap) {return swap ? CFSwapInt64(arg) : arg;} 1961 1962static CFMutableDictionaryRef _CFBundleCreateInfoDictFromData(const char *bytes, uint32_t length) { 1963 CFMutableDictionaryRef result = NULL; 1964 CFDataRef infoData = NULL; 1965 if (bytes && 0 < length) { 1966 infoData = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (uint8_t *)bytes, length, kCFAllocatorNull); 1967 if (infoData) { 1968 result = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, infoData, kCFPropertyListMutableContainers, NULL); 1969 if (result && CFDictionaryGetTypeID() != CFGetTypeID(result)) { 1970 CFRelease(result); 1971 result = NULL; 1972 } 1973 CFRelease(infoData); 1974 } 1975 if (!result) result = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1976 } 1977 if (result) _CFBundleInfoPlistProcessInfoDictionary((CFMutableDictionaryRef)result); 1978 return result; 1979} 1980 1981static char *_CFBundleGetSectData(const char *segname, const char *sectname, unsigned long *size) { 1982 char *retval = NULL; 1983 unsigned long localSize = 0; 1984 uint32_t i, numImages = _dyld_image_count(); 1985 const void *mhp = (const void *)_NSGetMachExecuteHeader(); 1986 1987 for (i = 0; i < numImages; i++) { 1988 if (mhp == (void *)_dyld_get_image_header(i)) { 1989#if __LP64__ 1990 const struct section_64 *sp = getsectbynamefromheader_64((const struct mach_header_64 *)mhp, segname, sectname); 1991 if (sp) { 1992 retval = (char *)(sp->addr + _dyld_get_image_vmaddr_slide(i)); 1993 localSize = (unsigned long)sp->size; 1994 } 1995#else /* __LP64__ */ 1996 const struct section *sp = getsectbynamefromheader((const struct mach_header *)mhp, segname, sectname); 1997 if (sp) { 1998 retval = (char *)(sp->addr + _dyld_get_image_vmaddr_slide(i)); 1999 localSize = (unsigned long)sp->size; 2000 } 2001#endif /* __LP64__ */ 2002 break; 2003 } 2004 } 2005 if (size) *size = localSize; 2006 return retval; 2007} 2008 2009static CFMutableDictionaryRef _CFBundleCreateInfoDictFromMainExecutable() { 2010 char *bytes = NULL; 2011 unsigned long length = 0; 2012 if (getsegbyname(TEXT_SEGMENT)) bytes = _CFBundleGetSectData(TEXT_SEGMENT, PLIST_SECTION, &length); 2013 return _CFBundleCreateInfoDictFromData(bytes, length); 2014} 2015 2016static Boolean _CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion, uint32_t *objcFlags) { 2017 Boolean retval = false; 2018 uint32_t localVersion = 0, localFlags = 0; 2019 char *bytes = NULL; 2020 unsigned long length = 0; 2021#if __LP64__ 2022 if (getsegbyname(OBJC_SEGMENT_64)) bytes = _CFBundleGetSectData(OBJC_SEGMENT_64, IMAGE_INFO_SECTION_64, &length); 2023#else /* __LP64__ */ 2024 if (getsegbyname(OBJC_SEGMENT)) bytes = _CFBundleGetSectData(OBJC_SEGMENT, IMAGE_INFO_SECTION, &length); 2025#endif /* __LP64__ */ 2026 if (bytes && length >= 8) { 2027 localVersion = *(uint32_t *)bytes; 2028 localFlags = *(uint32_t *)(bytes + 4); 2029 retval = true; 2030 } 2031 if (objcVersion) *objcVersion = localVersion; 2032 if (objcFlags) *objcFlags = localFlags; 2033 return retval; 2034} 2035 2036static Boolean _CFBundleGrokX11FromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) { 2037 static const char libX11name[] = LIB_X11; 2038 char *buffer = NULL; 2039 const char *loc = NULL; 2040 unsigned i; 2041 Boolean result = false; 2042 2043 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { 2044 buffer = malloc(X11_BYTES_TO_READ); 2045 if (buffer && read(fd, buffer, X11_BYTES_TO_READ) >= X11_BYTES_TO_READ) loc = buffer; 2046 } else if (bytes && length >= offset + X11_BYTES_TO_READ) { 2047 loc = bytes + offset; 2048 } 2049 if (loc) { 2050 if (sixtyFour) { 2051 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->ncmds, swapped); 2052 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->sizeofcmds, swapped); 2053 const char *startofcmds = loc + sizeof(struct mach_header_64); 2054 const char *endofcmds = startofcmds + sizeofcmds; 2055 struct dylib_command *dlp = (struct dylib_command *)startofcmds; 2056 if (endofcmds > loc + X11_BYTES_TO_READ) endofcmds = loc + X11_BYTES_TO_READ; 2057 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) { 2058 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) { 2059 uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped); 2060 const char *name = (const char *)dlp + nameoffset; 2061 if (startofcmds <= name && name + sizeof(libX11name) <= endofcmds && 0 == strncmp(name, libX11name, sizeof(libX11name) - 1)) result = true; 2062 } 2063 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped)); 2064 } 2065 } else { 2066 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->ncmds, swapped); 2067 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->sizeofcmds, swapped); 2068 const char *startofcmds = loc + sizeof(struct mach_header); 2069 const char *endofcmds = startofcmds + sizeofcmds; 2070 struct dylib_command *dlp = (struct dylib_command *)startofcmds; 2071 if (endofcmds > loc + X11_BYTES_TO_READ) endofcmds = loc + X11_BYTES_TO_READ; 2072 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) { 2073 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) { 2074 uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped); 2075 const char *name = (const char *)dlp + nameoffset; 2076 if (startofcmds <= name && name + sizeof(libX11name) <= endofcmds && 0 == strncmp(name, libX11name, sizeof(libX11name) - 1)) result = true; 2077 } 2078 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped)); 2079 } 2080 } 2081 } 2082 if (buffer) free(buffer); 2083 return result; 2084} 2085 2086static CFDictionaryRef _CFBundleCreateInfoDictFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) { 2087 struct statinfo statBuf; 2088 off_t fileLength = 0; 2089 char *maploc = NULL; 2090 const char *loc; 2091 unsigned i, j; 2092 CFDictionaryRef result = NULL; 2093 Boolean foundit = false; 2094 if (fd >= 0 && fstat(fd, &statBuf) == 0 && (maploc = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != (void *)-1) { 2095 loc = maploc; 2096 fileLength = statBuf.st_size; 2097 } else { 2098 loc = bytes; 2099 fileLength = length; 2100 } 2101 if (fileLength > offset + sizeof(struct mach_header_64)) { 2102 if (sixtyFour) { 2103 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->ncmds, swapped); 2104 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->sizeofcmds, swapped); 2105 const char *startofcmds = loc + offset + sizeof(struct mach_header_64); 2106 const char *endofcmds = startofcmds + sizeofcmds; 2107 struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds; 2108 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength; 2109 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { 2110 if (LC_SEGMENT_64 == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { 2111 struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64)); 2112 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); 2113 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { 2114 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, TEXT_SEGMENT, sizeof(sp->segname))) { 2115 uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped); 2116 uint32_t sectlength = (uint32_t)(sectlength64 & 0xffffffff); 2117 uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); 2118 const char *sectbytes = loc + offset + sectoffset; 2119 // we don't support huge-sized plists 2120 if (sectlength64 <= 0xffffffff && loc <= sectbytes && sectbytes + sectlength <= loc + fileLength) result = (CFDictionaryRef)_CFBundleCreateInfoDictFromData(sectbytes, sectlength); 2121 foundit = true; 2122 } 2123 sp = (struct section_64 *)((char *)sp + sizeof(struct section_64)); 2124 } 2125 } 2126 sgp = (struct segment_command_64 *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); 2127 } 2128 } else { 2129 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->ncmds, swapped); 2130 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->sizeofcmds, swapped); 2131 const char *startofcmds = loc + offset + sizeof(struct mach_header); 2132 const char *endofcmds = startofcmds + sizeofcmds; 2133 struct segment_command *sgp = (struct segment_command *)startofcmds; 2134 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength; 2135 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { 2136 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { 2137 struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command)); 2138 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); 2139 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { 2140 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, TEXT_SEGMENT, sizeof(sp->segname))) { 2141 uint32_t sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped); 2142 uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); 2143 const char *sectbytes = loc + offset + sectoffset; 2144 if (loc <= sectbytes && sectbytes + sectlength <= loc + fileLength) result = (CFDictionaryRef)_CFBundleCreateInfoDictFromData(sectbytes, sectlength); 2145 foundit = true; 2146 } 2147 sp = (struct section *)((char *)sp + sizeof(struct section)); 2148 } 2149 } 2150 sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); 2151 } 2152 } 2153 } 2154 if (maploc) munmap(maploc, statBuf.st_size); 2155 return result; 2156} 2157 2158static void _CFBundleGrokObjcImageInfoFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { 2159 uint32_t sectlength = 0, sectoffset = 0, localVersion = 0, localFlags = 0; 2160 char *buffer = NULL; 2161 char sectbuffer[8]; 2162 const char *loc = NULL; 2163 unsigned i, j; 2164 Boolean foundit = false, localHasObjc = false; 2165 2166 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { 2167 buffer = malloc(IMAGE_INFO_BYTES_TO_READ); 2168 if (buffer && read(fd, buffer, IMAGE_INFO_BYTES_TO_READ) >= IMAGE_INFO_BYTES_TO_READ) loc = buffer; 2169 } else if (bytes && length >= offset + IMAGE_INFO_BYTES_TO_READ) { 2170 loc = bytes + offset; 2171 } 2172 if (loc) { 2173 if (sixtyFour) { 2174 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->ncmds, swapped); 2175 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->sizeofcmds, swapped); 2176 const char *startofcmds = loc + sizeof(struct mach_header_64); 2177 const char *endofcmds = startofcmds + sizeofcmds; 2178 struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds; 2179 if (endofcmds > loc + IMAGE_INFO_BYTES_TO_READ) endofcmds = loc + IMAGE_INFO_BYTES_TO_READ; 2180 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { 2181 if (LC_SEGMENT_64 == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { 2182 struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64)); 2183 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); 2184 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { 2185 if (0 == strncmp(sp->segname, OBJC_SEGMENT_64, sizeof(sp->segname))) localHasObjc = true; 2186 if (0 == strncmp(sp->sectname, IMAGE_INFO_SECTION_64, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, OBJC_SEGMENT_64, sizeof(sp->segname))) { 2187 uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped); 2188 sectlength = (uint32_t)(sectlength64 & 0xffffffff); 2189 sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); 2190 foundit = true; 2191 } 2192 sp = (struct section_64 *)((char *)sp + sizeof(struct section_64)); 2193 } 2194 } 2195 sgp = (struct segment_command_64 *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); 2196 } 2197 } else { 2198 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->ncmds, swapped); 2199 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->sizeofcmds, swapped); 2200 const char *startofcmds = loc + sizeof(struct mach_header); 2201 const char *endofcmds = startofcmds + sizeofcmds; 2202 struct segment_command *sgp = (struct segment_command *)startofcmds; 2203 if (endofcmds > loc + IMAGE_INFO_BYTES_TO_READ) endofcmds = loc + IMAGE_INFO_BYTES_TO_READ; 2204 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { 2205 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { 2206 struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command)); 2207 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); 2208 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { 2209 if (0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) localHasObjc = true; 2210 if (0 == strncmp(sp->sectname, IMAGE_INFO_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) { 2211 sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped); 2212 sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); 2213 foundit = true; 2214 } 2215 sp = (struct section *)((char *)sp + sizeof(struct section)); 2216 } 2217 } 2218 sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); 2219 } 2220 } 2221 if (sectlength >= 8) { 2222 if (fd >= 0 && lseek(fd, offset + sectoffset, SEEK_SET) == (off_t)(offset + sectoffset) && read(fd, sectbuffer, 8) >= 8) { 2223 localVersion = _CFBundleSwapInt32Conditional(*(uint32_t *)sectbuffer, swapped); 2224 localFlags = _CFBundleSwapInt32Conditional(*(uint32_t *)(sectbuffer + 4), swapped); 2225 } else if (bytes && length >= offset + sectoffset + 8) { 2226 localVersion = _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes + offset + sectoffset), swapped); 2227 localFlags = _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes + offset + sectoffset + 4), swapped); 2228 } 2229 } 2230 } 2231 if (buffer) free(buffer); 2232 if (hasObjc) *hasObjc = localHasObjc; 2233 if (objcVersion) *objcVersion = localVersion; 2234 if (objcFlags) *objcFlags = localFlags; 2235} 2236 2237static UInt32 _CFBundleGrokMachTypeForFatFile(int fd, const void *bytes, CFIndex length, Boolean swap, Boolean *isX11, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { 2238 CFIndex headerLength = length; 2239 unsigned char headerBuffer[MAGIC_BYTES_TO_READ]; 2240 UInt32 machtype = UNKNOWN_FILETYPE, magic, numFatHeaders, maxFatHeaders, i; 2241 unsigned char buffer[sizeof(struct mach_header_64)]; 2242 const unsigned char *moreBytes = NULL; 2243 const NXArchInfo *archInfo = NXGetLocalArchInfo(); 2244 SInt32 curArch = _CFBundleCurrentArchitecture(); 2245 2246 struct fat_arch *fat = NULL; 2247 2248 if (isX11) *isX11 = false; 2249 if (architectures) *architectures = NULL; 2250 if (infodict) *infodict = NULL; 2251 if (hasObjc) *hasObjc = false; 2252 if (objcVersion) *objcVersion = 0; 2253 if (objcFlags) *objcFlags = 0; 2254 2255 if (headerLength > MAGIC_BYTES_TO_READ) headerLength = MAGIC_BYTES_TO_READ; 2256 (void)memmove(headerBuffer, bytes, headerLength); 2257 if (swap) { 2258 for (i = 0; i < headerLength; i += 4) *(UInt32 *)(headerBuffer + i) = CFSwapInt32(*(UInt32 *)(headerBuffer + i)); 2259 } 2260 numFatHeaders = ((struct fat_header *)headerBuffer)->nfat_arch; 2261 maxFatHeaders = (headerLength - sizeof(struct fat_header)) / sizeof(struct fat_arch); 2262 if (numFatHeaders > maxFatHeaders) numFatHeaders = maxFatHeaders; 2263 if (numFatHeaders > 0) { 2264 if (archInfo) fat = NXFindBestFatArch(archInfo->cputype, archInfo->cpusubtype, (struct fat_arch *)(headerBuffer + sizeof(struct fat_header)), numFatHeaders); 2265 if (!fat && curArch != 0) fat = NXFindBestFatArch((cpu_type_t)curArch, (cpu_subtype_t)0, (struct fat_arch *)(headerBuffer + sizeof(struct fat_header)), numFatHeaders); 2266 if (!fat) fat = (struct fat_arch *)(headerBuffer + sizeof(struct fat_header)); 2267 if (architectures) { 2268 CFMutableArrayRef mutableArchitectures = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 2269 for (i = 0; i < numFatHeaders; i++) { 2270 CFNumberRef architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, headerBuffer + sizeof(struct fat_header) + i * sizeof(struct fat_arch)); 2271 if (CFArrayGetFirstIndexOfValue(mutableArchitectures, CFRangeMake(0, CFArrayGetCount(mutableArchitectures)), architecture) < 0) CFArrayAppendValue(mutableArchitectures, architecture); 2272 CFRelease(architecture); 2273 } 2274 *architectures = (CFArrayRef)mutableArchitectures; 2275 } 2276 } 2277 if (fat) { 2278 if (fd >= 0 && lseek(fd, fat->offset, SEEK_SET) == (off_t)fat->offset && read(fd, buffer, sizeof(struct mach_header_64)) >= (int)sizeof(struct mach_header_64)) { 2279 moreBytes = buffer; 2280 } else if (bytes && (uint32_t)length >= fat->offset + sizeof(struct mach_header_64)) { 2281 moreBytes = bytes + fat->offset; 2282 } 2283 if (moreBytes) { 2284 magic = *((UInt32 *)moreBytes); 2285 if (MH_MAGIC == magic) { 2286 machtype = ((struct mach_header *)moreBytes)->filetype; 2287 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, false, false); 2288 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, fat->offset, false, false); 2289 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, false, false, hasObjc, objcVersion, objcFlags); 2290 } else if (MH_CIGAM == magic) { 2291 machtype = CFSwapInt32(((struct mach_header *)moreBytes)->filetype); 2292 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, true, false); 2293 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, fat->offset, true, false); 2294 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, true, false, hasObjc, objcVersion, objcFlags); 2295 } else if (MH_MAGIC_64 == magic) { 2296 machtype = ((struct mach_header_64 *)moreBytes)->filetype; 2297 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, false, true); 2298 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, fat->offset, false, true); 2299 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, false, true, hasObjc, objcVersion, objcFlags); 2300 } else if (MH_CIGAM_64 == magic) { 2301 machtype = CFSwapInt32(((struct mach_header_64 *)moreBytes)->filetype); 2302 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, true, true); 2303 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, fat->offset, true, true); 2304 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, true, true, hasObjc, objcVersion, objcFlags); 2305 } 2306 } 2307 } 2308 return machtype; 2309} 2310 2311static UInt32 _CFBundleGrokMachType(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { 2312 unsigned int magic = *((UInt32 *)bytes), machtype = UNKNOWN_FILETYPE, cputype; 2313 CFNumberRef architecture = NULL; 2314 2315 if (isX11) *isX11 = false; 2316 if (architectures) *architectures = NULL; 2317 if (infodict) *infodict = NULL; 2318 if (hasObjc) *hasObjc = false; 2319 if (objcVersion) *objcVersion = 0; 2320 if (objcFlags) *objcFlags = 0; 2321 if (MH_MAGIC == magic) { 2322 machtype = ((struct mach_header *)bytes)->filetype; 2323 cputype = ((struct mach_header *)bytes)->cputype; 2324 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype); 2325 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, false, false); 2326 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, 0, false, false); 2327 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, false, false, hasObjc, objcVersion, objcFlags); 2328 } else if (MH_CIGAM == magic) { 2329 machtype = CFSwapInt32(((struct mach_header *)bytes)->filetype); 2330 cputype = CFSwapInt32(((struct mach_header *)bytes)->cputype); 2331 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype); 2332 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, true, false); 2333 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, 0, true, false); 2334 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, true, false, hasObjc, objcVersion, objcFlags); 2335 } else if (MH_MAGIC_64 == magic) { 2336 machtype = ((struct mach_header_64 *)bytes)->filetype; 2337 cputype = ((struct mach_header_64 *)bytes)->cputype; 2338 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype); 2339 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, false, true); 2340 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, 0, false, true); 2341 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, false, true, hasObjc, objcVersion, objcFlags); 2342 } else if (MH_CIGAM_64 == magic) { 2343 machtype = CFSwapInt32(((struct mach_header_64 *)bytes)->filetype); 2344 cputype = CFSwapInt32(((struct mach_header_64 *)bytes)->cputype); 2345 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype); 2346 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, true, true); 2347 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, 0, true, true); 2348 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, true, true, hasObjc, objcVersion, objcFlags); 2349 } else if (FAT_MAGIC == magic) { 2350 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, false, isX11, architectures, infodict, hasObjc, objcVersion, objcFlags); 2351 } else if (FAT_CIGAM == magic) { 2352 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, true, isX11, architectures, infodict, hasObjc, objcVersion, objcFlags); 2353 } else if (PEF_MAGIC == magic || PEF_CIGAM == magic) { 2354 machtype = PEF_FILETYPE; 2355 } 2356 if (architectures && architecture) *architectures = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&architecture, 1, &kCFTypeArrayCallBacks); 2357 if (architecture) CFRelease(architecture); 2358 return machtype; 2359} 2360 2361#endif /* BINARY_SUPPORT_DYLD */ 2362 2363static Boolean _CFBundleGrokFileTypeForZipMimeType(const unsigned char *bytes, CFIndex length, const char **ext) { 2364 unsigned namelength = CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 26))), extralength = CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 28))); 2365 const unsigned char *data = bytes + 30 + namelength + extralength; 2366 int i = -1; 2367 if (bytes < data && data + 56 <= bytes + length && 0 == CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 8))) && (0 == ustrncasecmp(data, "application/vnd.", 16) || 0 == ustrncasecmp(data, "application/x-vnd.", 18))) { 2368 data += ('.' == *(data + 15)) ? 16 : 18; 2369 if (0 == ustrncasecmp(data, "sun.xml.", 8)) { 2370 data += 8; 2371 if (0 == ustrncasecmp(data, "calc", 4)) i = 0; 2372 else if (0 == ustrncasecmp(data, "draw", 4)) i = 1; 2373 else if (0 == ustrncasecmp(data, "writer.global", 13)) i = 2; 2374 else if (0 == ustrncasecmp(data, "impress", 7)) i = 3; 2375 else if (0 == ustrncasecmp(data, "math", 4)) i = 4; 2376 else if (0 == ustrncasecmp(data, "writer", 6)) i = 5; 2377 if (i >= 0 && ext) *ext = __CFBundleOOExtensionsArray + i * EXTENSION_LENGTH; 2378 } else if (0 == ustrncasecmp(data, "oasis.opendocument.", 19)) { 2379 data += 19; 2380 if (0 == ustrncasecmp(data, "chart", 5)) i = 0; 2381 else if (0 == ustrncasecmp(data, "formula", 7)) i = 1; 2382 else if (0 == ustrncasecmp(data, "graphics", 8)) i = 2; 2383 else if (0 == ustrncasecmp(data, "text-web", 8)) i = 3; 2384 else if (0 == ustrncasecmp(data, "image", 5)) i = 4; 2385 else if (0 == ustrncasecmp(data, "text-master", 11)) i = 5; 2386 else if (0 == ustrncasecmp(data, "presentation", 12)) i = 6; 2387 else if (0 == ustrncasecmp(data, "spreadsheet", 11)) i = 7; 2388 else if (0 == ustrncasecmp(data, "text", 4)) i = 8; 2389 if (i >= 0 && ext) *ext = __CFBundleODExtensionsArray + i * EXTENSION_LENGTH; 2390 } 2391 } else if (bytes < data && data + 41 <= bytes + length && 8 == CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 8))) && 0x4b2c28c8 == CFSwapInt32HostToBig(*((UInt32 *)data)) && 0xc94c4e2c == CFSwapInt32HostToBig(*((UInt32 *)(data + 4)))) { 2392 // AbiWord compressed mimetype odt 2393 if (ext) *ext = "odt"; 2394 // almost certainly this should set i to 0 but I don't want to upset the apple cart now 2395 } else if (bytes < data && data + 29 <= bytes + length && (0 == ustrncasecmp(data, "application/oebps-package+xml", 29))) { 2396 // epub, official epub 3 mime type 2397 if (ext) *ext = "epub"; 2398 i = 0; 2399 } else if (bytes < data && data + 20 <= bytes + length && (0 == ustrncasecmp(data, "application/epub+zip", 20))) { 2400 // epub, unofficial epub 2 mime type 2401 if (ext) *ext = "epub"; 2402 i = 0; 2403 } 2404 return (i >= 0); 2405} 2406 2407static const char *_CFBundleGrokFileTypeForZipFile(int fd, const unsigned char *bytes, CFIndex length, off_t fileLength) { 2408 const char *ext = "zip"; 2409 const unsigned char *moreBytes = NULL; 2410 unsigned char *buffer = NULL; 2411 CFIndex i; 2412 Boolean foundMimetype = false, hasMetaInf = false, hasContentXML = false, hasManifestMF = false, hasManifestXML = false, hasRels = false, hasContentTypes = false, hasWordDocument = false, hasExcelDocument = false, hasPowerPointDocument = false, hasOPF = false, hasSMIL = false; 2413 2414 if (bytes) { 2415 for (i = 0; !foundMimetype && i + 30 < length; i++) { 2416 if (0x50 == bytes[i] && 0x4b == bytes[i + 1]) { 2417 unsigned namelength = 0, offset = 0; 2418 if (0x01 == bytes[i + 2] && 0x02 == bytes[i + 3]) { 2419 namelength = (unsigned)CFSwapInt16HostToLittle(*((UInt16 *)(bytes + i + 28))); 2420 offset = 46; 2421 } else if (0x03 == bytes[i + 2] && 0x04 == bytes[i + 3]) { 2422 namelength = (unsigned)CFSwapInt16HostToLittle(*((UInt16 *)(bytes + i + 26))); 2423 offset = 30; 2424 } 2425 if (offset > 0 && (CFIndex)(i + offset + namelength) <= length) { 2426 //printf("%.*s\n", namelength, bytes + i + offset); 2427 if (8 == namelength && 30 == offset && 0 == ustrncasecmp(bytes + i + offset, "mimetype", 8)) foundMimetype = _CFBundleGrokFileTypeForZipMimeType(bytes + i, length - i, &ext); 2428 else if (9 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/", 9)) hasMetaInf = true; 2429 else if (11 == namelength && 0 == ustrncasecmp(bytes + i + offset, "content.xml", 11)) hasContentXML = true; 2430 else if (11 == namelength && 0 == ustrncasecmp(bytes + i + offset, "_rels/.rels", 11)) hasRels = true; 2431 else if (19 == namelength && 0 == ustrncasecmp(bytes + i + offset, "[Content_Types].xml", 19)) hasContentTypes = true; 2432 else if (20 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/MANIFEST.MF", 20)) hasManifestMF = true; 2433 else if (21 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/manifest.xml", 21)) hasManifestXML = true; 2434 else if (4 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".opf", 4)) hasOPF = true; 2435 else if (4 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".sml", 4)) hasSMIL = true; 2436 else if (5 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 5, ".smil", 5)) hasSMIL = true; 2437 else if (7 < namelength && 0 == ustrncasecmp(bytes + i + offset, "xl/", 3) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; 2438 else if (8 < namelength && 0 == ustrncasecmp(bytes + i + offset, "ppt/", 4) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; 2439 else if (9 < namelength && 0 == ustrncasecmp(bytes + i + offset, "word/", 5) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasWordDocument = true; 2440 else if (10 < namelength && 0 == ustrncasecmp(bytes + i + offset, "excel/", 6) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; 2441 else if (15 < namelength && 0 == ustrncasecmp(bytes + i + offset, "powerpoint/", 11) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; 2442 i += offset + namelength - 1; 2443 } 2444 } 2445 } 2446 } 2447 if (!foundMimetype) { 2448 if (fileLength >= ZIP_BYTES_TO_READ) { 2449 if (fd >= 0 && lseek(fd, fileLength - ZIP_BYTES_TO_READ, SEEK_SET) == fileLength - ZIP_BYTES_TO_READ) { 2450 buffer = (unsigned char *)malloc(ZIP_BYTES_TO_READ); 2451 if (buffer && read(fd, buffer, ZIP_BYTES_TO_READ) >= ZIP_BYTES_TO_READ) moreBytes = buffer; 2452 } else if (bytes && length >= ZIP_BYTES_TO_READ) { 2453 moreBytes = bytes + length - ZIP_BYTES_TO_READ; 2454 } 2455 } 2456 if (moreBytes) { 2457 for (i = 0; i + 30 < ZIP_BYTES_TO_READ; i++) { 2458 if (0x50 == moreBytes[i] && 0x4b == moreBytes[i + 1]) { 2459 unsigned namelength = 0, offset = 0; 2460 if (0x01 == moreBytes[i + 2] && 0x02 == moreBytes[i + 3]) { 2461 namelength = CFSwapInt16HostToLittle(*((UInt16 *)(moreBytes + i + 28))); 2462 offset = 46; 2463 } else if (0x03 == moreBytes[i + 2] && 0x04 == moreBytes[i + 3]) { 2464 namelength = CFSwapInt16HostToLittle(*((UInt16 *)(moreBytes + i + 26))); 2465 offset = 30; 2466 } 2467 if (offset > 0 && i + offset + namelength <= ZIP_BYTES_TO_READ) { 2468 //printf("%.*s\n", namelength, moreBytes + i + offset); 2469 if (9 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/", 9)) hasMetaInf = true; 2470 else if (11 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "content.xml", 11)) hasContentXML = true; 2471 else if (11 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "_rels/.rels", 11)) hasRels = true; 2472 else if (19 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "[Content_Types].xml", 19)) hasContentTypes = true; 2473 else if (20 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/MANIFEST.MF", 20)) hasManifestMF = true; 2474 else if (21 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/manifest.xml", 21)) hasManifestXML = true; 2475 else if (4 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".opf", 4)) hasOPF = true; 2476 else if (4 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".sml", 4)) hasSMIL = true; 2477 else if (5 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 5, ".smil", 5)) hasSMIL = true; 2478 else if (7 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "xl/", 3) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; 2479 else if (8 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "ppt/", 4) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; 2480 else if (9 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "word/", 5) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasWordDocument = true; 2481 else if (10 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "excel/", 6) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; 2482 else if (15 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "powerpoint/", 11) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; 2483 i += offset + namelength - 1; 2484 } 2485 } 2486 } 2487 } 2488 //printf("hasManifestMF %d hasManifestXML %d hasContentXML %d hasRels %d hasContentTypes %d hasWordDocument %d hasExcelDocument %d hasPowerPointDocument %d hasMetaInf %d hasOPF %d hasSMIL %d\n", hasManifestMF, hasManifestXML, hasContentXML, hasRels, hasContentTypes, hasWordDocument, hasExcelDocument, hasPowerPointDocument, hasMetaInf, hasOPF, hasSMIL); 2489 if (hasManifestMF) ext = "jar"; 2490 else if ((hasRels || hasContentTypes) && hasWordDocument) ext = "docx"; 2491 else if ((hasRels || hasContentTypes) && hasExcelDocument) ext = "xlsx"; 2492 else if ((hasRels || hasContentTypes) && hasPowerPointDocument) ext = "pptx"; 2493 else if (hasManifestXML || hasContentXML) ext = "odt"; 2494 else if (hasMetaInf) ext = "jar"; 2495 else if (hasOPF && hasSMIL) ext = "dtb"; 2496 else if (hasOPF) ext = "oeb"; 2497 2498 if (buffer) free(buffer); 2499 } 2500 return ext; 2501} 2502 2503static Boolean _CFBundleCheckOLEName(const char *name, const char *bytes, unsigned length) { 2504 Boolean retval = true; 2505 unsigned j; 2506 for (j = 0; retval && j < length; j++) if (bytes[2 * j] != name[j]) retval = false; 2507 return retval; 2508} 2509 2510static const char *_CFBundleGrokFileTypeForOLEFile(int fd, const void *bytes, CFIndex length, off_t offset) { 2511 const char *ext = "ole", *moreBytes = NULL; 2512 char *buffer = NULL; 2513 2514 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { 2515 buffer = (char *)malloc(OLE_BYTES_TO_READ); 2516 if (buffer && read(fd, buffer, OLE_BYTES_TO_READ) >= OLE_BYTES_TO_READ) moreBytes = buffer; 2517 } else if (bytes && length >= offset + OLE_BYTES_TO_READ) { 2518 moreBytes = (char *)bytes + offset; 2519 } 2520 if (moreBytes) { 2521 Boolean foundit = false; 2522 unsigned i; 2523 for (i = 0; !foundit && i < 4; i++) { 2524 char namelength = moreBytes[128 * i + 64] / 2; 2525 foundit = true; 2526 if (sizeof(XLS_NAME) == namelength && _CFBundleCheckOLEName(XLS_NAME, moreBytes + 128 * i, namelength - 1)) ext = "xls"; 2527 else if (sizeof(XLS_NAME2) == namelength && _CFBundleCheckOLEName(XLS_NAME2, moreBytes + 128 * i, namelength - 1)) ext = "xls"; 2528 else if (sizeof(DOC_NAME) == namelength && _CFBundleCheckOLEName(DOC_NAME, moreBytes + 128 * i, namelength - 1)) ext = "doc"; 2529 else if (sizeof(PPT_NAME) == namelength && _CFBundleCheckOLEName(PPT_NAME, moreBytes + 128 * i, namelength - 1)) ext = "ppt"; 2530 else foundit = false; 2531 } 2532 } 2533 if (buffer) free(buffer); 2534 return ext; 2535} 2536 2537static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef *extension, UInt32 *machtype, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { 2538 int fd = -1; 2539 const unsigned char *bytes = NULL; 2540 unsigned char buffer[MAGIC_BYTES_TO_READ]; 2541 CFIndex i, length = 0; 2542 off_t fileLength = 0; 2543 const char *ext = NULL; 2544 UInt32 mt = UNKNOWN_FILETYPE; 2545#if defined(BINARY_SUPPORT_DYLD) 2546 Boolean isX11 = false; 2547#endif /* BINARY_SUPPORT_DYLD */ 2548 Boolean isFile = false, isPlain = true, isZero = true, isSpace = true, hasBOM = false; 2549 // extensions returned: o, tool, x11app, pef, core, dylib, bundle, elf, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, rtfd, pdf, ra, rm, au, aiff, aifc, caf, wav, avi, wmv, ogg, flac, psd, mpeg, mid, zip, jar, sit, cpio, html, ps, mov, qtif, ttf, otf, sfont, bmp, hqx, bin, class, tar, txt, gz, Z, uu, ync, bz, bz2, sh, pl, py, rb, dvi, sgi, tga, mp3, xml, plist, xls, doc, ppt, mp4, m4a, m4b, m4p, m4v, 3gp, 3g2, dmg, cwk, webarchive, dwg, dgn, pfa, pfb, afm, tfm, xcf, cpx, dwf, swf, swc, abw, bom, lit, svg, rdf, x3d, oeb, dtb, docx, xlsx, pptx, sxc, sxd, sxg, sxi, sxm, sxw, odc, odf, odg, oth, odi, odm, odp, ods, cin, exr 2550 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf 2551 // ??? we do not distinguish between ordinary documents and template versions (often there is no difference in file contents) 2552 // ??? the distinctions between docx, xlsx, and pptx may not be entirely reliable 2553 if (architectures) *architectures = NULL; 2554 if (infodict) *infodict = NULL; 2555 if (hasObjc) *hasObjc = false; 2556 if (objcVersion) *objcVersion = 0; 2557 if (objcFlags) *objcFlags = 0; 2558 if (url) { 2559 Boolean gotPath = FALSE; 2560 char path[CFMaxPathSize]; 2561 gotPath = CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize); 2562 struct statinfo statBuf; 2563 if (gotPath && stat(path, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG && (fd = open(path, O_RDONLY | CF_OPENFLGS, 0777)) >= 0) { 2564 length = read(fd, buffer, MAGIC_BYTES_TO_READ); 2565 fileLength = statBuf.st_size; 2566 bytes = buffer; 2567 isFile = true; 2568 } 2569 } 2570 if (!isFile && data) { 2571 length = CFDataGetLength(data); 2572 fileLength = (off_t)length; 2573 bytes = CFDataGetBytePtr(data); 2574 if (length == 0) ext = "txt"; 2575 } 2576 if (bytes) { 2577 if (length >= 4) { 2578 UInt32 magic = CFSwapInt32HostToBig(*((UInt32 *)bytes)); 2579 for (i = 0; !ext && i < NUM_EXTENSIONS; i++) { 2580 if (__CFBundleMagicNumbersArray[i] == magic) ext = __CFBundleExtensionsArray + i * EXTENSION_LENGTH; 2581 } 2582 if (ext) { 2583 if (0xcafebabe == magic && 8 <= length && 0 != *((UInt16 *)(bytes + 4))) ext = "class"; 2584#if defined(BINARY_SUPPORT_DYLD) 2585 else if ((int)sizeof(struct mach_header_64) <= length) mt = _CFBundleGrokMachType(fd, bytes, length, extension ? &isX11 : NULL, architectures, infodict, hasObjc, objcVersion, objcFlags); 2586 2587 if (MH_OBJECT == mt) ext = "o"; 2588 else if (MH_EXECUTE == mt) ext = isX11 ? "x11app" : "tool"; 2589 else if (PEF_FILETYPE == mt) ext = "pef"; 2590 else if (MH_CORE == mt) ext = "core"; 2591 else if (MH_DYLIB == mt) ext = "dylib"; 2592 else if (MH_BUNDLE == mt) ext = "bundle"; 2593#endif /* BINARY_SUPPORT_DYLD */ 2594 else if (0x7b5c7274 == magic && (6 > length || 'f' != bytes[4])) ext = NULL; 2595 else if (0x25504446 == magic && (6 > length || '-' != bytes[4])) ext = NULL; 2596 else if (0x00010000 == magic && (6 > length || 0 != bytes[4])) ext = NULL; 2597 else if (0x47494638 == magic && (6 > length || (0x3761 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4)))))) ext = NULL; 2598 else if (0x0000000c == magic && (6 > length || 0x6a50 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL; 2599 else if (0x2356524d == magic && (6 > length || 0x4c20 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL; 2600 else if (0x28445746 == magic && (6 > length || 0x2056 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL; 2601 else if (0x30373037 == magic && (6 > length || 0x30 != bytes[4] || !isdigit(bytes[5]))) ext = NULL; 2602 else if (0x41433130 == magic && (6 > length || 0x31 != bytes[4] || !isdigit(bytes[5]))) ext = NULL; 2603 else if (0x89504e47 == magic && (8 > length || 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 2604 else if (0x53747566 == magic && (8 > length || 0x66497420 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 2605 else if (0x3026b275 == magic && (8 > length || 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 2606 else if (0x67696d70 == magic && (8 > length || 0x20786366 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 2607 else if (0x424f4d53 == magic && (8 > length || 0x746f7265 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 2608 else if (0x49544f4c == magic && (8 > length || 0x49544c53 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 2609 else if (0x72746664 == magic && (8 > length || 0x00000000 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 2610 else if (0x3d796265 == magic && (12 > length || 0x67696e20 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || (0x6c696e65 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))) && 0x70617274 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))))) ext = NULL; 2611 else if (0x63616666 == magic && (12 > length || 0 != bytes[4] || 0x64657363 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))))) ext = NULL; 2612 else if (0x504b0304 == magic) ext = _CFBundleGrokFileTypeForZipFile(fd, bytes, length, fileLength); 2613 else if (0x25215053 == magic) { 2614 if (11 <= length && 0 == ustrncmp(bytes + 4, "-Adobe-", 7)) ext = "ps"; 2615 else if (14 <= length && 0 == ustrncmp(bytes + 4, "-AdobeFont", 10)) ext = "pfa"; 2616 else ext = NULL; 2617 } else if (0x464f524d == magic) { 2618 // IFF 2619 ext = NULL; 2620 if (12 <= length) { 2621 UInt32 iffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))); 2622 if (0x41494646 == iffMagic) ext = "aiff"; 2623 else if (0x414946 == iffMagic) ext = "aifc"; 2624 } 2625 } else if (0x52494646 == magic) { 2626 // RIFF 2627 ext = NULL; 2628 if (12 <= length) { 2629 UInt32 riffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))); 2630 if (0x57415645 == riffMagic) ext = "wav"; 2631 else if (0x41564920 == riffMagic) ext = "avi"; 2632 } 2633 } else if (0xd0cf11e0 == magic) { 2634 // OLE 2635 if (52 <= length) ext = _CFBundleGrokFileTypeForOLEFile(fd, bytes, length, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 48))))); 2636 } else if (0x62656769 == magic) { 2637 // uu 2638 ext = NULL; 2639 if (76 <= length && 'n' == bytes[4] && ' ' == bytes[5] && isdigit(bytes[6]) && isdigit(bytes[7]) && isdigit(bytes[8]) && ' ' == bytes[9]) { 2640 CFIndex endOfLine = 0; 2641 for (i = 10; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i; 2642 if (10 <= endOfLine && endOfLine + 62 < length && 'M' == bytes[endOfLine + 1] && '\n' == bytes[endOfLine + 62]) { 2643 ext = "uu"; 2644 for (i = endOfLine + 1; ext && i < endOfLine + 62; i++) if (!isprint(bytes[i])) ext = NULL; 2645 } 2646 } 2647 } 2648 } 2649 if (extension && !ext) { 2650 UInt16 shortMagic = CFSwapInt16HostToBig(*((UInt16 *)bytes)); 2651 if (5 <= length && 0 == bytes[3] && 0 == bytes[4] && ((1 == bytes[1] && 1 == (0xf7 & bytes[2])) || (0 == bytes[1] && (2 == (0xf7 & bytes[2]) || (3 == (0xf7 & bytes[2])))))) ext = "tga"; 2652 else if (8 <= length && (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "mov"; 2653 else if (8 <= length && (0x69647363 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "qtif"; 2654 else if (8 <= length && 0x424f424f == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) ext = "cwk"; 2655 else if (8 <= length && 0x62706c69 == magic && 0x7374 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && isdigit(bytes[6]) && isdigit(bytes[7])) { 2656 for (i = 8; !ext && i < 128 && i + 16 <= length; i++) { 2657 if (0 == ustrncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive"; 2658 } 2659 if (!ext) ext = "plist"; 2660 } else if (0 == shortMagic && 12 <= length && 0x66747970 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) { 2661 // ??? may want more ftyp values 2662 UInt32 ftyp = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))); 2663 if (0x6d703431 == ftyp || 0x6d703432 == ftyp || 0x69736f6d == ftyp || 0x69736f32 == ftyp) ext = "mp4"; 2664 else if (0x4d344120 == ftyp) ext = "m4a"; 2665 else if (0x4d344220 == ftyp) ext = "m4b"; 2666 else if (0x4d345020 == ftyp) ext = "m4p"; 2667 else if (0x4d345620 == ftyp || 0x4d345648 == ftyp || 0x4d345650 == ftyp) ext = "m4v"; 2668 else if (0x3367 == (ftyp >> 16)) { 2669 UInt16 remainder = (ftyp & 0xffff); 2670 if (0x6536 == remainder || 0x6537 == remainder || 0x6736 == remainder || 0x7034 == remainder || 0x7035 == remainder || 0x7036 == remainder || 0x7236 == remainder || 0x7336 == remainder || 0x7337 == remainder) ext = "3gp"; 2671 else if (0x3261 == remainder) ext = "3g2"; 2672 } 2673 } else if (0x424d == shortMagic && 18 <= length) { 2674 UInt32 btyp = CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 14))); 2675 if (40 == btyp || btyp == 12 || btyp == 64 || btyp == 108 || btyp == 124) ext = "bmp"; 2676 } else if (20 <= length && 0 == ustrncmp(bytes + 6, "%!PS-AdobeFont", 14)) ext = "pfb"; 2677 else if (40 <= length && 0x42696e48 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 38)))) ext = "hqx"; 2678 else if (128 <= length && 0x6d42494e == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 102)))) ext = "bin"; 2679 else if (128 <= length && 0 == bytes[0] && 0 < bytes[1] && bytes[1] < 64 && 0 == bytes[74] && 0 == bytes[82] && 0 == (fileLength % 128)) { 2680 UInt32 df = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 83))), rf = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 87))), blocks = 1 + (df + 127) / 128 + (rf + 127) / 128; 2681 if (df < 0x00800000 && rf < 0x00800000 && 1 < blocks && (off_t)(128 * blocks) == fileLength) ext = "bin"; 2682 } else if (265 <= length && 0x75737461 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 261))))) ext = "tar"; 2683 else if (0xfeff == shortMagic || 0xfffe == shortMagic) { 2684 ext = "txt"; 2685 if (12 <= length && ((0x3cfeff == *((UInt32 *)bytes) && 0x740068 == *((UInt32 *)(bytes + 4)) && 0x6c006d == *((UInt32 *)(bytes + 8))) || (0xfffe3c00 == *((UInt32 *)bytes) && 0x68007400 == *((UInt32 *)(bytes + 4)) && 0x6d006c00 == *((UInt32 *)(bytes + 8))))) ext = "html"; 2686 } else if (0x1f9d == shortMagic) ext = "Z"; 2687 else if (0x1f8b == shortMagic) ext = "gz"; 2688 else if (0x71c7 == shortMagic || 0xc771 == shortMagic) ext = "cpio"; 2689 else if (0xf702 == shortMagic) ext = "dvi"; 2690 else if (0x01da == shortMagic && (0 == bytes[2] || 1 == bytes[2]) && (0 < bytes[3] && 16 > bytes[3])) ext = "sgi"; 2691 else if (0x2321 == shortMagic) { 2692 CFIndex endOfLine = 0, lastSlash = 0; 2693 for (i = 2; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i; 2694 if (endOfLine > 3) { 2695 for (i = endOfLine - 1; 0 == lastSlash && i > 1; i--) if ('/' == bytes[i]) lastSlash = i; 2696 if (lastSlash > 0) { 2697 if (0 == ustrncmp(bytes + lastSlash + 1, "perl", 4)) ext = "pl"; 2698 else if (0 == ustrncmp(bytes + lastSlash + 1, "python", 6)) ext = "py"; 2699 else if (0 == ustrncmp(bytes + lastSlash + 1, "ruby", 4)) ext = "rb"; 2700 else ext = "sh"; 2701 } 2702 } 2703 } else if (0xffd8 == shortMagic && 0xff == bytes[2]) ext = "jpeg"; 2704 else if (0x4657 == shortMagic && 0x53 == bytes[2]) ext = "swf"; 2705 else if (0x4357 == shortMagic && 0x53 == bytes[2]) ext = "swc"; 2706 else if (0x4944 == shortMagic && '3' == bytes[2] && 0x20 > bytes[3]) ext = "mp3"; 2707 else if (0x425a == shortMagic && isdigit(bytes[2]) && isdigit(bytes[3])) ext = "bz"; 2708 else if (0x425a == shortMagic && 'h' == bytes[2] && isdigit(bytes[3]) && 8 <= length && (0x31415926 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "bz2"; 2709 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2)))) ext = "tfm"; 2710 } 2711 } 2712 if (extension && !ext) { 2713 //??? what about MacOSRoman? 2714 if (0xef == bytes[0] && 0xbb == bytes[1] && 0xbf == bytes[2]) { // UTF-8 BOM 2715 hasBOM = true; 2716 isZero = false; 2717 } 2718 for (i = (hasBOM ? 3 : 0); (isPlain || isZero) && !ext && i < length && i < 512; i++) { 2719 char c = bytes[i]; 2720 if (isPlain && '<' == c && i + 14 <= length && 0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html"; 2721 if (isSpace && '<' == c && i + 14 <= length) { 2722 if (0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13) || 0 == ustrncasecmp(bytes + i + 1, "head", 4) || 0 == ustrncasecmp(bytes + i + 1, "title", 5) || 0 == ustrncasecmp(bytes + i + 1, "script", 6) || 0 == ustrncasecmp(bytes + i + 1, "html", 4)) { 2723 ext = "html"; 2724 } else if (0 == ustrncasecmp(bytes + i + 1, "?xml", 4)) { 2725 for (i += 4; !ext && i < 128 && i + 20 <= length; i++) { 2726 if ('<' == bytes[i]) { 2727 if (0 == ustrncasecmp(bytes + i + 1, "abiword", 7)) ext = "abw"; 2728 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype svg", 12)) ext = "svg"; 2729 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype rdf", 12)) ext = "rdf"; 2730 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype x3d", 12)) ext = "x3d"; 2731 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html"; 2732 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype posingfont", 19)) ext = "sfont"; 2733 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype plist", 14)) { 2734 for (i += 14; !ext && i < 256 && i + 16 <= length; i++) { 2735 if (0 == ustrncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive"; 2736 } 2737 if (!ext) ext = "plist"; 2738 } 2739 } 2740 } 2741 if (!ext) ext = "xml"; 2742 } 2743 } 2744 if (0 != c) isZero = false; 2745 if (isZero || 0x7f <= c || (0x20 > c && !isspace(c))) isPlain = false; 2746 if (isZero || !isspace(c)) isSpace = false; 2747 } 2748 if (!ext) { 2749 if (isPlain) { 2750 if (16 <= length && 0 == ustrncmp(bytes, "StartFontMetrics", 16)) ext = "afm"; 2751 else ext = "txt"; 2752 } else if (isZero && length >= MAGIC_BYTES_TO_READ && fileLength >= 526) { 2753 if (isFile) { 2754 if (lseek(fd, 512, SEEK_SET) == 512 && read(fd, buffer, MAGIC_BYTES_TO_READ) >= 14) { 2755 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(buffer + 10)))) ext = "pict"; 2756 } 2757 } else { 2758 if (526 <= length && 0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 522)))) ext = "pict"; 2759 } 2760 } 2761 } 2762 } 2763 if (extension && (!ext || 0 == strcmp(ext, "bz2")) && length >= MAGIC_BYTES_TO_READ && fileLength >= DMG_BYTES_TO_READ) { 2764 if (isFile) { 2765 if (lseek(fd, fileLength - DMG_BYTES_TO_READ, SEEK_SET) == fileLength - DMG_BYTES_TO_READ && read(fd, buffer, DMG_BYTES_TO_READ) >= DMG_BYTES_TO_READ) { 2766 if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)buffer)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + DMG_BYTES_TO_READ - 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + DMG_BYTES_TO_READ - 4))))) ext = "dmg"; 2767 } 2768 } else { 2769 if (DMG_BYTES_TO_READ <= length && (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - DMG_BYTES_TO_READ))) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 4)))))) ext = "dmg"; 2770 } 2771 } 2772 } 2773 if (extension) *extension = ext ? CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault, ext, kCFStringEncodingUTF8, kCFAllocatorNull) : NULL; 2774 if (machtype) *machtype = mt; 2775 if (fd >= 0) close(fd); 2776 return (ext ? true : false); 2777} 2778 2779CFStringRef _CFBundleCopyFileTypeForFileURL(CFURLRef url) { 2780 CFStringRef extension = NULL; 2781 (void)_CFBundleGrokFileType(url, NULL, &extension, NULL, NULL, NULL, NULL, NULL, NULL); 2782 return extension; 2783} 2784 2785CFStringRef _CFBundleCopyFileTypeForFileData(CFDataRef data) { 2786 CFStringRef extension = NULL; 2787 (void)_CFBundleGrokFileType(NULL, data, &extension, NULL, NULL, NULL, NULL, NULL, NULL); 2788 return extension; 2789} 2790 2791CF_PRIVATE CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url) { 2792 CFDictionaryRef result = NULL; 2793 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, &result, NULL, NULL, NULL); 2794 return result; 2795} 2796 2797CF_PRIVATE CFArrayRef _CFBundleCopyArchitecturesForExecutable(CFURLRef url) { 2798 CFArrayRef result = NULL; 2799 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, &result, NULL, NULL, NULL, NULL); 2800 return result; 2801} 2802 2803#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 2804static Boolean _CFBundleGetObjCImageInfoForExecutable(CFURLRef url, uint32_t *objcVersion, uint32_t *objcFlags) { 2805 Boolean retval = false; 2806 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, NULL, &retval, objcVersion, objcFlags); 2807 return retval; 2808} 2809#endif 2810 2811#if defined(BINARY_SUPPORT_DYLD) 2812 2813CF_PRIVATE __CFPBinaryType _CFBundleGrokBinaryType(CFURLRef executableURL) { 2814 // 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. 2815 __CFPBinaryType result = executableURL ? __CFBundleUnreadableBinary : __CFBundleNoBinary; 2816 UInt32 machtype = UNKNOWN_FILETYPE; 2817 if (_CFBundleGrokFileType(executableURL, NULL, NULL, &machtype, NULL, NULL, NULL, NULL, NULL)) { 2818 switch (machtype) { 2819 case MH_EXECUTE: 2820 result = __CFBundleDYLDExecutableBinary; 2821 break; 2822 case MH_BUNDLE: 2823 result = __CFBundleDYLDBundleBinary; 2824 break; 2825 case MH_DYLIB: 2826 result = __CFBundleDYLDFrameworkBinary; 2827 break; 2828 case PEF_FILETYPE: 2829 result = __CFBundleCFMBinary; 2830 break; 2831 } 2832 } 2833 return result; 2834} 2835 2836#endif /* BINARY_SUPPORT_DYLD */ 2837 2838void _CFBundleSetCFMConnectionID(CFBundleRef bundle, void *connectionID) { 2839 bundle->_connectionCookie = connectionID; 2840 bundle->_isLoaded = true; 2841} 2842 2843static CFStringRef _CFBundleCopyLastPathComponent(CFBundleRef bundle) { 2844 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle); 2845 if (!bundleURL) { 2846 return CFSTR("<unknown>"); 2847 } 2848 CFStringRef str = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle); 2849 UniChar buff[CFMaxPathSize]; 2850 CFIndex buffLen = CFStringGetLength(str), startOfLastDir = 0; 2851 2852 CFRelease(bundleURL); 2853 if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize; 2854 CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff); 2855 CFRelease(str); 2856 if (buffLen > 0) startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen); 2857 return CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir); 2858} 2859 2860static CFErrorRef _CFBundleCreateErrorDebug(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code, CFStringRef debugString) { 2861 const void *userInfoKeys[6], *userInfoValues[6]; 2862 CFIndex numKeys = 0; 2863 CFURLRef bundleURL = CFBundleCopyBundleURL(bundle), absoluteURL = CFURLCopyAbsoluteURL(bundleURL), executableURL = CFBundleCopyExecutableURL(bundle); 2864 CFBundleRef bdl = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation")); 2865 CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE), executablePath = executableURL ? CFURLCopyFileSystemPath(executableURL, PLATFORM_PATH_STYLE) : NULL, descFormat = NULL, desc = NULL, reason = NULL, suggestion = NULL; 2866 CFErrorRef error; 2867 if (bdl) { 2868 CFStringRef name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey); 2869 name = name ? (CFStringRef)CFRetain(name) : _CFBundleCopyLastPathComponent(bundle); 2870 if (CFBundleExecutableNotFoundError == code) { 2871 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable couldn\\U2019t be located."), "NSFileNoSuchFileError"); 2872 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable couldn\\U2019t be located."), "NSFileNoSuchFileError"); 2873 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError"); 2874 } else if (CFBundleExecutableNotLoadableError == code) { 2875 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because its executable isn\\U2019t loadable."), "NSExecutableNotLoadableError"); 2876 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable isn\\U2019t loadable."), "NSExecutableNotLoadableError"); 2877 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError"); 2878 } else if (CFBundleExecutableArchitectureMismatchError == code) { 2879 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError"); 2880 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl, CFSTR("The bundle doesn\\U2019t contain a version for the current architecture."), "NSExecutableArchitectureMismatchError"); 2881 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError"); 2882 } else if (CFBundleExecutableRuntimeMismatchError == code) { 2883 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it isn\\U2019t compatible with the current application."), "NSExecutableRuntimeMismatchError"); 2884 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl, CFSTR("The bundle isn\\U2019t compatible with this application."), "NSExecutableRuntimeMismatchError"); 2885 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError"); 2886 } else if (CFBundleExecutableLoadError == code) { 2887 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded because it is damaged or missing necessary resources."), "NSExecutableLoadError"); 2888 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError"); 2889 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError"); 2890 } else if (CFBundleExecutableLinkError == code) { 2891 descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d couldn\\U2019t be loaded."), "NSExecutableLinkError"); 2892 reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl, CFSTR("The bundle couldn\\U2019t be loaded."), "NSExecutableLinkError"); 2893 suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError"); 2894 } 2895 if (descFormat) { 2896 desc = CFStringCreateWithFormat(allocator, NULL, descFormat, name); 2897 CFRelease(descFormat); 2898 } 2899 CFRelease(name); 2900 } 2901 if (bundlePath) { 2902 userInfoKeys[numKeys] = CFSTR("NSBundlePath"); 2903 userInfoValues[numKeys] = bundlePath; 2904 numKeys++; 2905 } 2906 if (executablePath) { 2907 userInfoKeys[numKeys] = CFSTR("NSFilePath"); 2908 userInfoValues[numKeys] = executablePath; 2909 numKeys++; 2910 } 2911 if (desc) { 2912 userInfoKeys[numKeys] = kCFErrorLocalizedDescriptionKey; 2913 userInfoValues[numKeys] = desc; 2914 numKeys++; 2915 } 2916 if (reason) { 2917 userInfoKeys[numKeys] = kCFErrorLocalizedFailureReasonKey; 2918 userInfoValues[numKeys] = reason; 2919 numKeys++; 2920 } 2921 if (suggestion) { 2922 userInfoKeys[numKeys] = kCFErrorLocalizedRecoverySuggestionKey; 2923 userInfoValues[numKeys] = suggestion; 2924 numKeys++; 2925 } 2926 if (debugString) { 2927 userInfoKeys[numKeys] = CFSTR("NSDebugDescription"); 2928 userInfoValues[numKeys] = debugString; 2929 numKeys++; 2930 } 2931 error = CFErrorCreateWithUserInfoKeysAndValues(allocator, kCFErrorDomainCocoa, code, userInfoKeys, userInfoValues, numKeys); 2932 if (bundleURL) CFRelease(bundleURL); 2933 if (absoluteURL) CFRelease(absoluteURL); 2934 if (executableURL) CFRelease(executableURL); 2935 if (bundlePath) CFRelease(bundlePath); 2936 if (executablePath) CFRelease(executablePath); 2937 if (desc) CFRelease(desc); 2938 if (reason) CFRelease(reason); 2939 if (suggestion) CFRelease(suggestion); 2940 return error; 2941} 2942 2943CFErrorRef _CFBundleCreateError(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code) { 2944 return _CFBundleCreateErrorDebug(allocator, bundle, code, NULL); 2945} 2946 2947Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) { 2948 Boolean result = false; 2949 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); 2950 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 2951 2952 2953 pthread_mutex_lock(&(bundle->_bundleLoadingLock)); 2954 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary; 2955 // make sure we know whether bundle is already loaded or not 2956#if defined(BINARY_SUPPORT_DLFCN) 2957 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle); 2958#elif defined(BINARY_SUPPORT_DYLD) 2959 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle); 2960#endif /* BINARY_SUPPORT_DLFCN */ 2961#if defined(BINARY_SUPPORT_DYLD) 2962 // We might need to figure out what it is 2963 if (bundle->_binaryType == __CFBundleUnknownBinary) { 2964 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); 2965 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true; 2966 } 2967#endif /* BINARY_SUPPORT_DYLD */ 2968 if (executableURL) CFRelease(executableURL); 2969 2970 if (bundle->_isLoaded) { 2971 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 2972 // Remove from the scheduled unload set if we are there. 2973 pthread_mutex_lock(&CFBundleGlobalDataLock); 2974#if AVOID_WEAK_COLLECTIONS 2975 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); 2976#else /* AVOID_WEAK_COLLECTIONS */ 2977 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle]; 2978#endif /* AVOID_WEAK_COLLECTIONS */ 2979 pthread_mutex_unlock(&CFBundleGlobalDataLock); 2980 return true; 2981 } 2982 2983 // Unload bundles scheduled for unloading 2984 if (!_scheduledBundlesAreUnloading) { 2985 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 2986 _CFBundleUnloadScheduledBundles(); 2987 pthread_mutex_lock(&(bundle->_bundleLoadingLock)); 2988 } 2989 2990 if (bundle->_isLoaded) { 2991 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 2992 // Remove from the scheduled unload set if we are there. 2993 pthread_mutex_lock(&CFBundleGlobalDataLock); 2994#if AVOID_WEAK_COLLECTIONS 2995 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); 2996#else /* AVOID_WEAK_COLLECTIONS */ 2997 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle]; 2998#endif /* AVOID_WEAK_COLLECTIONS */ 2999 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3000 return true; 3001 } 3002 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 3003 3004 switch (bundle->_binaryType) { 3005#if defined(BINARY_SUPPORT_DLFCN) 3006 case __CFBundleUnreadableBinary: 3007 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError); 3008 break; 3009#endif /* BINARY_SUPPORT_DLFCN */ 3010#if defined(BINARY_SUPPORT_DYLD) 3011 case __CFBundleDYLDBundleBinary: 3012#if defined(BINARY_SUPPORT_DLFCN) 3013 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError); 3014#else /* BINARY_SUPPORT_DLFCN */ 3015 result = _CFBundleDYLDLoadBundle(bundle, forceGlobal, subError); 3016#endif /* BINARY_SUPPORT_DLFCN */ 3017 break; 3018 case __CFBundleDYLDFrameworkBinary: 3019#if defined(BINARY_SUPPORT_DLFCN) 3020 result = _CFBundleDlfcnLoadFramework(bundle, subError); 3021#else /* BINARY_SUPPORT_DLFCN */ 3022 result = _CFBundleDYLDLoadFramework(bundle, subError); 3023#endif /* BINARY_SUPPORT_DLFCN */ 3024 break; 3025 case __CFBundleDYLDExecutableBinary: 3026 if (error) { 3027 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); 3028 } else { 3029 CFLog(__kCFLogBundle, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle); 3030 } 3031 break; 3032#endif /* BINARY_SUPPORT_DYLD */ 3033#if defined(BINARY_SUPPORT_DLFCN) 3034 case __CFBundleUnknownBinary: 3035 case __CFBundleELFBinary: 3036 result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError); 3037 break; 3038#endif /* BINARY_SUPPORT_DLFCN */ 3039#if defined(BINARY_SUPPORT_DLL) 3040 case __CFBundleDLLBinary: 3041 result = _CFBundleDLLLoad(bundle, subError); 3042 break; 3043#endif /* BINARY_SUPPORT_DLL */ 3044 case __CFBundleNoBinary: 3045 if (error) { 3046 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); 3047 } else { 3048 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for %@"), bundle); 3049 } 3050 break; 3051 default: 3052 if (error) { 3053 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); 3054 } else { 3055 CFLog(__kCFLogBundle, CFSTR("Cannot recognize type of executable for %@"), bundle); 3056 } 3057 break; 3058 } 3059 if (result && bundle->_plugInData._isPlugIn) _CFBundlePlugInLoaded(bundle); 3060 if (!result && error) *error = localError; 3061 return result; 3062} 3063 3064Boolean CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, CFErrorRef *error) { 3065 return _CFBundleLoadExecutableAndReturnError(bundle, false, error); 3066} 3067 3068Boolean CFBundleLoadExecutable(CFBundleRef bundle) { 3069 return _CFBundleLoadExecutableAndReturnError(bundle, false, NULL); 3070} 3071 3072Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) { 3073 Boolean result = false; 3074 CFErrorRef localError = NULL; 3075#if defined(BINARY_SUPPORT_DLFCN) 3076 CFErrorRef *subError = (error ? &localError : NULL); 3077#endif 3078 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 3079 3080 pthread_mutex_lock(&(bundle->_bundleLoadingLock)); 3081 if (!executableURL) bundle->_binaryType = __CFBundleNoBinary; 3082 // make sure we know whether bundle is already loaded or not 3083#if defined(BINARY_SUPPORT_DLFCN) 3084 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle); 3085#elif defined(BINARY_SUPPORT_DYLD) 3086 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle); 3087#endif /* BINARY_SUPPORT_DLFCN */ 3088#if defined(BINARY_SUPPORT_DYLD) 3089 // We might need to figure out what it is 3090 if (bundle->_binaryType == __CFBundleUnknownBinary) { 3091 bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); 3092 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true; 3093 } 3094#endif /* BINARY_SUPPORT_DYLD */ 3095 if (executableURL) CFRelease(executableURL); 3096 3097 if (bundle->_isLoaded) { 3098 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 3099 return true; 3100 } 3101 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 3102 3103 switch (bundle->_binaryType) { 3104#if defined(BINARY_SUPPORT_DLFCN) 3105 case __CFBundleUnreadableBinary: 3106 result = _CFBundleDlfcnPreflight(bundle, subError); 3107 break; 3108#endif /* BINARY_SUPPORT_DLFCN */ 3109#if defined(BINARY_SUPPORT_DYLD) 3110 case __CFBundleDYLDBundleBinary: 3111 result = true; 3112#if defined(BINARY_SUPPORT_DLFCN) 3113 result = _CFBundleDlfcnPreflight(bundle, subError); 3114#endif /* BINARY_SUPPORT_DLFCN */ 3115 break; 3116 case __CFBundleDYLDFrameworkBinary: 3117 result = true; 3118#if defined(BINARY_SUPPORT_DLFCN) 3119 result = _CFBundleDlfcnPreflight(bundle, subError); 3120#endif /* BINARY_SUPPORT_DLFCN */ 3121 break; 3122 case __CFBundleDYLDExecutableBinary: 3123 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); 3124 break; 3125#endif /* BINARY_SUPPORT_DYLD */ 3126#if defined(BINARY_SUPPORT_DLFCN) 3127 case __CFBundleUnknownBinary: 3128 case __CFBundleELFBinary: 3129 result = _CFBundleDlfcnPreflight(bundle, subError); 3130 break; 3131#endif /* BINARY_SUPPORT_DLFCN */ 3132#if defined(BINARY_SUPPORT_DLL) 3133 case __CFBundleDLLBinary: 3134 result = true; 3135 break; 3136#endif /* BINARY_SUPPORT_DLL */ 3137 case __CFBundleNoBinary: 3138 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); 3139 break; 3140 default: 3141 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); 3142 break; 3143 } 3144 if (!result && error) *error = localError; 3145 return result; 3146} 3147 3148CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) { 3149 CFArrayRef result = NULL; 3150 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 3151 if (executableURL) { 3152 result = _CFBundleCopyArchitecturesForExecutable(executableURL); 3153 CFRelease(executableURL); 3154 } 3155 return result; 3156} 3157 3158#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 3159static Boolean _CFBundleGetObjCImageInfo(CFBundleRef bundle, uint32_t *objcVersion, uint32_t *objcFlags) { 3160 Boolean retval = false; 3161 uint32_t localVersion = 0, localFlags = 0; 3162 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 3163 if (executableURL) { 3164 retval = _CFBundleGetObjCImageInfoForExecutable(executableURL, &localVersion, &localFlags); 3165 CFRelease(executableURL); 3166 } 3167 if (objcVersion) *objcVersion = localVersion; 3168 if (objcFlags) *objcFlags = localFlags; 3169 return retval; 3170} 3171#endif 3172 3173void CFBundleUnloadExecutable(CFBundleRef bundle) { 3174 // First unload bundles scheduled for unloading (if that's not what we are already doing.) 3175 if (!_scheduledBundlesAreUnloading) _CFBundleUnloadScheduledBundles(); 3176 3177 if (!bundle->_isLoaded) return; 3178 3179 // Remove from the scheduled unload set if we are there. 3180 if (!_scheduledBundlesAreUnloading) pthread_mutex_lock(&CFBundleGlobalDataLock); 3181#if AVOID_WEAK_COLLECTIONS 3182 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); 3183#else /* AVOID_WEAK_COLLECTIONS */ 3184 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle]; 3185#endif /* AVOID_WEAK_COLLECTIONS */ 3186 if (!_scheduledBundlesAreUnloading) pthread_mutex_unlock(&CFBundleGlobalDataLock); 3187 3188 // Give the plugIn code a chance to realize this... 3189 _CFPlugInWillUnload(bundle); 3190 3191 pthread_mutex_lock(&(bundle->_bundleLoadingLock)); 3192 if (!bundle->_isLoaded) { 3193 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 3194 return; 3195 } 3196 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 3197 3198 switch (bundle->_binaryType) { 3199#if defined(BINARY_SUPPORT_DYLD) 3200 case __CFBundleDYLDBundleBinary: 3201#if defined(BINARY_SUPPORT_DLFCN) 3202 if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle); 3203#else /* BINARY_SUPPORT_DLFCN */ 3204 _CFBundleDYLDUnloadBundle(bundle); 3205#endif /* BINARY_SUPPORT_DLFCN */ 3206 break; 3207 case __CFBundleDYLDFrameworkBinary: 3208#if defined(BINARY_SUPPORT_DLFCN) 3209 if (bundle->_handleCookie && _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) _CFBundleDlfcnUnload(bundle); 3210#endif /* BINARY_SUPPORT_DLFCN */ 3211 break; 3212#endif /* BINARY_SUPPORT_DYLD */ 3213#if defined(BINARY_SUPPORT_DLL) 3214 case __CFBundleDLLBinary: 3215 _CFBundleDLLUnload(bundle); 3216 break; 3217#endif /* BINARY_SUPPORT_DLL */ 3218 default: 3219#if defined(BINARY_SUPPORT_DLFCN) 3220 if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle); 3221#endif /* BINARY_SUPPORT_DLFCN */ 3222 break; 3223 } 3224 if (!bundle->_isLoaded && bundle->_glueDict) { 3225 CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle)); 3226 CFRelease(bundle->_glueDict); 3227 bundle->_glueDict = NULL; 3228 } 3229} 3230 3231#if AVOID_WEAK_COLLECTIONS 3232 3233CF_PRIVATE void _CFBundleScheduleForUnloading(CFBundleRef bundle) { 3234 pthread_mutex_lock(&CFBundleGlobalDataLock); 3235 if (!_bundlesToUnload) { 3236 CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks; 3237 nonRetainingCallbacks.retain = NULL; 3238 nonRetainingCallbacks.release = NULL; 3239 _bundlesToUnload = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingCallbacks); 3240 } 3241 CFSetAddValue(_bundlesToUnload, bundle); 3242 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3243} 3244 3245CF_PRIVATE void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) { 3246 pthread_mutex_lock(&CFBundleGlobalDataLock); 3247 if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); 3248 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3249} 3250 3251CF_PRIVATE void _CFBundleUnloadScheduledBundles(void) { 3252 pthread_mutex_lock(&CFBundleGlobalDataLock); 3253 if (_bundlesToUnload) { 3254 CFIndex i, c = CFSetGetCount(_bundlesToUnload); 3255 if (c > 0) { 3256 CFBundleRef *unloadThese = (CFBundleRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFBundleRef) * c, 0); 3257 CFSetGetValues(_bundlesToUnload, (const void **)unloadThese); 3258 _scheduledBundlesAreUnloading = true; 3259 for (i = 0; i < c; i++) { 3260 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.) 3261 CFBundleUnloadExecutable(unloadThese[i]); 3262 } 3263 _scheduledBundlesAreUnloading = false; 3264 CFAllocatorDeallocate(kCFAllocatorSystemDefault, unloadThese); 3265 } 3266 } 3267 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3268} 3269 3270#else /* AVOID_WEAK_COLLECTIONS */ 3271 3272CF_PRIVATE void _CFBundleScheduleForUnloading(CFBundleRef bundle) { 3273 pthread_mutex_lock(&CFBundleGlobalDataLock); 3274 if (!_bundlesToUnload) _bundlesToUnload = [[__CFHashTable alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory capacity:0]; 3275 [_bundlesToUnload addObject:(id)bundle]; 3276 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3277} 3278 3279CF_PRIVATE void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) { 3280 pthread_mutex_lock(&CFBundleGlobalDataLock); 3281 if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle]; 3282 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3283} 3284 3285CF_PRIVATE void _CFBundleUnloadScheduledBundles(void) { 3286 pthread_mutex_lock(&CFBundleGlobalDataLock); 3287 if (_bundlesToUnload && [_bundlesToUnload count] > 0) { 3288 CFIndex i, c; 3289 CFMutableArrayRef unloadThese = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 3290 for (id value in _bundlesToUnload) CFArrayAppendValue(unloadThese, value); 3291 c = CFArrayGetCount(unloadThese); 3292 if (c > 0) { 3293 _scheduledBundlesAreUnloading = true; 3294 for (i = 0; i < c; i++) { 3295 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.) 3296 CFBundleUnloadExecutable((CFBundleRef)CFArrayGetValueAtIndex(unloadThese, i)); 3297 } 3298 _scheduledBundlesAreUnloading = false; 3299 } 3300 CFRelease(unloadThese); 3301 } 3302 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3303} 3304 3305#endif /* AVOID_WEAK_COLLECTIONS */ 3306 3307void *CFBundleGetFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) { 3308 void *tvp = NULL; 3309 // Load if necessary 3310 if (!bundle->_isLoaded) { 3311 if (!CFBundleLoadExecutable(bundle)) return NULL; 3312 } 3313 3314 switch (bundle->_binaryType) { 3315#if defined(BINARY_SUPPORT_DYLD) 3316 case __CFBundleDYLDBundleBinary: 3317 case __CFBundleDYLDFrameworkBinary: 3318 case __CFBundleDYLDExecutableBinary: 3319#if defined(BINARY_SUPPORT_DLFCN) 3320 if (bundle->_handleCookie) return _CFBundleDlfcnGetSymbolByName(bundle, funcName); 3321#else /* BINARY_SUPPORT_DLFCN */ 3322 return _CFBundleDYLDGetSymbolByName(bundle, funcName); 3323#endif /* BINARY_SUPPORT_DLFCN */ 3324 break; 3325#endif /* BINARY_SUPPORT_DYLD */ 3326#if defined(BINARY_SUPPORT_DLL) 3327 case __CFBundleDLLBinary: 3328 tvp = _CFBundleDLLGetSymbolByName(bundle, funcName); 3329 break; 3330#endif /* BINARY_SUPPORT_DLL */ 3331 default: 3332#if defined(BINARY_SUPPORT_DLFCN) 3333 if (bundle->_handleCookie) return _CFBundleDlfcnGetSymbolByName(bundle, funcName); 3334#endif /* BINARY_SUPPORT_DLFCN */ 3335 break; 3336 } 3337 return tvp; 3338} 3339 3340void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName) { 3341 void *fp = NULL; 3342 // Load if necessary 3343 if (!bundle->_isLoaded) { 3344 if (!CFBundleLoadExecutable(bundle)) return NULL; 3345 } 3346#if defined (BINARY_SUPPORT_DYLD) || defined (BINARY_SUPPORT_DLFCN) 3347 switch (bundle->_binaryType) { 3348#if defined(BINARY_SUPPORT_DYLD) 3349 case __CFBundleDYLDBundleBinary: 3350 case __CFBundleDYLDFrameworkBinary: 3351 case __CFBundleDYLDExecutableBinary: 3352#if defined(BINARY_SUPPORT_DLFCN) 3353 if (bundle->_handleCookie) fp = _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, funcName, true); 3354#else /* BINARY_SUPPORT_DLFCN */ 3355 fp = _CFBundleDYLDGetSymbolByNameWithSearch(bundle, funcName, true); 3356#endif /* BINARY_SUPPORT_DLFCN */ 3357 break; 3358#endif /* BINARY_SUPPORT_DYLD */ 3359 default: 3360#if defined(BINARY_SUPPORT_DLFCN) 3361 if (bundle->_handleCookie) fp = _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, funcName, true); 3362#endif /* BINARY_SUPPORT_DLFCN */ 3363 break; 3364 } 3365#endif /* BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */ 3366 return fp; 3367} 3368 3369void CFBundleGetFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) { 3370 SInt32 i, c; 3371 3372 if (!ftbl) return; 3373 3374 c = CFArrayGetCount(functionNames); 3375 for (i = 0; i < c; i++) ftbl[i] = CFBundleGetFunctionPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(functionNames, i)); 3376} 3377 3378void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle, CFArrayRef functionNames, void *ftbl[]) { 3379 SInt32 i, c; 3380 3381 if (!ftbl) return; 3382 3383 c = CFArrayGetCount(functionNames); 3384 for (i = 0; i < c; i++) ftbl[i] = _CFBundleGetCFMFunctionPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(functionNames, i)); 3385} 3386 3387void *CFBundleGetDataPointerForName(CFBundleRef bundle, CFStringRef symbolName) { 3388 void *dp = NULL; 3389 // Load if necessary 3390 if (!bundle->_isLoaded && !CFBundleLoadExecutable(bundle)) return NULL; 3391 3392 switch (bundle->_binaryType) { 3393#if defined(BINARY_SUPPORT_DYLD) 3394 case __CFBundleDYLDBundleBinary: 3395 case __CFBundleDYLDFrameworkBinary: 3396 case __CFBundleDYLDExecutableBinary: 3397#if defined(BINARY_SUPPORT_DLFCN) 3398 if (bundle->_handleCookie) dp = _CFBundleDlfcnGetSymbolByName(bundle, symbolName); 3399#else /* BINARY_SUPPORT_DLFCN */ 3400 dp = _CFBundleDYLDGetSymbolByName(bundle, symbolName); 3401#endif /* BINARY_SUPPORT_DLFCN */ 3402 break; 3403#endif /* BINARY_SUPPORT_DYLD */ 3404#if defined(BINARY_SUPPORT_DLL) 3405 case __CFBundleDLLBinary: 3406 /* MF:!!! Handle this someday */ 3407 break; 3408#endif /* BINARY_SUPPORT_DLL */ 3409 default: 3410#if defined(BINARY_SUPPORT_DLFCN) 3411 if (bundle->_handleCookie) dp = _CFBundleDlfcnGetSymbolByName(bundle, symbolName); 3412#endif /* BINARY_SUPPORT_DLFCN */ 3413 break; 3414 } 3415 return dp; 3416} 3417 3418void CFBundleGetDataPointersForNames(CFBundleRef bundle, CFArrayRef symbolNames, void *stbl[]) { 3419 SInt32 i, c; 3420 3421 if (!stbl) return; 3422 3423 c = CFArrayGetCount(symbolNames); 3424 for (i = 0; i < c; i++) stbl[i] = CFBundleGetDataPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(symbolNames, i)); 3425} 3426 3427CF_PRIVATE _CFResourceData *__CFBundleGetResourceData(CFBundleRef bundle) { 3428 return &(bundle->_resourceData); 3429} 3430 3431CFPlugInRef CFBundleGetPlugIn(CFBundleRef bundle) { 3432 return (bundle->_plugInData._isPlugIn) ? (CFPlugInRef)bundle : NULL; 3433} 3434 3435CF_PRIVATE _CFPlugInData *__CFBundleGetPlugInData(CFBundleRef bundle) { 3436 return &(bundle->_plugInData); 3437} 3438 3439CF_PRIVATE Boolean _CFBundleCouldBeBundle(CFURLRef url) { 3440 Boolean result = false; 3441 Boolean exists; 3442 SInt32 mode; 3443 if (_CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) result = (exists && (mode & S_IFMT) == S_IFDIR && (mode & 0444) != 0); 3444 return result; 3445} 3446 3447#define LENGTH_OF(A) (sizeof(A) / sizeof(A[0])) 3448 3449//If 'permissive' is set, we will maintain the historical behavior of returning frameworks with names that don't match, and frameworks for executables in Resources/ 3450static CFURLRef __CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath, Boolean permissive) { 3451 // 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. 3452#if DEPLOYMENT_TARGET_WINDOWS 3453 UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; 3454 UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; 3455 UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'}; 3456#endif 3457 UniChar pathBuff[CFMaxPathSize] = {0}; 3458 UniChar nameBuff[CFMaxPathSize] = {0}; 3459 CFIndex length, nameStart, nameLength, savedLength; 3460 CFMutableStringRef cheapStr = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, NULL); 3461 CFURLRef bundleURL = NULL; 3462 3463 length = CFStringGetLength(executablePath); 3464 if (length > CFMaxPathSize) length = CFMaxPathSize; 3465 CFStringGetCharacters(executablePath, CFRangeMake(0, length), pathBuff); 3466 3467 // Save the name in nameBuff 3468 length = _CFLengthAfterDeletingPathExtension(pathBuff, length); 3469 nameStart = _CFStartOfLastPathComponent(pathBuff, length); 3470 nameLength = length - nameStart; 3471 memmove(nameBuff, &(pathBuff[nameStart]), nameLength * sizeof(UniChar)); 3472 3473 // Strip the name from pathBuff 3474 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length); 3475 savedLength = length; 3476 3477#if DEPLOYMENT_TARGET_WINDOWS 3478 // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case. 3479 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, LENGTH_OF(executablesToFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) { 3480 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); 3481 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); 3482 if (!_CFBundleCouldBeBundle(bundleURL)) { 3483 CFRelease(bundleURL); 3484 bundleURL = NULL; 3485 } 3486 } 3487 // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case. 3488 if (!bundleURL) { 3489 length = savedLength; 3490 if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, LENGTH_OF(executablesToPrivateFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) { 3491 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); 3492 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); 3493 if (!_CFBundleCouldBeBundle(bundleURL)) { 3494 CFRelease(bundleURL); 3495 bundleURL = NULL; 3496 } 3497 } 3498 } 3499#endif 3500 // * Finally check the executable inside the framework case. 3501 if (!bundleURL) { 3502 length = savedLength; 3503 // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files". 3504 3505 CFStringRef name = permissive ? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, (const char *)nameBuff); 3506 3507 while (length > 0) { 3508 CFIndex curStart = _CFStartOfLastPathComponent(pathBuff, length); 3509 if (curStart >= length) break; 3510 CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[curStart]), length - curStart, CFMaxPathSize - curStart); 3511 if (!permissive && CFEqual(cheapStr, _CFBundleResourcesDirectoryName)) break; 3512 if (CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName1) || CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName2)) { 3513 if (!permissive) { 3514 CFIndex fmwkStart = _CFStartOfLastPathComponent(pathBuff, length); 3515 CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[fmwkStart]), length - fmwkStart, CFMaxPathSize - fmwkStart); 3516 } 3517 if (permissive || CFStringHasPrefix(cheapStr, name)) { 3518 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length); 3519 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); 3520 3521 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); 3522 if (!_CFBundleCouldBeBundle(bundleURL)) { 3523 CFRelease(bundleURL); 3524 bundleURL = NULL; 3525 } 3526 break; 3527 } 3528 } else if (CFStringHasSuffix(cheapStr, CFSTR(".framework")) && (permissive || CFStringHasPrefix(cheapStr, name))) { 3529 CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); 3530 bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); 3531 if (!_CFBundleCouldBeBundle(bundleURL)) { 3532 CFRelease(bundleURL); 3533 bundleURL = NULL; 3534 } 3535 break; 3536 } 3537 length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length); 3538 } 3539 if (!permissive) CFRelease(name); 3540 } 3541 CFStringSetExternalCharactersNoCopy(cheapStr, NULL, 0, 0); 3542 CFRelease(cheapStr); 3543 3544 return bundleURL; 3545} 3546 3547//SPI version; separated out to minimize linkage changes 3548CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath) { 3549 return __CFBundleCopyFrameworkURLForExecutablePath(executablePath, false); 3550} 3551 3552static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath) { 3553 // This finds the bundle for the given path. 3554 // 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. 3555 CFBundleRef bundle; 3556 CFURLRef curURL = __CFBundleCopyFrameworkURLForExecutablePath(imagePath, true); 3557 Boolean createdBundle = false; 3558 3559 if (curURL) { 3560 bundle = _CFBundleCopyBundleForURL(curURL, true); 3561 if (!bundle) { 3562 // Ensure bundle exists by creating it if necessary 3563 // NB doFinalProcessing must be false here, see below 3564 bundle = _CFBundleCreate(kCFAllocatorSystemDefault, curURL, true, false); 3565 createdBundle = true; 3566 } 3567 if (bundle) { 3568 pthread_mutex_lock(&(bundle->_bundleLoadingLock)); 3569 if (!bundle->_isLoaded) { 3570 // 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) 3571 #if defined(BINARY_SUPPORT_DLFCN) 3572 if (!bundle->_isLoaded) _CFBundleDlfcnCheckLoaded(bundle); 3573 #elif defined(BINARY_SUPPORT_DYLD) 3574 if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle); 3575 #endif /* BINARY_SUPPORT_DLFCN */ 3576 #if defined(BINARY_SUPPORT_DYLD) 3577 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary; 3578 if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true; 3579 #endif /* BINARY_SUPPORT_DYLD */ 3580 #if LOG_BUNDLE_LOAD 3581 if (!bundle->_isLoaded) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle, bundle->_handleCookie, bundle->_imageCookie, bundle->_connectionCookie); 3582 #endif /* LOG_BUNDLE_LOAD */ 3583 bundle->_isLoaded = true; 3584 } 3585 pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); 3586 if (createdBundle) { 3587 // Perform delayed final processing steps. 3588 // This must be done after _isLoaded has been set, for security reasons (3624341). 3589 if (_CFBundleNeedsInitPlugIn(bundle)) { 3590 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3591 _CFBundleInitPlugIn(bundle); 3592 pthread_mutex_lock(&CFBundleGlobalDataLock); 3593 } 3594 } else { 3595 // Release the bundle if we did not create it here 3596 CFRelease(bundle); 3597 } 3598 } 3599 CFRelease(curURL); 3600 } 3601} 3602 3603static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths) { 3604 // This finds the bundles for the given paths. 3605 // 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). 3606 CFIndex i, imagePathCount = CFArrayGetCount(imagePaths); 3607 for (i = 0; i < imagePathCount; i++) _CFBundleEnsureBundleExistsForImagePath((CFStringRef)CFArrayGetValueAtIndex(imagePaths, i)); 3608} 3609 3610static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint) { 3611 CFArrayRef imagePaths = NULL; 3612 // Tickle the main bundle into existence 3613 (void)_CFBundleGetMainBundleAlreadyLocked(); 3614#if defined(BINARY_SUPPORT_DYLD) 3615 imagePaths = _CFBundleDYLDCopyLoadedImagePathsForHint(hint); 3616#endif /* BINARY_SUPPORT_DYLD */ 3617 if (imagePaths) { 3618 _CFBundleEnsureBundlesExistForImagePaths(imagePaths); 3619 CFRelease(imagePaths); 3620 } 3621} 3622 3623static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) { 3624 // 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. 3625 CFArrayRef imagePaths = NULL; 3626 // Tickle the main bundle into existence 3627 (void)_CFBundleGetMainBundleAlreadyLocked(); 3628 3629#if defined(BINARY_SUPPORT_DLL) 3630// Dont know how to find static bundles for DLLs 3631#endif /* BINARY_SUPPORT_DLL */ 3632 3633#if defined(BINARY_SUPPORT_DYLD) 3634 imagePaths = _CFBundleDYLDCopyLoadedImagePathsIfChanged(); 3635#endif /* BINARY_SUPPORT_DYLD */ 3636 if (imagePaths) { 3637 _CFBundleEnsureBundlesExistForImagePaths(imagePaths); 3638 CFRelease(imagePaths); 3639 } 3640} 3641 3642CFArrayRef CFBundleGetAllBundles(void) { 3643 // To answer this properly, we have to have created the static bundles! 3644#if !AVOID_WEAK_COLLECTIONS 3645 static CFMutableArrayRef externalAllBundles = NULL; 3646#endif /* AVOID_WEAK_COLLECTIONS */ 3647 CFArrayRef bundles; 3648 pthread_mutex_lock(&CFBundleGlobalDataLock); 3649 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(); 3650#if AVOID_WEAK_COLLECTIONS 3651 bundles = _allBundles; 3652#else /* AVOID_WEAK_COLLECTIONS */ 3653 if (!externalAllBundles) { 3654 CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks; 3655 nonRetainingArrayCallbacks.retain = NULL; 3656 nonRetainingArrayCallbacks.release = NULL; 3657 externalAllBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks); 3658 } 3659 CFArrayRemoveAllValues(externalAllBundles); 3660 for (id value in _allBundles) CFArrayAppendValue(externalAllBundles, value); 3661 bundles = externalAllBundles; 3662#endif /* AVOID_WEAK_COLLECTIONS */ 3663 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3664 return bundles; 3665} 3666 3667CF_EXPORT CFArrayRef _CFBundleCopyAllBundles(void) { 3668 // To answer this properly, we have to have created the static bundles! 3669 pthread_mutex_lock(&CFBundleGlobalDataLock); 3670 _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(); 3671#if AVOID_WEAK_COLLECTIONS 3672 CFArrayRef bundles = CFArrayCreateCopy(kCFAllocatorSystemDefault, _allBundles); 3673#else /* AVOID_WEAK_COLLECTIONS */ 3674 CFMutableArrayRef bundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 3675 for (id value in _allBundles) CFArrayAppendValue(bundles, value); 3676#endif /* AVOID_WEAK_COLLECTIONS */ 3677 pthread_mutex_unlock(&CFBundleGlobalDataLock); 3678 return bundles; 3679} 3680 3681CF_PRIVATE uint8_t _CFBundleLayoutVersion(CFBundleRef bundle) { 3682 return bundle->_version; 3683} 3684 3685static void __addPlatformAndProductNamesToKeys(const void *value, void *context) { 3686 CFMutableSetRef newKeys = (CFMutableSetRef)context; 3687 CFStringRef key = (CFStringRef)value; 3688 CFStringRef firstPartOfKey = NULL; 3689 CFStringRef restOfKey = NULL; 3690 3691 // Find the first ':' 3692 CFRange range; 3693 Boolean success = CFStringFindWithOptions(key, CFSTR(":"), CFRangeMake(0, CFStringGetLength(key)), 0, &range); 3694 if (success) { 3695 firstPartOfKey = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, key, CFRangeMake(0, range.location)); 3696 restOfKey = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, key, CFRangeMake(range.location + 1, CFStringGetLength(key) - range.location - 1)); 3697 } else { 3698 firstPartOfKey = (CFStringRef)CFRetain(key); 3699 } 3700 3701 // only apply product and platform to top-level key 3702 CFStringRef newKeyWithPlatform = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@-%@%@%@"), firstPartOfKey, _CFGetPlatformName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR("")); 3703 CFStringRef newKeyWithProduct = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@~%@%@%@"), firstPartOfKey, _CFGetProductName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR("")); 3704 CFStringRef newKeyWithProductAndPlatform = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@-%@~%@%@%@"), firstPartOfKey, _CFGetPlatformName(), _CFGetProductName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR("")); 3705 3706 CFSetAddValue(newKeys, key); 3707 CFSetAddValue(newKeys, newKeyWithPlatform); 3708 CFSetAddValue(newKeys, newKeyWithProduct); 3709 CFSetAddValue(newKeys, newKeyWithProductAndPlatform); 3710 3711 if (firstPartOfKey) CFRelease(firstPartOfKey); 3712 if (restOfKey) CFRelease(restOfKey); 3713 CFRelease(newKeyWithPlatform); 3714 CFRelease(newKeyWithProduct); 3715 CFRelease(newKeyWithProductAndPlatform); 3716} 3717 3718// from CFUtilities.c 3719CF_PRIVATE Boolean _CFReadMappedFromFile(CFStringRef path, Boolean map, Boolean uncached, void **outBytes, CFIndex *outLength, CFErrorRef *errorPtr); 3720 3721// implementation of below functions - takes URL as parameter 3722static CFPropertyListRef _CFBundleCreateFilteredInfoPlistWithURL(CFURLRef infoPlistURL, CFSetRef keyPaths, _CFBundleFilteredPlistOptions options) { 3723 CFPropertyListRef result = NULL; 3724 3725 if (!infoPlistURL) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 3726 3727 CFURLRef absoluteURL = CFURLCopyAbsoluteURL(infoPlistURL); 3728 CFStringRef filePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); 3729 CFRelease(absoluteURL); 3730 3731 if (!filePath) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 3732 3733 void *bytes = NULL; 3734 CFIndex length = 0; 3735#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 3736 Boolean mapped = options & _CFBundleFilteredPlistMemoryMapped ? true : false; 3737#else 3738 Boolean mapped = false; 3739#endif 3740 Boolean success = _CFReadMappedFromFile(filePath, mapped, false, &bytes, &length, NULL); 3741 CFRelease(filePath); 3742 if (!success) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 3743 3744 CFDataRef infoPlistData = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8 *)bytes, length, kCFAllocatorNull); 3745 // We need to include all possible variants of the platform/product combo as possible keys. 3746 CFMutableSetRef newKeyPaths = CFSetCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(keyPaths), &kCFTypeSetCallBacks); 3747 CFSetApplyFunction(keyPaths, __addPlatformAndProductNamesToKeys, newKeyPaths); 3748 3749 success = _CFPropertyListCreateFiltered(kCFAllocatorSystemDefault, infoPlistData, kCFPropertyListMutableContainers, newKeyPaths, &result, NULL); 3750 3751 if (!success) { 3752 result = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 3753 } else { 3754 _CFBundleInfoPlistProcessInfoDictionary((CFMutableDictionaryRef)result); 3755 } 3756 3757 CFRelease(newKeyPaths); 3758 CFRelease(infoPlistData); 3759 if (mapped) { 3760#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI 3761 munmap(bytes, length); 3762#endif 3763 } else { 3764 free(bytes); 3765 } 3766 3767 return result; 3768} 3769 3770// Returns a subset of the bundle's property list, only including the keyPaths in the CFSet. If the top level object is not a dictionary, you will get back an empty dictionary as the result. If the Info.plist does not exist or could not be parsed, you will get back an empty dictionary. 3771CF_EXPORT CFPropertyListRef _CFBundleCreateFilteredInfoPlist(CFBundleRef bundle, CFSetRef keyPaths, _CFBundleFilteredPlistOptions options) { 3772 CFURLRef infoPlistURL = _CFBundleCopyInfoPlistURL(bundle); 3773 CFPropertyListRef result = _CFBundleCreateFilteredInfoPlistWithURL(infoPlistURL, keyPaths, options); 3774 if (infoPlistURL) CFRelease(infoPlistURL); 3775 return result; 3776} 3777 3778CF_EXPORT CFPropertyListRef _CFBundleCreateFilteredLocalizedInfoPlist(CFBundleRef bundle, CFSetRef keyPaths, CFStringRef localizationName, _CFBundleFilteredPlistOptions options) { 3779 CFURLRef infoPlistURL = CFBundleCopyResourceURLForLocalization(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL, localizationName); 3780 CFPropertyListRef result = _CFBundleCreateFilteredInfoPlistWithURL(infoPlistURL, keyPaths, options); 3781 if (infoPlistURL) CFRelease(infoPlistURL); 3782 return result; 3783} 3784 3785CF_EXPORT CFURLRef _CFBundleCopyInfoPlistURL(CFBundleRef bundle) { 3786 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); 3787 CFURLRef url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey); 3788 if (!url) url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleRawInfoPlistURLKey); 3789 return (url ? (CFURLRef)CFRetain(url) : NULL); 3790} 3791 3792CF_EXPORT CFURLRef _CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) { 3793 return CFBundleCopyPrivateFrameworksURL(bundle); 3794} 3795 3796CF_EXPORT CFURLRef CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) { 3797 CFURLRef result = NULL; 3798 3799 if (1 == bundle->_version) { 3800 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase1, bundle->_url); 3801 } else if (2 == bundle->_version) { 3802 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase2, bundle->_url); 3803 } else { 3804 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundlePrivateFrameworksURLFromBase0, bundle->_url); 3805 } 3806 return result; 3807} 3808 3809CF_EXPORT CFURLRef _CFBundleCopySharedFrameworksURL(CFBundleRef bundle) { 3810 return CFBundleCopySharedFrameworksURL(bundle); 3811} 3812 3813CF_EXPORT CFURLRef CFBundleCopySharedFrameworksURL(CFBundleRef bundle) { 3814 CFURLRef result = NULL; 3815 3816 if (1 == bundle->_version) { 3817 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase1, bundle->_url); 3818 } else if (2 == bundle->_version) { 3819 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase2, bundle->_url); 3820 } else { 3821 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedFrameworksURLFromBase0, bundle->_url); 3822 } 3823 return result; 3824} 3825 3826CF_EXPORT CFURLRef _CFBundleCopySharedSupportURL(CFBundleRef bundle) { 3827 return CFBundleCopySharedSupportURL(bundle); 3828} 3829 3830CF_EXPORT CFURLRef CFBundleCopySharedSupportURL(CFBundleRef bundle) { 3831 CFURLRef result = NULL; 3832 3833 if (1 == bundle->_version) { 3834 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase1, bundle->_url); 3835 } else if (2 == bundle->_version) { 3836 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase2, bundle->_url); 3837 } else { 3838 result = CFURLCreateWithString(CFGetAllocator(bundle), _CFBundleSharedSupportURLFromBase0, bundle->_url); 3839 } 3840 return result; 3841} 3842 3843CF_PRIVATE CFURLRef _CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) { 3844 return CFBundleCopyBuiltInPlugInsURL(bundle); 3845} 3846 3847CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) { 3848 CFURLRef result = NULL, alternateResult = NULL; 3849 3850 CFAllocatorRef alloc = CFGetAllocator(bundle); 3851 if (1 == bundle->_version) { 3852 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase1, bundle->_url); 3853 } else if (2 == bundle->_version) { 3854 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase2, bundle->_url); 3855 } else { 3856 result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase0, bundle->_url); 3857 } 3858 if (!result || !_urlExists(result)) { 3859 if (1 == bundle->_version) { 3860 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase1, bundle->_url); 3861 } else if (2 == bundle->_version) { 3862 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase2, bundle->_url); 3863 } else { 3864 alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase0, bundle->_url); 3865 } 3866 if (alternateResult && _urlExists(alternateResult)) { 3867 if (result) CFRelease(result); 3868 result = alternateResult; 3869 } else { 3870 if (alternateResult) CFRelease(alternateResult); 3871 } 3872 } 3873 return result; 3874} 3875 3876#if defined(BINARY_SUPPORT_DYLD) 3877 3878CF_PRIVATE CFArrayRef _CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint) { 3879 uint32_t i, numImages = _dyld_image_count(); 3880 CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 3881 CFRange range = CFRangeMake(0, CFStringGetLength(hint)), altRange = CFRangeMake(0, 0), testRange = CFRangeMake(0, 0); 3882 const char *processPath = _CFProcessPath(); 3883 const void *mhp = (const void *)_NSGetMachExecuteHeader(); 3884 3885 if (range.length > 14) { 3886 // handle some common variations on framework bundle identifiers 3887 if (CFStringFindWithOptions(hint, CFSTR(".framework"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) { 3888 // identifier has .framework appended 3889 altRange.length = testRange.location; 3890 } else if (CFStringFindWithOptions(hint, CFSTR("framework"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) { 3891 // identifier has Framework appended 3892 altRange.length = testRange.location; 3893 } else if (CFStringFindWithOptions(hint, CFSTR("fw"), range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, &testRange) && testRange.location > 0 && testRange.length > 0) { 3894 // identifier has FW appended 3895 altRange.length = testRange.location; 3896 } 3897 } 3898 for (i = 0; i < numImages; i++) { 3899 const char *curName = _dyld_get_image_name(i), *lastComponent = NULL; 3900 if (curName && (!processPath || 0 != strcmp(curName, processPath)) && mhp != (void *)_dyld_get_image_header(i)) lastComponent = strrchr(curName, '/'); 3901 if (lastComponent) { 3902 CFStringRef str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, lastComponent + 1); 3903 if (str) { 3904 if (CFStringFindWithOptions(hint, str, range, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL) || (altRange.length > 0 && CFStringFindWithOptions(hint, str, altRange, kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL))) { 3905 CFStringRef curStr = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, curName); 3906 if (curStr) { 3907 CFArrayAppendValue(result, curStr); 3908 CFRelease(curStr); 3909 } 3910 } 3911 CFRelease(str); 3912 } 3913 } 3914 } 3915 return result; 3916} 3917 3918static char *_cleanedPathForPath(const char *curName) { 3919 char *thePath = strdup(curName); 3920 if (thePath) { 3921 // We are going to process the buffer replacing all "/./" and "//" with "/" 3922 CFIndex srcIndex = 0, dstIndex = 0; 3923 CFIndex len = strlen(thePath); 3924 for (srcIndex=0; srcIndex<len; srcIndex++) { 3925 thePath[dstIndex] = thePath[srcIndex]; 3926 dstIndex++; 3927 while (srcIndex < len-1 && thePath[srcIndex] == '/' && (thePath[srcIndex+1] == '/' || (thePath[srcIndex+1] == '.' && srcIndex < len-2 && thePath[srcIndex+2] == '/'))) srcIndex += (thePath[srcIndex+1] == '/' ? 1 : 2); 3928 } 3929 thePath[dstIndex] = 0; 3930 } 3931 return thePath; 3932} 3933 3934CF_PRIVATE CFArrayRef _CFBundleDYLDCopyLoadedImagePathsIfChanged(void) { 3935 // 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. 3936 uint32_t i, numImages = _dyld_image_count(); 3937 CFMutableArrayRef result = NULL; 3938 static uint32_t _cachedDYLDImageCount = -1; 3939 3940 if (numImages != _cachedDYLDImageCount) { 3941 const char *curName; 3942 char *cleanedCurName = NULL; 3943 CFStringRef curStr; 3944 const char *processPath = _CFProcessPath(); 3945 const void *mhp = (const void *)_NSGetMachExecuteHeader(); 3946 3947 result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 3948 3949 for (i = 0; i < numImages; i++) { 3950 curName = _dyld_get_image_name(i); 3951 if (curName && i == 0) cleanedCurName = _cleanedPathForPath(curName); 3952 if (curName && (!processPath || 0 != strcmp(curName, processPath)) && (!processPath || !cleanedCurName || 0 != strcmp(cleanedCurName, processPath)) && mhp != (void *)_dyld_get_image_header(i)) { 3953 curStr = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, curName); 3954 if (curStr) { 3955 CFArrayAppendValue(result, curStr); 3956 CFRelease(curStr); 3957 } 3958 } 3959 if (cleanedCurName) { 3960 free(cleanedCurName); 3961 cleanedCurName = NULL; 3962 } 3963 } 3964 _cachedDYLDImageCount = numImages; 3965 } 3966 return result; 3967} 3968 3969static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p) { 3970 CFStringRef result = NULL; 3971#if defined(USE_DYLD_PRIV) 3972 const char *name = dyld_image_path_containing_address(p); 3973 if (name) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, name); 3974#else /* USE_DYLD_PRIV */ 3975 if (!result) { 3976 uint32_t i, j, n = _dyld_image_count(); 3977 Boolean foundit = false; 3978 const char *name; 3979#if __LP64__ 3980#define MACH_HEADER_TYPE struct mach_header_64 3981#define MACH_SEGMENT_CMD_TYPE struct segment_command_64 3982#define MACH_SEGMENT_FLAVOR LC_SEGMENT_64 3983#else 3984#define MACH_HEADER_TYPE struct mach_header 3985#define MACH_SEGMENT_CMD_TYPE struct segment_command 3986#define MACH_SEGMENT_FLAVOR LC_SEGMENT 3987#endif 3988 for (i = 0; !foundit && i < n; i++) { 3989 const MACH_HEADER_TYPE *mh = (const MACH_HEADER_TYPE *)_dyld_get_image_header(i); 3990 uintptr_t addr = (uintptr_t)p - _dyld_get_image_vmaddr_slide(i); 3991 if (mh) { 3992 struct load_command *lc = (struct load_command *)((char *)mh + sizeof(MACH_HEADER_TYPE)); 3993 for (j = 0; !foundit && j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) { 3994 if (MACH_SEGMENT_FLAVOR == lc->cmd && ((MACH_SEGMENT_CMD_TYPE *)lc)->vmaddr <= addr && addr < ((MACH_SEGMENT_CMD_TYPE *)lc)->vmaddr + ((MACH_SEGMENT_CMD_TYPE *)lc)->vmsize) { 3995 foundit = true; 3996 name = _dyld_get_image_name(i); 3997 if (name) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, name); 3998 } 3999 } 4000 } 4001 } 4002#undef MACH_HEADER_TYPE 4003#undef MACH_SEGMENT_CMD_TYPE 4004#undef MACH_SEGMENT_FLAVOR 4005 } 4006#endif /* USE_DYLD_PRIV */ 4007#if LOG_BUNDLE_LOAD 4008 printf("dyld image path for pointer %p is %p\n", p, result); 4009#endif /* LOG_BUNDLE_LOAD */ 4010 return result; 4011} 4012 4013#if !defined(BINARY_SUPPORT_DLFCN) 4014 4015static const void *__CFBundleDYLDFindImage(char *buff) { 4016 const void *header = NULL; 4017 uint32_t i, numImages = _dyld_image_count(), numMatches = 0; 4018 const char *curName, *p, *q; 4019 4020 for (i = 0; !header && i < numImages; i++) { 4021 curName = _dyld_get_image_name(i); 4022 if (curName && 0 == strncmp(curName, buff, CFMaxPathSize)) { 4023 header = _dyld_get_image_header(i); 4024 numMatches = 1; 4025 } 4026 } 4027 if (!header) { 4028 for (i = 0; i < numImages; i++) { 4029 curName = _dyld_get_image_name(i); 4030 if (curName) { 4031 for (p = buff, q = curName; *p && *q && (q - curName < CFMaxPathSize); p++, q++) { 4032 if (*p != *q && (q - curName > 11) && 0 == strncmp(q - 11, ".framework/Versions/", 20) && *(q + 9) && '/' == *(q + 10)) q += 11; 4033 else if (*p != *q && (q - curName > 12) && 0 == strncmp(q - 12, ".framework/Versions/", 20) && *(q + 8) && '/' == *(q + 9)) q += 10; 4034 if (*p != *q) break; 4035 } 4036 if (*p == *q) { 4037 header = _dyld_get_image_header(i); 4038 numMatches++; 4039 } 4040 } 4041 } 4042 } 4043 return (numMatches == 1) ? header : NULL; 4044} 4045 4046CF_PRIVATE Boolean _CFBundleDYLDCheckLoaded(CFBundleRef bundle) { 4047 if (!bundle->_isLoaded) { 4048 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 4049 char buff[CFMaxPathSize]; 4050 4051 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { 4052 const void *header = __CFBundleDYLDFindImage(buff); 4053 if (header) { 4054 if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary; 4055 if (!bundle->_imageCookie) { 4056 bundle->_imageCookie = header; 4057#if LOG_BUNDLE_LOAD 4058 printf("dyld check load bundle %p, find %s getting image %p\n", bundle, buff, bundle->_imageCookie); 4059#endif /* LOG_BUNDLE_LOAD */ 4060 } 4061 bundle->_isLoaded = true; 4062 } else { 4063#if LOG_BUNDLE_LOAD 4064 printf("dyld check load bundle %p, find %s no image\n", bundle, buff); 4065#endif /* LOG_BUNDLE_LOAD */ 4066 } 4067 } 4068 if (executableURL) CFRelease(executableURL); 4069 } 4070 return bundle->_isLoaded; 4071} 4072 4073CF_PRIVATE Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) { 4074 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); 4075 NSLinkEditErrors c = NSLinkEditUndefinedError; 4076 int errorNumber = 0; 4077 const char *fileName = NULL; 4078 const char *errorString = NULL; 4079 4080 if (!bundle->_isLoaded) { 4081 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 4082 char buff[CFMaxPathSize]; 4083 4084 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { 4085 NSObjectFileImage image; 4086 NSObjectFileImageReturnCode retCode = NSCreateObjectFileImageFromFile(buff, &image); 4087#if LOG_BUNDLE_LOAD 4088 printf("dyld load bundle %p, create image of %s returns image %p retcode %d\n", bundle, buff, image, retCode); 4089#endif /* LOG_BUNDLE_LOAD */ 4090 if (retCode == NSObjectFileImageSuccess) { 4091 uint32_t options = forceGlobal ? NSLINKMODULE_OPTION_RETURN_ON_ERROR : (NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR); 4092 NSModule module = NSLinkModule(image, buff, options); 4093#if LOG_BUNDLE_LOAD 4094 printf("dyld load bundle %p, link module of %s options 0x%x returns module %p image %p\n", bundle, buff, options, module, image); 4095#endif /* LOG_BUNDLE_LOAD */ 4096 if (module) { 4097 bundle->_imageCookie = image; 4098 bundle->_moduleCookie = module; 4099 bundle->_isLoaded = true; 4100 } else { 4101 NSLinkEditError(&c, &errorNumber, &fileName, &errorString); 4102 if (error) { 4103#if defined(BINARY_SUPPORT_DLFCN) 4104 _CFBundleDlfcnPreflight(bundle, subError); 4105#endif /* BINARY_SUPPORT_DLFCN */ 4106 if (!localError) { 4107 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("error code %d, error number %d (%@)"), c, errorNumber, tempString); 4108 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); 4109 if (tempString) CFRelease(tempString); 4110 if (debugString) CFRelease(debugString); 4111 } 4112 } else { 4113 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, fileName); 4114 CFLog(__kCFLogBundle, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString, c, errorNumber, tempString); 4115 if (tempString) CFRelease(tempString); 4116 if (executableString) CFRelease(executableString); 4117 } 4118 (void)NSDestroyObjectFileImage(image); 4119 } 4120 } else { 4121 if (error) { 4122 if (retCode == NSObjectFileImageArch) { 4123 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableArchitectureMismatchError); 4124 } else if (retCode == NSObjectFileImageInappropriateFile) { 4125 Boolean hasRuntimeMismatch = false; 4126 uint32_t mainFlags = 0, bundleFlags = 0; 4127 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) { 4128 if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true; 4129 } 4130 if (hasRuntimeMismatch) { 4131 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableRuntimeMismatchError); 4132 } else { 4133 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); 4134 } 4135 } else { 4136#if defined(BINARY_SUPPORT_DLFCN) 4137 _CFBundleDlfcnPreflight(bundle, subError); 4138#endif /* BINARY_SUPPORT_DLFCN */ 4139 if (!localError) { 4140 CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("dyld returns %d"), retCode); 4141 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); 4142 CFRelease(debugString); 4143 } 4144 } 4145 } else { 4146 CFLog(__kCFLogBundle, CFSTR("dyld returns %d when trying to load %@"), retCode, executableURL); 4147 } 4148 } 4149 } else { 4150 if (error) { 4151 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); 4152 } else { 4153 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); 4154 } 4155 } 4156 if (executableURL) CFRelease(executableURL); 4157 } 4158 if (!bundle->_isLoaded && error) *error = localError; 4159 return bundle->_isLoaded; 4160} 4161 4162CF_PRIVATE Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle, CFErrorRef *error) { 4163 // !!! Framework loading should be better. Can't unload frameworks. 4164 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); 4165 NSLinkEditErrors c = NSLinkEditUndefinedError; 4166 int errorNumber = 0; 4167 const char *fileName = NULL; 4168 const char *errorString = NULL; 4169 4170 if (!bundle->_isLoaded) { 4171 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 4172 char buff[CFMaxPathSize]; 4173 4174 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { 4175 void *image = (void *)NSAddImage(buff, NSADDIMAGE_OPTION_RETURN_ON_ERROR); 4176#if LOG_BUNDLE_LOAD 4177 printf("dyld load framework %p, add image of %s returns image %p\n", bundle, buff, image); 4178#endif /* LOG_BUNDLE_LOAD */ 4179 if (image) { 4180 bundle->_imageCookie = image; 4181 bundle->_isLoaded = true; 4182 } else { 4183 NSLinkEditError(&c, &errorNumber, &fileName, &errorString); 4184 if (error) { 4185#if defined(BINARY_SUPPORT_DLFCN) 4186 _CFBundleDlfcnPreflight(bundle, subError); 4187#endif /* BINARY_SUPPORT_DLFCN */ 4188 if (!localError) { 4189 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("error code %d, error number %d (%@)"), c, errorNumber, tempString); 4190 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); 4191 if (tempString) CFRelease(tempString); 4192 if (debugString) CFRelease(debugString); 4193 } 4194 } else { 4195 CFStringRef tempString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString), executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, fileName); 4196 CFLog(__kCFLogBundle, CFSTR("Error loading %@: error code %d, error number %d (%@)"), executableString, c, errorNumber, tempString); 4197 if (tempString) CFRelease(tempString); 4198 if (executableString) CFRelease(executableString); 4199 } 4200 } 4201 } else { 4202 if (error) { 4203 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); 4204 } else { 4205 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); 4206 } 4207 } 4208 if (executableURL) CFRelease(executableURL); 4209 } 4210 if (!bundle->_isLoaded && error) *error = localError; 4211 return bundle->_isLoaded; 4212} 4213 4214CF_PRIVATE void _CFBundleDYLDUnloadBundle(CFBundleRef bundle) { 4215 if (bundle->_isLoaded) { 4216#if LOG_BUNDLE_LOAD 4217 printf("dyld unload bundle %p, handle %p module %p image %p\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie); 4218#endif /* LOG_BUNDLE_LOAD */ 4219 if (bundle->_moduleCookie && !NSUnLinkModule((NSModule)(bundle->_moduleCookie), NSUNLINKMODULE_OPTION_NONE)) { 4220 CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle); 4221 } else { 4222 if (bundle->_moduleCookie && bundle->_imageCookie) (void)NSDestroyObjectFileImage((NSObjectFileImage)(bundle->_imageCookie)); 4223 bundle->_connectionCookie = bundle->_handleCookie = NULL; 4224 bundle->_imageCookie = bundle->_moduleCookie = NULL; 4225 bundle->_isLoaded = false; 4226 } 4227 } 4228} 4229 4230CF_PRIVATE void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) { 4231 return _CFBundleDYLDGetSymbolByNameWithSearch(bundle, symbolName, false); 4232} 4233 4234static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) { 4235 void *result = NULL; 4236 char buff[1026]; 4237 NSSymbol symbol = NULL; 4238 4239 buff[0] = '_'; 4240 if (CFStringGetCString(symbolName, &(buff[1]), 1024, kCFStringEncodingUTF8)) { 4241 if (bundle->_moduleCookie) { 4242 symbol = NSLookupSymbolInModule((NSModule)(bundle->_moduleCookie), buff); 4243 } else if (bundle->_imageCookie) { 4244 symbol = NSLookupSymbolInImage(bundle->_imageCookie, buff, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); 4245 } 4246 if (!symbol && !bundle->_moduleCookie && (!bundle->_imageCookie || globalSearch)) { 4247 char hintBuff[1026]; 4248 CFStringRef executableName = _CFBundleCopyExecutableName(bundle, NULL, NULL); 4249 hintBuff[0] = '\0'; 4250 if (executableName) { 4251 if (!CFStringGetCString(executableName, hintBuff, 1024, kCFStringEncodingUTF8)) hintBuff[0] = '\0'; 4252 CFRelease(executableName); 4253 } 4254 // Nowdays, NSIsSymbolNameDefinedWithHint() and NSLookupAndBindSymbolWithHint() 4255 // are identical, except the first just returns a bool, so checking with the 4256 // Is function first just causes a redundant lookup. 4257 // This returns NULL on failure. 4258 symbol = NSLookupAndBindSymbolWithHint(buff, hintBuff); 4259 } 4260 if (symbol) result = NSAddressOfSymbol(symbol); 4261#if defined(DEBUG) 4262 if (!result) CFLog(__kCFLogBundle, CFSTR("dyld cannot find symbol %@ in %@"), symbolName, bundle); 4263#endif /* DEBUG */ 4264#if LOG_BUNDLE_LOAD 4265 printf("bundle %p handle %p module %p image %p dyld returns symbol %p for %s\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie, result, buff + 1); 4266#endif /* LOG_BUNDLE_LOAD */ 4267 } 4268 return result; 4269} 4270 4271#endif /* !BINARY_SUPPORT_DLFCN */ 4272#endif /* BINARY_SUPPORT_DYLD */ 4273 4274#if defined(BINARY_SUPPORT_DLFCN) 4275 4276CF_PRIVATE Boolean _CFBundleDlfcnCheckLoaded(CFBundleRef bundle) { 4277 if (!bundle->_isLoaded) { 4278 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 4279 char buff[CFMaxPathSize]; 4280 4281 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { 4282 int mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD | RTLD_FIRST; 4283 void *handle = dlopen(buff, mode); 4284 if (handle) { 4285 if (!bundle->_handleCookie) { 4286 bundle->_handleCookie = handle; 4287#if LOG_BUNDLE_LOAD 4288 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x getting handle %p\n", bundle, buff, mode, bundle->_handleCookie); 4289#endif /* LOG_BUNDLE_LOAD */ 4290 } 4291 bundle->_isLoaded = true; 4292 } else { 4293#if LOG_BUNDLE_LOAD 4294 printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x no handle\n", bundle, buff, mode); 4295#endif /* LOG_BUNDLE_LOAD */ 4296 } 4297 } 4298 if (executableURL) CFRelease(executableURL); 4299 } 4300 return bundle->_isLoaded; 4301} 4302 4303CF_EXPORT Boolean _CFBundleDlfcnPreflight(CFBundleRef bundle, CFErrorRef *error) { 4304 Boolean retval = true; 4305 CFErrorRef localError = NULL; 4306 if (!bundle->_isLoaded) { 4307 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 4308 char buff[CFMaxPathSize]; 4309 4310 retval = false; 4311 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { 4312 retval = dlopen_preflight(buff); 4313 if (!retval && error) { 4314 CFArrayRef archs = CFBundleCopyExecutableArchitectures(bundle); 4315 CFStringRef debugString = NULL; 4316 const char *errorString = dlerror(); 4317 if (errorString && strlen(errorString) > 0) debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString); 4318 if (archs) { 4319 Boolean hasSuitableArch = false, hasRuntimeMismatch = false; 4320 CFIndex i, count = CFArrayGetCount(archs); 4321 SInt32 arch, curArch = _CFBundleCurrentArchitecture(); 4322 for (i = 0; !hasSuitableArch && i < count; i++) { 4323 if (CFNumberGetValue((CFNumberRef)CFArrayGetValueAtIndex(archs, i), kCFNumberSInt32Type, (void *)&arch) && arch == curArch) hasSuitableArch = true; 4324 } 4325#if defined(BINARY_SUPPORT_DYLD) 4326 if (hasSuitableArch) { 4327 uint32_t mainFlags = 0; 4328 if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) { 4329#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 4330 uint32_t bundleFlags = 0; 4331 if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true; 4332#endif 4333 } 4334 } 4335#endif /* BINARY_SUPPORT_DYLD */ 4336 if (hasRuntimeMismatch) { 4337 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableRuntimeMismatchError, debugString); 4338 } else if (!hasSuitableArch) { 4339 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableArchitectureMismatchError, debugString); 4340 } else { 4341 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLoadError, debugString); 4342 } 4343 CFRelease(archs); 4344 } else { 4345 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLoadError, debugString); 4346 } 4347 if (debugString) CFRelease(debugString); 4348 } 4349 } else { 4350 if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); 4351 } 4352 if (executableURL) CFRelease(executableURL); 4353 } 4354 if (!retval && error) *error = localError; 4355 return retval; 4356} 4357 4358CF_PRIVATE Boolean _CFBundleDlfcnLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) { 4359 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); 4360 if (!bundle->_isLoaded) { 4361 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 4362 char buff[CFMaxPathSize]; 4363 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { 4364 int mode = forceGlobal ? (RTLD_LAZY | RTLD_GLOBAL | RTLD_FIRST) : (RTLD_NOW | RTLD_LOCAL | RTLD_FIRST); 4365 void *cookie = dlopen(buff, mode); 4366#if LOG_BUNDLE_LOAD 4367 printf("dlfcn load bundle %p, dlopen of %s mode 0x%x returns handle %p\n", bundle, buff, mode, cookie); 4368#endif /* LOG_BUNDLE_LOAD */ 4369 if (cookie && cookie == bundle->_handleCookie) { 4370 // during the call to dlopen, arbitrary init routines may have run and caused bundle->_handleCookie to be set, in which case proper reference counting requires that reference to be released with dlclose 4371#if LOG_BUNDLE_LOAD 4372 printf("dlfcn load bundle %p closing existing reference to handle %p\n", bundle, cookie); 4373#endif /* LOG_BUNDLE_LOAD */ 4374 dlclose(bundle->_handleCookie); 4375 } 4376 bundle->_handleCookie = cookie; 4377 if (bundle->_handleCookie) { 4378 bundle->_isLoaded = true; 4379 } else { 4380 const char *errorString = dlerror(); 4381 if (error) { 4382 _CFBundleDlfcnPreflight(bundle, subError); 4383 if (!localError) { 4384 CFStringRef debugString = errorString ? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString) : NULL; 4385 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); 4386 if (debugString) CFRelease(debugString); 4387 } 4388 } else { 4389 CFStringRef executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff); 4390 if (errorString) { 4391 CFStringRef debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString); 4392 CFLog(__kCFLogBundle, CFSTR("Error loading %@: %@"), executableString, debugString); 4393 if (debugString) CFRelease(debugString); 4394 } else { 4395 CFLog(__kCFLogBundle, CFSTR("Error loading %@"), executableString); 4396 } 4397 if (executableString) CFRelease(executableString); 4398 } 4399 } 4400 } else { 4401 if (error) { 4402 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); 4403 } else { 4404 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); 4405 } 4406 } 4407 if (executableURL) CFRelease(executableURL); 4408 } 4409 if (!bundle->_isLoaded && error) *error = localError; 4410 return bundle->_isLoaded; 4411} 4412 4413CF_PRIVATE Boolean _CFBundleDlfcnLoadFramework(CFBundleRef bundle, CFErrorRef *error) { 4414 CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); 4415 if (!bundle->_isLoaded) { 4416 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 4417 char buff[CFMaxPathSize]; 4418 if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { 4419 int mode = RTLD_LAZY | RTLD_GLOBAL | RTLD_FIRST; 4420 void *cookie = dlopen(buff, mode); 4421#if LOG_BUNDLE_LOAD 4422 printf("dlfcn load framework %p, dlopen of %s mode 0x%x returns handle %p\n", bundle, buff, mode, cookie); 4423#endif /* LOG_BUNDLE_LOAD */ 4424 if (cookie && cookie == bundle->_handleCookie) { 4425 // during the call to dlopen, arbitrary init routines may have run and caused bundle->_handleCookie to be set, in which case proper reference counting requires that reference to be released with dlclose 4426#if LOG_BUNDLE_LOAD 4427 printf("dlfcn load framework %p closing existing reference to handle %p\n", bundle, cookie); 4428#endif /* LOG_BUNDLE_LOAD */ 4429 dlclose(bundle->_handleCookie); 4430 } 4431 bundle->_handleCookie = cookie; 4432 if (bundle->_handleCookie) { 4433 bundle->_isLoaded = true; 4434 } else { 4435 const char *errorString = dlerror(); 4436 if (error) { 4437 _CFBundleDlfcnPreflight(bundle, subError); 4438 if (!localError) { 4439 CFStringRef debugString = errorString ? CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString) : NULL; 4440 localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); 4441 if (debugString) CFRelease(debugString); 4442 } 4443 } else { 4444 CFStringRef executableString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff); 4445 if (errorString) { 4446 CFStringRef debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString); 4447 CFLog(__kCFLogBundle, CFSTR("Error loading %@: %@"), executableString, debugString); 4448 if (debugString) CFRelease(debugString); 4449 } else { 4450 CFLog(__kCFLogBundle, CFSTR("Error loading %@"), executableString); 4451 } 4452 if (executableString) CFRelease(executableString); 4453 } 4454 } 4455 } else { 4456 if (error) { 4457 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); 4458 } else { 4459 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); 4460 } 4461 } 4462 if (executableURL) CFRelease(executableURL); 4463 } 4464 if (!bundle->_isLoaded && error) *error = localError; 4465 return bundle->_isLoaded; 4466} 4467 4468CF_PRIVATE void _CFBundleDlfcnUnload(CFBundleRef bundle) { 4469 if (bundle->_isLoaded) { 4470#if LOG_BUNDLE_LOAD 4471 printf("dlfcn unload bundle %p, handle %p module %p image %p\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie); 4472#endif /* LOG_BUNDLE_LOAD */ 4473 if (0 != dlclose(bundle->_handleCookie)) { 4474 CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle); 4475 } else { 4476 bundle->_connectionCookie = bundle->_handleCookie = NULL; 4477 bundle->_imageCookie = bundle->_moduleCookie = NULL; 4478 bundle->_isLoaded = false; 4479 } 4480 } 4481} 4482 4483CF_PRIVATE void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) { 4484 return _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, symbolName, false); 4485} 4486 4487static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) { 4488 void *result = NULL; 4489 char buff[1026]; 4490 4491 if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingUTF8)) { 4492 result = dlsym(bundle->_handleCookie, buff); 4493 if (!result && globalSearch) result = dlsym(RTLD_DEFAULT, buff); 4494#if defined(DEBUG) 4495 if (!result) CFLog(__kCFLogBundle, CFSTR("dlsym cannot find symbol %@ in %@"), symbolName, bundle); 4496#endif /* DEBUG */ 4497#if LOG_BUNDLE_LOAD 4498 printf("bundle %p handle %p module %p image %p dlsym returns symbol %p for %s\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie, result, buff); 4499#endif /* LOG_BUNDLE_LOAD */ 4500 } 4501 return result; 4502} 4503 4504#if !defined(BINARY_SUPPORT_DYLD) 4505 4506static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p) { 4507 CFStringRef result = NULL; 4508 Dl_info info; 4509 if (0 != dladdr(p, &info) && info.dli_fname) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, info.dli_fname); 4510#if LOG_BUNDLE_LOAD 4511 printf("dlfcn image path for pointer %p is %p\n", p, result); 4512#endif /* LOG_BUNDLE_LOAD */ 4513 return result; 4514} 4515 4516#endif /* !BINARY_SUPPORT_DYLD */ 4517#endif /* BINARY_SUPPORT_DLFCN */ 4518 4519#if defined(BINARY_SUPPORT_DLL) 4520 4521CF_PRIVATE Boolean _CFBundleDLLLoad(CFBundleRef bundle, CFErrorRef *error) { 4522 CFErrorRef localError = NULL; 4523 if (!bundle->_isLoaded) { 4524 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 4525 wchar_t buff[CFMaxPathSize]; 4526 4527 if (executableURL && _CFURLGetWideFileSystemRepresentation(executableURL, true, (wchar_t *)buff, CFMaxPathSize)) { 4528 bundle->_hModule = LoadLibraryW(buff); 4529 if (bundle->_hModule) { 4530 bundle->_isLoaded = true; 4531 } else { 4532 if (error) { 4533 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError); 4534 } else { 4535 CFLog(__kCFLogBundle, CFSTR("Failed to load bundle %@"), bundle); 4536 } 4537 } 4538 } else { 4539 if (error) { 4540 localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); 4541 } else { 4542 CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); 4543 } 4544 } 4545 if (executableURL) CFRelease(executableURL); 4546 } 4547 if (!bundle->_isLoaded && error) *error = localError; 4548 return bundle->_isLoaded; 4549} 4550 4551CF_PRIVATE void _CFBundleDLLUnload(CFBundleRef bundle) { 4552 if (bundle->_isLoaded) { 4553 FreeLibrary(bundle->_hModule); 4554 bundle->_hModule = NULL; 4555 bundle->_isLoaded = false; 4556 } 4557} 4558 4559CF_PRIVATE void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) { 4560 void *result = NULL; 4561 char buff[1024]; 4562 if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingWindowsLatin1)) result = GetProcAddress(bundle->_hModule, buff); 4563 return result; 4564} 4565 4566#endif /* BINARY_SUPPORT_DLL */ 4567 4568/* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation. 4569*/ 4570 4571 4572 4573 4574