]> git.saurik.com Git - apple/cf.git/blob - Base.subproj/CFUtilities.c
CF-368.tar.gz
[apple/cf.git] / Base.subproj / CFUtilities.c
1 /*
2 * Copyright (c) 2005 Apple Computer, 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 /* CFUtilities.c
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28 #include "CFUtilitiesPriv.h"
29 #include "CFInternal.h"
30 #include "CFPriv.h"
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>
38 #include <stdlib.h>
39 #if defined(__MACH__)
40 #include <mach/mach.h>
41 #include <pthread.h>
42 #include <mach-o/loader.h>
43 #include <mach-o/dyld.h>
44 #include <crt_externs.h>
45 #include <dlfcn.h>
46 #include <Security/AuthSession.h>
47 #include <sys/stat.h>
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>
56 #endif
57
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
64 uint32_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
73 int 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
170 CFHashCode 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__)
193 struct _args {
194 void *func;
195 void *arg;
196 HANDLE handle;
197 };
198 static __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
247 static 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
264 static 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
307 CFStringRef 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
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().
322
323 CFDictionaryRef _CFCopySystemVersionDictionary(void) {
324 CFPropertyListRef plist = NULL;
325 plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
326 return plist;
327 }
328
329 CFDictionaryRef _CFCopyServerVersionDictionary(void) {
330 CFPropertyListRef plist = NULL;
331 plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
332 return plist;
333 }
334
335 CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName")
336 CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright")
337 CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion")
338 CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra")
339 CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion")
340 CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion")
341 CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version")
342 CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build")
343
344 #if defined(__MACH__)
345
346 typedef struct {
347 uint16_t primaryVersion;
348 uint8_t secondaryVersion;
349 uint8_t tertiaryVersion;
350 } CFLibraryVersion;
351
352 CFLibraryVersion CFGetExecutableLinkedLibraryVersion(CFStringRef libraryName) {
353 CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
354 char library[CFMaxPathSize]; // search specs larger than this are pointless
355 if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
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;
361 }
362 return ret;
363 }
364
365 CFLibraryVersion CFGetExecutingLibraryVersion(CFStringRef libraryName) {
366 CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
367 char library[CFMaxPathSize]; // search specs larger than this are pointless
368 if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
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;
374 }
375 return ret;
376 }
377
378
379 /*
380 If
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
384 Then
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
388 Else
389 Continue checking (the next library)
390 */
391 #define checkLibrary(LIBNAME, VERSIONFIELD) \
392 {uint16_t vers = (NSVersionOfLinkTimeLibrary(LIBNAME) >> 16); \
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
395 CF_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 */
418 {73, 10, 750, 505, 305, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, /* CFSystemVersionTiger */
419 {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, /* CFSystemVersionChablis */
420 };
421 static char results[CFSystemVersionMax] = {-2, -2, -2, -2, -2, -2}; /* We cache the results per-release; there are only a few of these... */
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
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);
439
440 /* If not found, then simply return NO to indicate earlier --- compatibility by default, unfortunately */
441 return false;
442 }
443 #else
444 CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
445 return true;
446 }
447 #endif
448
449
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 }
473
474
475
476 static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) {
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
495 // iTunes used OutputDebugStringW(theString);
496
497 CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
498 for (idx = 0; idx < cnt; idx++) {
499 UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
500 if (ch < 128) {
501 fprintf(file, "%c", ch);
502 lastNL = (ch == '\n');
503 } else {
504 fprintf(file, "\\u%04x", ch);
505 }
506 }
507 if (!lastNL) {
508 fprintf(file, "\n");
509 if (flush) fflush(file);
510 }
511
512 if (str) CFRelease(str);
513 }
514
515 void CFShow(const void *obj) {
516 _CFShowToFile(stderr, true, obj);
517 }
518
519 static 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
527 void 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__)
538 fprintf(stderr, "*** %s[%ld] CFLog(%d): ", *_CFGetProgname(), GetCurrentProcessId(), p);
539 #else
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);
543 #endif
544
545 CFShow(result);
546 __CFSpinUnlock(&lock);
547 CFRelease(result);
548 }
549
550