2 * Copyright (c) 2008 Apple 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
29 #include "CFInternal.h"
31 #include <CoreFoundation/CFBundle.h>
32 #include <CoreFoundation/CFURLAccess.h>
33 #include <CoreFoundation/CFPropertyList.h>
34 #include <CoreFoundation/CFTimeZone.h>
35 #include <CoreFoundation/CFCalendar.h>
36 #if (DEPLOYMENT_TARGET_MACOSX)
37 #include <CoreFoundation/CFLogUtilities.h>
45 #if DEPLOYMENT_TARGET_MACOSX
46 #include <mach/mach.h>
48 #include <mach-o/loader.h>
49 #include <mach-o/dyld.h>
50 #include <crt_externs.h>
53 #include <vproc_priv.h>
56 #include <mach/mach.h>
57 #include <mach/mach_vm.h>
60 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
66 /* Comparator is passed the address of the values. */
67 /* Binary searches a sorted-increasing array of some type.
68 Return value is either 1) the index of the element desired,
69 if the target value exists in the list, 2) greater than or
70 equal to count, if the element is greater than all the values
71 in the list, or 3) the index of the element greater than the
74 For example, a search in the list of integers:
84 For instance, if you just care about found/not found:
85 index = CFBSearch(list, count, elem);
86 if (count <= index || list[index] != elem) {
93 __private_extern__ CFIndex
CFBSearch(const void *element
, CFIndex elementSize
, const void *list
, CFIndex count
, CFComparatorFunction comparator
, void *context
) {
94 const char *ptr
= (const char *)list
;
96 CFIndex half
= count
/ 2;
97 const char *probe
= ptr
+ elementSize
* half
;
98 CFComparisonResult cr
= comparator(element
, probe
, context
);
99 if (0 == cr
) return (probe
- (const char *)list
) / elementSize
;
100 ptr
= (cr
< 0) ? ptr
: probe
+ elementSize
;
101 count
= (cr
< 0) ? half
: (half
+ (count
& 1) - 1);
103 return (ptr
- (const char *)list
) / elementSize
;
107 #define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
109 CFHashCode
CFHashBytes(uint8_t *bytes
, CFIndex length
) {
110 /* The ELF hash algorithm, used in the ELF object file format */
111 UInt32 H
= 0, T1
, T2
;
114 ELF_STEP(bytes
[length
- rem
]);
115 ELF_STEP(bytes
[length
- rem
+ 1]);
116 ELF_STEP(bytes
[length
- rem
+ 2]);
117 ELF_STEP(bytes
[length
- rem
+ 3]);
121 case 3: ELF_STEP(bytes
[length
- 3]);
122 case 2: ELF_STEP(bytes
[length
- 2]);
123 case 1: ELF_STEP(bytes
[length
- 1]);
132 #if DEPLOYMENT_TARGET_MACOSX
133 __private_extern__
uintptr_t __CFFindPointer(uintptr_t ptr
, uintptr_t start
) {
134 vm_map_t task
= mach_task_self();
135 mach_vm_address_t address
= start
;
137 mach_vm_size_t size
= 0;
138 vm_region_basic_info_data_64_t info
;
139 mach_msg_type_number_t count
= VM_REGION_BASIC_INFO_COUNT_64
;
140 mach_port_t object_name
;
141 kern_return_t ret
= mach_vm_region(task
, &address
, &size
, VM_REGION_BASIC_INFO_64
, (vm_region_info_t
)&info
, &count
, &object_name
);
142 if (KERN_SUCCESS
!= ret
) break;
143 boolean_t scan
= (info
.protection
& VM_PROT_WRITE
) ? 1 : 0;
145 uintptr_t *addr
= (uintptr_t *)((uintptr_t)address
);
146 uintptr_t *end
= (uintptr_t *)((uintptr_t)address
+ (uintptr_t)size
);
148 if ((uintptr_t *)start
<= addr
&& *addr
== ptr
) {
149 return (uintptr_t)addr
;
161 __private_extern__
void *__CFStartSimpleThread(void *func
, void *arg
) {
162 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
165 pthread_attr_init(&attr
);
166 pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
);
167 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
168 pthread_attr_setstacksize(&attr
, 60 * 1024); // 60K stack for our internal threads is sufficient
169 OSMemoryBarrier(); // ensure arg is fully initialized and set in memory
170 pthread_create(&tid
, &attr
, func
, arg
);
171 pthread_attr_destroy(&attr
);
172 //warning CF: we dont actually know that a pthread_t is the same size as void *
176 struct _args
*args
= (struct _args
*)CFAllocatorAllocate(kCFAllocatorSystemDefault
, sizeof(struct _args
), 0);
177 if (__CFOASafe
) __CFSetLastAllocationEventName(args
, "CFUtilities (thread-args)");
181 /* 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. */
182 args
->handle
= (HANDLE
)_beginthreadex(NULL
, 0, __CFWinThreadFunc
, args
, CREATE_SUSPENDED
, &tid
);
183 handle
= args
->handle
;
184 ResumeThread(handle
);
189 __private_extern__ CFStringRef
_CFCreateLimitedUniqueString() {
190 /* this unique string is only unique to the current host during the current boot */
191 uint64_t tsr
= __CFReadTSR();
192 UInt32 tsrh
= (UInt32
)(tsr
>> 32), tsrl
= (UInt32
)(tsr
& (int64_t)0xFFFFFFFF);
193 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("CFUniqueString-%lu%lu$"), tsrh
, tsrl
);
197 // Looks for localized version of "nonLocalized" in the SystemVersion bundle
198 // If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL
199 // If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released
201 static CFStringRef
_CFCopyLocalizedVersionKey(CFBundleRef
*bundlePtr
, CFStringRef nonLocalized
) {
202 CFStringRef localized
= NULL
;
203 CFBundleRef locBundle
= bundlePtr
? *bundlePtr
: NULL
;
205 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle
, false);
207 locBundle
= CFBundleCreate(kCFAllocatorSystemDefault
, url
);
212 localized
= CFBundleCopyLocalizedString(locBundle
, nonLocalized
, nonLocalized
, CFSTR("SystemVersion"));
213 if (bundlePtr
) *bundlePtr
= locBundle
; else CFRelease(locBundle
);
215 return localized
? localized
: (CFStringRef
)CFRetain(nonLocalized
);
218 static CFDictionaryRef
_CFCopyVersionDictionary(CFStringRef path
) {
219 CFPropertyListRef plist
= NULL
;
223 url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, path
, kCFURLPOSIXPathStyle
, false);
224 if (url
&& CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault
, url
, &data
, NULL
, NULL
, NULL
)) {
225 plist
= CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault
, data
, kCFPropertyListMutableContainers
, NULL
);
228 if (url
) CFRelease(url
);
231 #if DEPLOYMENT_TARGET_MACOSX
232 CFBundleRef locBundle
= NULL
;
233 CFStringRef fullVersion
, vers
, versExtra
, build
;
234 CFStringRef versionString
= _CFCopyLocalizedVersionKey(&locBundle
, _kCFSystemVersionProductVersionStringKey
);
235 CFStringRef buildString
= _CFCopyLocalizedVersionKey(&locBundle
, _kCFSystemVersionBuildStringKey
);
236 CFStringRef fullVersionString
= _CFCopyLocalizedVersionKey(&locBundle
, CFSTR("FullVersionString"));
237 if (locBundle
) CFRelease(locBundle
);
239 // Now build the full version string
240 if (CFEqual(fullVersionString
, CFSTR("FullVersionString"))) {
241 CFRelease(fullVersionString
);
242 fullVersionString
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@ %%@ (%@ %%@)"), versionString
, buildString
);
244 vers
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)plist
, _kCFSystemVersionProductVersionKey
);
245 versExtra
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)plist
, _kCFSystemVersionProductVersionExtraKey
);
246 if (vers
&& versExtra
) vers
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@ %@"), vers
, versExtra
);
247 build
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)plist
, _kCFSystemVersionBuildVersionKey
);
248 fullVersion
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, fullVersionString
, (vers
? vers
: CFSTR("?")), build
? build
: CFSTR("?"));
249 if (vers
&& versExtra
) CFRelease(vers
);
251 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, _kCFSystemVersionProductVersionStringKey
, versionString
);
252 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, _kCFSystemVersionBuildStringKey
, buildString
);
253 CFDictionarySetValue((CFMutableDictionaryRef
)plist
, CFSTR("FullVersionString"), fullVersion
);
254 CFRelease(versionString
);
255 CFRelease(buildString
);
256 CFRelease(fullVersionString
);
257 CFRelease(fullVersion
);
260 return (CFDictionaryRef
)plist
;
263 #if defined (__MACH__) || 0
264 CFStringRef
CFCopySystemVersionString(void) {
265 CFStringRef versionString
;
266 CFDictionaryRef dict
= _CFCopyServerVersionDictionary();
267 if (!dict
) dict
= _CFCopySystemVersionDictionary();
268 versionString
= CFDictionaryGetValue(dict
, CFSTR("FullVersionString"));
269 if (versionString
) CFRetain(versionString
);
271 return versionString
;
274 // Obsolete: These two functions cache the dictionaries to avoid calling _CFCopyVersionDictionary() more than once per dict desired
275 // In fact, they do not cache any more, because the file can change after
276 // apps are running in some situations, and apps need the new info.
277 // Proper caching and testing to see if the file has changed, without race
278 // conditions, would require semi-convoluted use of fstat().
280 CFDictionaryRef
_CFCopySystemVersionDictionary(void) {
281 CFPropertyListRef plist
= NULL
;
282 plist
= _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
286 CFDictionaryRef
_CFCopyServerVersionDictionary(void) {
287 CFPropertyListRef plist
= NULL
;
288 plist
= _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
292 CONST_STRING_DECL(_kCFSystemVersionProductNameKey
, "ProductName")
293 CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey
, "ProductCopyright")
294 CONST_STRING_DECL(_kCFSystemVersionProductVersionKey
, "ProductVersion")
295 CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey
, "ProductVersionExtra")
296 CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey
, "ProductUserVisibleVersion")
297 CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey
, "ProductBuildVersion")
298 CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey
, "Version")
299 CONST_STRING_DECL(_kCFSystemVersionBuildStringKey
, "Build")
302 CF_EXPORT Boolean
_CFExecutableLinkedOnOrAfter(CFSystemVersion version
) {
306 #if DEPLOYMENT_TARGET_MACOSX
307 __private_extern__
void *__CFLookupCFNetworkFunction(const char *name
) {
308 static void *image
= NULL
;
310 const char *path
= NULL
;
312 path
= getenv("CFNETWORK_LIBRARY_PATH");
315 path
= "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork";
317 image
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
321 dyfunc
= dlsym(image
, name
);
328 #ifndef __CFGetSessionID_defined
330 __private_extern__
uint32_t __CFGetSessionID(void) {
336 const char *_CFPrintForDebugger(const void *obj
) {
337 static char *result
= NULL
;
341 free(result
); // Let go of result from previous call.
344 if (CFGetTypeID(obj
) == CFStringGetTypeID()) {
345 // Makes Ali marginally happier
346 str
= __CFCopyFormattingDescription(obj
, NULL
);
347 if (!str
) str
= CFCopyDescription(obj
);
349 str
= CFCopyDescription(obj
);
352 str
= (CFStringRef
)CFRetain(CFSTR("(null)"));
356 CFStringGetBytes(str
, CFRangeMake(0, CFStringGetLength(str
)), kCFStringEncodingUTF8
, 0, FALSE
, NULL
, 0, &cnt
);
358 result
= (char *) malloc(cnt
+ 2); // 1 for '\0', 1 for an optional '\n'
360 CFStringGetBytes(str
, CFRangeMake(0, CFStringGetLength(str
)), kCFStringEncodingUTF8
, 0, FALSE
, (UInt8
*) result
, cnt
, &cnt
);
364 if (str
) CFRelease(str
);
368 static void _CFShowToFile(FILE *file
, Boolean flush
, const void *obj
) {
371 CFStringInlineBuffer buffer
;
375 if (CFGetTypeID(obj
) == CFStringGetTypeID()) {
376 // Makes Ali marginally happier
377 str
= __CFCopyFormattingDescription(obj
, NULL
);
378 if (!str
) str
= CFCopyDescription(obj
);
380 str
= CFCopyDescription(obj
);
383 str
= (CFStringRef
)CFRetain(CFSTR("(null)"));
385 cnt
= CFStringGetLength(str
);
387 // iTunes used OutputDebugStringW(theString);
389 CFStringInitInlineBuffer(str
, &buffer
, CFRangeMake(0, cnt
));
390 #if defined (__WIN32__)
391 TCHAR
*accumulatedBuffer
= (TCHAR
*)malloc((cnt
+1) * sizeof(TCHAR
));
393 for (idx
= 0; idx
< cnt
; idx
++) {
394 UniChar ch
= __CFStringGetCharacterFromInlineBufferQuick(&buffer
, idx
);
396 #if DEPLOYMENT_TARGET_MACOSX
398 fprintf_l(file
, NULL
, "%c", ch
);
399 lastNL
= (ch
== '\n');
401 fprintf_l(file
, NULL
, "\\u%04x", ch
);
403 #elif defined (__WIN32__)
405 _fprintf_l(file
, "%c", NULL
, ch
);
406 lastNL
= (ch
== '\n');
408 _fprintf_l(file
, "\\u%04x", NULL
, ch
);
412 #if defined(__WIN32__)
416 #if DEPLOYMENT_TARGET_MACOSX
417 fprintf_l(file
, NULL
, "\n");
419 if (flush
) fflush(file
);
422 if (str
) CFRelease(str
);
425 void CFShow(const void *obj
) {
426 _CFShowToFile(stderr
, true, obj
);
431 void CFLog(int32_t lev
, CFStringRef format
, ...) {
434 static CFSpinLock_t lock
= CFSpinLockInit
;
436 va_start(argList
, format
);
437 result
= CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault
, NULL
, format
, argList
);
441 CFTimeZoneRef tz
= CFTimeZoneCopySystem(); // specifically choose system time zone for logs
442 CFGregorianDate gdate
= CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz
);
444 gdate
.second
= gdate
.second
+ 0.0005;
445 // Date format: YYYY '-' MM '-' DD ' ' hh ':' mm ':' ss.fff
446 fprintf_l(stderr
, NULL
, "%04d-%02d-%02d %02d:%02d:%06.3f %s[%d:%x] CFLog: ", (int)gdate
.year
, gdate
.month
, gdate
.day
, gdate
.hour
, gdate
.minute
, gdate
.second
, *_CFGetProgname(), getpid(), pthread_mach_thread_np(pthread_self()));
449 __CFSpinUnlock(&lock
);