2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1998-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
28 #include "CFUtilitiesPriv.h"
29 #include "CFInternal.h"
31 #include <CoreFoundation/CFBundle.h>
32 #include <CoreFoundation/CFURLAccess.h>
33 #include <CoreFoundation/CFPropertyList.h>
34 #include <CoreFoundation/CFTimeZone.h>
40 #include <mach/mach.h>
42 #include <mach-o/loader.h>
43 #include <mach-o/dyld.h>
44 #include <crt_externs.h>
46 #include <Security/AuthSession.h>
49 #if defined(__WIN32__)
53 #if defined(__LINUX__) || defined(__FREEBSD__)
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)
64 uint32_t CFLog2(uint64_t x
) {
65 if (x
< ((uint64_t)1 << 32))
72 // faster version for PPC
73 int Lg2d(unsigned x
) {
74 // use PPC-specific instruction to count leading zeros
77 __asm__
volatile("cntlzw %0,%1" : "=r" (ret
) : "r" (x
));
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
96 For example, a search in the list of integers:
106 For instance, if you just care about found/not found:
107 index = CFBSearch(list, count, elem);
108 if (count <= index || list[index] != elem) {
114 This isn't optimal yet.
116 __private_extern__ CFIndex
CFBSearch(const void *element
, CFIndex elementSize
, const void *list
, CFIndex count
, CFComparatorFunction comparator
, void *context
) {
118 const char *ptr
= (const char *)list
;
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;
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;
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);
168 #define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
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
;
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]);
182 case 3: ELF_STEP(bytes
[length
- 3]);
183 case 2: ELF_STEP(bytes
[length
- 2]);
184 case 1: ELF_STEP(bytes
[length
- 1]);
192 #if defined(__WIN32__)
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
);
208 __private_extern__
void *__CFStartSimpleThread(void *func
, void *arg
) {
209 #if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
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 *
222 struct _args
*args
= CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct _args
), 0);
223 if (__CFOASafe
) __CFSetLastAllocationEventName(args
, "CFUtilities (thread-args)");
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
);
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
);
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
247 static CFStringRef
_CFCopyLocalizedVersionKey(CFBundleRef
*bundlePtr
, CFStringRef nonLocalized
) {
248 CFStringRef localized
= NULL
;
249 CFBundleRef locBundle
= bundlePtr
? *bundlePtr
: NULL
;
251 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle
, false);
253 locBundle
= CFBundleCreate(kCFAllocatorDefault
, url
);
258 localized
= CFBundleCopyLocalizedString(locBundle
, nonLocalized
, nonLocalized
, CFSTR("SystemVersion"));
259 if (bundlePtr
) *bundlePtr
= locBundle
; else CFRelease(locBundle
);
261 return localized
? localized
: CFRetain(nonLocalized
);
264 static CFDictionaryRef
_CFCopyVersionDictionary(CFStringRef path
) {
265 CFPropertyListRef plist
= NULL
;
269 url
= CFURLCreateWithFileSystemPath(kCFAllocatorDefault
, path
, kCFURLPOSIXPathStyle
, false);
270 if (url
&& CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, url
, &data
, NULL
, NULL
, NULL
)) {
271 plist
= CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, data
, kCFPropertyListMutableContainers
, NULL
);
274 if (url
) CFRelease(url
);
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
);
284 // Now build the full version string
285 if (CFEqual(fullVersionString
, CFSTR("FullVersionString"))) {
286 CFRelease(fullVersionString
);
287 fullVersionString
= CFStringCreateWithFormat(NULL
, NULL
, CFSTR("%@ %%@ (%@ %%@)"), versionString
, buildString
);
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
);
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
);
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
);
314 return versionString
;
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().
323 CFDictionaryRef
_CFCopySystemVersionDictionary(void) {
324 CFPropertyListRef plist
= NULL
;
325 plist
= _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
329 CFDictionaryRef
_CFCopyServerVersionDictionary(void) {
330 CFPropertyListRef plist
= NULL
;
331 plist
= _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
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")
344 #if defined(__MACH__)
347 uint16_t primaryVersion
;
348 uint8_t secondaryVersion
;
349 uint8_t tertiaryVersion
;
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
);
358 ret
.primaryVersion
= version
>> 16;
359 ret
.secondaryVersion
= (version
>> 8) & 0xff;
360 ret
.tertiaryVersion
= version
& 0xff;
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
);
371 ret
.primaryVersion
= version
>> 16;
372 ret
.secondaryVersion
= (version
>> 8) & 0xff;
373 ret
.tertiaryVersion
= version
& 0xff;
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
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
389 Continue checking (the next library)
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)); }
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
;
409 uint16_t carbonVersion
;
410 uint16_t applicationServicesVersion
;
411 uint16_t coreServicesVersion
;
412 uint16_t iokitVersion
;
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 */
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
];
426 results
[version
] = (version
<= CFSystemVersionJaguar
) ? true : false;
427 return results
[version
];
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
);
440 /* If not found, then simply return NO to indicate earlier --- compatibility by default, unfortunately */
444 CF_EXPORT Boolean
_CFExecutableLinkedOnOrAfter(CFSystemVersion version
) {
450 __private_extern__
void *__CFLookupCarbonCoreFunction(const char *name
) {
451 static void *image
= NULL
;
453 image
= dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY
| RTLD_LOCAL
);
457 dyfunc
= dlsym(image
, name
);
462 __private_extern__
void *__CFLookupCFNetworkFunction(const char *name
) {
463 static void *image
= NULL
;
465 image
= dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork", RTLD_LAZY
| RTLD_LOCAL
);
469 dyfunc
= dlsym(image
, name
);
476 static void _CFShowToFile(FILE *file
, Boolean flush
, const void *obj
) {
479 CFStringInlineBuffer buffer
;
483 if (CFGetTypeID(obj
) == CFStringGetTypeID()) {
484 // Makes Ali marginally happier
485 str
= __CFCopyFormattingDescription(obj
, NULL
);
486 if (!str
) str
= CFCopyDescription(obj
);
488 str
= CFCopyDescription(obj
);
491 str
= CFRetain(CFSTR("(null)"));
493 cnt
= CFStringGetLength(str
);
495 // iTunes used OutputDebugStringW(theString);
497 CFStringInitInlineBuffer(str
, &buffer
, CFRangeMake(0, cnt
));
498 for (idx
= 0; idx
< cnt
; idx
++) {
499 UniChar ch
= __CFStringGetCharacterFromInlineBufferQuick(&buffer
, idx
);
501 fprintf(file
, "%c", ch
);
502 lastNL
= (ch
== '\n');
504 fprintf(file
, "\\u%04x", ch
);
509 if (flush
) fflush(file
);
512 if (str
) CFRelease(str
);
515 void CFShow(const void *obj
) {
516 _CFShowToFile(stderr
, true, obj
);
519 static CFGregorianDate
gregorianDate(void) {
520 CFTimeZoneRef tz
= CFTimeZoneCopySystem(); // specifically choose system time zone for logs
521 CFGregorianDate gdate
= CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz
);
523 gdate
.second
= gdate
.second
+ 0.0005;
527 void CFLog(int p
, CFStringRef format
, ...) {
530 static CFSpinLock_t lock
= 0;
532 va_start(argList
, format
);
533 result
= CFStringCreateWithFormatAndArguments(NULL
, NULL
, format
, argList
);
537 #if defined(__WIN32__)
538 fprintf(stderr
, "*** %s[%ld] CFLog(%d): ", *_CFGetProgname(), GetCurrentProcessId(), p
);
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
);
546 __CFSpinUnlock(&lock
);