/ CFXPCBridge.c
CFXPCBridge.c
1 /* 2 This file is part of Darling. 3 4 Copyright (C) 2016 Lubos Dolezel 5 6 Darling is free software: you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 Darling is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with Darling. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include <CoreFoundation/CFXPCBridge.h> 21 #include <CoreFoundation/CFString.h> 22 #include <CoreFoundation/CFDictionary.h> 23 #include <CoreFoundation/CFNumber.h> 24 #include <CoreFoundation/CFArray.h> 25 #include <CoreFoundation/CFData.h> 26 #include <CoreFoundation/CFNumber.h> 27 28 #include <xpc/xpc.h> 29 30 CFTypeRef _CFXPCCreateCFObjectFromXPCObject(xpc_object_t xo) { 31 xpc_type_t type = xpc_get_type(xo); 32 33 if (type == XPC_TYPE_DICTIONARY) { 34 size_t count = xpc_dictionary_get_count(xo); 35 CFStringRef* keys = malloc(count * sizeof(CFStringRef)); 36 CFTypeRef* values = malloc(count * sizeof(CFTypeRef)); 37 __block size_t idx = 0; 38 39 xpc_dictionary_apply(xo, ^bool(const char* key, xpc_object_t value) { 40 keys[idx] = CFStringCreateWithCString(NULL, key, kCFStringEncodingUTF8); 41 values[idx] = _CFXPCCreateCFObjectFromXPCObject(value); 42 ++idx; 43 return true; 44 }); 45 46 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 47 48 for (size_t i = 0; i < count; ++i) { 49 CFRelease(keys[i]); 50 CFRelease(values[i]); 51 } 52 free(keys); 53 free(values); 54 55 return dict; 56 } 57 58 if (type == XPC_TYPE_ARRAY) { 59 size_t count = xpc_array_get_count(xo); 60 CFTypeRef* entries = malloc(count * sizeof(CFTypeRef)); 61 62 xpc_array_apply(xo, ^bool(size_t idx, xpc_object_t entry) { 63 entries[idx] = _CFXPCCreateCFObjectFromXPCObject(entry); 64 return true; 65 }); 66 67 CFArrayRef array = CFArrayCreate(NULL, entries, count, &kCFTypeArrayCallBacks); 68 69 for (size_t i = 0; i < count; ++i) 70 CFRelease(entries[i]); 71 free(entries); 72 73 return array; 74 } 75 76 if (type == XPC_TYPE_STRING) { 77 return CFStringCreateWithCString(NULL, xpc_string_get_string_ptr(xo), kCFStringEncodingUTF8); 78 } 79 80 if (type == XPC_TYPE_BOOL) { 81 return CFRetain(xpc_bool_get_value(xo) == true ? kCFBooleanTrue : kCFBooleanFalse); 82 } 83 84 if (type == XPC_TYPE_DATA) { 85 return CFDataCreate(NULL, xpc_data_get_bytes_ptr(xo), xpc_data_get_length(xo)); 86 } 87 88 if (type == XPC_TYPE_INT64) { 89 int64_t val = xpc_int64_get_value(xo); 90 return CFNumberCreate(NULL, kCFNumberSInt64Type, &val); 91 } 92 93 if (type == XPC_TYPE_UINT64) { 94 uint64_t val = xpc_uint64_get_value(xo); 95 // CFNumber doesn't provide an unsigned 64-bit integer type 96 // i guess kCFNumberSInt64Type is the next best thing 97 return CFNumberCreate(NULL, kCFNumberSInt64Type, &val); 98 } 99 100 if (type == XPC_TYPE_NULL) { 101 return CFRetain(kCFNull); 102 } 103 104 // TODO: double, date, and uuid 105 106 return NULL; 107 }; 108 109 static void CFXPCDictionaryApplier(const void* raw_key, const void* raw_value, void* context) { 110 struct { 111 char** keys; 112 xpc_object_t* objs; 113 size_t i; 114 }* ctx = context; 115 116 // NOTE(@facekapow): 117 // we're assuming that the dictionary passed in contains only CFStrings as keys. 118 // is this a bad assumption? probably maybe kinda sorta possibly definitely. 119 // however, xpc dictionaries can only contain strings as keys so... 120 // 121 // here's to hoping that whoever uses `_CFXPCCreateXPCObjectFromCFObject` knows this 122 // and only uses CFString keys for their dictionaries :/ 123 124 CFStringRef key = raw_key; 125 126 CFIndex length = CFStringGetLength(key); 127 CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; 128 ctx->keys[ctx->i] = malloc(maxSize); 129 CFStringGetCString(key, ctx->keys[ctx->i], maxSize, kCFStringEncodingUTF8); 130 131 // we're also assuming that the values in the dictionary are all CF objects 132 133 ctx->objs[ctx->i] = _CFXPCCreateXPCObjectFromCFObject(raw_value); 134 135 ++ctx->i; 136 }; 137 138 xpc_object_t _CFXPCCreateXPCObjectFromCFObject(CFTypeRef attrs) { 139 CFTypeID id = CFGetTypeID(attrs); 140 141 if (id == CFStringGetTypeID()) { 142 CFStringRef str = attrs; 143 CFIndex length = CFStringGetLength(str); 144 CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; 145 char* tmp = malloc(maxSize); 146 if (!CFStringGetCString(str, tmp, maxSize, kCFStringEncodingUTF8)) { 147 free(tmp); 148 return NULL; 149 } 150 xpc_object_t xo = xpc_string_create(tmp); 151 free(tmp); 152 return xo; 153 } 154 155 if (id == CFDictionaryGetTypeID()) { 156 CFDictionaryRef dict = attrs; 157 CFIndex length = CFDictionaryGetCount(dict); 158 char** keys = malloc(sizeof(char*) * length); 159 xpc_object_t* objs = malloc(sizeof(xpc_object_t) * length); 160 struct { 161 char** keys; 162 xpc_object_t* objs; 163 size_t i; 164 } ctx = { 165 .keys = keys, 166 .objs = objs, 167 .i = 0, 168 }; 169 CFDictionaryApplyFunction(dict, CFXPCDictionaryApplier, &ctx); 170 171 xpc_object_t xdict = xpc_dictionary_create(keys, objs, length); 172 173 for (CFIndex i = 0; i < length; ++i) { 174 free(keys[i]); 175 xpc_release(objs[i]); 176 } 177 free(keys); 178 free(objs); 179 180 return xdict; 181 } 182 183 if (id == CFBooleanGetTypeID()) { 184 CFBooleanRef boolean = attrs; 185 return xpc_bool_create(CFBooleanGetValue(boolean)); 186 } 187 188 if (id == CFArrayGetTypeID()) { 189 CFArrayRef array = attrs; 190 CFIndex length = CFArrayGetCount(array); 191 xpc_object_t* objs = malloc(sizeof(xpc_object_t) * length); 192 193 for (CFIndex i = 0; i < length; ++i) 194 objs[i] = _CFXPCCreateXPCObjectFromCFObject(CFArrayGetValueAtIndex(array, i)); 195 196 xpc_object_t xarray = xpc_array_create(objs, length); 197 198 for (CFIndex i = 0; i < length; ++i) 199 xpc_release(objs[i]); 200 free(objs); 201 202 return xarray; 203 } 204 205 if (id == CFDataGetTypeID()) { 206 CFDataRef data = attrs; 207 return xpc_data_create(CFDataGetBytePtr(data), CFDataGetLength(data)); 208 } 209 210 if (id == CFNumberGetTypeID()) { 211 CFNumberRef num = attrs; 212 int64_t tmp = 0; 213 CFNumberGetValue(num, kCFNumberSInt64Type, &tmp); 214 return xpc_int64_create(tmp); 215 } 216 217 if (id == CFNullGetTypeID()) { 218 return xpc_null_create(); 219 } 220 221 return NULL; 222 } 223 224 xpc_object_t _CFXPCCreateXPCMessageWithCFObject(CFTypeRef obj) { 225 return NULL; 226 } 227 228 CFTypeRef _CFXPCCreateCFObjectFromXPCMessage(xpc_object_t obj) { 229 return NULL; 230 } 231 232 // TODO: _CFXPCCreateCFObjectFromXPCMessage 233 // This function takes the "ECF19A18-7AA6-4141-B4DC-A2E5123B2B5C" data value 234 // from the dictionary and parses it as a binary plist.