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