]> git.saurik.com Git - apple/cf.git/blob - CFUtilities.c
CF-476.10.tar.gz
[apple/cf.git] / CFUtilities.c
1 /*
2 * Copyright (c) 2008 Apple 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 "CFPriv.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 <CoreFoundation/CFCalendar.h>
36 #if (DEPLOYMENT_TARGET_MACOSX)
37 #include <CoreFoundation/CFLogUtilities.h>
38 #include <asl.h>
39 #include <sys/uio.h>
40 #endif
41 #include <math.h>
42 #include <string.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #if DEPLOYMENT_TARGET_MACOSX
46 #include <mach/mach.h>
47 #include <pthread.h>
48 #include <mach-o/loader.h>
49 #include <mach-o/dyld.h>
50 #include <crt_externs.h>
51 #include <dlfcn.h>
52 #include <vproc.h>
53 #include <vproc_priv.h>
54 #include <sys/stat.h>
55 #include <unistd.h>
56 #include <mach/mach.h>
57 #include <mach/mach_vm.h>
58 #include <stdio.h>
59 #endif
60 #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
61 #include <string.h>
62 #include <pthread.h>
63 #endif
64
65
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
72 target value.
73
74 For example, a search in the list of integers:
75 2 3 5 7 11 13 17
76
77 For... Will Return...
78 2 0
79 5 2
80 23 7
81 1 0
82 9 4
83
84 For instance, if you just care about found/not found:
85 index = CFBSearch(list, count, elem);
86 if (count <= index || list[index] != elem) {
87 * Not found *
88 } else {
89 * Found *
90 }
91
92 */
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;
95 while (0 < count) {
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);
102 }
103 return (ptr - (const char *)list) / elementSize;
104 }
105
106
107 #define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
108
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;
112 SInt32 rem = length;
113 while (3 < rem) {
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]);
118 rem -= 4;
119 }
120 switch (rem) {
121 case 3: ELF_STEP(bytes[length - 3]);
122 case 2: ELF_STEP(bytes[length - 2]);
123 case 1: ELF_STEP(bytes[length - 1]);
124 case 0: ;
125 }
126 return H;
127 }
128
129 #undef ELF_STEP
130
131
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;
136 for (;;) {
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;
144 if (scan) {
145 uintptr_t *addr = (uintptr_t *)((uintptr_t)address);
146 uintptr_t *end = (uintptr_t *)((uintptr_t)address + (uintptr_t)size);
147 while (addr < end) {
148 if ((uintptr_t *)start <= addr && *addr == ptr) {
149 return (uintptr_t)addr;
150 }
151 addr++;
152 }
153 }
154 address += size;
155 }
156 return 0;
157 }
158 #endif
159
160
161 __private_extern__ void *__CFStartSimpleThread(void *func, void *arg) {
162 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD
163 pthread_attr_t attr;
164 pthread_t tid = 0;
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 *
173 return (void *)tid;
174 #else
175 unsigned tid;
176 struct _args *args = (struct _args*)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0);
177 if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)");
178 HANDLE handle;
179 args->func = func;
180 args->arg = arg;
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);
185 return handle;
186 #endif
187 }
188
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);
194 }
195
196
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
200
201 static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) {
202 CFStringRef localized = NULL;
203 CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL;
204 if (!locBundle) {
205 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false);
206 if (url) {
207 locBundle = CFBundleCreate(kCFAllocatorSystemDefault, url);
208 CFRelease(url);
209 }
210 }
211 if (locBundle) {
212 localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion"));
213 if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle);
214 }
215 return localized ? localized : (CFStringRef)CFRetain(nonLocalized);
216 }
217
218 static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) {
219 CFPropertyListRef plist = NULL;
220 CFDataRef data;
221 CFURLRef url;
222
223 url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false);
224 if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, NULL)) {
225 plist = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL);
226 CFRelease(data);
227 }
228 if (url) CFRelease(url);
229
230 if (plist) {
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);
238
239 // Now build the full version string
240 if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) {
241 CFRelease(fullVersionString);
242 fullVersionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString);
243 }
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);
250
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);
258 #endif
259 }
260 return (CFDictionaryRef)plist;
261 }
262
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);
270 CFRelease(dict);
271 return versionString;
272 }
273
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().
279
280 CFDictionaryRef _CFCopySystemVersionDictionary(void) {
281 CFPropertyListRef plist = NULL;
282 plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
283 return plist;
284 }
285
286 CFDictionaryRef _CFCopyServerVersionDictionary(void) {
287 CFPropertyListRef plist = NULL;
288 plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
289 return plist;
290 }
291
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")
300 #endif //__MACH__
301
302 CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
303 return true;
304 }
305
306 #if DEPLOYMENT_TARGET_MACOSX
307 __private_extern__ void *__CFLookupCFNetworkFunction(const char *name) {
308 static void *image = NULL;
309 if (NULL == image) {
310 const char *path = NULL;
311 if (!issetugid()) {
312 path = getenv("CFNETWORK_LIBRARY_PATH");
313 }
314 if (!path) {
315 path = "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork";
316 }
317 image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
318 }
319 void *dyfunc = NULL;
320 if (image) {
321 dyfunc = dlsym(image, name);
322 }
323 return dyfunc;
324 }
325 #endif //__MACH__
326
327
328 #ifndef __CFGetSessionID_defined
329
330 __private_extern__ uint32_t __CFGetSessionID(void) {
331 return 0;
332 }
333
334 #endif
335
336 const char *_CFPrintForDebugger(const void *obj) {
337 static char *result = NULL;
338 CFStringRef str;
339 CFIndex cnt = 0;
340
341 free(result); // Let go of result from previous call.
342 result = NULL;
343 if (obj) {
344 if (CFGetTypeID(obj) == CFStringGetTypeID()) {
345 // Makes Ali marginally happier
346 str = __CFCopyFormattingDescription(obj, NULL);
347 if (!str) str = CFCopyDescription(obj);
348 } else {
349 str = CFCopyDescription(obj);
350 }
351 } else {
352 str = (CFStringRef)CFRetain(CFSTR("(null)"));
353 }
354
355 if (str != NULL) {
356 CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &cnt);
357 }
358 result = (char *) malloc(cnt + 2); // 1 for '\0', 1 for an optional '\n'
359 if (str != NULL) {
360 CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, (UInt8 *) result, cnt, &cnt);
361 }
362 result[cnt] = '\0';
363
364 if (str) CFRelease(str);
365 return result;
366 }
367
368 static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) {
369 CFStringRef str;
370 CFIndex idx, cnt;
371 CFStringInlineBuffer buffer;
372 bool lastNL = false;
373
374 if (obj) {
375 if (CFGetTypeID(obj) == CFStringGetTypeID()) {
376 // Makes Ali marginally happier
377 str = __CFCopyFormattingDescription(obj, NULL);
378 if (!str) str = CFCopyDescription(obj);
379 } else {
380 str = CFCopyDescription(obj);
381 }
382 } else {
383 str = (CFStringRef)CFRetain(CFSTR("(null)"));
384 }
385 cnt = CFStringGetLength(str);
386
387 // iTunes used OutputDebugStringW(theString);
388
389 CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
390 #if defined (__WIN32__)
391 TCHAR *accumulatedBuffer = (TCHAR *)malloc((cnt+1) * sizeof(TCHAR));
392 #endif
393 for (idx = 0; idx < cnt; idx++) {
394 UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
395
396 #if DEPLOYMENT_TARGET_MACOSX
397 if (ch < 128) {
398 fprintf_l(file, NULL, "%c", ch);
399 lastNL = (ch == '\n');
400 } else {
401 fprintf_l(file, NULL, "\\u%04x", ch);
402 }
403 #elif defined (__WIN32__)
404 if (ch < 128) {
405 _fprintf_l(file, "%c", NULL, ch);
406 lastNL = (ch == '\n');
407 } else {
408 _fprintf_l(file, "\\u%04x", NULL, ch);
409 }
410 #endif
411 }
412 #if defined(__WIN32__)
413 }
414 #endif
415 if (!lastNL) {
416 #if DEPLOYMENT_TARGET_MACOSX
417 fprintf_l(file, NULL, "\n");
418 #endif
419 if (flush) fflush(file);
420 }
421
422 if (str) CFRelease(str);
423 }
424
425 void CFShow(const void *obj) {
426 _CFShowToFile(stderr, true, obj);
427 }
428
429
430
431 void CFLog(int32_t lev, CFStringRef format, ...) {
432 CFStringRef result;
433 va_list argList;
434 static CFSpinLock_t lock = CFSpinLockInit;
435
436 va_start(argList, format);
437 result = CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault, NULL, format, argList);
438 va_end(argList);
439
440 __CFSpinLock(&lock);
441 CFTimeZoneRef tz = CFTimeZoneCopySystem(); // specifically choose system time zone for logs
442 CFGregorianDate gdate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz);
443 CFRelease(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()));
447 CFShow(result);
448
449 __CFSpinUnlock(&lock);
450 CFRelease(result);
451 }
452
453