#include "CFUtilities.h"
#include "CFInternal.h"
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFURLAccess.h>
#include <CoreFoundation/CFPropertyList.h>
#include <CoreFoundation/CFTimeZone.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#if defined(__MACH__)
#include <mach/mach.h>
#include <pthread.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
#include <crt_externs.h>
#include <Security/AuthSession.h>
#endif
#if defined(__WIN32__)
#include <windows.h>
#include <process.h>
#endif
#if defined(__LINUX__) || defined(__FREEBSD__)
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#endif
extern char **_CFGetProgname(void);
#define LESS16(A, W) do { if (A < ((uint64_t)1 << (W))) LESS8(A, (W) - 8); LESS8(A, (W) + 8); } while (0)
#define LESS8(A, W) do { if (A < ((uint64_t)1 << (W))) LESS4(A, (W) - 4); LESS4(A, (W) + 4); } while (0)
#define LESS4(A, W) do { if (A < ((uint64_t)1 << (W))) LESS2(A, (W) - 2); LESS2(A, (W) + 2); } while (0)
#define LESS2(A, W) do { if (A < ((uint64_t)1 << (W))) LESS1(A, (W) - 1); LESS1(A, (W) + 1); } while (0)
#define LESS1(A, W) do { if (A < ((uint64_t)1 << (W))) return (W) - 1; return (W); } while (0)
uint32_t CFLog2(uint64_t x) {
if (x < ((uint64_t)1 << 32))
LESS16(x, 16);
LESS16(x, 48);
return 0;
}
#if 0
int Lg2d(unsigned x) {
int ret;
if (0 == x) return 0;
__asm__ volatile("cntlzw %0,%1" : "=r" (ret) : "r" (x));
return 31 - ret;
}
#endif
#undef LESS1
#undef LESS2
#undef LESS4
#undef LESS8
#undef LESS16
__private_extern__ CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) {
SInt32 idx, lg;
const char *ptr = (const char *)list;
if (count < 4) {
switch (count) {
case 3: if (comparator(ptr + elementSize * 2, element, context) < 0) return 3;
case 2: if (comparator(ptr + elementSize * 1, element, context) < 0) return 2;
case 1: if (comparator(ptr + elementSize * 0, element, context) < 0) return 1;
}
return 0;
}
if (comparator(ptr + elementSize * (count - 1), element, context) < 0) return count;
if (comparator(element, ptr + elementSize * 0, context) < 0) return 0;
lg = CFLog2(count);
idx = (comparator(ptr + elementSize * (-1 + (1 << lg)), element, context) < 0) ? count - (1 << lg) : -1;
switch (--lg) {
case 30: if (comparator(ptr + elementSize * (idx + (1 << 30)), element, context) < 0) idx += (1 << 30);
case 29: if (comparator(ptr + elementSize * (idx + (1 << 29)), element, context) < 0) idx += (1 << 29);
case 28: if (comparator(ptr + elementSize * (idx + (1 << 28)), element, context) < 0) idx += (1 << 28);
case 27: if (comparator(ptr + elementSize * (idx + (1 << 27)), element, context) < 0) idx += (1 << 27);
case 26: if (comparator(ptr + elementSize * (idx + (1 << 26)), element, context) < 0) idx += (1 << 26);
case 25: if (comparator(ptr + elementSize * (idx + (1 << 25)), element, context) < 0) idx += (1 << 25);
case 24: if (comparator(ptr + elementSize * (idx + (1 << 24)), element, context) < 0) idx += (1 << 24);
case 23: if (comparator(ptr + elementSize * (idx + (1 << 23)), element, context) < 0) idx += (1 << 23);
case 22: if (comparator(ptr + elementSize * (idx + (1 << 22)), element, context) < 0) idx += (1 << 22);
case 21: if (comparator(ptr + elementSize * (idx + (1 << 21)), element, context) < 0) idx += (1 << 21);
case 20: if (comparator(ptr + elementSize * (idx + (1 << 20)), element, context) < 0) idx += (1 << 20);
case 19: if (comparator(ptr + elementSize * (idx + (1 << 19)), element, context) < 0) idx += (1 << 19);
case 18: if (comparator(ptr + elementSize * (idx + (1 << 18)), element, context) < 0) idx += (1 << 18);
case 17: if (comparator(ptr + elementSize * (idx + (1 << 17)), element, context) < 0) idx += (1 << 17);
case 16: if (comparator(ptr + elementSize * (idx + (1 << 16)), element, context) < 0) idx += (1 << 16);
case 15: if (comparator(ptr + elementSize * (idx + (1 << 15)), element, context) < 0) idx += (1 << 15);
case 14: if (comparator(ptr + elementSize * (idx + (1 << 14)), element, context) < 0) idx += (1 << 14);
case 13: if (comparator(ptr + elementSize * (idx + (1 << 13)), element, context) < 0) idx += (1 << 13);
case 12: if (comparator(ptr + elementSize * (idx + (1 << 12)), element, context) < 0) idx += (1 << 12);
case 11: if (comparator(ptr + elementSize * (idx + (1 << 11)), element, context) < 0) idx += (1 << 11);
case 10: if (comparator(ptr + elementSize * (idx + (1 << 10)), element, context) < 0) idx += (1 << 10);
case 9: if (comparator(ptr + elementSize * (idx + (1 << 9)), element, context) < 0) idx += (1 << 9);
case 8: if (comparator(ptr + elementSize * (idx + (1 << 8)), element, context) < 0) idx += (1 << 8);
case 7: if (comparator(ptr + elementSize * (idx + (1 << 7)), element, context) < 0) idx += (1 << 7);
case 6: if (comparator(ptr + elementSize * (idx + (1 << 6)), element, context) < 0) idx += (1 << 6);
case 5: if (comparator(ptr + elementSize * (idx + (1 << 5)), element, context) < 0) idx += (1 << 5);
case 4: if (comparator(ptr + elementSize * (idx + (1 << 4)), element, context) < 0) idx += (1 << 4);
case 3: if (comparator(ptr + elementSize * (idx + (1 << 3)), element, context) < 0) idx += (1 << 3);
case 2: if (comparator(ptr + elementSize * (idx + (1 << 2)), element, context) < 0) idx += (1 << 2);
case 1: if (comparator(ptr + elementSize * (idx + (1 << 1)), element, context) < 0) idx += (1 << 1);
case 0: if (comparator(ptr + elementSize * (idx + (1 << 0)), element, context) < 0) idx += (1 << 0);
}
return ++idx;
}
#define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1;
CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) {
UInt32 H = 0, T1, T2;
SInt32 rem = length;
while (3 < rem) {
ELF_STEP(bytes[length - rem]);
ELF_STEP(bytes[length - rem + 1]);
ELF_STEP(bytes[length - rem + 2]);
ELF_STEP(bytes[length - rem + 3]);
rem -= 4;
}
switch (rem) {
case 3: ELF_STEP(bytes[length - 3]);
case 2: ELF_STEP(bytes[length - 2]);
case 1: ELF_STEP(bytes[length - 1]);
case 0: ;
}
return H;
}
#undef ELF_STEP
#if defined(__WIN32__)
struct _args {
void *func;
void *arg;
HANDLE handle;
};
static __stdcall unsigned __CFWinThreadFunc(void *arg) {
struct _args *args = arg;
((void (*)(void *))args->func)(args->arg);
CloseHandle(args->handle);
CFAllocatorDeallocate(kCFAllocatorSystemDefault, arg);
_endthreadex(0);
return 0;
}
#endif
__private_extern__ void *__CFStartSimpleThread(void *func, void *arg) {
#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__)
pthread_attr_t attr;
pthread_t tid;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_attr_setstacksize(&attr, 60 * 1024); pthread_create(&tid, &attr, func, arg);
pthread_attr_destroy(&attr);
return (void *)tid;
#else
unsigned tid;
struct _args *args = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0);
if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)");
HANDLE handle;
args->func = func;
args->arg = arg;
args->handle = (HANDLE)_beginthreadex(NULL, 0, (void *)__CFWinThreadFunc, args, CREATE_SUSPENDED, &tid);
handle = args->handle;
ResumeThread(handle);
return handle;
#endif
}
__private_extern__ CFStringRef _CFCreateLimitedUniqueString() {
uint64_t tsr = __CFReadTSR();
UInt32 tsrh = (tsr >> 32), tsrl = (tsr & (int64_t)0xFFFFFFFF);
return CFStringCreateWithFormat(NULL, NULL, CFSTR("CFUniqueString-%lu%lu$"), tsrh, tsrl);
}
static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) {
CFStringRef localized = NULL;
CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL;
if (!locBundle) {
CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false);
if (url) {
locBundle = CFBundleCreate(kCFAllocatorDefault, url);
CFRelease(url);
}
}
if (locBundle) {
localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion"));
if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle);
}
return localized ? localized : CFRetain(nonLocalized);
}
static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) {
CFPropertyListRef plist = NULL;
CFDataRef data;
CFURLRef url;
url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false);
if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &data, NULL, NULL, NULL)) {
plist = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL);
CFRelease(data);
}
if (url) CFRelease(url);
if (plist) {
CFBundleRef locBundle = NULL;
CFStringRef fullVersion, vers, versExtra, build;
CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey);
CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey);
CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString"));
if (locBundle) CFRelease(locBundle);
if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) {
CFRelease(fullVersionString);
fullVersionString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString);
}
vers = CFDictionaryGetValue(plist, _kCFSystemVersionProductVersionKey);
versExtra = CFDictionaryGetValue(plist, _kCFSystemVersionProductVersionExtraKey);
if (vers && versExtra) vers = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ %@"), vers, versExtra);
build = CFDictionaryGetValue(plist, _kCFSystemVersionBuildVersionKey);
fullVersion = CFStringCreateWithFormat(NULL, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?"));
if (vers && versExtra) CFRelease(vers);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString);
CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString);
CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion);
CFRelease(versionString);
CFRelease(buildString);
CFRelease(fullVersionString);
CFRelease(fullVersion);
}
return plist;
}
CFStringRef CFCopySystemVersionString(void) {
CFStringRef versionString;
CFDictionaryRef dict = _CFCopyServerVersionDictionary();
if (!dict) dict = _CFCopySystemVersionDictionary();
versionString = CFDictionaryGetValue(dict, CFSTR("FullVersionString"));
if (versionString) CFRetain(versionString);
CFRelease(dict);
return versionString;
}
CFDictionaryRef _CFCopySystemVersionDictionary(void) {
static CFPropertyListRef plist = NULL; if (!plist) {
plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist"));
if (!plist) plist = (CFPropertyListRef)(-1);
}
return (plist == (CFPropertyListRef)(-1)) ? NULL : CFRetain(plist);
}
CFDictionaryRef _CFCopyServerVersionDictionary(void) {
static CFPropertyListRef plist = NULL; if (!plist) {
plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist"));
if (!plist) plist = (CFPropertyListRef)(-1);
}
return (plist == (CFPropertyListRef)(-1)) ? NULL : CFRetain(plist);
}
CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName")
CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright")
CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion")
CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra")
CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion")
CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion")
CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version")
CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build")
#if defined(__MACH__)
CFLibraryVersion CFGetExecutableLinkedLibraryVersion(CFStringRef libraryName) {
CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
struct mach_header *mh;
struct load_command *lc;
unsigned int idx;
char library[CFMaxPathSize];
if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
mh = _dyld_get_image_header(0); if (NULL == mh) return ret;
lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
for (idx = 0; idx < mh->ncmds; idx++) {
if (lc->cmd == LC_LOAD_DYLIB) {
struct dylib_command *dl = (struct dylib_command *)lc;
char *path = (char *)lc + dl->dylib.name.offset;
if (NULL != strstr(path, library)) {
ret.primaryVersion = dl->dylib.current_version >> 16;
ret.secondaryVersion = (dl->dylib.current_version >> 8) & 0xff;
ret.tertiaryVersion = dl->dylib.current_version & 0xff;
return ret;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
return ret;
}
CFLibraryVersion CFGetExecutingLibraryVersion(CFStringRef libraryName) {
CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF};
struct mach_header *mh;
struct load_command *lc;
unsigned int idx1, idx2, cnt;
char library[CFMaxPathSize];
if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret;
cnt = _dyld_image_count();
for (idx1 = 1; idx1 < cnt; idx1++) {
char *image_name = _dyld_get_image_name(idx1);
if (NULL == image_name || NULL == strstr(image_name, library)) continue;
mh = _dyld_get_image_header(idx1);
if (NULL == mh) return ret;
lc = (struct load_command *)((char *)mh + sizeof(struct mach_header));
for (idx2 = 0; idx2 < mh->ncmds; idx2++) {
if (lc->cmd == LC_ID_DYLIB) {
struct dylib_command *dl = (struct dylib_command *)lc;
ret.primaryVersion = dl->dylib.current_version >> 16;
ret.secondaryVersion = (dl->dylib.current_version >> 8) & 0xff;
ret.tertiaryVersion = dl->dylib.current_version & 0xff;
return ret;
}
}
}
return ret;
}
#define checkLibrary(LIBNAME, VERSIONFIELD) \
{int vers = CFGetExecutableLinkedLibraryVersion(LIBNAME).primaryVersion; \
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)); }
CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) {
static const struct {
uint16_t libSystemVersion;
uint16_t cocoaVersion;
uint16_t appkitVersion;
uint16_t fouVersion;
uint16_t cfVersion;
uint16_t carbonVersion;
uint16_t applicationServicesVersion;
uint16_t coreServicesVersion;
uint16_t iokitVersion;
} versionInfo[] = {
{50, 5, 577, 397, 196, 113, 16, 9, 52},
{55, 7, 620, 425, 226, 122, 16, 10, 67},
{56, 8, 631, 431, 232, 122, 17, 11, 73},
{67, 9, 704, 481, 281, 126, 19, 16, 159},
{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}
};
static char results[CFSystemVersionMax] = {-2, -2, -2, -2, -2};
if (version >= CFSystemVersionMax) return false;
if (results[version] != -2) return results[version];
if (_CFIsCFM()) {
results[version] = (version <= CFSystemVersionJaguar) ? true : false;
return results[version];
}
checkLibrary(CFSTR("/libSystem."), libSystemVersion); checkLibrary(CFSTR("/Cocoa."), cocoaVersion);
checkLibrary(CFSTR("/AppKit."), appkitVersion);
checkLibrary(CFSTR("/Foundation."), fouVersion);
checkLibrary(CFSTR("/CoreFoundation."), cfVersion);
checkLibrary(CFSTR("/Carbon."), carbonVersion);
checkLibrary(CFSTR("/ApplicationServices."), applicationServicesVersion);
checkLibrary(CFSTR("/CoreServices."), coreServicesVersion);
checkLibrary(CFSTR("/IOKit."), iokitVersion);
return false;
}
#endif
void CFShow(const void *obj) { CFStringRef str;
CFIndex idx, cnt;
CFStringInlineBuffer buffer;
bool lastNL = false;
if (obj) {
if (CFGetTypeID(obj) == CFStringGetTypeID()) {
str = __CFCopyFormattingDescription(obj, NULL);
if (!str) str = CFCopyDescription(obj);
} else {
str = CFCopyDescription(obj);
}
} else {
str = CFRetain(CFSTR("(null)"));
}
cnt = CFStringGetLength(str);
CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt));
for (idx = 0; idx < cnt; idx++) {
UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx);
if (ch < 128) {
fprintf (stderr, "%c", ch);
lastNL = (ch == '\n');
} else {
fprintf (stderr, "\\u%04x", ch);
}
}
if (!lastNL) fprintf(stderr, "\n");
if (str) CFRelease(str);
}
void CFLog(int p, CFStringRef format, ...) {
CFStringRef result;
va_list argList;
static CFSpinLock_t lock = 0;
va_start(argList, format);
result = CFStringCreateWithFormatAndArguments(NULL, NULL, format, argList);
va_end(argList);
__CFSpinLock(&lock);
#if defined(__WIN32__)
printf("*** CFLog (%d): %s[%d] ", p, __argv[0], GetCurrentProcessId());
#else
CFTimeZoneRef tz = CFTimeZoneCopySystem(); CFGregorianDate gdate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz);
CFRelease(tz);
gdate.second = gdate.second + 0.0005;
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);
#endif
CFShow(result);
__CFSpinUnlock(&lock);
CFRelease(result);
}