diff options
| author | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
|---|---|---|
| committer | sumuel <samuel@yakubos.org> | 2026-08-17 20:44:55 +0000 |
| commit | 76424950e373d3b04ac3dd13019151bfba3e8423 (patch) | |
| tree | 4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /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.c | 225 |
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); +} |