mirror of
https://github.com/darlinghq/darling-corefoundation.git
synced 2024-10-06 16:53:28 +00:00
235 lines
6.4 KiB
C
235 lines
6.4 KiB
C
/*
|
|
This file is part of Darling.
|
|
|
|
Copyright (C) 2016 Lubos Dolezel
|
|
|
|
Darling is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Darling is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Darling. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <CoreFoundation/CFXPCBridge.h>
|
|
#include <CoreFoundation/CFString.h>
|
|
#include <CoreFoundation/CFDictionary.h>
|
|
#include <CoreFoundation/CFNumber.h>
|
|
#include <CoreFoundation/CFArray.h>
|
|
#include <CoreFoundation/CFData.h>
|
|
#include <CoreFoundation/CFNumber.h>
|
|
|
|
#include <xpc/xpc.h>
|
|
|
|
CFTypeRef _CFXPCCreateCFObjectFromXPCObject(xpc_object_t xo) {
|
|
xpc_type_t type = xpc_get_type(xo);
|
|
|
|
if (type == XPC_TYPE_DICTIONARY) {
|
|
size_t count = xpc_dictionary_get_count(xo);
|
|
CFStringRef* keys = malloc(count * sizeof(CFStringRef));
|
|
CFTypeRef* values = malloc(count * sizeof(CFTypeRef));
|
|
__block size_t idx = 0;
|
|
|
|
xpc_dictionary_apply(xo, ^bool(const char* key, xpc_object_t value) {
|
|
keys[idx] = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8);
|
|
values[idx] = _CFXPCCreateCFObjectFromXPCObject(value);
|
|
++idx;
|
|
return true;
|
|
});
|
|
|
|
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
|
for (size_t i = 0; i < count; ++i) {
|
|
CFRelease(keys[i]);
|
|
CFRelease(values[i]);
|
|
}
|
|
free(keys);
|
|
free(values);
|
|
|
|
return dict;
|
|
}
|
|
|
|
if (type == XPC_TYPE_ARRAY) {
|
|
size_t count = xpc_array_get_count(xo);
|
|
CFTypeRef* entries = malloc(count * sizeof(CFTypeRef));
|
|
|
|
xpc_array_apply(xo, ^bool(size_t idx, xpc_object_t entry) {
|
|
entries[idx] = _CFXPCCreateCFObjectFromXPCObject(entry);
|
|
return true;
|
|
});
|
|
|
|
CFArrayRef array = CFArrayCreate(NULL, entries, count, &kCFTypeArrayCallBacks);
|
|
|
|
for (size_t i = 0; i < count; ++i)
|
|
CFRelease(entries[i]);
|
|
free(entries);
|
|
|
|
return array;
|
|
}
|
|
|
|
if (type == XPC_TYPE_STRING) {
|
|
return CFStringCreateWithCString(NULL, xpc_string_get_string_ptr(xo), kCFStringEncodingUTF8);
|
|
}
|
|
|
|
if (type == XPC_TYPE_BOOL) {
|
|
return CFRetain(xpc_bool_get_value(xo) == true ? kCFBooleanTrue : kCFBooleanFalse);
|
|
}
|
|
|
|
if (type == XPC_TYPE_DATA) {
|
|
return CFDataCreate(NULL, xpc_data_get_bytes_ptr(xo), xpc_data_get_length(xo));
|
|
}
|
|
|
|
if (type == XPC_TYPE_INT64) {
|
|
int64_t val = xpc_int64_get_value(xo);
|
|
return CFNumberCreate(NULL, kCFNumberSInt64Type, &val);
|
|
}
|
|
|
|
if (type == XPC_TYPE_UINT64) {
|
|
uint64_t val = xpc_uint64_get_value(xo);
|
|
// CFNumber doesn't provide an unsigned 64-bit integer type
|
|
// i guess kCFNumberSInt64Type is the next best thing
|
|
return CFNumberCreate(NULL, kCFNumberSInt64Type, &val);
|
|
}
|
|
|
|
if (type == XPC_TYPE_NULL) {
|
|
return CFRetain(kCFNull);
|
|
}
|
|
|
|
// TODO: double, date, and uuid
|
|
|
|
return NULL;
|
|
};
|
|
|
|
static void CFXPCDictionaryApplier(const void* raw_key, const void* raw_value, void* context) {
|
|
struct {
|
|
char** keys;
|
|
xpc_object_t* objs;
|
|
size_t i;
|
|
}* ctx = context;
|
|
|
|
// NOTE(@facekapow):
|
|
// we're assuming that the dictionary passed in contains only CFStrings as keys.
|
|
// is this a bad assumption? probably maybe kinda sorta possibly definitely.
|
|
// however, xpc dictionaries can only contain strings as keys so...
|
|
//
|
|
// here's to hoping that whoever uses `_CFXPCCreateXPCObjectFromCFObject` knows this
|
|
// and only uses CFString keys for their dictionaries :/
|
|
|
|
CFStringRef key = raw_key;
|
|
|
|
CFIndex length = CFStringGetLength(key);
|
|
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
|
|
ctx->keys[ctx->i] = malloc(maxSize);
|
|
CFStringGetCString(key, ctx->keys[ctx->i], maxSize, kCFStringEncodingUTF8);
|
|
|
|
// we're also assuming that the values in the dictionary are all CF objects
|
|
|
|
ctx->objs[ctx->i] = _CFXPCCreateXPCObjectFromCFObject(raw_value);
|
|
|
|
++ctx->i;
|
|
};
|
|
|
|
xpc_object_t _CFXPCCreateXPCObjectFromCFObject(CFTypeRef attrs) {
|
|
CFTypeID id = CFGetTypeID(attrs);
|
|
|
|
if (id == CFStringGetTypeID()) {
|
|
CFStringRef str = attrs;
|
|
CFIndex length = CFStringGetLength(str);
|
|
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
|
|
char* tmp = malloc(maxSize);
|
|
if (!CFStringGetCString(str, tmp, maxSize, kCFStringEncodingUTF8)) {
|
|
free(tmp);
|
|
return NULL;
|
|
}
|
|
xpc_object_t xo = xpc_string_create(tmp);
|
|
free(tmp);
|
|
return xo;
|
|
}
|
|
|
|
if (id == CFDictionaryGetTypeID()) {
|
|
CFDictionaryRef dict = attrs;
|
|
CFIndex length = CFDictionaryGetCount(dict);
|
|
char** keys = malloc(sizeof(char*) * length);
|
|
xpc_object_t* objs = malloc(sizeof(xpc_object_t) * length);
|
|
struct {
|
|
char** keys;
|
|
xpc_object_t* objs;
|
|
size_t i;
|
|
} ctx = {
|
|
.keys = keys,
|
|
.objs = objs,
|
|
.i = 0,
|
|
};
|
|
CFDictionaryApplyFunction(dict, CFXPCDictionaryApplier, &ctx);
|
|
|
|
xpc_object_t xdict = xpc_dictionary_create(keys, objs, length);
|
|
|
|
for (CFIndex i = 0; i < length; ++i) {
|
|
free(keys[i]);
|
|
xpc_release(objs[i]);
|
|
}
|
|
free(keys);
|
|
free(objs);
|
|
|
|
return xdict;
|
|
}
|
|
|
|
if (id == CFBooleanGetTypeID()) {
|
|
CFBooleanRef boolean = attrs;
|
|
return xpc_bool_create(CFBooleanGetValue(boolean));
|
|
}
|
|
|
|
if (id == CFArrayGetTypeID()) {
|
|
CFArrayRef array = attrs;
|
|
CFIndex length = CFArrayGetCount(array);
|
|
xpc_object_t* objs = malloc(sizeof(xpc_object_t) * length);
|
|
|
|
for (CFIndex i = 0; i < length; ++i)
|
|
objs[i] = _CFXPCCreateXPCObjectFromCFObject(CFArrayGetValueAtIndex(array, i));
|
|
|
|
xpc_object_t xarray = xpc_array_create(objs, length);
|
|
|
|
for (CFIndex i = 0; i < length; ++i)
|
|
xpc_release(objs[i]);
|
|
free(objs);
|
|
|
|
return xarray;
|
|
}
|
|
|
|
if (id == CFDataGetTypeID()) {
|
|
CFDataRef data = attrs;
|
|
return xpc_data_create(CFDataGetBytePtr(data), CFDataGetLength(data));
|
|
}
|
|
|
|
if (id == CFNumberGetTypeID()) {
|
|
CFNumberRef num = attrs;
|
|
int64_t tmp = 0;
|
|
CFNumberGetValue(num, kCFNumberSInt64Type, &tmp);
|
|
return xpc_int64_create(tmp);
|
|
}
|
|
|
|
if (id == CFNullGetTypeID()) {
|
|
return xpc_null_create();
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
xpc_object_t _CFXPCCreateXPCMessageWithCFObject(CFTypeRef obj) {
|
|
return NULL;
|
|
}
|
|
|
|
CFTypeRef _CFXPCCreateCFObjectFromXPCMessage(xpc_object_t obj) {
|
|
return NULL;
|
|
}
|
|
|
|
// TODO: _CFXPCCreateCFObjectFromXPCMessage
|
|
// This function takes the "ECF19A18-7AA6-4141-B4DC-A2E5123B2B5C" data value
|
|
// from the dictionary and parses it as a binary plist.
|