4 // Created by Mitch Adler on 1/27/11.
5 // Copyright 2011 Apple Inc. All rights reserved.
8 #ifndef _SECCFWRAPPERS_H_
9 #define _SECCFWRAPPERS_H_
11 #include <CoreFoundation/CFRuntime.h>
12 #include <CoreFoundation/CFNumber.h>
13 #include <CoreFoundation/CFData.h>
14 #include <CoreFoundation/CFDate.h>
15 #include <CoreFoundation/CFString.h>
16 #include <CoreFoundation/CFPropertyList.h>
18 #include <utilities/SecCFRelease.h>
19 #include <utilities/debugging.h>
22 #include <dispatch/dispatch.h>
29 // Convenience routines.
33 // Macros for the pattern
35 // typedef struct _privateNewClass* NewClassRef;
37 // struct _privateNewClass {
38 // CFRuntimeBase _base;
39 // ... class additions
42 // kClassNameRegisterClass
45 // ClassNameGetTypeID()
47 // CFGiblisFor(NewClass);
49 // .. define NewClassDestroy
50 // .. define NewClassCopyDescription
52 // .. use CFTypeAllocate(NewClass, _privateNewClass, allocator);
56 #define CFGiblisWithFunctions(gibliClassName, describe_func, destroy_func, compare_func, hash_func) \
57 CFTypeID gibliClassName##GetTypeID(void); \
58 CFTypeID gibliClassName##GetTypeID(void) { \
59 static dispatch_once_t k##gibliClassName##RegisterClass; \
60 static CFTypeID k##gibliClassName##TypeID = _kCFRuntimeNotATypeID; \
62 dispatch_once(&k##gibliClassName##RegisterClass, ^{ \
63 static const CFRuntimeClass k##gibliClassName##Class = { \
64 .className = #gibliClassName, \
65 .finalize = destroy_func, \
66 .copyDebugDesc = describe_func, \
67 .equal = compare_func, \
71 k##gibliClassName##TypeID = _CFRuntimeRegisterClass(&k##gibliClassName##Class); \
73 return k##gibliClassName##TypeID; \
77 #define CFGiblisWithHashFor(gibliClassName) \
78 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf); \
79 static void gibliClassName##Destroy(CFTypeRef cf); \
80 static Boolean gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
81 static CFHashCode gibliClassName##Hash(CFTypeRef cf); \
83 CFGiblisWithFunctions(gibliClassName, gibliClassName##CopyDescription, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash)
85 #define CFGiblisWithCompareFor(gibliClassName) \
86 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf); \
87 static void gibliClassName##Destroy(CFTypeRef cf); \
88 static Boolean gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
90 CFGiblisWithFunctions(gibliClassName, gibliClassName##CopyDescription, gibliClassName##Destroy, gibliClassName##Compare, NULL)
93 #define CFGiblisFor(gibliClassName) \
94 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf); \
95 static void gibliClassName##Destroy(CFTypeRef cf); \
97 CFGiblisWithFunctions(gibliClassName, gibliClassName##CopyDescription, gibliClassName##Destroy, NULL, NULL)
99 #define CFTypeAllocate(classType, internalType, allocator) \
100 (classType##Ref) _CFRuntimeCreateInstance(allocator, classType##GetTypeID(), \
101 sizeof(internalType) - sizeof(CFRuntimeBase), \
107 // Call block function
110 static void apply_block_1(const void *value
, void *context
)
112 return ((void (^)(const void *value
))context
)(value
);
115 static void apply_block_2(const void *key
, const void *value
, void *context
)
117 return ((void (^)(const void *key
, const void *value
))context
)(key
, value
);
124 static inline bool CFEqualSafe(CFTypeRef left
, CFTypeRef right
)
126 if (left
== NULL
|| right
== NULL
)
127 return left
== right
;
129 return CFEqual(left
, right
);
136 static inline CFNumberRef
CFNumberCreateWithCFIndex(CFAllocatorRef allocator
, CFIndex value
)
138 return CFNumberCreate(allocator
, kCFNumberCFIndexType
, &value
);
145 static inline CFMutableDataRef
CFDataCreateMutableWithScratch(CFAllocatorRef allocator
, CFIndex size
) {
146 CFMutableDataRef result
= CFDataCreateMutable(allocator
, 0);
147 CFDataSetLength(result
, size
);
152 static inline void CFDataAppend(CFMutableDataRef appendTo
, CFDataRef dataToAppend
)
154 CFDataAppendBytes(appendTo
, CFDataGetBytePtr(dataToAppend
), CFDataGetLength(dataToAppend
));
157 static inline CFDataRef
CFDataCreateReferenceFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
159 return CFDataCreateWithBytesNoCopy(allocator
,
160 CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
,
164 static inline CFDataRef
CFDataCreateCopyFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
)
166 return CFDataCreate(allocator
, CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
);
169 static inline uint8_t* CFDataIncreaseLengthAndGetMutableBytes(CFMutableDataRef data
, CFIndex extraLength
)
171 CFIndex startOffset
= CFDataGetLength(data
);
173 CFDataIncreaseLength(data
, extraLength
);
175 return CFDataGetMutableBytePtr(data
) + startOffset
;
178 static inline uint8_t* CFDataGetMutablePastEndPtr(CFMutableDataRef theData
)
180 return CFDataGetMutableBytePtr(theData
) + CFDataGetLength(theData
);
183 static inline const uint8_t* CFDataGetPastEndPtr(CFDataRef theData
) {
184 return CFDataGetBytePtr(theData
) + CFDataGetLength(theData
);
187 static inline CFComparisonResult
CFDataCompare(CFDataRef left
, CFDataRef right
)
189 const size_t left_size
= CFDataGetLength(left
);
190 const size_t right_size
= CFDataGetLength(right
);
191 const size_t shortest
= (left_size
<= right_size
) ? left_size
: right_size
;
193 int comparison
= memcmp(CFDataGetBytePtr(left
), CFDataGetBytePtr(right
), shortest
);
195 if (comparison
> 0 || (comparison
== 0 && left_size
> right_size
))
196 return kCFCompareGreaterThan
;
197 else if (comparison
< 0 || (comparison
== 0 && left_size
< right_size
))
198 return kCFCompareLessThan
;
200 return kCFCompareEqualTo
;
209 // Turn a CFString into an allocated UTF8-encoded C string.
211 static inline char *CFStringToCString(CFStringRef inStr
)
214 return (char *)strdup("");
215 CFRetain(inStr
); // compensate for release on exit
217 // need to extract into buffer
218 CFIndex length
= CFStringGetLength(inStr
); // in 16-bit character units
219 size_t len
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
);
220 char *buffer
= (char *)malloc(len
); // pessimistic
221 if (!CFStringGetCString(inStr
, buffer
, len
, kCFStringEncodingUTF8
))
228 // runs operation with inStr as a zero terminated C string
229 // in utf8 encoding passed to the operation block.
230 void CFStringPerformWithCString(CFStringRef inStr
, void(^operation
)(const char *utf8Str
));
232 // runs operation with inStr as a zero terminated C string
233 // in utf8 passed to the operation block, the length of
234 // the string is also provided to the block.
235 void CFStringPerformWithCStringAndLength(CFStringRef inStr
, void(^operation
)(const char *utf8Str
, size_t utf8Length
));
237 #include <CommonNumerics/CommonCRC.h>
239 static inline void CFStringAppendEncryptedData(CFMutableStringRef s
, CFDataRef edata
)
241 const uint8_t *bytes
= CFDataGetBytePtr(edata
);
242 CFIndex len
= CFDataGetLength(edata
);
243 CFStringAppendFormat(s
, 0, CFSTR("%04lx:"), len
);
245 for (CFIndex ix
= 0; ix
< len
; ++ix
) {
246 CFStringAppendFormat(s
, 0, CFSTR("%02X"), bytes
[ix
]);
250 CNCRC(kCN_CRC_64_ECMA_182
, bytes
+8, len
-8, &crc
);
251 for (CFIndex ix
= 0; ix
< 8; ++ix
) {
252 CFStringAppendFormat(s
, 0, CFSTR("%02X"), bytes
[ix
]);
254 CFStringAppendFormat(s
, 0, CFSTR("...|%08llx"), crc
);
258 static inline void CFStringAppendHexData(CFMutableStringRef s
, CFDataRef data
) {
259 const uint8_t *bytes
= CFDataGetBytePtr(data
);
260 CFIndex len
= CFDataGetLength(data
);
261 for (CFIndex ix
= 0; ix
< len
; ++ix
) {
262 CFStringAppendFormat(s
, 0, CFSTR("%02X"), bytes
[ix
]);
266 static inline CFStringRef
CFDataCopyHexString(CFDataRef data
) {
267 CFMutableStringRef hexString
= CFStringCreateMutable(kCFAllocatorDefault
, 2 * CFDataGetLength(data
));
268 CFStringAppendHexData(hexString
, data
);
272 static inline void CFDataPerformWithHexString(CFDataRef data
, void (^operation
)(CFStringRef dataString
)) {
273 CFStringRef hexString
= CFDataCopyHexString(data
);
274 operation(hexString
);
275 CFRelease(hexString
);
278 static inline void BufferPerformWithHexString(const UInt8
*bytes
, CFIndex length
, void (^operation
)(CFStringRef dataString
)) {
279 CFDataRef bufferAsData
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, bytes
, length
, kCFAllocatorNull
);
281 CFDataPerformWithHexString(bufferAsData
, operation
);
283 CFReleaseNull(bufferAsData
);
288 static inline void CFStringWriteToFile(CFStringRef inStr
, FILE* file
)
290 CFStringPerformWithCStringAndLength(inStr
, ^(const char *utf8Str
, size_t utf8Length
) {
291 fwrite(utf8Str
, 1, utf8Length
, file
);
295 static inline void CFStringWriteToFileWithNewline(CFStringRef inStr
, FILE* file
)
297 CFStringWriteToFile(inStr
, file
);
302 // MARK: CFArray Helpers
305 static inline CFIndex
CFArrayRemoveAllValue(CFMutableArrayRef array
, const void* value
)
307 CFIndex position
= kCFNotFound
;
308 CFIndex numberRemoved
= 0;
310 position
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), value
);
311 while (position
!= kCFNotFound
) {
312 CFArrayRemoveValueAtIndex(array
, position
);
314 position
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), value
);
317 return numberRemoved
;
320 static inline void CFArrayForEach(CFArrayRef array
, void (^operation
)(const void *value
)) {
321 CFArrayApplyFunction(array
, CFRangeMake(0, CFArrayGetCount(array
)), apply_block_1
, operation
);
324 static inline void CFArrayForEachReverse(CFArrayRef array
, void (^operation
)(const void *value
)) {
325 for(CFIndex count
= CFArrayGetCount(array
); count
> 0; --count
) {
326 operation(CFArrayGetValueAtIndex(array
, count
- 1));
330 static inline const void *CFArrayGetValueMatching(CFArrayRef array
, bool (^match
)(const void *value
)) {
331 CFIndex i
, n
= CFArrayGetCount(array
);
332 for (i
= 0; i
< n
; ++i
) {
333 const void *value
= CFArrayGetValueAtIndex(array
, i
);
341 static inline bool CFArrayHasValueMatching(CFArrayRef array
, bool (^match
)(const void *value
)) {
342 return CFArrayGetValueMatching(array
, match
) != NULL
;
345 static inline void CFMutableArrayModifyValues(CFMutableArrayRef array
, const void * (^process
)(const void *value
)) {
346 CFIndex i
, n
= CFArrayGetCount(array
);
347 for (i
= 0; i
< n
; ++i
) {
348 const void *value
= CFArrayGetValueAtIndex(array
, i
);
349 CFArraySetValueAtIndex(array
, i
, process(value
));
354 // MARK: CFArray creatino Var args helper functions.
356 static inline CFArrayRef
CFArrayCreateCountedForVC(CFAllocatorRef allocator
, const CFArrayCallBacks
*cbs
, CFIndex entries
, va_list args
)
358 const void *values
[entries
];
360 for(CFIndex currentValue
= 0; currentValue
< entries
; ++currentValue
)
362 values
[currentValue
] = va_arg(args
, void*);
364 if (values
[currentValue
] == NULL
)
365 values
[currentValue
] = kCFNull
;
368 return CFArrayCreate(allocator
, values
, entries
, cbs
);
371 static inline CFArrayRef
CFArrayCreateForVC(CFAllocatorRef allocator
, const CFArrayCallBacks
*cbs
, va_list args
)
374 va_copy(count
, args
);
377 while (NULL
!= va_arg(count
, void*)) {
381 return CFArrayCreateCountedForVC(allocator
, cbs
, entries
, args
);
386 // MARK: CFArray of CFTypes support
389 static inline CFMutableArrayRef
CFArrayCreateMutableForCFTypes(CFAllocatorRef allocator
)
391 return CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
);
394 static inline CFArrayRef
CFArrayCreateForCFTypes(CFAllocatorRef allocator
, ...)
397 va_start(args
, allocator
);
399 return CFArrayCreateForVC(allocator
, &kCFTypeArrayCallBacks
, args
);
403 static inline CFArrayRef
CFArrayCreateCountedForCFTypes(CFAllocatorRef allocator
, CFIndex entries
, ...)
406 va_start(args
, entries
);
408 return CFArrayCreateCountedForVC(allocator
, &kCFTypeArrayCallBacks
, entries
, args
);
411 static inline CFArrayRef
CFArrayCreateCountedForCFTypesV(CFAllocatorRef allocator
, CFIndex entries
, va_list args
)
413 return CFArrayCreateCountedForVC(allocator
, &kCFTypeArrayCallBacks
, entries
, args
);
417 // MARK: CFDictionary of CFTypes helpers
420 static inline CFDictionaryRef
CFDictionaryCreateCountedForCFTypesV(CFAllocatorRef allocator
, CFIndex entries
, va_list args
)
422 const void *keys
[entries
];
423 const void *values
[entries
];
425 for(CFIndex currentValue
= 0; currentValue
< entries
; ++currentValue
)
427 keys
[currentValue
] = va_arg(args
, void*);
428 values
[currentValue
] = va_arg(args
, void*);
430 if (values
[currentValue
] == NULL
)
431 values
[currentValue
] = kCFNull
;
434 return CFDictionaryCreate(allocator
, keys
, values
, entries
,
435 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
438 static inline CFDictionaryRef
CFDictionaryCreateForCFTypes(CFAllocatorRef allocator
, ...)
441 va_start(args
, allocator
);
444 while (NULL
!= va_arg(args
, void*)) {
446 (void) va_arg(args
, void*);
451 va_start(args
, allocator
);
453 return CFDictionaryCreateCountedForCFTypesV(allocator
, entries
, args
);
457 static inline CFDictionaryRef
CFDictionaryCreateCountedForCFTypes(CFAllocatorRef allocator
, CFIndex entries
, ...)
460 va_start(args
, entries
);
462 return CFDictionaryCreateCountedForCFTypesV(allocator
, entries
, args
);
465 static inline CFMutableDictionaryRef
CFDictionaryCreateMutableForCFTypes(CFAllocatorRef allocator
)
467 return CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
470 static inline CFMutableDictionaryRef
CFDictionaryCreateMutableForCFTypesWith(CFAllocatorRef allocator
, ...)
472 CFMutableDictionaryRef result
= CFDictionaryCreateMutableForCFTypes(allocator
);
475 va_start(args
, allocator
);
477 void* key
= va_arg(args
, void*);
479 while (key
!= NULL
) {
480 CFDictionarySetValue(result
, key
, va_arg(args
, void*));
481 key
= va_arg(args
, void*);
488 // MARK: CFDictionary Helpers
491 static inline void CFDictionaryForEach(CFDictionaryRef dictionary
, void (^operation
)(const void *key
, const void *value
)) {
492 CFDictionaryApplyFunction(dictionary
, apply_block_2
, operation
);
499 static inline bool isArray(CFTypeRef cfType
) {
500 return cfType
&& CFGetTypeID(cfType
) == CFArrayGetTypeID();
503 static inline bool isData(CFTypeRef cfType
) {
504 return cfType
&& CFGetTypeID(cfType
) == CFDataGetTypeID();
507 static inline bool isDate(CFTypeRef cfType
) {
508 return cfType
&& CFGetTypeID(cfType
) == CFDateGetTypeID();
511 static inline bool isDictionary(CFTypeRef cfType
) {
512 return cfType
&& CFGetTypeID(cfType
) == CFDictionaryGetTypeID();
515 static inline bool isNumber(CFTypeRef cfType
) {
516 return cfType
&& CFGetTypeID(cfType
) == CFNumberGetTypeID();
519 static inline bool isNumberOfType(CFTypeRef cfType
, CFNumberType number
) {
520 return isNumber(cfType
) && CFNumberGetType((CFNumberRef
)cfType
) == number
;
523 static inline bool isString(CFTypeRef cfType
) {
524 return cfType
&& CFGetTypeID(cfType
) == CFStringGetTypeID();
527 static inline bool isBoolean(CFTypeRef cfType
) {
528 return cfType
&& CFGetTypeID(cfType
) == CFBooleanGetTypeID();
531 static inline bool isNull(CFTypeRef cfType
) {
532 return cfType
&& CFGetTypeID(cfType
) == CFNullGetTypeID();
537 // MARK: PropertyList Helpers
541 // Crazy reading and writing stuff
544 static inline void CFPropertyListWriteToFile(CFPropertyListRef plist
, CFURLRef file
)
546 CFWriteStreamRef writeStream
= CFWriteStreamCreateWithFile(kCFAllocatorDefault
, file
);
547 CFErrorRef error
= NULL
;
549 CFWriteStreamOpen(writeStream
);
550 CFPropertyListWrite(plist
, writeStream
, kCFPropertyListBinaryFormat_v1_0
, 0, &error
);
552 secerror("Can't write plist: %@", error
);
554 CFReleaseNull(error
);
555 CFReleaseNull(writeStream
);
558 static inline CF_RETURNS_RETAINED CFPropertyListRef
CFPropertyListReadFromFile(CFURLRef file
)
560 CFPropertyListRef result
= NULL
;
561 CFErrorRef error
= NULL
;
562 CFBooleanRef isRegularFile
;
563 if (!CFURLCopyResourcePropertyForKey(file
, kCFURLIsRegularFileKey
, &isRegularFile
, &error
)) {
564 secerror("file %@: %@", file
, error
);
565 } else if (CFBooleanGetValue(isRegularFile
)) {
566 CFReadStreamRef readStream
= CFReadStreamCreateWithFile(kCFAllocatorDefault
, file
);
568 if (CFReadStreamOpen(readStream
)) {
569 CFPropertyListFormat format
;
570 result
= CFPropertyListCreateWithStream(kCFAllocatorDefault
, readStream
, 0, kCFPropertyListMutableContainers
, &format
, &error
);
572 secerror("read plist from %@: %@", file
, error
);
575 CFRelease(readStream
);
578 CFReleaseNull(error
);