#ifndef _SECCFWRAPPERS_H_
#define _SECCFWRAPPERS_H_
#include <CoreFoundation/CFRuntime.h>
#include <CoreFoundation/CoreFoundation.h>
#include "utilities/SecCFRelease.h"
#include "utilities/debugging.h"
#include "utilities/SecCFError.h"
#include <IOKit/IOReturn.h>
#include <assert.h>
#include <dispatch/dispatch.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <corecrypto/ccdigest.h>
#include <libaks.h>
#if __has_feature(objc_arc)
#define __SECBRIDGE __bridge
#else
#define __SECBRIDGE
#endif
extern CFStringRef kSecDebugFormatOption;
extern CFDictionaryRef SecGetDebugDescriptionFormatOptions(void);
typedef void (^SecBoolCFErrorCallback) (bool, CFErrorRef);
#define CFGiblisGetSingleton(returnType, giblisClassName, result, doThisOnce) \
returnType giblisClassName(void); \
returnType giblisClassName(void) { \
static dispatch_once_t s##giblisClassName##Once; \
static returnType s##giblisClassName##Singleton; \
returnType *result = &s##giblisClassName##Singleton; \
dispatch_once(&s##giblisClassName##Once, doThisOnce); \
return s##giblisClassName##Singleton; \
}
#define CFGiblisWithFunctions(gibliClassName, init_func, copy_func, finalize_func, equal_func, hash_func, copyFormattingDesc_func, copyDebugDesc_func, reclaim_func, refcount_func, run_once_block) \
CFGiblisGetSingleton(CFTypeID, gibliClassName##GetTypeID, typeID, (^{ \
void (^ const _onceBlock)(void) = (run_once_block); \
static const CFRuntimeClass s##gibliClassName##Class = { \
.version = (reclaim_func == NULL ? 0 : _kCFRuntimeResourcefulObject) \
| (refcount_func == NULL ? 0 : _kCFRuntimeCustomRefCount), \
.className = #gibliClassName, \
.init = init_func, \
.copy = copy_func, \
.finalize = finalize_func, \
.equal = equal_func, \
.hash = hash_func, \
.copyFormattingDesc = copyFormattingDesc_func, \
.copyDebugDesc = copyDebugDesc_func, \
.reclaim = reclaim_func, \
.refcount = refcount_func, \
}; \
*typeID = _CFRuntimeRegisterClass(&s##gibliClassName##Class); \
if (_onceBlock) \
_onceBlock(); \
}))
#define CFGiblisWithHashFor(gibliClassName) \
static CFStringRef gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
static void gibliClassName##Destroy(CFTypeRef cf); \
static Boolean gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
static CFHashCode gibliClassName##Hash(CFTypeRef cf); \
static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
}\
\
CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
#define CFGiblisWithCompareFor(gibliClassName) \
static CFStringRef gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
static void gibliClassName##Destroy(CFTypeRef cf); \
static Boolean gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
}\
\
CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
#define CFGiblisFor(gibliClassName) \
static CFStringRef gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
static void gibliClassName##Destroy(CFTypeRef cf); \
static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
}\
\
CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, NULL, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
#define CFTypeAllocateWithSpace(classType, space, allocator) \
(classType##Ref) _CFRuntimeCreateInstance(allocator, classType##GetTypeID(), space, NULL)
#define CFTypeAllocate(classType, internalType, allocator) \
CFTypeAllocateWithSpace(classType, sizeof(internalType) - sizeof(CFRuntimeBase), allocator)
#define SECWRAPPER_SENTINEL __attribute__((__sentinel__))
__BEGIN_DECLS
void withStringOfAbsoluteTime(CFAbsoluteTime at, void (^action)(CFStringRef decription));
static void apply_block_1(const void *value, void *context)
{
((__SECBRIDGE void (^)(const void *value))context)(value);
}
static void apply_block_2(const void *key, const void *value, void *context)
{
((__SECBRIDGE void (^)(const void *key, const void *value))context)(key, value);
}
static inline bool isArray(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFArrayGetTypeID();
}
static inline bool isSet(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFSetGetTypeID();
}
static inline bool isData(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFDataGetTypeID();
}
static inline bool isDate(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFDateGetTypeID();
}
static inline bool isDictionary(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID();
}
static inline bool isNumber(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFNumberGetTypeID();
}
static inline bool isNumberOfType(CFTypeRef cfType, CFNumberType number) {
return isNumber(cfType) && CFNumberGetType((CFNumberRef)cfType) == number;
}
static inline bool isString(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFStringGetTypeID();
}
static inline bool isBoolean(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFBooleanGetTypeID();
}
static inline bool isNull(CFTypeRef cfType) {
return cfType && CFGetTypeID(cfType) == CFNullGetTypeID();
}
static inline bool CFEqualSafe(CFTypeRef left, CFTypeRef right)
{
if (left == NULL || right == NULL)
return left == right;
else
return CFEqual(left, right);
}
static void fprint_string(FILE *file, CFStringRef string) {
UInt8 buf[256];
CFRange range = { .location = 0 };
range.length = CFStringGetLength(string);
while (range.length > 0) {
CFIndex bytesUsed = 0;
CFIndex converted = CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, false, buf, sizeof(buf), &bytesUsed);
fwrite(buf, 1, bytesUsed, file);
range.length -= converted;
range.location += converted;
}
}
static inline void cffprint_v(FILE *file, CFStringRef fmt, va_list args) CF_FORMAT_FUNCTION(2, 0);
static void cffprint(FILE *file, CFStringRef fmt, ...) CF_FORMAT_FUNCTION(2,0);
static inline void cffprint_v(FILE *file, CFStringRef fmt, va_list args) {
CFStringRef line = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, args);
fprint_string(file, line);
CFRelease(line);
}
static inline void cffprint(FILE *file, CFStringRef fmt, ...) {
va_list args;
va_start(args, fmt);
cffprint_v(file, fmt, args);
va_end(args);
}
static inline
bool CFErrorPropagate(CFErrorRef possibleError CF_CONSUMED, CFErrorRef *error) {
if (possibleError) {
if (error && !*error) {
*error = possibleError;
} else {
CFRelease(possibleError);
}
return false;
}
return true;
}
static inline bool CFErrorIsMalfunctioningKeybagError(CFErrorRef error){
switch(CFErrorGetCode(error))
{
case(kAKSReturnError):
case(kAKSReturnBusy):
case(kAKSReturnNoPermission):
break;
default:
return false;
}
return CFEqualSafe(CFErrorGetDomain(error), kSecKernDomain);
}
static inline CFNumberRef CFNumberCreateWithCFIndex(CFAllocatorRef allocator, CFIndex value)
{
return CFNumberCreate(allocator, kCFNumberCFIndexType, &value);
}
static inline CFMutableDataRef CFDataCreateMutableWithScratch(CFAllocatorRef allocator, CFIndex size) {
CFMutableDataRef result = CFDataCreateMutable(allocator, 0);
CFDataSetLength(result, size);
return result;
}
static inline void CFDataAppend(CFMutableDataRef appendTo, CFDataRef dataToAppend)
{
CFDataAppendBytes(appendTo, CFDataGetBytePtr(dataToAppend), CFDataGetLength(dataToAppend));
}
static inline CFDataRef CFDataCreateReferenceFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
{
return CFDataCreateWithBytesNoCopy(allocator,
CFDataGetBytePtr(sourceData) + range.location, range.length,
kCFAllocatorNull);
}
static inline CFDataRef CFDataCreateCopyFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
{
return CFDataCreate(allocator, CFDataGetBytePtr(sourceData) + range.location, range.length);
}
CFDataRef CFDataCreateWithRandomBytes(size_t len);
CFDataRef CFDataCreateWithInitializer(CFAllocatorRef allocator, CFIndex size, bool (^operation)(size_t size, uint8_t *buffer));
static inline uint8_t* CFDataIncreaseLengthAndGetMutableBytes(CFMutableDataRef data, CFIndex extraLength)
{
CFIndex startOffset = CFDataGetLength(data);
CFDataIncreaseLength(data, extraLength);
return CFDataGetMutableBytePtr(data) + startOffset;
}
static inline uint8_t* CFDataGetMutablePastEndPtr(CFMutableDataRef theData)
{
return CFDataGetMutableBytePtr(theData) + CFDataGetLength(theData);
}
static inline const uint8_t* CFDataGetPastEndPtr(CFDataRef theData) {
return CFDataGetBytePtr(theData) + CFDataGetLength(theData);
}
static inline CFComparisonResult CFDataCompare(CFDataRef left, CFDataRef right)
{
const size_t left_size = CFDataGetLength(left);
const size_t right_size = CFDataGetLength(right);
const size_t shortest = (left_size <= right_size) ? left_size : right_size;
int comparison = memcmp(CFDataGetBytePtr(left), CFDataGetBytePtr(right), shortest);
if (comparison > 0 || (comparison == 0 && left_size > right_size))
return kCFCompareGreaterThan;
else if (comparison < 0 || (comparison == 0 && left_size < right_size))
return kCFCompareLessThan;
else
return kCFCompareEqualTo;
}
static inline CFDataRef CFDataCreateWithHash(CFAllocatorRef allocator, const struct ccdigest_info *di, const uint8_t *buffer, const uint8_t length) {
CFMutableDataRef result = CFDataCreateMutableWithScratch(allocator, di->output_size);
ccdigest(di, length, buffer, CFDataGetMutableBytePtr(result));
return result;
}
static inline CFDataRef CFDataCreateCopyFromPositions(CFAllocatorRef allocator, CFDataRef source, CFIndex start, CFIndex end)
{
return CFDataCreateCopyFromRange(allocator, source, CFRangeMake(start, end - start));
}
static inline int nibletToByte(char niblet) {
if(niblet >= '0' && niblet <= '9') return niblet - '0';
if(niblet >= 'a' && niblet <= 'f') return niblet - 'a' + 10;
if(niblet >= 'A' && niblet <= 'F') return niblet - 'A' + 10;
return 0;
}
static inline CFDataRef CFDataCreateFromHexString(CFAllocatorRef allocator, CFStringRef sourceHex) {
CFIndex sourceLen = CFStringGetLength(sourceHex);
if((sourceLen % 2) != 0) return NULL;
const char *src = CFStringGetCStringPtr(sourceHex, kCFStringEncodingUTF8);
UInt8 bytes[sourceLen/2];
for(int i = 0; i < sourceLen; i+=2) {
bytes[i/2] = (UInt8) (nibletToByte(src[i]) * 16 + nibletToByte(src[i+1]));
}
return CFDataCreate(allocator, bytes, sourceLen/2);
}
CFComparisonResult CFStringCompareSafe(const void *val1, const void *val2, void *context);
static inline char *CFStringToCString(CFStringRef inStr)
{
if (!inStr)
return (char *)strdup("");
CFRetain(inStr);
CFIndex length = CFStringGetLength(inStr); size_t len = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
char *buffer = (char *)malloc(len); if (!CFStringGetCString(inStr, buffer, len, kCFStringEncodingUTF8))
buffer[0] = 0;
CFRelease(inStr);
return buffer;
}
void CFStringPerformWithCString(CFStringRef inStr, void(^operation)(const char *utf8Str));
void CFStringPerformWithCStringAndLength(CFStringRef inStr, void(^operation)(const char *utf8Str, size_t utf8Length));
void CFStringPerformWithUTF8CFData(CFStringRef inStr, void (^operation)(CFDataRef stringAsData));
#include <CommonNumerics/CommonCRC.h>
static inline void CFStringAppendEncryptedData(CFMutableStringRef s, CFDataRef edata)
{
const uint8_t *bytes = CFDataGetBytePtr(edata);
CFIndex len = CFDataGetLength(edata);
CFStringAppendFormat(s, 0, CFSTR("%04lx:"), len);
if(len<=8) {
for (CFIndex ix = 0; ix < len; ++ix) {
CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
}
} else {
uint64_t crc = 0;
CNCRC(kCN_CRC_64_ECMA_182, bytes+8, len-8, &crc);
for (CFIndex ix = 0; ix < 8; ++ix) {
CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
}
CFStringAppendFormat(s, 0, CFSTR("...|%08llx"), crc);
}
}
static inline void CFStringAppendHexData(CFMutableStringRef s, CFDataRef data) {
const uint8_t *bytes = CFDataGetBytePtr(data);
CFIndex len = CFDataGetLength(data);
for (CFIndex ix = 0; ix < len; ++ix) {
CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
}
}
static inline CF_RETURNS_RETAINED CFStringRef CFDataCopyHexString(CFDataRef data) {
CFMutableStringRef hexString = CFStringCreateMutable(kCFAllocatorDefault, 2 * CFDataGetLength(data));
CFStringAppendHexData(hexString, data);
return hexString;
}
static inline void CFDataPerformWithHexString(CFDataRef data, void (^operation)(CFStringRef dataString)) {
CFStringRef hexString = data ? CFDataCopyHexString(data) : CFSTR("(null)");
operation(hexString);
CFRelease(hexString);
}
static inline void BufferPerformWithHexString(const UInt8 *bytes, CFIndex length, void (^operation)(CFStringRef dataString)) {
CFDataRef bufferAsData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorNull);
CFDataPerformWithHexString(bufferAsData, operation);
CFReleaseNull(bufferAsData);
}
static inline void CFStringWriteToFile(CFStringRef inStr, FILE* file)
{
CFStringPerformWithCStringAndLength(inStr, ^(const char *utf8Str, size_t utf8Length) {
fwrite(utf8Str, 1, utf8Length, file);
});
}
static inline void CFStringWriteToFileWithNewline(CFStringRef inStr, FILE* file)
{
CFStringWriteToFile(inStr, file);
fputc('\n', file);
}
static inline CFStringRef CFStringCreateTruncatedCopy(CFStringRef s, CFIndex len) {
if(!s) return NULL;
if(len >= CFStringGetLength(s)) return CFStringCreateCopy(kCFAllocatorDefault, s);
return CFStringCreateWithSubstring(kCFAllocatorDefault, s, CFRangeMake(0, len));
}
static inline
const void *SecCFRetainForCollection(CFAllocatorRef allocator, const void *value)
{
return CFRetain(value);
}
static inline
void SecCFReleaseForCollection(CFAllocatorRef allocator, const void *value)
{
CFRelease(value);
}
static inline CFIndex CFArrayRemoveAllValue(CFMutableArrayRef array, const void* value)
{
CFIndex position = kCFNotFound;
CFIndex numberRemoved = 0;
position = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value);
while (position != kCFNotFound) {
CFArrayRemoveValueAtIndex(array, position);
++numberRemoved;
position = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value);
}
return numberRemoved;
}
static inline void CFArrayAppendAll(CFMutableArrayRef array, CFArrayRef arrayToAppend) {
CFArrayAppendArray(array, arrayToAppend, CFRangeMake(0, CFArrayGetCount(arrayToAppend)));
}
#define CFArrayForEachC(array, value) for (CFIndex _aCount = CFArrayGetCount(array), _aIX = 0;value = (__typeof__(value))(_aIX < _aCount ? CFArrayGetValueAtIndex(array, _aIX) : 0), _aIX < _aCount; ++_aIX)
static inline void CFArrayForEach(CFArrayRef array, void (^operation)(const void *value)) {
CFArrayApplyFunction(array, CFRangeMake(0, CFArrayGetCount(array)), apply_block_1, (__SECBRIDGE void *)operation);
}
static inline void CFArrayForEachReverse(CFArrayRef array, void (^operation)(const void *value)) {
for(CFIndex count = CFArrayGetCount(array); count > 0; --count) {
operation(CFArrayGetValueAtIndex(array, count - 1));
}
}
static inline const void *CFArrayGetValueMatching(CFArrayRef array, bool (^match)(const void *value)) {
CFIndex i, n = CFArrayGetCount(array);
for (i = 0; i < n; ++i) {
const void *value = CFArrayGetValueAtIndex(array, i);
if (match(value)) {
return value;
}
}
return NULL;
}
static inline bool CFArrayHasValueMatching(CFArrayRef array, bool (^match)(const void *value)) {
return CFArrayGetValueMatching(array, match) != NULL;
}
static inline void CFMutableArrayModifyValues(CFMutableArrayRef array, const void * (^process)(const void *value)) {
CFIndex i, n = CFArrayGetCount(array);
for (i = 0; i < n; ++i) {
const void *value = CFArrayGetValueAtIndex(array, i);
CFArraySetValueAtIndex(array, i, process(value));
}
}
static inline void CFArraySubtract(CFMutableArrayRef from, CFArrayRef remove) {
if (remove && from) {
CFArrayForEach(remove, ^(const void *value) {
CFArrayRemoveAllValue(from, value);
});
}
}
static inline CFMutableArrayRef CFArrayCreateDifference(CFAllocatorRef alloc, CFArrayRef set, CFArrayRef remove) {
CFMutableArrayRef result;
if (!set) {
result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
} else {
result = CFArrayCreateMutableCopy(alloc, 0, set);
if (remove)
CFArraySubtract(result, remove);
}
return result;
}
static inline CFArrayRef CFArrayCreateCountedForVC(CFAllocatorRef allocator, const CFArrayCallBacks *cbs, CFIndex entries, va_list args)
{
CFMutableArrayRef array = CFArrayCreateMutable(allocator, entries, cbs);
if (array == NULL) {
return NULL;
}
for (CFIndex currentValue = 0; currentValue < entries; ++currentValue) {
const void * value = va_arg(args, const void *);
if (value == NULL) {
value = kCFNull;
}
CFArrayAppendValue(array, value);
}
CFArrayRef constArray = CFArrayCreateCopy(allocator, array);
CFRelease(array);
return constArray;
}
static inline CFArrayRef CFArrayCreateForVC(CFAllocatorRef allocator, const CFArrayCallBacks *cbs, va_list args)
{
va_list count;
va_copy(count, args);
CFIndex entries = 0;
while (NULL != va_arg(count, void*)) {
entries += 1;
}
return CFArrayCreateCountedForVC(allocator, cbs, entries, args);
}
static inline CFMutableArrayRef CFArrayCreateMutableForCFTypesWithCapacity(CFAllocatorRef allocator, CFIndex capacity)
{
return CFArrayCreateMutable(allocator, capacity, &kCFTypeArrayCallBacks);
}
static inline CFMutableArrayRef SECWRAPPER_SENTINEL CFArrayCreateMutableForCFTypesWith(CFAllocatorRef allocator, ...)
{
va_list args;
va_start(args, allocator);
CFIndex capacity = 0;
void* object = va_arg(args, void*);
while (object != NULL) {
object = va_arg(args, void*);
capacity++;
};
va_end(args);
CFMutableArrayRef result = CFArrayCreateMutableForCFTypesWithCapacity(allocator, capacity);
va_start(args, allocator);
object = va_arg(args, void*);
while (object != NULL) {
CFArrayAppendValue(result, object);
object = va_arg(args, void*);
};
va_end(args);
return result;
}
static inline CFMutableArrayRef CFArrayCreateMutableForCFTypes(CFAllocatorRef allocator)
{
return CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
}
static inline CFArrayRef SECWRAPPER_SENTINEL CFArrayCreateForCFTypes(CFAllocatorRef allocator, ...)
{
va_list args;
va_start(args, allocator);
CFArrayRef allocatedArray = CFArrayCreateForVC(allocator, &kCFTypeArrayCallBacks, args);
va_end(args);
return allocatedArray;
}
static inline CFArrayRef CFArrayCreateCountedForCFTypes(CFAllocatorRef allocator, CFIndex entries, ...)
{
va_list args;
va_start(args, entries);
CFArrayRef allocatedArray = CFArrayCreateCountedForVC(allocator, &kCFTypeArrayCallBacks, entries, args);
va_end(args);
return allocatedArray;
}
static inline CFArrayRef CFArrayCreateCountedForCFTypesV(CFAllocatorRef allocator, CFIndex entries, va_list args)
{
return CFArrayCreateCountedForVC(allocator, &kCFTypeArrayCallBacks, entries, args);
}
static void CFDictionarySetIfNonNull(CFMutableDictionaryRef dictionary, const void *key, const void *value) {
if (value) {
CFDictionarySetValue(dictionary, key, value);
}
}
static inline CFDictionaryRef CFDictionaryCreateCountedForCFTypesV(CFAllocatorRef allocator, CFIndex entries, va_list args)
{
CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(allocator, entries,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (dictionary == NULL) {
return NULL;
}
for(CFIndex currentValue = 0; currentValue < entries; ++currentValue) {
CFTypeRef key = va_arg(args, CFTypeRef);
CFTypeRef value = va_arg(args, CFTypeRef);
if (value == NULL) {
value = kCFNull;
}
CFDictionarySetValue(dictionary, key, value);
}
CFDictionaryRef constDictionary = CFDictionaryCreateCopy(allocator, dictionary);
CFRelease(dictionary);
return constDictionary;
}
static inline CFDictionaryRef SECWRAPPER_SENTINEL CFDictionaryCreateForCFTypes(CFAllocatorRef allocator, ...)
{
va_list args;
va_start(args, allocator);
CFIndex entries = 0;
while (NULL != va_arg(args, void*)) {
entries += 2;
(void) va_arg(args, void*);
}
entries /= 2;
va_end(args);
va_start(args, allocator);
CFDictionaryRef allocatedDictionary = CFDictionaryCreateCountedForCFTypesV(allocator, entries, args);
va_end(args);
return allocatedDictionary;
}
static inline CFDictionaryRef CFDictionaryCreateCountedForCFTypes(CFAllocatorRef allocator, CFIndex entries, ...)
{
va_list args;
va_start(args, entries);
CFDictionaryRef allocatedDictionary = CFDictionaryCreateCountedForCFTypesV(allocator, entries, args);
va_end(args);
return allocatedDictionary;
}
static inline CFMutableDictionaryRef CFDictionaryCreateMutableForCFTypes(CFAllocatorRef allocator)
{
return CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL CFDictionaryCreateMutableForCFTypesWith(CFAllocatorRef allocator, ...)
{
CFMutableDictionaryRef result = CFDictionaryCreateMutableForCFTypes(allocator);
va_list args;
va_start(args, allocator);
void* key = va_arg(args, void*);
while (key != NULL) {
CFDictionarySetValue(result, key, va_arg(args, void*));
key = va_arg(args, void*);
};
va_end(args);
return result;
}
static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL CFDictionaryCreateMutableForCFTypesWithSafe(CFAllocatorRef allocator, ...)
{
CFMutableDictionaryRef result = CFDictionaryCreateMutableForCFTypes(allocator);
va_list args;
va_start(args, allocator);
void* key = va_arg(args, void*);
while (key != NULL) {
CFDictionarySetIfNonNull(result, key, va_arg(args, void*));
key = va_arg(args, void*);
};
va_end(args);
return result;
}
static inline CFMutableSetRef CFSetCreateMutableForCFTypes(CFAllocatorRef allocator)
{
return CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks);
}
static inline bool CFSetIsEmpty(CFSetRef set) {
return CFSetGetCount(set) == 0;
}
static inline void CFSetForEach(CFSetRef set, void (^operation)(const void *value)) {
CFSetApplyFunction(set, apply_block_1, (__SECBRIDGE void *)operation);
}
static inline void CFSetUnion(CFMutableSetRef set, CFSetRef unionWith) {
CFSetForEach(unionWith, ^(const void *value) {
CFSetSetValue(set, value);
});
}
static inline void CFSetSubtract(CFMutableSetRef set, CFSetRef subtract) {
CFSetForEach(subtract, ^(const void *value) {
CFSetRemoveValue(set, value);
});
}
static inline bool CFSetIsSubset(CFSetRef smaller, CFSetRef bigger) {
__block bool isSubset = true;
CFSetForEach(smaller, ^(const void *value) {
if (!CFSetContainsValue(bigger, value)) {
isSubset = false;
}
});
return isSubset;
}
static inline void CFSetSetValues(CFMutableSetRef set, CFArrayRef valuesToSet) {
CFArrayForEach(valuesToSet, ^(const void *value) {
CFSetSetValue(set, value);
});
}
static inline CFMutableArrayRef CFSetCopyValues(CFSetRef set) {
CFMutableArrayRef values = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
CFSetForEach(set, ^(const void *value) {
CFArrayAppendValue(values, value);
});
return values;
}
static inline bool CFSetIntersectionIsEmpty(CFSetRef set1, CFSetRef set2) {
__block bool intersectionIsEmpty = true;
if(set1 != NULL && set2 != NULL) {
CFSetForEach(set1, ^(const void *value) {
intersectionIsEmpty &= !CFSetContainsValue(set2, value);
});
}
return intersectionIsEmpty;
}
static inline bool CFSetIntersects(CFSetRef set1, CFSetRef set2) {
return !CFSetIntersectionIsEmpty(set1, set2);
}
static inline CFMutableSetRef CFSetCreateIntersection(CFAllocatorRef allocator, CFSetRef a, CFSetRef b) {
CFMutableSetRef result = CFSetCreateMutableCopy(allocator, 0, a);
CFSetRemoveAllValues(result);
CFSetForEach(a, ^(const void *value) {
if (CFSetContainsValue(b, value)) {
CFSetAddValue(result, value);
}
});
return result;
}
static inline CFSetRef CFSetCreateCopyOfArrayForCFTypes(CFArrayRef array) {
CFIndex count = CFArrayGetCount(array);
const void **values = (const void **)malloc(sizeof(const void *) * count);
CFArrayGetValues(array, CFRangeMake(0, count), values);
CFSetRef set = CFSetCreate(CFGetAllocator(array), values, count, &kCFTypeSetCallBacks);
free(values);
return set;
}
static inline void CFSetTransferObject(CFTypeRef object, CFMutableSetRef from, CFMutableSetRef to) {
CFSetAddValue(to, object);
CFSetRemoveValue(from, object);
}
void CFStringArrayPerformWithDelimiterWithDescription(CFArrayRef strings, CFStringRef start, CFStringRef end, void (^action)(CFStringRef description));
void CFStringArrayPerformWithDescription(CFArrayRef strings, void (^action)(CFStringRef description));
void CFStringSetPerformWithDescription(CFSetRef set, void (^action)(CFStringRef description));
static inline void CFDictionaryForEach(CFDictionaryRef dictionary, void (^operation)(const void *key, const void *value)) {
CFDictionaryApplyFunction(dictionary, apply_block_2, (__SECBRIDGE void *)operation);
}
CFStringRef CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary);
CFStringRef CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary);
void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar));
static inline CFAbsoluteTime CFAbsoluteTimeForCalendarMoment(CFCalendarRef cal, int year, int month, int day, int hour, int minute, int second) {
CFAbsoluteTime at;
CFCalendarComposeAbsoluteTime(cal, &at, "yMdHms", year, month, day, hour, minute, second);
return at;
}
static inline CFAbsoluteTime CFAbsoluteTimeForCalendarDay(CFCalendarRef cal, int year, int month, int day) {
CFAbsoluteTime at;
CFCalendarComposeAbsoluteTime(cal, &at, "yMd", year, month, day);
return at;
}
static inline CFAbsoluteTime CFAbsoluteTimeForGregorianMoment(CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
{
CFCalendarRef cal = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar);
CFCalendarSetTimeZone(cal, tz);
CFAbsoluteTime at = CFAbsoluteTimeForCalendarMoment(cal, year, month, day, hour, minute, second);
CFReleaseSafe(cal);
return at;
}
static inline CFAbsoluteTime CFAbsoluteTimeForGregorianDay(CFTimeZoneRef tz, int year, int month, int day)
{
CFCalendarRef cal = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar);
CFCalendarSetTimeZone(cal, tz);
CFAbsoluteTime at = CFAbsoluteTimeForCalendarDay(cal, year, month, day);
CFReleaseSafe(cal);
return at;
}
static inline CFAbsoluteTime CFAbsoluteTimeForGregorianZuluMoment(int year, int month, int day, int hour, int minute, int second)
{
__block CFAbsoluteTime result = 0.0;
SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
result = CFAbsoluteTimeForCalendarMoment(zuluCalendar, year, month, day, hour, minute, second);
});
return result;
}
static inline CFAbsoluteTime CFAbsoluteTimeForGregorianZuluDay(int year, int month, int day)
{
__block CFAbsoluteTime result = 0.0;
SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
result = CFAbsoluteTimeForCalendarDay(zuluCalendar, year, month, day);
});
return result;
}
static inline CFDateRef CFDateCreateForGregorianMoment(CFAllocatorRef allocator, CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
{
return CFDateCreate(allocator, CFAbsoluteTimeForGregorianMoment(tz, year, month, day, hour, minute, second));
}
static inline CFDateRef CFDateCreateForGregorianDay(CFAllocatorRef allocator, CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
{
return CFDateCreate(allocator, CFAbsoluteTimeForGregorianDay(tz, year, month, day));
}
static inline CFDateRef CFDateCreateForGregorianZuluMoment(CFAllocatorRef allocator, int year, int month, int day, int hour, int minute, int second)
{
return CFDateCreate(allocator, CFAbsoluteTimeForGregorianZuluMoment(year, month, day, hour, minute, second));
}
static inline CFDateRef CFDateCreateForGregorianZuluDay(CFAllocatorRef allocator, int year, int month, int day)
{
return CFDateCreate(allocator, CFAbsoluteTimeForGregorianZuluDay(year, month, day));
}
static inline void CFPropertyListWriteToFile(CFPropertyListRef plist, CFURLRef file)
{
CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, file);
CFErrorRef error = NULL;
CFWriteStreamOpen(writeStream);
CFPropertyListWrite(plist, writeStream, kCFPropertyListBinaryFormat_v1_0, 0, &error);
if (error)
secerror("Can't write plist: %@", error);
CFReleaseNull(error);
CFReleaseNull(writeStream);
}
static inline CF_RETURNS_RETAINED CFPropertyListRef CFPropertyListReadFromFile(CFURLRef file)
{
CFPropertyListRef result = NULL;
CFErrorRef error = NULL;
CFBooleanRef isRegularFile;
if (!CFURLCopyResourcePropertyForKey(file, kCFURLIsRegularFileKey, &isRegularFile, &error)) {
secinfo("plist", "file %@: %@", file, error);
} else if (CFBooleanGetValue(isRegularFile)) {
CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, file);
if (readStream) {
if (CFReadStreamOpen(readStream)) {
CFPropertyListFormat format;
result = CFPropertyListCreateWithStream(kCFAllocatorDefault, readStream, 0, kCFPropertyListMutableContainers, &format, &error);
if (!result) {
secerror("read plist from %@: %@", file, error);
}
}
CFRelease(readStream);
}
}
CFReleaseNull(error);
return result;
}
__END_DECLS
#endif