summaryrefslogtreecommitdiffstats
path: root/src/common/apple/cf_helpers.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/common/apple/cf_helpers.c
Add the files
Diffstat (limited to 'src/common/apple/cf_helpers.c')
-rw-r--r--src/common/apple/cf_helpers.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/common/apple/cf_helpers.c b/src/common/apple/cf_helpers.c
new file mode 100644
index 0000000..60e1a1c
--- /dev/null
+++ b/src/common/apple/cf_helpers.c
@@ -0,0 +1,225 @@
+#include "cf_helpers.h"
+
+const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result) {
+ if (CFGetTypeID(cf) == CFNumberGetTypeID()) {
+ if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberSInt64Type, result)) {
+ return "Number type is not SInt64";
+ }
+ return NULL;
+ } else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
+ if (CFDataGetLength((CFDataRef) cf) != sizeof(int64_t)) {
+ return "Data length is not sizeof(int64_t)";
+ }
+ CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(int64_t)), (uint8_t*) result);
+ return NULL;
+ }
+
+ return "TypeID is neither 'CFNumber' nor 'CFData'";
+}
+
+const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result) {
+ if (CFGetTypeID(cf) == CFNumberGetTypeID()) {
+ if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberSInt32Type, result)) {
+ return "Number type is not SInt32";
+ }
+ return NULL;
+ } else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
+ if (CFDataGetLength((CFDataRef) cf) != sizeof(*result)) {
+ return "Data length is not sizeof(int32_t)";
+ }
+ CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(*result)), (uint8_t*) result);
+ return NULL;
+ }
+
+ return "TypeID is neither 'CFNumber' nor 'CFData'";
+}
+
+const char* ffCfNumGetDouble(CFTypeRef cf, double* result) {
+ if (CFGetTypeID(cf) == CFNumberGetTypeID()) {
+ if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberDoubleType, result) &&
+ !CFNumberGetValue((CFNumberRef) cf, kCFNumberFloatType, result)) {
+ return "Number type is not Double or Float";
+ }
+ return NULL;
+ }
+
+ return "TypeID is neither 'CFNumber'";
+}
+
+const char* ffCfDateGetEpoch(CFTypeRef cf, uint64_t* result) {
+ if (CFGetTypeID(cf) != CFDateGetTypeID()) {
+ return "TypeID is not 'CFDate'";
+ }
+
+ CFAbsoluteTime absTime = CFDateGetAbsoluteTime((CFDateRef) cf);
+ // Convert from seconds to milliseconds and add the difference between 1970 and 2001 in milliseconds
+ *result = (uint64_t) ((absTime + 978307200 /*kCFAbsoluteTimeIntervalSince1970*/) * 1000);
+ return NULL;
+}
+
+const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) {
+ ffStrbufClear(result);
+ if (!cf) {
+ return NULL;
+ }
+
+ if (CFGetTypeID(cf) == CFStringGetTypeID()) {
+ CFStringRef cfStr = (CFStringRef) cf;
+
+ const char* cstr = CFStringGetCStringPtr(cfStr, kCFStringEncodingUTF8);
+ if (cstr) {
+ ffStrbufSetS(result, cstr);
+ } else {
+ uint32_t length = (uint32_t) CFStringGetLength(cfStr);
+ if (length == 0) {
+ return NULL;
+ }
+ ffStrbufEnsureFixedLengthFree(result, (uint32_t) CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8));
+ if (!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8)) {
+ return "CFStringGetCString() failed";
+ }
+ // CFStringGetCString ensures the buffer is NUL terminated
+ // https://developer.apple.com/documentation/corefoundation/1542721-cfstringgetcstring
+ result->length = (uint32_t) strnlen(result->chars, (uint32_t) result->allocated);
+ }
+ } else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
+ CFDataRef cfData = (CFDataRef) cf;
+ uint32_t length = (uint32_t) CFDataGetLength(cfData);
+ if (length == 0) {
+ return NULL;
+ }
+ ffStrbufEnsureFixedLengthFree(result, length + 1);
+ CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*) result->chars);
+ result->length = (uint32_t) strnlen(result->chars, length);
+ result->chars[result->length] = '\0';
+ } else {
+ return "TypeID is neither 'CFString' nor 'CFData'";
+ }
+
+ return NULL;
+}
+
+const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result) {
+ ffStrbufClear(result);
+ if (!cf) {
+ return NULL;
+ }
+
+ if (CFGetTypeID(cf) == CFDataGetTypeID()) {
+ CFDataRef cfData = (CFDataRef) cf;
+ uint32_t length = (uint32_t) CFDataGetLength(cfData);
+ if (length == 0) {
+ return NULL;
+ }
+ ffStrbufEnsureFixedLengthFree(result, length + 1);
+ CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*) result->chars);
+ result->length = length;
+ result->chars[result->length] = '\0';
+ } else {
+ return "TypeID is not 'CFData'";
+ }
+
+ return NULL;
+}
+
+const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) {
+ CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL) {
+ return "CFDictionaryGetValue() failed";
+ }
+
+ return ffCfStrGetString(cf, result);
+}
+
+const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result) {
+ CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL) {
+ return "CFDictionaryGetValue() failed";
+ }
+
+ return ffCfDataGetDataAsString(cf, result);
+}
+
+const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) {
+ CFBooleanRef cf = (CFBooleanRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL) {
+ return "CFDictionaryGetValue() failed";
+ }
+
+ if (CFGetTypeID(cf) != CFBooleanGetTypeID()) {
+ return "TypeID is not 'CFBoolean'";
+ }
+
+ *result = CFBooleanGetValue(cf);
+ return NULL;
+}
+
+const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result) {
+ CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL) {
+ return "CFDictionaryGetValue() failed";
+ }
+
+ return ffCfNumGetInt(cf, result);
+}
+
+const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result) {
+ CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL) {
+ return "CFDictionaryGetValue() failed";
+ }
+
+ return ffCfNumGetInt64(cf, result);
+}
+
+const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* result) {
+ CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL) {
+ return "CFDictionaryGetValue() failed";
+ }
+
+ return ffCfNumGetDouble(cf, result);
+}
+
+const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length) {
+ CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL) {
+ return "CFDictionaryGetValue() failed";
+ }
+
+ if (CFGetTypeID(cf) != CFDataGetTypeID()) {
+ return "TypeID is not 'CFData'";
+ }
+
+ CFIndex trueLength = CFDataGetLength((CFDataRef) cf);
+
+ if (trueLength < offset + size) {
+ return "Data length is less than offset + size";
+ }
+
+ if (length) {
+ *length = (uint32_t) trueLength;
+ }
+
+ CFDataGetBytes((CFDataRef) cf, CFRangeMake(offset, size), result);
+ return NULL;
+}
+
+const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result) {
+ CFDictionaryRef cf = (CFDictionaryRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL || CFGetTypeID(cf) != CFDictionaryGetTypeID()) {
+ return "TypeID is not 'CFDictionary'";
+ }
+
+ *result = cf;
+ return NULL;
+}
+
+const char* ffCfDictGetDateAsEpoch(CFDictionaryRef dict, CFStringRef key, uint64_t* result) {
+ CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
+ if (cf == NULL) {
+ return "CFDictionaryGetValue() failed";
+ }
+
+ return ffCfDateGetEpoch(cf, result);
+}