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