2  * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  25 #ifndef _SECCFWRAPPERS_H_ 
  26 #define _SECCFWRAPPERS_H_ 
  28 #include <CoreFoundation/CFRuntime.h> 
  29 #include <CoreFoundation/CoreFoundation.h> 
  31 #include <utilities/SecCFRelease.h> 
  32 #include <utilities/debugging.h> 
  33 #include <utilities/SecCFError.h> 
  35 #include <IOKit/IOReturn.h> 
  38 #include <dispatch/dispatch.h> 
  43 #include <corecrypto/ccdigest.h> 
  45 #if __has_feature(objc_arc) 
  46 #define __SECBRIDGE  __bridge 
  52 // Convenience routines. 
  56 // Macros for the pattern 
  58 // typedef struct _privateNewClass* NewClassRef; 
  60 // struct _privateNewClass { 
  61 //      CFRuntimeBase _base; 
  62 //      ... class additions 
  65 // kClassNameRegisterClass 
  68 // ClassNameGetTypeID() 
  70 // CFGiblisFor(NewClass); 
  72 // .. define NewClassDestroy 
  73 // .. define NewClassCopyDescription 
  75 // .. use CFTypeAllocate(NewClass, _privateNewClass, allocator); 
  79 // Call this to create a function that returns a singleton instance of type stype, 
  80 // which is initialized once by calling doThisOnce, with result in its context.  Upon 
  81 // completion body should assign to *result. 
  83 extern CFStringRef kSecDebugFormatOption
; 
  85 extern CFDictionaryRef 
SecGetDebugDescriptionFormatOptions(void); 
  88 #define CFGiblisGetSingleton(returnType, giblisClassName, result, doThisOnce) \ 
  89 returnType giblisClassName(void); \ 
  90 returnType giblisClassName(void) { \ 
  91     static dispatch_once_t s##giblisClassName##Once; \ 
  92     static returnType s##giblisClassName##Singleton; \ 
  93     returnType *result = &s##giblisClassName##Singleton; \ 
  94     dispatch_once(&s##giblisClassName##Once, doThisOnce); \ 
  95     return s##giblisClassName##Singleton; \ 
  98 #define CFGiblisWithFunctions(gibliClassName, init_func, copy_func, finalize_func, equal_func, hash_func, copyFormattingDesc_func, copyDebugDesc_func, reclaim_func, refcount_func, run_once_block) \ 
  99 CFGiblisGetSingleton(CFTypeID, gibliClassName##GetTypeID, typeID, (^{ \ 
 100     void(^_onceBlock)() = (run_once_block); \ 
 101     static const CFRuntimeClass s##gibliClassName##Class = { \ 
 102         .version = (reclaim_func == NULL ? 0 : _kCFRuntimeResourcefulObject) \ 
 103                  | (refcount_func == NULL ? 0 : _kCFRuntimeCustomRefCount), \ 
 104         .className = #gibliClassName, \ 
 107         .finalize = finalize_func, \ 
 108         .equal = equal_func, \ 
 110         .copyFormattingDesc = copyFormattingDesc_func, \ 
 111         .copyDebugDesc = copyDebugDesc_func, \ 
 112         .reclaim = reclaim_func, \ 
 113         .refcount = refcount_func, \ 
 115     *typeID = _CFRuntimeRegisterClass(&s##gibliClassName##Class); \ 
 120 #define CFGiblisWithHashFor(gibliClassName) \ 
 121     static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \ 
 122     static void         gibliClassName##Destroy(CFTypeRef cf); \ 
 123     static Boolean      gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \ 
 124     static CFHashCode   gibliClassName##Hash(CFTypeRef cf); \ 
 125     static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\ 
 126         return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\ 
 129     CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL) 
 131 #define CFGiblisWithCompareFor(gibliClassName) \ 
 132     static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \ 
 133     static void         gibliClassName##Destroy(CFTypeRef cf); \ 
 134     static Boolean      gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \ 
 135     static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\ 
 136         return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\ 
 139     CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL) 
 142 #define CFGiblisFor(gibliClassName) \ 
 143     static CFStringRef  gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \ 
 144     static void         gibliClassName##Destroy(CFTypeRef cf); \ 
 145     static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\ 
 146         return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\ 
 149     CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, NULL, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL) 
 151 #define CFTypeAllocateWithSpace(classType, space, allocator) \ 
 152     (classType##Ref) _CFRuntimeCreateInstance(allocator, classType##GetTypeID(), space, NULL) 
 154 #define CFTypeAllocate(classType, internalType, allocator) \ 
 155     CFTypeAllocateWithSpace(classType, sizeof(internalType) - sizeof(CFRuntimeBase), allocator) 
 157 #define SECWRAPPER_SENTINEL __attribute__((__sentinel__)) 
 161 void withStringOfAbsoluteTime(CFAbsoluteTime at
, void (^action
)(CFStringRef decription
)); 
 165 // MARK: Call block function 
 169 static void apply_block_1(const void *value
, void *context
) 
 171     ((__SECBRIDGE 
void (^)(const void *value
))context
)(value
); 
 174 static void apply_block_2(const void *key
, const void *value
, void *context
) 
 176     ((__SECBRIDGE 
void (^)(const void *key
, const void *value
))context
)(key
, value
); 
 180 // MARK: Type checking 
 183 static inline bool isArray(CFTypeRef cfType
) { 
 184     return cfType 
&& CFGetTypeID(cfType
) == CFArrayGetTypeID(); 
 187 static inline bool isSet(CFTypeRef cfType
) { 
 188     return cfType 
&& CFGetTypeID(cfType
) == CFSetGetTypeID(); 
 191 static inline bool isData(CFTypeRef cfType
) { 
 192     return cfType 
&& CFGetTypeID(cfType
) == CFDataGetTypeID(); 
 195 static inline bool isDate(CFTypeRef cfType
) { 
 196     return cfType 
&& CFGetTypeID(cfType
) == CFDateGetTypeID(); 
 199 static inline bool isDictionary(CFTypeRef cfType
) { 
 200     return cfType 
&& CFGetTypeID(cfType
) == CFDictionaryGetTypeID(); 
 203 static inline bool isNumber(CFTypeRef cfType
) { 
 204     return cfType 
&& CFGetTypeID(cfType
) == CFNumberGetTypeID(); 
 207 static inline bool isNumberOfType(CFTypeRef cfType
, CFNumberType number
) { 
 208     return isNumber(cfType
) && CFNumberGetType((CFNumberRef
)cfType
) == number
; 
 211 static inline bool isString(CFTypeRef cfType
) { 
 212     return cfType 
&& CFGetTypeID(cfType
) == CFStringGetTypeID(); 
 215 static inline bool isBoolean(CFTypeRef cfType
) { 
 216     return cfType 
&& CFGetTypeID(cfType
) == CFBooleanGetTypeID(); 
 219 static inline bool isNull(CFTypeRef cfType
) { 
 220     return cfType 
&& CFGetTypeID(cfType
) == CFNullGetTypeID(); 
 224 // MARK CFEqual Helpers 
 227 static inline bool CFEqualSafe(CFTypeRef left
, CFTypeRef right
) 
 229     if (left 
== NULL 
|| right 
== NULL
) 
 230         return left 
== right
; 
 232         return CFEqual(left
, right
); 
 240 static void fprint_string(FILE *file
, CFStringRef string
) { 
 242     CFRange range 
= { .location 
= 0 }; 
 243     range
.length 
= CFStringGetLength(string
); 
 244     while (range
.length 
> 0) { 
 245         CFIndex bytesUsed 
= 0; 
 246         CFIndex converted 
= CFStringGetBytes(string
, range
, kCFStringEncodingUTF8
, 0, false, buf
, sizeof(buf
), &bytesUsed
); 
 247         fwrite(buf
, 1, bytesUsed
, file
); 
 248         range
.length 
-= converted
; 
 249         range
.location 
+= converted
; 
 253 static inline void cffprint_v(FILE *file
, CFStringRef fmt
, va_list args
) { 
 254     CFStringRef line 
= CFStringCreateWithFormatAndArguments(NULL
, NULL
, fmt
, args
); 
 255     fprint_string(file
, line
); 
 259 static inline void cffprint_c_v(FILE *file
, const char *fmt
, va_list args
) { 
 260     CFStringRef cffmt 
= CFStringCreateWithCString(kCFAllocatorDefault
, fmt
, kCFStringEncodingUTF8
); 
 261     cffprint_v(file
, cffmt
, args
); 
 265 static void cffprint(FILE *file
, CFStringRef fmt
, ...) CF_FORMAT_FUNCTION(2,0); 
 266 static inline void cffprint(FILE *file
, CFStringRef fmt
, ...) { 
 269     cffprint_v(file
, fmt
, args
); 
 274 // MARK: CFError Helpers 
 277 /* Return false if possibleError is set.  Propagates possibleError into *error 
 278    if *error is NULL, otherwise releases possibleError. */ 
 280 bool CFErrorPropagate(CFErrorRef possibleError CF_CONSUMED
, CFErrorRef 
*error
) { 
 282         if (error 
&& !*error
) { 
 283             *error 
= possibleError
; 
 285             CFRelease(possibleError
); 
 292 static inline bool CFErrorIsMalfunctioningKeybagError(CFErrorRef error
){ 
 293     switch(CFErrorGetCode(error
)) 
 295         case(kIOReturnError
): 
 297         case(kIOReturnNotPermitted
): 
 302     return CFEqualSafe(CFErrorGetDomain(error
), kSecKernDomain
); 
 306 // MARK: CFNumber Helpers 
 309 static inline CFNumberRef 
CFNumberCreateWithCFIndex(CFAllocatorRef allocator
, CFIndex value
) 
 311     return CFNumberCreate(allocator
, kCFNumberCFIndexType
, &value
); 
 315 // MARK: CFData Helpers 
 318 static inline CFMutableDataRef 
CFDataCreateMutableWithScratch(CFAllocatorRef allocator
, CFIndex size
) { 
 319     CFMutableDataRef result 
= CFDataCreateMutable(allocator
, 0); 
 320     CFDataSetLength(result
, size
); 
 325 static inline void CFDataAppend(CFMutableDataRef appendTo
, CFDataRef dataToAppend
) 
 327     CFDataAppendBytes(appendTo
, CFDataGetBytePtr(dataToAppend
), CFDataGetLength(dataToAppend
)); 
 330 static inline CFDataRef 
CFDataCreateReferenceFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
) 
 332     return CFDataCreateWithBytesNoCopy(allocator
, 
 333                                        CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
, 
 337 static inline CFDataRef 
CFDataCreateCopyFromRange(CFAllocatorRef allocator
, CFDataRef sourceData
, CFRange range
) 
 339     return CFDataCreate(allocator
, CFDataGetBytePtr(sourceData
) + range
.location
, range
.length
); 
 342 CFDataRef 
CFDataCreateWithRandomBytes(size_t len
); 
 344 CFDataRef 
CFDataCreateWithInitializer(CFAllocatorRef allocator
, CFIndex size
, bool (^operation
)(size_t size
, uint8_t *buffer
)); 
 346 static inline uint8_t* CFDataIncreaseLengthAndGetMutableBytes(CFMutableDataRef data
, CFIndex extraLength
) 
 348     CFIndex startOffset 
= CFDataGetLength(data
); 
 350     CFDataIncreaseLength(data
, extraLength
); 
 352     return CFDataGetMutableBytePtr(data
) + startOffset
; 
 355 static inline uint8_t* CFDataGetMutablePastEndPtr(CFMutableDataRef theData
) 
 357     return CFDataGetMutableBytePtr(theData
) + CFDataGetLength(theData
); 
 360 static inline const uint8_t* CFDataGetPastEndPtr(CFDataRef theData
) { 
 361     return CFDataGetBytePtr(theData
) + CFDataGetLength(theData
); 
 364 static inline CFComparisonResult 
CFDataCompare(CFDataRef left
, CFDataRef right
) 
 366     const size_t left_size 
= CFDataGetLength(left
); 
 367     const size_t right_size 
= CFDataGetLength(right
); 
 368     const size_t shortest 
= (left_size 
<= right_size
) ? left_size 
: right_size
; 
 370     int comparison 
= memcmp(CFDataGetBytePtr(left
), CFDataGetBytePtr(right
), shortest
); 
 372     if (comparison 
> 0 || (comparison 
== 0 && left_size 
> right_size
)) 
 373         return kCFCompareGreaterThan
; 
 374     else if (comparison 
< 0 || (comparison 
== 0 && left_size 
< right_size
)) 
 375         return kCFCompareLessThan
; 
 377         return kCFCompareEqualTo
; 
 380 static inline CFDataRef 
CFDataCreateWithHash(CFAllocatorRef allocator
, const struct ccdigest_info 
*di
, const uint8_t *buffer
, const uint8_t length
) { 
 381     CFMutableDataRef result 
= CFDataCreateMutableWithScratch(allocator
, di
->output_size
); 
 383     ccdigest(di
, length
, buffer
, CFDataGetMutableBytePtr(result
)); 
 389 static inline CFDataRef 
CFDataCreateCopyFromPositions(CFAllocatorRef allocator
, CFDataRef source
, CFIndex start
, CFIndex end
) 
 391     return CFDataCreateCopyFromRange(allocator
, source
, CFRangeMake(start
, end 
- start
)); 
 394 static inline int nibletToByte(char niblet
) { 
 395     if(niblet 
>= '0' && niblet 
<= '9') return niblet 
- '0'; 
 396     if(niblet 
>= 'a' && niblet 
<= 'f') return niblet 
- 'a' + 10; 
 397     if(niblet 
>= 'A' && niblet 
<= 'F') return niblet 
- 'A' + 10; 
 401 static inline CFDataRef 
CFDataCreateFromHexString(CFAllocatorRef allocator
, CFStringRef sourceHex
) { 
 402     CFIndex sourceLen 
= CFStringGetLength(sourceHex
); 
 403     if((sourceLen 
% 2) != 0) return NULL
; 
 404     const char *src 
= CFStringGetCStringPtr(sourceHex
, kCFStringEncodingUTF8
); 
 405     UInt8 bytes
[sourceLen
/2]; 
 406     for(int i 
= 0; i 
< sourceLen
; i
+=2) { 
 407         bytes
[i
/2] = (UInt8
) (nibletToByte(src
[i
]) * 16 + nibletToByte(src
[i
+1])); 
 409     return CFDataCreate(allocator
, bytes
, sourceLen
/2); 
 414 // MARK: CFString Helpers 
 417 CFComparisonResult 
CFStringCompareSafe(const void *val1
, const void *val2
, void *context
); 
 420 // Turn a CFString into an allocated UTF8-encoded C string. 
 422 static inline char *CFStringToCString(CFStringRef inStr
) 
 425         return (char *)strdup(""); 
 426     CFRetain(inStr
);        // compensate for release on exit 
 428     // need to extract into buffer 
 429     CFIndex length 
= CFStringGetLength(inStr
);  // in 16-bit character units 
 430     size_t len 
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
); 
 431     char *buffer 
= (char *)malloc(len
);                 // pessimistic 
 432     if (!CFStringGetCString(inStr
, buffer
, len
, kCFStringEncodingUTF8
)) 
 439 // runs operation with inStr as a zero terminated C string 
 440 // in utf8 encoding passed to the operation block. 
 441 void CFStringPerformWithCString(CFStringRef inStr
, void(^operation
)(const char *utf8Str
)); 
 443 // runs operation with inStr as a zero terminated C string 
 444 // in utf8 passed to the operation block, the length of 
 445 // the string is also provided to the block. 
 446 void CFStringPerformWithCStringAndLength(CFStringRef inStr
, void(^operation
)(const char *utf8Str
, size_t utf8Length
)); 
 448 void CFStringPerformWithUTF8CFData(CFStringRef inStr
, void (^operation
)(CFDataRef stringAsData
)); 
 450 #include <CommonNumerics/CommonCRC.h> 
 452 static inline void CFStringAppendEncryptedData(CFMutableStringRef s
, CFDataRef edata
) 
 454     const uint8_t *bytes 
= CFDataGetBytePtr(edata
); 
 455     CFIndex len 
= CFDataGetLength(edata
); 
 456     CFStringAppendFormat(s
, 0, CFSTR("%04lx:"), len
); 
 458         for (CFIndex ix 
= 0; ix 
< len
; ++ix
) { 
 459             CFStringAppendFormat(s
, 0, CFSTR("%02X"), bytes
[ix
]); 
 463         CNCRC(kCN_CRC_64_ECMA_182
, bytes
+8, len
-8, &crc
); 
 464         for (CFIndex ix 
= 0; ix 
< 8; ++ix
) { 
 465             CFStringAppendFormat(s
, 0, CFSTR("%02X"), bytes
[ix
]); 
 467         CFStringAppendFormat(s
, 0, CFSTR("...|%08llx"), crc
); 
 471 static inline void CFStringAppendHexData(CFMutableStringRef s
, CFDataRef data
) { 
 472     const uint8_t *bytes 
= CFDataGetBytePtr(data
); 
 473     CFIndex len 
= CFDataGetLength(data
); 
 474     for (CFIndex ix 
= 0; ix 
< len
; ++ix
) { 
 475         CFStringAppendFormat(s
, 0, CFSTR("%02X"), bytes
[ix
]); 
 479 static inline CF_RETURNS_RETAINED CFStringRef 
CFDataCopyHexString(CFDataRef data
) { 
 480     CFMutableStringRef hexString 
= CFStringCreateMutable(kCFAllocatorDefault
, 2 * CFDataGetLength(data
)); 
 481     CFStringAppendHexData(hexString
, data
); 
 485 static inline void CFDataPerformWithHexString(CFDataRef data
, void (^operation
)(CFStringRef dataString
)) { 
 486     CFStringRef hexString 
= data 
? CFDataCopyHexString(data
) : CFSTR("(null)"); 
 487     operation(hexString
); 
 488     CFRelease(hexString
); 
 491 static inline void BufferPerformWithHexString(const UInt8 
*bytes
, CFIndex length
, void (^operation
)(CFStringRef dataString
)) { 
 492     CFDataRef bufferAsData 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, bytes
, length
, kCFAllocatorNull
); 
 494     CFDataPerformWithHexString(bufferAsData
, operation
); 
 496     CFReleaseNull(bufferAsData
); 
 501 static inline void CFStringWriteToFile(CFStringRef inStr
, FILE* file
) 
 503     CFStringPerformWithCStringAndLength(inStr
, ^(const char *utf8Str
, size_t utf8Length
) { 
 504         fwrite(utf8Str
, 1, utf8Length
, file
); 
 508 static inline void CFStringWriteToFileWithNewline(CFStringRef inStr
, FILE* file
) 
 510     CFStringWriteToFile(inStr
, file
); 
 514 static inline CFStringRef 
CFStringCreateTruncatedCopy(CFStringRef s
, CFIndex len
) { 
 516     if(len 
>= CFStringGetLength(s
)) return CFStringCreateCopy(kCFAllocatorDefault
, s
); 
 517     return CFStringCreateWithSubstring(kCFAllocatorDefault
, s
, CFRangeMake(0, len
)); 
 521 // MARK: CFCollectionHelpers 
 525 const void *SecCFRetainForCollection(CFAllocatorRef allocator
, const void *value
) 
 527     return CFRetain(value
); 
 531 void SecCFReleaseForCollection(CFAllocatorRef allocator
, const void *value
) 
 537 // MARK: CFArray Helpers 
 540 static inline CFIndex 
CFArrayRemoveAllValue(CFMutableArrayRef array
, const void* value
) 
 542     CFIndex position 
= kCFNotFound
; 
 543     CFIndex numberRemoved 
= 0; 
 545     position 
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), value
); 
 546     while (position 
!= kCFNotFound
) { 
 547         CFArrayRemoveValueAtIndex(array
, position
); 
 549         position 
= CFArrayGetFirstIndexOfValue(array
, CFRangeMake(0, CFArrayGetCount(array
)), value
); 
 552     return numberRemoved
; 
 555 static inline void CFArrayAppendAll(CFMutableArrayRef array
, CFArrayRef arrayToAppend
) { 
 556     CFArrayAppendArray(array
, arrayToAppend
, CFRangeMake(0, CFArrayGetCount(arrayToAppend
))); 
 559 #define CFArrayForEachC(array, value) for (CFIndex _aCount = CFArrayGetCount(array), _aIX = 0;value = (__typeof__(value))(_aIX < _aCount ? CFArrayGetValueAtIndex(array, _aIX) : 0), _aIX < _aCount; ++_aIX) 
 561 static inline void CFArrayForEach(CFArrayRef array
, void (^operation
)(const void *value
)) { 
 562     CFArrayApplyFunction(array
, CFRangeMake(0, CFArrayGetCount(array
)), apply_block_1
, (__SECBRIDGE 
void *)operation
); 
 565 static inline void CFArrayForEachReverse(CFArrayRef array
, void (^operation
)(const void *value
)) { 
 566     for(CFIndex count 
= CFArrayGetCount(array
); count 
> 0; --count
) { 
 567         operation(CFArrayGetValueAtIndex(array
, count 
- 1)); 
 571 static inline const void *CFArrayGetValueMatching(CFArrayRef array
, bool (^match
)(const void *value
)) { 
 572     CFIndex i
, n 
= CFArrayGetCount(array
); 
 573     for (i 
= 0; i 
< n
; ++i
) { 
 574         const void *value 
= CFArrayGetValueAtIndex(array
, i
); 
 582 static inline bool CFArrayHasValueMatching(CFArrayRef array
, bool (^match
)(const void *value
)) { 
 583     return CFArrayGetValueMatching(array
, match
) != NULL
; 
 586 static inline void CFMutableArrayModifyValues(CFMutableArrayRef array
, const void * (^process
)(const void *value
)) { 
 587     CFIndex i
, n 
= CFArrayGetCount(array
); 
 588     for (i 
= 0; i 
< n
; ++i
) { 
 589         const void *value 
= CFArrayGetValueAtIndex(array
, i
); 
 590         CFArraySetValueAtIndex(array
, i
, process(value
)); 
 594 static inline void CFArraySubtract(CFMutableArrayRef from
, CFArrayRef remove
) { 
 595     if (remove 
&& from
) { 
 596         CFArrayForEach(remove
, ^(const void *value
) { 
 597             CFArrayRemoveAllValue(from
, value
); 
 602 static inline CFMutableArrayRef 
CFArrayCreateDifference(CFAllocatorRef alloc
, CFArrayRef set
, CFArrayRef remove
) { 
 603     CFMutableArrayRef result
; 
 605         result 
= CFArrayCreateMutable(alloc
, 0, &kCFTypeArrayCallBacks
); 
 607         result 
= CFArrayCreateMutableCopy(alloc
, 0, set
); 
 609             CFArraySubtract(result
, remove
); 
 616 // MARK: CFArray creation Var args helper functions. 
 618 static inline CFArrayRef 
CFArrayCreateCountedForVC(CFAllocatorRef allocator
, const CFArrayCallBacks 
*cbs
, CFIndex entries
, va_list args
) 
 620     const void *values
[entries 
? entries 
: 1]; 
 621     for (CFIndex currentValue 
= 0; currentValue 
< entries
; ++currentValue
) 
 623         values
[currentValue
] = va_arg(args
, void*); 
 625         if (values
[currentValue
] == NULL
) 
 626             values
[currentValue
] = kCFNull
; 
 629     return CFArrayCreate(allocator
, values
, entries
, cbs
); 
 632 static inline CFArrayRef 
CFArrayCreateForVC(CFAllocatorRef allocator
, const CFArrayCallBacks 
*cbs
, va_list args
) 
 635     va_copy(count
, args
); 
 638     while (NULL 
!= va_arg(count
, void*)) { 
 642     return CFArrayCreateCountedForVC(allocator
, cbs
, entries
, args
); 
 649 // MARK: CFArray of CFTypes support 
 652 static inline CFMutableArrayRef 
CFArrayCreateMutableForCFTypesWithCapacity(CFAllocatorRef allocator
, CFIndex capacity
) 
 654     return CFArrayCreateMutable(allocator
, capacity
, &kCFTypeArrayCallBacks
); 
 657 static inline CFMutableArrayRef SECWRAPPER_SENTINEL 
CFArrayCreateMutableForCFTypesWith(CFAllocatorRef allocator
, ...) 
 661     va_start(args
, allocator
); 
 662     CFIndex capacity 
= 0; 
 663     void* object 
= va_arg(args
, void*); 
 665     while (object 
!= NULL
) { 
 666         object 
= va_arg(args
, void*); 
 672     CFMutableArrayRef result 
= CFArrayCreateMutableForCFTypesWithCapacity(allocator
, capacity
); 
 674     va_start(args
, allocator
); 
 675     object 
= va_arg(args
, void*); 
 677     while (object 
!= NULL
) { 
 678         CFArrayAppendValue(result
, object
); 
 679         object 
= va_arg(args
, void*); 
 687 static inline CFMutableArrayRef 
CFArrayCreateMutableForCFTypes(CFAllocatorRef allocator
) 
 689     return CFArrayCreateMutable(allocator
, 0, &kCFTypeArrayCallBacks
); 
 692 static inline CFArrayRef SECWRAPPER_SENTINEL 
CFArrayCreateForCFTypes(CFAllocatorRef allocator
, ...) 
 695     va_start(args
, allocator
); 
 696     CFArrayRef allocatedArray 
= CFArrayCreateForVC(allocator
, &kCFTypeArrayCallBacks
, args
); 
 698     return allocatedArray
; 
 702 static inline CFArrayRef 
CFArrayCreateCountedForCFTypes(CFAllocatorRef allocator
, CFIndex entries
, ...) 
 705     va_start(args
, entries
); 
 706     CFArrayRef allocatedArray 
= CFArrayCreateCountedForVC(allocator
, &kCFTypeArrayCallBacks
, entries
, args
); 
 708     return allocatedArray
; 
 711 static inline CFArrayRef 
CFArrayCreateCountedForCFTypesV(CFAllocatorRef allocator
, CFIndex entries
, va_list args
) 
 713     return CFArrayCreateCountedForVC(allocator
, &kCFTypeArrayCallBacks
, entries
, args
); 
 717 // MARK: CFDictionary of CFTypes helpers 
 720 static void CFDictionarySetIfNonNull(CFMutableDictionaryRef dictionary
, const void *key
, const void *value
) { 
 722         CFDictionarySetValue(dictionary
, key
, value
); 
 726 static inline CFDictionaryRef 
CFDictionaryCreateCountedForCFTypesV(CFAllocatorRef allocator
, CFIndex entries
, va_list args
) 
 728     const void *keys
[entries
]; 
 729     const void *values
[entries
]; 
 731     for(CFIndex currentValue 
= 0; currentValue 
< entries
; ++currentValue
) 
 733         keys
[currentValue
] = va_arg(args
, void*); 
 734         values
[currentValue
] = va_arg(args
, void*); 
 736         if (values
[currentValue
] == NULL
) 
 737             values
[currentValue
] = kCFNull
; 
 740     return CFDictionaryCreate(allocator
, keys
, values
, entries
, 
 741                               &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 744 static inline CFDictionaryRef SECWRAPPER_SENTINEL 
CFDictionaryCreateForCFTypes(CFAllocatorRef allocator
, ...) 
 747     va_start(args
, allocator
); 
 750     while (NULL 
!= va_arg(args
, void*)) { 
 752         (void) va_arg(args
, void*); 
 757     va_start(args
, allocator
); 
 758     CFDictionaryRef allocatedDictionary 
= CFDictionaryCreateCountedForCFTypesV(allocator
, entries
, args
); 
 760     return allocatedDictionary
; 
 763 static inline CFDictionaryRef 
CFDictionaryCreateCountedForCFTypes(CFAllocatorRef allocator
, CFIndex entries
, ...) 
 766     va_start(args
, entries
); 
 767     CFDictionaryRef allocatedDictionary 
= CFDictionaryCreateCountedForCFTypesV(allocator
, entries
, args
); 
 770     return allocatedDictionary
; 
 773 static inline CFMutableDictionaryRef 
CFDictionaryCreateMutableForCFTypes(CFAllocatorRef allocator
) 
 775     return CFDictionaryCreateMutable(allocator
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
); 
 778 static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL 
CFDictionaryCreateMutableForCFTypesWith(CFAllocatorRef allocator
, ...) 
 780     CFMutableDictionaryRef result 
= CFDictionaryCreateMutableForCFTypes(allocator
); 
 783     va_start(args
, allocator
); 
 785     void* key 
= va_arg(args
, void*); 
 787     while (key 
!= NULL
) { 
 788         CFDictionarySetValue(result
, key
, va_arg(args
, void*)); 
 789         key 
= va_arg(args
, void*); 
 795 static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL 
CFDictionaryCreateMutableForCFTypesWithSafe(CFAllocatorRef allocator
, ...) 
 797     CFMutableDictionaryRef result 
= CFDictionaryCreateMutableForCFTypes(allocator
); 
 800     va_start(args
, allocator
); 
 802     void* key 
= va_arg(args
, void*); 
 804     while (key 
!= NULL
) { 
 805         CFDictionarySetIfNonNull(result
, key
, va_arg(args
, void*)); 
 806         key 
= va_arg(args
, void*); 
 813 // MARK: CFSet Helpers 
 816 static inline CFMutableSetRef 
CFSetCreateMutableForCFTypes(CFAllocatorRef allocator
) 
 818     return CFSetCreateMutable(allocator
, 0, &kCFTypeSetCallBacks
); 
 821 static inline bool CFSetIsEmpty(CFSetRef set
) { 
 822     return CFSetGetCount(set
) == 0; 
 825 static inline void CFSetForEach(CFSetRef set
, void (^operation
)(const void *value
)) { 
 826     CFSetApplyFunction(set
, apply_block_1
, (__SECBRIDGE 
void *)operation
); 
 829 static inline void CFSetUnion(CFMutableSetRef set
, CFSetRef unionWith
) { 
 830     CFSetForEach(unionWith
, ^(const void *value
) { 
 831         CFSetSetValue(set
, value
); 
 835 static inline void CFSetSubtract(CFMutableSetRef set
, CFSetRef subtract
) { 
 836     CFSetForEach(subtract
, ^(const void *value
) { 
 837         CFSetRemoveValue(set
, value
); 
 841 static inline bool CFSetIsSubset(CFSetRef smaller
, CFSetRef bigger
) { 
 842     __block 
bool isSubset 
= true; 
 843     CFSetForEach(smaller
, ^(const void *value
) { 
 844         if (!CFSetContainsValue(bigger
, value
)) { 
 852 static inline void CFSetSetValues(CFMutableSetRef set
, CFArrayRef valuesToSet
) { 
 853     CFArrayForEach(valuesToSet
, ^(const void *value
) { 
 854         CFSetSetValue(set
, value
); 
 858 static inline CFMutableArrayRef 
CFSetCopyValues(CFSetRef set
) { 
 859     CFMutableArrayRef values 
= CFArrayCreateMutableForCFTypes(kCFAllocatorDefault
); 
 861     CFSetForEach(set
, ^(const void *value
) { 
 862         CFArrayAppendValue(values
, value
); 
 868 static inline bool CFSetIntersectionIsEmpty(CFSetRef set1
, CFSetRef set2
) { 
 869     __block 
bool intersectionIsEmpty 
= true; 
 870     CFSetForEach(set1
, ^(const void *value
) { 
 871         intersectionIsEmpty 
&= !CFSetContainsValue(set2
, value
); 
 873     return intersectionIsEmpty
; 
 876 static inline bool CFSetIntersects(CFSetRef set1
, CFSetRef set2
) { 
 877     return !CFSetIntersectionIsEmpty(set1
, set2
); 
 880 static inline CFMutableSetRef 
CFSetCreateIntersection(CFAllocatorRef allocator
, CFSetRef a
, CFSetRef b
) { 
 881     CFMutableSetRef result 
= CFSetCreateMutableCopy(allocator
, 0, a
); 
 883     CFSetRemoveAllValues(result
); 
 884     CFSetForEach(a
, ^(const void *value
) { 
 885         if (CFSetContainsValue(b
, value
)) { 
 886             CFSetAddValue(result
, value
); 
 893 static inline CFSetRef 
CFSetCreateCopyOfArrayForCFTypes(CFArrayRef array
) { 
 894     CFIndex count 
= CFArrayGetCount(array
); 
 895     const void **values 
= (const void **)malloc(sizeof(const void *) * count
); 
 896     CFArrayGetValues(array
, CFRangeMake(0, count
), values
); 
 897     CFSetRef set 
= CFSetCreate(CFGetAllocator(array
), values
, count
, &kCFTypeSetCallBacks
); 
 902 static inline void CFSetTransferObject(CFTypeRef object
, CFMutableSetRef from
, CFMutableSetRef to
) { 
 903     CFSetAddValue(to
, object
); 
 904     CFSetRemoveValue(from
, object
); 
 908 // MARK: CFStringXxx Helpers 
 911 void CFStringArrayPerfromWithDelimeterWithDescription(CFArrayRef strings
, CFStringRef start
, CFStringRef end
, void (^action
)(CFStringRef description
)); 
 912 void CFStringArrayPerfromWithDescription(CFArrayRef strings
, void (^action
)(CFStringRef description
)); 
 913 void CFStringSetPerformWithDescription(CFSetRef set
, void (^action
)(CFStringRef description
)); 
 916 // MARK: CFDictionary Helpers 
 919 static inline void CFDictionaryForEach(CFDictionaryRef dictionary
, void (^operation
)(const void *key
, const void *value
)) { 
 920     CFDictionaryApplyFunction(dictionary
, apply_block_2
, (__SECBRIDGE 
void *)operation
); 
 923 CFStringRef 
CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary
); 
 924 CFStringRef 
CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary
); 
 927 // MARK: CFCalendar helpers 
 930 void SecCFCalendarDoWithZuluCalendar(void(^action
)(CFCalendarRef zuluCalendar
)); 
 933 // MARK: CFAbsoluteTime helpers 
 936 static inline CFAbsoluteTime 
CFAbsoluteTimeForCalendarMoment(CFCalendarRef cal
, int year
, int month
, int day
, int hour
, int minute
, int second
) { 
 938     CFCalendarComposeAbsoluteTime(cal
, &at
, "yMdHms", year
, month
, day
, hour
, minute
, second
); 
 942 static inline CFAbsoluteTime 
CFAbsoluteTimeForCalendarDay(CFCalendarRef cal
, int year
, int month
, int day
) { 
 944     CFCalendarComposeAbsoluteTime(cal
, &at
, "yMd", year
, month
, day
); 
 948 static inline CFAbsoluteTime 
CFAbsoluteTimeForGregorianMoment(CFTimeZoneRef tz
, int year
, int month
, int day
, int hour
, int minute
, int second
) 
 950     CFCalendarRef cal 
= CFCalendarCreateWithIdentifier(NULL
, kCFGregorianCalendar
); 
 951     CFCalendarSetTimeZone(cal
, tz
); 
 952     CFAbsoluteTime at 
= CFAbsoluteTimeForCalendarMoment(cal
, year
, month
, day
, hour
, minute
, second
); 
 957 static inline CFAbsoluteTime 
CFAbsoluteTimeForGregorianDay(CFTimeZoneRef tz
, int year
, int month
, int day
) 
 959     CFCalendarRef cal 
= CFCalendarCreateWithIdentifier(NULL
, kCFGregorianCalendar
); 
 960     CFCalendarSetTimeZone(cal
, tz
); 
 961     CFAbsoluteTime at 
= CFAbsoluteTimeForCalendarDay(cal
, year
, month
, day
); 
 966 static inline CFAbsoluteTime 
CFAbsoluteTimeForGregorianZuluMoment(int year
, int month
, int day
, int hour
, int minute
, int second
) 
 968     __block CFAbsoluteTime result 
= 0.0; 
 969     SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) { 
 970         result 
= CFAbsoluteTimeForCalendarMoment(zuluCalendar
, year
, month
, day
, hour
, minute
, second
); 
 976 static inline CFAbsoluteTime 
CFAbsoluteTimeForGregorianZuluDay(int year
, int month
, int day
) 
 978     __block CFAbsoluteTime result 
= 0.0; 
 979     SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) { 
 980         result 
= CFAbsoluteTimeForCalendarDay(zuluCalendar
, year
, month
, day
); 
 988 // MARK: CFDate Helpers 
 991 static inline CFDateRef 
CFDateCreateForGregorianMoment(CFAllocatorRef allocator
, CFTimeZoneRef tz
, int year
, int month
, int day
, int hour
, int minute
, int second
) 
 993     return CFDateCreate(allocator
, CFAbsoluteTimeForGregorianMoment(tz
, year
, month
, day
, hour
, minute
, second
)); 
 996 static inline CFDateRef 
CFDateCreateForGregorianDay(CFAllocatorRef allocator
, CFTimeZoneRef tz
, int year
, int month
, int day
, int hour
, int minute
, int second
) 
 998     return CFDateCreate(allocator
, CFAbsoluteTimeForGregorianDay(tz
, year
, month
, day
)); 
1001 static inline CFDateRef 
CFDateCreateForGregorianZuluMoment(CFAllocatorRef allocator
, int year
, int month
, int day
, int hour
, int minute
, int second
) 
1003     return CFDateCreate(allocator
, CFAbsoluteTimeForGregorianZuluMoment(year
, month
, day
, hour
, minute
, second
)); 
1006 static inline CFDateRef 
CFDateCreateForGregorianZuluDay(CFAllocatorRef allocator
, int year
, int month
, int day
) 
1008     return CFDateCreate(allocator
, CFAbsoluteTimeForGregorianZuluDay(year
, month
, day
)); 
1012 // MARK: PropertyList Helpers 
1016 // Crazy reading and writing stuff 
1019 static inline void CFPropertyListWriteToFile(CFPropertyListRef plist
, CFURLRef file
) 
1021     CFWriteStreamRef writeStream 
= CFWriteStreamCreateWithFile(kCFAllocatorDefault
, file
); 
1022     CFErrorRef error 
= NULL
; 
1024     CFWriteStreamOpen(writeStream
); 
1025     CFPropertyListWrite(plist
, writeStream
, kCFPropertyListBinaryFormat_v1_0
, 0, &error
); 
1027         secerror("Can't write plist: %@", error
); 
1029     CFReleaseNull(error
); 
1030     CFReleaseNull(writeStream
); 
1033 static inline CF_RETURNS_RETAINED CFPropertyListRef 
CFPropertyListReadFromFile(CFURLRef file
) 
1035     CFPropertyListRef result 
= NULL
; 
1036     CFErrorRef error 
= NULL
; 
1037     CFBooleanRef isRegularFile
; 
1038     if (!CFURLCopyResourcePropertyForKey(file
, kCFURLIsRegularFileKey
, &isRegularFile
, &error
)) { 
1039         secinfo("plist", "file %@: %@", file
, error
); 
1040     } else if (CFBooleanGetValue(isRegularFile
)) { 
1041         CFReadStreamRef readStream 
= CFReadStreamCreateWithFile(kCFAllocatorDefault
, file
); 
1043             if (CFReadStreamOpen(readStream
)) { 
1044                 CFPropertyListFormat format
; 
1045                 result 
= CFPropertyListCreateWithStream(kCFAllocatorDefault
, readStream
, 0, kCFPropertyListMutableContainers
, &format
, &error
); 
1047                     secerror("read plist from %@: %@", file
, error
); 
1050             CFRelease(readStream
); 
1053     CFReleaseNull(error
); 
1060 #endif /* _SECCFWRAPPERS_H_ */