]> git.saurik.com Git - apple/cf.git/blame - Base.subproj/CFUtilities.c
CF-368.11.tar.gz
[apple/cf.git] / Base.subproj / CFUtilities.c
CommitLineData
9ce05555 1/*
d8925383 2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
9ce05555
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9ce05555
A
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/* CFUtilities.c
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26*/
27
d8925383 28#include "CFUtilitiesPriv.h"
9ce05555 29#include "CFInternal.h"
d8925383 30#include "CFPriv.h"
9ce05555
A
31#include <CoreFoundation/CFBundle.h>
32#include <CoreFoundation/CFURLAccess.h>
33#include <CoreFoundation/CFPropertyList.h>
34#include <CoreFoundation/CFTimeZone.h>
35#include <math.h>
36#include <string.h>
37#include <stdio.h>
d8925383 38#include <stdlib.h>
9ce05555
A
39#if defined(__MACH__)
40 #include <mach/mach.h>
41 #include <pthread.h>
9ce05555 42 #include <mach-o/loader.h>
d8925383 43 #include <mach-o/dyld.h>
9ce05555 44 #include <crt_externs.h>
d8925383 45 #include <dlfcn.h>
9ce05555 46 #include <Security/AuthSession.h>
d8925383 47 #include <sys/stat.h>
9ce05555
A
48#endif
49#if defined(__WIN32__)
50 #include <windows.h>
51 #include <process.h>
52#endif
53#if defined(__LINUX__) || defined(__FREEBSD__)
54 #include <string.h>
55 #include <pthread.h>
9ce05555
A
56#endif
57
9ce05555
A
58#define LESS16(A, W) do { if (A < ((uint64_t)1 << (W))) LESS8(A, (W) - 8); LESS8(A, (W) + 8); } while (0)
59#define LESS8(A, W) do { if (A < ((uint64_t)1 << (W))) LESS4(A, (W) - 4); LESS4(A, (W) + 4); } while (0)
60#define LESS4(A, W) do { if (A < ((uint64_t)1 << (W))) LESS2(A, (W) - 2); LESS2(A, (W) + 2); } while (0)
61#define LESS2(A, W) do { if (A < ((uint64_t)1 << (W))) LESS1(A, (W) - 1); LESS1(A, (W) + 1); } while (0)
62#define LESS1(A, W) do { if (A < ((uint64_t)1 << (W))) return (W) - 1; return (W); } while (0)
63
64uint32_t CFLog2(uint64_t x) {
65 if (x < ((uint64_t)1 << 32))
66 LESS16(x, 16);
67 LESS16(x, 48);
68 return 0;
69}
70
71#if 0
72// faster version for PPC
73int Lg2d(unsigned x) {
74// use PPC-specific instruction to count leading zeros
75 int ret;
76 if (0 == x) return 0;
77 __asm__ volatile("cntlzw %0,%1" : "=r" (ret) : "r" (x));
78 return 31 - ret;
79}
80#endif
81
82#undef LESS1
83#undef LESS2
84#undef LESS4
85#undef LESS8
86#undef LESS16
87
88/* Comparator is passed the address of the values. */
89/* Binary searches a sorted-increasing array of some type.
90 Return value is either 1) the index of the element desired,
91 if the target value exists in the list, 2) greater than or
92 equal to count, if the element is greater than all the values
93 in the list, or 3) the index of the element greater than the
94 target value.
95
96 For example, a search in the list of integers:
97 2 3 5 7 11 13 17
98
99 For... Will Return...
100 2 0
101 5 2
102 23 7
103 1 0
104 9 4
105
106 For instance, if you just care about found/not found:
107 index = CFBSearch(list, count, elem);
108 if (count <= index || list[index] != elem) {
109 * Not found *
110 } else {
111 * Found *
112 }
113
114 This isn't optimal yet.
115*/
116__private_extern__ CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
117 SInt32 idx, lg;
118 const char *ptr = (const char *)list;
119 if (count < 4) {
120 switch (count) {
121 case 3: if (comparator(ptr + elementSize * 2, element, context) < 0) return 3;
122 case 2: if (comparator(ptr + elementSize * 1, element, context) < 0) return 2;
123 case 1: if (comparator(ptr + elementSize * 0, element, context) < 0) return 1;
124 }
125 return 0;
126 }
127 if (comparator(ptr + elementSize * (count - 1), element, context) < 0) return count;
128 if (comparator(element, ptr + elementSize * 0, context) < 0) return 0;
129 lg = CFLog2(count); /* This takes about 1/3rd of the time, discounting calls to comparator */
130 idx = (comparator(ptr + elementSize * (-1 + (1 << lg)), element, context) < 0) ? count - (1 << lg) : -1;
131 switch (--lg) {
132 case 30: if (comparator(ptr + elementSize * (idx + (1 << 30)), element, context) < 0) idx += (1 << 30);
133 case 29: if (comparator(ptr + elementSize * (idx + (1 << 29)), element, context) < 0) idx += (1 << 29);
134 case 28: if (comparator(ptr + elementSize * (idx + (1 << 28)), element, context) < 0) idx += (1 << 28);
135 case 27: if (comparator(ptr + elementSize * (idx + (1 << 27)), element, context) < 0) idx += (1 << 27);
136 case 26: if (comparator(ptr + elementSize * (idx + (1 << 26)), element, context) < 0) idx += (1 << 26);
137 case 25: if (comparator(ptr + elementSize * (idx + (1 << 25)), element, context) < 0) idx += (1 << 25);
138 case 24: if (comparator(ptr + elementSize * (idx + (1 << 24)), element, context) < 0) idx += (1 << 24);
139 case 23: if (comparator(ptr + elementSize * (idx + (1 << 23)), element, context) < 0) idx += (1 << 23);
140 case 22: if (comparator(ptr + elementSize * (idx + (1 << 22)), element, context) < 0) idx += (1 << 22);
141 case 21: if (comparator(ptr + elementSize * (idx + (1 << 21)), element, context) < 0) idx += (1 << 21);
142 case 20: if (comparator(ptr + elementSize * (idx + (1 << 20)), element, context) < 0) idx += (1 << 20);
143 case 19: if (comparator(ptr + elementSize * (idx + (1 << 19)), element, context) < 0) idx += (1 << 19);
144 case 18: if (comparator(ptr + elementSize * (idx + (1 << 18)), element, context) < 0) idx += (1 << 18);
145 case 17: if (comparator(ptr + elementSize * (idx + (1 << 17)), element, context) < 0) idx += (1 << 17);
146 case 16: if (comparator(ptr + elementSize * (idx + (1 << 16)), element, context) < 0) idx += (1 << 16);
147 case 15: if (comparator(ptr + elementSize * (idx + (1 << 15)), element, context) < 0) idx += (1 << 15);
148 case 14: if (comparator(ptr + elementSize * (idx + (1 << 14)), element, context) < 0) idx += (1 << 14);
149 case 13: if (comparator(ptr + elementSize * (idx + (1 << 13)), element, context) < 0) idx += (1 << 13);
150 case 12: if (comparator(ptr + elementSize * (idx + (1 << 12)), element, context) < 0) idx += (1 << 12);
151 case 11: if (comparator(ptr + elementSize * (idx + (1 << 11)), element, context) < 0) idx += (1 << 11);
152 case 10: if (comparator(ptr + elementSize * (idx + (1 << 10)), element, context) < 0) idx += (1 << 10);
153 case 9: if (comparator(ptr + elementSize * (idx + (1 << 9)), element, context) < 0) idx += (1 << 9);
154 case 8: if (comparator(ptr + elementSize * (idx + (1 << 8)), element, context) < 0) idx += (1 << 8);
155 case 7: if (comparator(ptr + elementSize * (idx + (1 << 7)), element, context) < 0) idx += (1 << 7);
156 case 6: if (comparator(ptr + elementSize * (idx + (1 << 6)), element, context) < 0) idx += (1 << 6);
157 case 5: if (comparator(ptr + elementSize * (idx + (1 << 5)), element, context) < 0) idx += (1 << 5);
158 case 4: if (comparator(ptr + elementSize * (idx + (1 << 4)), element, context) < 0) idx += (1 << 4);
159 case 3: if (comparator(ptr + elementSize * (idx + (1 << 3)), element, context) < 0) idx += (1 << 3);
160 case 2: if (comparator(ptr + elementSize * (idx + (1 << 2)), element, context) < 0) idx += (1 << 2);
161 case 1: if (comparator(ptr + elementSize * (idx + (1 << 1)), element, context) < 0) idx += (1 << 1);
162 case 0: if (comparator(ptr + elementSize * (idx + (1 << 0)), element, context) < 0) idx += (1 << 0);
163 }
164 return ++idx;
165}
166
167
168#define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
169
170CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) {
171 /* The ELF hash algorithm, used in the ELF object file format */
172 UInt32 H = 0, T1, T2;
173 SInt32 rem = length;
174 while (3 < rem) {
175 ELF_STEP(bytes[length - rem]);
176 ELF_STEP(bytes[length - rem + 1]);
177 ELF_STEP(bytes[length - rem + 2]);
178 ELF_STEP(bytes[length - rem + 3]);
179 rem -= 4;
180 }
181 switch (rem) {
182 case 3: ELF_STEP(bytes[length - 3]);
183 case 2: ELF_STEP(bytes[length - 2]);
184 case 1: ELF_STEP(bytes[length - 1]);
185 case 0: ;
186 }
187 return H;
188}
189
190#undef ELF_STEP
191
192#if defined(__WIN32__)
193struct _args {
194 void *func;
195 void *arg;
196 HANDLE handle;
197};
198static __stdcall unsigned __CFWinThreadFunc(void *arg) {
199 struct _args *args = arg;
200 ((void (*)(void *))args->func)(args->arg);
201 CloseHandle(args->handle);
202 CFAllocatorDeallocate(kCFAllocatorSystemDefault, arg);
203 _endthreadex(0);
204 return 0;
205}
206#endif
207
208__private_extern__ void *__CFStartSimpleThread(void *func, void *arg) {
209#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
210 pthread_attr_t attr;
211 pthread_t tid;
212 pthread_attr_init(&attr);
213 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
214 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
215 pthread_attr_setstacksize(&attr, 60 * 1024); // 60K stack for our internal threads is sufficient
216 pthread_create(&tid, &attr, func, arg);
217 pthread_attr_destroy(&attr);
218//warning CF: we dont actually know that a pthread_t is the same size as void *
219 return (void *)tid;
220#else
221 unsigned tid;
222 struct _args *args = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0);
223 if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)");
224 HANDLE handle;
225 args->func = func;
226 args->arg = arg;
227 /* The thread is created suspended, because otherwise there would be a race between the assignment below of the handle field, and it's possible use in the thread func above. */
228 args->handle = (HANDLE)_beginthreadex(NULL, 0, (void *)__CFWinThreadFunc, args, CREATE_SUSPENDED, &tid);
229 handle = args->handle;
230 ResumeThread(handle);
231 return handle;
232#endif
233}
234
235__private_extern__ CFStringRef _CFCreateLimitedUniqueString() {
236 /* this unique string is only unique to the current host during the current boot */
237 uint64_t tsr = __CFReadTSR();
238 UInt32 tsrh = (tsr >> 32), tsrl = (tsr & (int64_t)0xFFFFFFFF);
239 return CFStringCreateWithFormat(NULL, NULL, CFSTR("CFUniqueString-%lu%lu$"), tsrh, tsrl);
240}
241
242
243// Looks for localized version of "nonLocalized" in the SystemVersion bundle
244// If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL
245// If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released
246
247static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) {
248 CFStringRef localized = NULL;
249 CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL;
250 if (!locBundle) {
251 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false);
252 if (url) {
253 locBundle = CFBundleCreate(kCFAllocatorDefault, url);
254 CFRelease(url);
255 }
256 }
257 if (locBundle) {
258 localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion"));
259 if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle);
260 }
261 return localized ? localized : CFRetain(nonLocalized);
262}
263
9ce05555
A
264static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) {
265 CFPropertyListRef plist = NULL;
266 CFDataRef data;
267 CFURLRef url;
268
269 url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false);
270 if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &data, NULL, NULL, NULL)) {
271 plist = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL);
272 CFRelease(data);
273 }
274 if (url) CFRelease(url);
275
276 if (plist) {
277 CFBundleRef locBundle = NULL;
278 CFStringRef fullVersion, vers, versExtra, build;
279 CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey);
280 CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey);
281 CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString"));
282 if (locBundle) CFRelease(locBundle);
283
284 // Now build the full version string
285 if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) {
286 CFRelease(fullVersionString);
287 fullVersionString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString);
288 }
289 vers = CFDictionaryGetValue(plist, _kCFSystemVersionProductVersionKey);
290 versExtra = CFDictionaryGetValue(plist, _kCFSystemVersionProductVersionExtraKey);
291 if (vers && versExtra) vers = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ %@"), vers, versExtra);
292 build = CFDictionaryGetValue(plist, _kCFSystemVersionBuildVersionKey);
293 fullVersion = CFStringCreateWithFormat(NULL, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?"));
294 if (vers && versExtra) CFRelease(vers);
295
296 CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString);
297 CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString);
298 CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion);
299 CFRelease(versionString);
300 CFRelease(buildString);
301 CFRelease(fullVersionString);
302 CFRelease(fullVersion);
303 }
304 return plist;
305}
306
307CFStringRef CFCopySystemVersionString(void) {
308 CFStringRef versionString;
309 CFDictionaryRef dict = _CFCopyServerVersionDictionary();
310 if (!dict) dict = _CFCopySystemVersionDictionary();
311 versionString = CFDictionaryGetValue(dict, CFSTR("FullVersionString"));
312 if (versionString) CFRetain(versionString);
313 CFRelease(dict);
314 return versionString;
315}
316
d8925383
A
317// Obsolete: These two functions cache the dictionaries to avoid calling _CFCopyVersionDictionary() more than once per dict desired
318// In fact, they do not cache any more, because the file can change after
319// apps are running in some situations, and apps need the new info.
320// Proper caching and testing to see if the file has changed, without race
321// conditions, would require semi-convoluted use of fstat().
9ce05555
A
322
323CFDictionaryRef _CFCopySystemVersionDictionary(void) {
d8925383 324 CFPropertyListRef plist = NULL;
9ce05555 325 plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
d8925383 326 return plist;
9ce05555
A
327}
328
329CFDictionaryRef _CFCopyServerVersionDictionary(void) {
d8925383 330 CFPropertyListRef plist = NULL;
9ce05555 331 plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
d8925383 332 return plist;
9ce05555
A
333}
334
335CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName")
336CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright")
337CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion")
338CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra")
339CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion")
340CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion")
341CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version")
342CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build")
343
344#if defined(__MACH__)
d8925383
A
345
346typedef struct {
347 uint16_t primaryVersion;
348 uint8_t secondaryVersion;
349 uint8_t tertiaryVersion;
350} CFLibraryVersion;
351
9ce05555
A
352CFLibraryVersion CFGetExecutableLinkedLibraryVersion(CFStringRef libraryName) {
353 CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
9ce05555 354 char library[CFMaxPathSize]; // search specs larger than this are pointless
9ce05555 355 if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
d8925383
A
356 int32_t version = NSVersionOfLinkTimeLibrary(library);
357 if (-1 != version) {
358 ret.primaryVersion = version >> 16;
359 ret.secondaryVersion = (version >> 8) & 0xff;
360 ret.tertiaryVersion = version & 0xff;
9ce05555
A
361 }
362 return ret;
363}
364
365CFLibraryVersion CFGetExecutingLibraryVersion(CFStringRef libraryName) {
366 CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
9ce05555 367 char library[CFMaxPathSize]; // search specs larger than this are pointless
9ce05555 368 if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
d8925383
A
369 int32_t version = NSVersionOfRunTimeLibrary(library);
370 if (-1 != version) {
371 ret.primaryVersion = version >> 16;
372 ret.secondaryVersion = (version >> 8) & 0xff;
373 ret.tertiaryVersion = version & 0xff;
9ce05555
A
374 }
375 return ret;
376}
377
378
379/*
380If
381 (vers != 0xFFFF): We know the version number of the library this app was linked against
382 and (versionInfo[version].VERSIONFIELD != 0xFFFF): And we know what version number started the specified release
383 and ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD)): And it's distinct from the prev release
384Then
385 If the version the app is linked against is less than the version recorded for the specified release
386 Then stop checking and return false
387 Else stop checking and return YES
388Else
389 Continue checking (the next library)
390*/
391#define checkLibrary(LIBNAME, VERSIONFIELD) \
d8925383 392 {uint16_t vers = (NSVersionOfLinkTimeLibrary(LIBNAME) >> 16); \
9ce05555
A
393 if ((vers != 0xFFFF) && (versionInfo[version].VERSIONFIELD != 0xFFFF) && ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD))) return (results[version] = ((vers < versionInfo[version].VERSIONFIELD) ? false : true)); }
394
395CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
396 // The numbers in the below table should be the numbers for any version of the framework in the release.
397 // When adding new entries to this table for a new build train, it's simplest to use the versions of the
398 // first new versions of projects submitted to the new train. These can later be updated. One thing to watch for is that software updates
399 // for the previous release do not increase numbers beyond the number used for the next release!
400 // For a given train, don't ever use the last versions submitted to the previous train! (This to assure room for software updates.)
401 // If versions are the same as previous release, use 0xFFFF; this will assure the answer is a conservative NO.
402 // NOTE: Also update the CFM check below, perhaps to the previous release... (???)
403 static const struct {
404 uint16_t libSystemVersion;
405 uint16_t cocoaVersion;
406 uint16_t appkitVersion;
407 uint16_t fouVersion;
408 uint16_t cfVersion;
409 uint16_t carbonVersion;
410 uint16_t applicationServicesVersion;
411 uint16_t coreServicesVersion;
412 uint16_t iokitVersion;
413 } versionInfo[] = {
414 {50, 5, 577, 397, 196, 113, 16, 9, 52}, /* CFSystemVersionCheetah (used the last versions) */
415 {55, 7, 620, 425, 226, 122, 16, 10, 67}, /* CFSystemVersionPuma (used the last versions) */
416 {56, 8, 631, 431, 232, 122, 17, 11, 73}, /* CFSystemVersionJaguar */
417 {67, 9, 704, 481, 281, 126, 19, 16, 159}, /* CFSystemVersionPanther */
d8925383
A
418 {73, 10, 750, 505, 305, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, /* CFSystemVersionTiger */
419 {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, /* CFSystemVersionChablis */
9ce05555 420 };
d8925383 421 static char results[CFSystemVersionMax] = {-2, -2, -2, -2, -2, -2}; /* We cache the results per-release; there are only a few of these... */
9ce05555
A
422 if (version >= CFSystemVersionMax) return false; /* Actually, we don't know the answer, and something scary is going on */
423 if (results[version] != -2) return results[version];
424
425 if (_CFIsCFM()) {
426 results[version] = (version <= CFSystemVersionJaguar) ? true : false;
427 return results[version];
428 }
429
d8925383
A
430 checkLibrary("System", libSystemVersion); // Pretty much everyone links with this
431 checkLibrary("Cocoa", cocoaVersion);
432 checkLibrary("AppKit", appkitVersion);
433 checkLibrary("Foundation", fouVersion);
434 checkLibrary("CoreFoundation", cfVersion);
435 checkLibrary("Carbon", carbonVersion);
436 checkLibrary("ApplicationServices", applicationServicesVersion);
437 checkLibrary("CoreServices", coreServicesVersion);
438 checkLibrary("IOKit", iokitVersion);
9ce05555
A
439
440 /* If not found, then simply return NO to indicate earlier --- compatibility by default, unfortunately */
441 return false;
442}
d8925383
A
443#else
444CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
445 return true;
446}
9ce05555
A
447#endif
448
449
d8925383
A
450__private_extern__ void *__CFLookupCarbonCoreFunction(const char *name) {
451 static void *image = NULL;
452 if (NULL == image) {
453 image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY | RTLD_LOCAL);
454 }
455 void *dyfunc = NULL;
456 if (image) {
457 dyfunc = dlsym(image, name);
458 }
459 return dyfunc;
460}
461
462__private_extern__ void *__CFLookupCFNetworkFunction(const char *name) {
463 static void *image = NULL;
464 if (NULL == image) {
465 image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork", RTLD_LAZY | RTLD_LOCAL);
466 }
467 void *dyfunc = NULL;
468 if (image) {
469 dyfunc = dlsym(image, name);
470 }
471 return dyfunc;
472}
9ce05555
A
473
474
d8925383
A
475
476static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) {
9ce05555
A
477 CFStringRef str;
478 CFIndex idx, cnt;
479 CFStringInlineBuffer buffer;
480 bool lastNL = false;
481
482 if (obj) {
483 if (CFGetTypeID(obj) == CFStringGetTypeID()) {
484 // Makes Ali marginally happier
485 str = __CFCopyFormattingDescription(obj, NULL);
486 if (!str) str = CFCopyDescription(obj);
487 } else {
488 str = CFCopyDescription(obj);
489 }
490 } else {
491 str = CFRetain(CFSTR("(null)"));
492 }
493 cnt = CFStringGetLength(str);
494
d8925383
A
495 // iTunes used OutputDebugStringW(theString);
496
9ce05555
A
497 CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
498 for (idx = 0; idx < cnt; idx++) {
499 UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
500 if (ch < 128) {
d8925383 501 fprintf(file, "%c", ch);
9ce05555
A
502 lastNL = (ch == '\n');
503 } else {
d8925383 504 fprintf(file, "\\u%04x", ch);
9ce05555
A
505 }
506 }
d8925383
A
507 if (!lastNL) {
508 fprintf(file, "\n");
509 if (flush) fflush(file);
510 }
9ce05555
A
511
512 if (str) CFRelease(str);
513}
514
d8925383
A
515void CFShow(const void *obj) {
516 _CFShowToFile(stderr, true, obj);
517}
518
519static CFGregorianDate gregorianDate(void) {
520 CFTimeZoneRef tz = CFTimeZoneCopySystem(); // specifically choose system time zone for logs
521 CFGregorianDate gdate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz);
522 CFRelease(tz);
523 gdate.second = gdate.second + 0.0005;
524 return gdate;
525}
526
9ce05555
A
527void CFLog(int p, CFStringRef format, ...) {
528 CFStringRef result;
529 va_list argList;
530 static CFSpinLock_t lock = 0;
531
532 va_start(argList, format);
533 result = CFStringCreateWithFormatAndArguments(NULL, NULL, format, argList);
534 va_end(argList);
535
536 __CFSpinLock(&lock);
537#if defined(__WIN32__)
d8925383 538 fprintf(stderr, "*** %s[%ld] CFLog(%d): ", *_CFGetProgname(), GetCurrentProcessId(), p);
9ce05555 539#else
d8925383
A
540 CFGregorianDate gdate = gregorianDate();
541 // Date format: YYYY '-' MM '-' DD ' ' hh ':' mm ':' ss.fff
542 fprintf_l(stderr, NULL, "%04d-%02d-%02d %02d:%02d:%06.3f %s[%d] CFLog (%d): ", (int)gdate.year, gdate.month, gdate.day, gdate.hour, gdate.minute, gdate.second, *_CFGetProgname(), getpid(), p);
9ce05555
A
543#endif
544
545 CFShow(result);
546 __CFSpinUnlock(&lock);
547 CFRelease(result);
548}
549
d8925383 550