]> git.saurik.com Git - apple/security.git/blob - OSX/utilities/src/SecCFWrappers.h
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / utilities / src / SecCFWrappers.h
1 /*
2 * Copyright (c) 2011-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 #ifndef _SECCFWRAPPERS_H_
26 #define _SECCFWRAPPERS_H_
27
28 #include <CoreFoundation/CFRuntime.h>
29 #include <CoreFoundation/CoreFoundation.h>
30
31 #include <utilities/SecCFRelease.h>
32 #include <utilities/debugging.h>
33
34 #include <assert.h>
35 #include <dispatch/dispatch.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39
40 #include <corecrypto/ccdigest.h>
41
42 #if __has_feature(objc_arc)
43 #define __SECBRIDGE __bridge
44 #else
45 #define __SECBRIDGE
46 #endif
47
48 //
49 // Convenience routines.
50 //
51
52 //
53 // Macros for the pattern
54 //
55 // typedef struct _privateNewClass* NewClassRef;
56 //
57 // struct _privateNewClass {
58 // CFRuntimeBase _base;
59 // ... class additions
60 // };
61 //
62 // kClassNameRegisterClass
63 // kClassNameTypeID
64 //
65 // ClassNameGetTypeID()
66 //
67 // CFGiblisFor(NewClass);
68 //
69 // .. define NewClassDestroy
70 // .. define NewClassCopyDescription
71 //
72 // .. use CFTypeAllocate(NewClass, _privateNewClass, allocator);
73 //
74 //
75
76 // Call this to create a function that returns a singleton instance of type stype,
77 // which is initialized once by calling doThisOnce, with result in its context. Upon
78 // completion body should assign to *result.
79
80 extern CFStringRef kSecDebugFormatOption;
81
82 extern CFDictionaryRef SecGetDebugDescriptionFormatOptions(void);
83
84
85 #define CFGiblisGetSingleton(returnType, giblisClassName, result, doThisOnce) \
86 returnType giblisClassName(void); \
87 returnType giblisClassName(void) { \
88 static dispatch_once_t s##giblisClassName##Once; \
89 static returnType s##giblisClassName##Singleton; \
90 returnType *result = &s##giblisClassName##Singleton; \
91 dispatch_once(&s##giblisClassName##Once, doThisOnce); \
92 return s##giblisClassName##Singleton; \
93 }
94
95 #define CFGiblisWithFunctions(gibliClassName, init_func, copy_func, finalize_func, equal_func, hash_func, copyFormattingDesc_func, copyDebugDesc_func, reclaim_func, refcount_func, run_once_block) \
96 CFGiblisGetSingleton(CFTypeID, gibliClassName##GetTypeID, typeID, (^{ \
97 void(^_onceBlock)() = (run_once_block); \
98 static const CFRuntimeClass s##gibliClassName##Class = { \
99 .version = (reclaim_func == NULL ? 0 : _kCFRuntimeResourcefulObject) \
100 | (refcount_func == NULL ? 0 : _kCFRuntimeCustomRefCount), \
101 .className = #gibliClassName, \
102 .init = init_func, \
103 .copy = copy_func, \
104 .finalize = finalize_func, \
105 .equal = equal_func, \
106 .hash = hash_func, \
107 .copyFormattingDesc = copyFormattingDesc_func, \
108 .copyDebugDesc = copyDebugDesc_func, \
109 .reclaim = reclaim_func, \
110 .refcount = refcount_func, \
111 }; \
112 *typeID = _CFRuntimeRegisterClass(&s##gibliClassName##Class); \
113 if (_onceBlock) \
114 _onceBlock(); \
115 }))
116
117 #define CFGiblisWithHashFor(gibliClassName) \
118 static CFStringRef gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
119 static void gibliClassName##Destroy(CFTypeRef cf); \
120 static Boolean gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
121 static CFHashCode gibliClassName##Hash(CFTypeRef cf); \
122 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
123 return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
124 }\
125 \
126 CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, gibliClassName##Hash, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
127
128 #define CFGiblisWithCompareFor(gibliClassName) \
129 static CFStringRef gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
130 static void gibliClassName##Destroy(CFTypeRef cf); \
131 static Boolean gibliClassName##Compare(CFTypeRef lhs, CFTypeRef rhs); \
132 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
133 return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
134 }\
135 \
136 CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, gibliClassName##Compare, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
137
138
139 #define CFGiblisFor(gibliClassName) \
140 static CFStringRef gibliClassName##CopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions); \
141 static void gibliClassName##Destroy(CFTypeRef cf); \
142 static CFStringRef gibliClassName##CopyDescription(CFTypeRef cf){\
143 return gibliClassName##CopyFormatDescription(cf, SecGetDebugDescriptionFormatOptions());\
144 }\
145 \
146 CFGiblisWithFunctions(gibliClassName, NULL, NULL, gibliClassName##Destroy, NULL, NULL, gibliClassName##CopyFormatDescription, gibliClassName##CopyDescription, NULL, NULL, NULL)
147
148 #define CFTypeAllocateWithSpace(classType, space, allocator) \
149 (classType##Ref) _CFRuntimeCreateInstance(allocator, classType##GetTypeID(), space, NULL)
150
151 #define CFTypeAllocate(classType, internalType, allocator) \
152 CFTypeAllocateWithSpace(classType, sizeof(internalType) - sizeof(CFRuntimeBase), allocator)
153
154 #define SECWRAPPER_SENTINEL __attribute__((__sentinel__))
155
156 __BEGIN_DECLS
157
158 void withStringOfAbsoluteTime(CFAbsoluteTime at, void (^action)(CFStringRef decription));
159
160
161 //
162 // MARK: Call block function
163 //
164
165
166 static void apply_block_1(const void *value, void *context)
167 {
168 ((__SECBRIDGE void (^)(const void *value))context)(value);
169 }
170
171 static void apply_block_2(const void *key, const void *value, void *context)
172 {
173 ((__SECBRIDGE void (^)(const void *key, const void *value))context)(key, value);
174 }
175
176 //
177 // MARK: Type checking
178 //
179
180 static inline bool isArray(CFTypeRef cfType) {
181 return cfType && CFGetTypeID(cfType) == CFArrayGetTypeID();
182 }
183
184 static inline bool isSet(CFTypeRef cfType) {
185 return cfType && CFGetTypeID(cfType) == CFSetGetTypeID();
186 }
187
188 static inline bool isData(CFTypeRef cfType) {
189 return cfType && CFGetTypeID(cfType) == CFDataGetTypeID();
190 }
191
192 static inline bool isDate(CFTypeRef cfType) {
193 return cfType && CFGetTypeID(cfType) == CFDateGetTypeID();
194 }
195
196 static inline bool isDictionary(CFTypeRef cfType) {
197 return cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID();
198 }
199
200 static inline bool isNumber(CFTypeRef cfType) {
201 return cfType && CFGetTypeID(cfType) == CFNumberGetTypeID();
202 }
203
204 static inline bool isNumberOfType(CFTypeRef cfType, CFNumberType number) {
205 return isNumber(cfType) && CFNumberGetType((CFNumberRef)cfType) == number;
206 }
207
208 static inline bool isString(CFTypeRef cfType) {
209 return cfType && CFGetTypeID(cfType) == CFStringGetTypeID();
210 }
211
212 static inline bool isBoolean(CFTypeRef cfType) {
213 return cfType && CFGetTypeID(cfType) == CFBooleanGetTypeID();
214 }
215
216 static inline bool isNull(CFTypeRef cfType) {
217 return cfType && CFGetTypeID(cfType) == CFNullGetTypeID();
218 }
219
220 //
221 // MARK CFEqual Helpers
222 //
223
224 static inline bool CFEqualSafe(CFTypeRef left, CFTypeRef right)
225 {
226 if (left == NULL || right == NULL)
227 return left == right;
228 else
229 return CFEqual(left, right);
230 }
231
232
233 //
234 // MARK: Printing
235 //
236
237 static void fprint_string(FILE *file, CFStringRef string) {
238 UInt8 buf[256];
239 CFRange range = { .location = 0 };
240 range.length = CFStringGetLength(string);
241 while (range.length > 0) {
242 CFIndex bytesUsed = 0;
243 CFIndex converted = CFStringGetBytes(string, range, kCFStringEncodingUTF8, 0, false, buf, sizeof(buf), &bytesUsed);
244 fwrite(buf, 1, bytesUsed, file);
245 range.length -= converted;
246 range.location += converted;
247 }
248 }
249
250 static inline void cffprint_v(FILE *file, CFStringRef fmt, va_list args) {
251 CFStringRef line = CFStringCreateWithFormatAndArguments(NULL, NULL, fmt, args);
252 fprint_string(file, line);
253 CFRelease(line);
254 }
255
256 static inline void cffprint_c_v(FILE *file, const char *fmt, va_list args) {
257 CFStringRef cffmt = CFStringCreateWithCString(kCFAllocatorDefault, fmt, kCFStringEncodingUTF8);
258 cffprint_v(file, cffmt, args);
259 CFRelease(cffmt);
260 }
261
262 static void cffprint(FILE *file, CFStringRef fmt, ...) CF_FORMAT_FUNCTION(2,0);
263 static inline void cffprint(FILE *file, CFStringRef fmt, ...) {
264 va_list args;
265 va_start(args, fmt);
266 cffprint_v(file, fmt, args);
267 va_end(args);
268 }
269
270 //
271 // MARK: CFError Helpers
272 //
273
274 /* Return false if possibleError is set. Propagates possibleError into *error
275 if *error is NULL, otherwise releases possibleError. */
276 static inline
277 bool CFErrorPropagate(CFErrorRef possibleError CF_CONSUMED, CFErrorRef *error) {
278 if (possibleError) {
279 if (error && !*error) {
280 *error = possibleError;
281 } else {
282 CFRelease(possibleError);
283 }
284 return false;
285 }
286 return true;
287 }
288
289 //
290 // MARK: CFNumber Helpers
291 //
292
293 static inline CFNumberRef CFNumberCreateWithCFIndex(CFAllocatorRef allocator, CFIndex value)
294 {
295 return CFNumberCreate(allocator, kCFNumberCFIndexType, &value);
296 }
297
298 //
299 // MARK: CFData Helpers
300 //
301
302 static inline CFMutableDataRef CFDataCreateMutableWithScratch(CFAllocatorRef allocator, CFIndex size) {
303 CFMutableDataRef result = CFDataCreateMutable(allocator, 0);
304 CFDataSetLength(result, size);
305
306 return result;
307 }
308
309 static inline void CFDataAppend(CFMutableDataRef appendTo, CFDataRef dataToAppend)
310 {
311 CFDataAppendBytes(appendTo, CFDataGetBytePtr(dataToAppend), CFDataGetLength(dataToAppend));
312 }
313
314 static inline CFDataRef CFDataCreateReferenceFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
315 {
316 return CFDataCreateWithBytesNoCopy(allocator,
317 CFDataGetBytePtr(sourceData) + range.location, range.length,
318 kCFAllocatorNull);
319 }
320
321 static inline CFDataRef CFDataCreateCopyFromRange(CFAllocatorRef allocator, CFDataRef sourceData, CFRange range)
322 {
323 return CFDataCreate(allocator, CFDataGetBytePtr(sourceData) + range.location, range.length);
324 }
325
326 CFDataRef CFDataCreateWithRandomBytes(size_t len);
327
328 CFDataRef CFDataCreateWithInitializer(CFAllocatorRef allocator, CFIndex size, bool (^operation)(size_t size, uint8_t *buffer));
329
330 static inline uint8_t* CFDataIncreaseLengthAndGetMutableBytes(CFMutableDataRef data, CFIndex extraLength)
331 {
332 CFIndex startOffset = CFDataGetLength(data);
333
334 CFDataIncreaseLength(data, extraLength);
335
336 return CFDataGetMutableBytePtr(data) + startOffset;
337 }
338
339 static inline uint8_t* CFDataGetMutablePastEndPtr(CFMutableDataRef theData)
340 {
341 return CFDataGetMutableBytePtr(theData) + CFDataGetLength(theData);
342 }
343
344 static inline const uint8_t* CFDataGetPastEndPtr(CFDataRef theData) {
345 return CFDataGetBytePtr(theData) + CFDataGetLength(theData);
346 }
347
348 static inline CFComparisonResult CFDataCompare(CFDataRef left, CFDataRef right)
349 {
350 const size_t left_size = CFDataGetLength(left);
351 const size_t right_size = CFDataGetLength(right);
352 const size_t shortest = (left_size <= right_size) ? left_size : right_size;
353
354 int comparison = memcmp(CFDataGetBytePtr(left), CFDataGetBytePtr(right), shortest);
355
356 if (comparison > 0 || (comparison == 0 && left_size > right_size))
357 return kCFCompareGreaterThan;
358 else if (comparison < 0 || (comparison == 0 && left_size < right_size))
359 return kCFCompareLessThan;
360 else
361 return kCFCompareEqualTo;
362 }
363
364 static inline CFDataRef CFDataCreateWithHash(CFAllocatorRef allocator, const struct ccdigest_info *di, const uint8_t *buffer, const uint8_t length) {
365 CFMutableDataRef result = CFDataCreateMutableWithScratch(allocator, di->output_size);
366
367 ccdigest(di, length, buffer, CFDataGetMutableBytePtr(result));
368
369 return result;
370 }
371
372
373 static inline CFDataRef CFDataCreateCopyFromPositions(CFAllocatorRef allocator, CFDataRef source, CFIndex start, CFIndex end)
374 {
375 return CFDataCreateCopyFromRange(allocator, source, CFRangeMake(start, end - start));
376 }
377
378 static inline int nibletToByte(char niblet) {
379 if(niblet >= '0' && niblet <= '9') return niblet - '0';
380 if(niblet >= 'a' && niblet <= 'f') return niblet - 'a' + 10;
381 if(niblet >= 'A' && niblet <= 'F') return niblet - 'A' + 10;
382 return 0;
383 }
384
385 static inline CFDataRef CFDataCreateFromHexString(CFAllocatorRef allocator, CFStringRef sourceHex) {
386 CFIndex sourceLen = CFStringGetLength(sourceHex);
387 if((sourceLen % 2) != 0) return NULL;
388 const char *src = CFStringGetCStringPtr(sourceHex, kCFStringEncodingUTF8);
389 UInt8 bytes[sourceLen/2];
390 for(int i = 0; i < sourceLen; i+=2) {
391 bytes[i/2] = (UInt8) (nibletToByte(src[i]) * 16 + nibletToByte(src[i+1]));
392 }
393 return CFDataCreate(allocator, bytes, sourceLen/2);
394 }
395
396
397 //
398 // MARK: CFString Helpers
399 //
400
401 CFComparisonResult CFStringCompareSafe(const void *val1, const void *val2, void *context);
402
403 //
404 // Turn a CFString into an allocated UTF8-encoded C string.
405 //
406 static inline char *CFStringToCString(CFStringRef inStr)
407 {
408 if (!inStr)
409 return (char *)strdup("");
410 CFRetain(inStr); // compensate for release on exit
411
412 // need to extract into buffer
413 CFIndex length = CFStringGetLength(inStr); // in 16-bit character units
414 size_t len = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
415 char *buffer = (char *)malloc(len); // pessimistic
416 if (!CFStringGetCString(inStr, buffer, len, kCFStringEncodingUTF8))
417 buffer[0] = 0;
418
419 CFRelease(inStr);
420 return buffer;
421 }
422
423 // runs operation with inStr as a zero terminated C string
424 // in utf8 encoding passed to the operation block.
425 void CFStringPerformWithCString(CFStringRef inStr, void(^operation)(const char *utf8Str));
426
427 // runs operation with inStr as a zero terminated C string
428 // in utf8 passed to the operation block, the length of
429 // the string is also provided to the block.
430 void CFStringPerformWithCStringAndLength(CFStringRef inStr, void(^operation)(const char *utf8Str, size_t utf8Length));
431
432 void CFStringPerformWithUTF8CFData(CFStringRef inStr, void (^operation)(CFDataRef stringAsData));
433
434 #include <CommonNumerics/CommonCRC.h>
435
436 static inline void CFStringAppendEncryptedData(CFMutableStringRef s, CFDataRef edata)
437 {
438 const uint8_t *bytes = CFDataGetBytePtr(edata);
439 CFIndex len = CFDataGetLength(edata);
440 CFStringAppendFormat(s, 0, CFSTR("%04lx:"), len);
441 if(len<=8) {
442 for (CFIndex ix = 0; ix < len; ++ix) {
443 CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
444 }
445 } else {
446 uint64_t crc = 0;
447 CNCRC(kCN_CRC_64_ECMA_182, bytes+8, len-8, &crc);
448 for (CFIndex ix = 0; ix < 8; ++ix) {
449 CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
450 }
451 CFStringAppendFormat(s, 0, CFSTR("...|%08llx"), crc);
452 }
453 }
454
455 static inline void CFStringAppendHexData(CFMutableStringRef s, CFDataRef data) {
456 const uint8_t *bytes = CFDataGetBytePtr(data);
457 CFIndex len = CFDataGetLength(data);
458 for (CFIndex ix = 0; ix < len; ++ix) {
459 CFStringAppendFormat(s, 0, CFSTR("%02X"), bytes[ix]);
460 }
461 }
462
463 static inline CF_RETURNS_RETAINED CFStringRef CFDataCopyHexString(CFDataRef data) {
464 CFMutableStringRef hexString = CFStringCreateMutable(kCFAllocatorDefault, 2 * CFDataGetLength(data));
465 CFStringAppendHexData(hexString, data);
466 return hexString;
467 }
468
469 static inline void CFDataPerformWithHexString(CFDataRef data, void (^operation)(CFStringRef dataString)) {
470 CFStringRef hexString = data ? CFDataCopyHexString(data) : CFSTR("(null)");
471 operation(hexString);
472 CFRelease(hexString);
473 }
474
475 static inline void BufferPerformWithHexString(const UInt8 *bytes, CFIndex length, void (^operation)(CFStringRef dataString)) {
476 CFDataRef bufferAsData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorNull);
477
478 CFDataPerformWithHexString(bufferAsData, operation);
479
480 CFReleaseNull(bufferAsData);
481 }
482
483
484
485 static inline void CFStringWriteToFile(CFStringRef inStr, FILE* file)
486 {
487 CFStringPerformWithCStringAndLength(inStr, ^(const char *utf8Str, size_t utf8Length) {
488 fwrite(utf8Str, 1, utf8Length, file);
489 });
490 }
491
492 static inline void CFStringWriteToFileWithNewline(CFStringRef inStr, FILE* file)
493 {
494 CFStringWriteToFile(inStr, file);
495 fputc('\n', file);
496 }
497
498 static inline CFStringRef CFStringCreateTruncatedCopy(CFStringRef s, CFIndex len) {
499 if(!s) return NULL;
500 if(len >= CFStringGetLength(s)) return CFStringCreateCopy(kCFAllocatorDefault, s);
501 return CFStringCreateWithSubstring(kCFAllocatorDefault, s, CFRangeMake(0, len));
502 }
503
504 //
505 // MARK: CFCollectionHelpers
506 //
507
508 static inline
509 const void *SecCFRetainForCollection(CFAllocatorRef allocator, const void *value)
510 {
511 return CFRetain(value);
512 }
513
514 static inline
515 void SecCFReleaseForCollection(CFAllocatorRef allocator, const void *value)
516 {
517 CFRelease(value);
518 }
519
520 //
521 // MARK: CFArray Helpers
522 //
523
524 static inline CFIndex CFArrayRemoveAllValue(CFMutableArrayRef array, const void* value)
525 {
526 CFIndex position = kCFNotFound;
527 CFIndex numberRemoved = 0;
528
529 position = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value);
530 while (position != kCFNotFound) {
531 CFArrayRemoveValueAtIndex(array, position);
532 ++numberRemoved;
533 position = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), value);
534 }
535
536 return numberRemoved;
537 }
538
539 static inline void CFArrayAppendAll(CFMutableArrayRef array, CFArrayRef arrayToAppend) {
540 CFArrayAppendArray(array, arrayToAppend, CFRangeMake(0, CFArrayGetCount(arrayToAppend)));
541 }
542
543 #define CFArrayForEachC(array, value) for (CFIndex _aCount = CFArrayGetCount(array), _aIX = 0;value = (__typeof__(value))(_aIX < _aCount ? CFArrayGetValueAtIndex(array, _aIX) : 0), _aIX < _aCount; ++_aIX)
544
545 static inline void CFArrayForEach(CFArrayRef array, void (^operation)(const void *value)) {
546 CFArrayApplyFunction(array, CFRangeMake(0, CFArrayGetCount(array)), apply_block_1, (__SECBRIDGE void *)operation);
547 }
548
549 static inline void CFArrayForEachReverse(CFArrayRef array, void (^operation)(const void *value)) {
550 for(CFIndex count = CFArrayGetCount(array); count > 0; --count) {
551 operation(CFArrayGetValueAtIndex(array, count - 1));
552 }
553 }
554
555 static inline const void *CFArrayGetValueMatching(CFArrayRef array, bool (^match)(const void *value)) {
556 CFIndex i, n = CFArrayGetCount(array);
557 for (i = 0; i < n; ++i) {
558 const void *value = CFArrayGetValueAtIndex(array, i);
559 if (match(value)) {
560 return value;
561 }
562 }
563 return NULL;
564 }
565
566 static inline bool CFArrayHasValueMatching(CFArrayRef array, bool (^match)(const void *value)) {
567 return CFArrayGetValueMatching(array, match) != NULL;
568 }
569
570 static inline void CFMutableArrayModifyValues(CFMutableArrayRef array, const void * (^process)(const void *value)) {
571 CFIndex i, n = CFArrayGetCount(array);
572 for (i = 0; i < n; ++i) {
573 const void *value = CFArrayGetValueAtIndex(array, i);
574 CFArraySetValueAtIndex(array, i, process(value));
575 }
576 }
577
578 static inline void CFArraySubtract(CFMutableArrayRef from, CFArrayRef remove) {
579 if (remove && from) {
580 CFArrayForEach(remove, ^(const void *value) {
581 CFArrayRemoveAllValue(from, value);
582 });
583 }
584 }
585
586 static inline CFMutableArrayRef CFArrayCreateDifference(CFAllocatorRef alloc, CFArrayRef set, CFArrayRef remove) {
587 CFMutableArrayRef result;
588 if (!set) {
589 result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks);
590 } else {
591 result = CFArrayCreateMutableCopy(alloc, 0, set);
592 if (remove)
593 CFArraySubtract(result, remove);
594 }
595
596 return result;
597 }
598
599 //
600 // MARK: CFArray creation Var args helper functions.
601 //
602 static inline CFArrayRef CFArrayCreateCountedForVC(CFAllocatorRef allocator, const CFArrayCallBacks *cbs, CFIndex entries, va_list args)
603 {
604 const void *values[entries ? entries : 1];
605 for (CFIndex currentValue = 0; currentValue < entries; ++currentValue)
606 {
607 values[currentValue] = va_arg(args, void*);
608
609 if (values[currentValue] == NULL)
610 values[currentValue] = kCFNull;
611 }
612
613 return CFArrayCreate(allocator, values, entries, cbs);
614 }
615
616 static inline CFArrayRef CFArrayCreateForVC(CFAllocatorRef allocator, const CFArrayCallBacks *cbs, va_list args)
617 {
618 va_list count;
619 va_copy(count, args);
620
621 CFIndex entries = 0;
622 while (NULL != va_arg(count, void*)) {
623 entries += 1;
624 }
625
626 return CFArrayCreateCountedForVC(allocator, cbs, entries, args);
627
628 }
629
630
631
632 //
633 // MARK: CFArray of CFTypes support
634 //
635
636 static inline CFMutableArrayRef CFArrayCreateMutableForCFTypesWithCapacity(CFAllocatorRef allocator, CFIndex capacity)
637 {
638 return CFArrayCreateMutable(allocator, capacity, &kCFTypeArrayCallBacks);
639 }
640
641
642 static inline CFMutableArrayRef CFArrayCreateMutableForCFTypes(CFAllocatorRef allocator)
643 {
644 return CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
645 }
646
647 static inline CFArrayRef SECWRAPPER_SENTINEL CFArrayCreateForCFTypes(CFAllocatorRef allocator, ...)
648 {
649 va_list args;
650 va_start(args, allocator);
651
652 return CFArrayCreateForVC(allocator, &kCFTypeArrayCallBacks, args);
653
654 }
655
656 static inline CFArrayRef CFArrayCreateCountedForCFTypes(CFAllocatorRef allocator, CFIndex entries, ...)
657 {
658 va_list args;
659 va_start(args, entries);
660
661 return CFArrayCreateCountedForVC(allocator, &kCFTypeArrayCallBacks, entries, args);
662 }
663
664 static inline CFArrayRef CFArrayCreateCountedForCFTypesV(CFAllocatorRef allocator, CFIndex entries, va_list args)
665 {
666 return CFArrayCreateCountedForVC(allocator, &kCFTypeArrayCallBacks, entries, args);
667 }
668
669 //
670 // MARK: CFDictionary of CFTypes helpers
671 //
672
673 static inline CFDictionaryRef CFDictionaryCreateCountedForCFTypesV(CFAllocatorRef allocator, CFIndex entries, va_list args)
674 {
675 const void *keys[entries];
676 const void *values[entries];
677
678 for(CFIndex currentValue = 0; currentValue < entries; ++currentValue)
679 {
680 keys[currentValue] = va_arg(args, void*);
681 values[currentValue] = va_arg(args, void*);
682
683 if (values[currentValue] == NULL)
684 values[currentValue] = kCFNull;
685 }
686
687 return CFDictionaryCreate(allocator, keys, values, entries,
688 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
689 }
690
691 static inline CFDictionaryRef SECWRAPPER_SENTINEL CFDictionaryCreateForCFTypes(CFAllocatorRef allocator, ...)
692 {
693 va_list args;
694 va_start(args, allocator);
695
696 CFIndex entries = 0;
697 while (NULL != va_arg(args, void*)) {
698 entries += 2;
699 (void) va_arg(args, void*);
700 }
701
702 entries /= 2;
703
704 va_start(args, allocator);
705
706 return CFDictionaryCreateCountedForCFTypesV(allocator, entries, args);
707
708 }
709
710 static inline CFDictionaryRef CFDictionaryCreateCountedForCFTypes(CFAllocatorRef allocator, CFIndex entries, ...)
711 {
712 va_list args;
713 va_start(args, entries);
714
715 return CFDictionaryCreateCountedForCFTypesV(allocator, entries, args);
716 }
717
718 static inline CFMutableDictionaryRef CFDictionaryCreateMutableForCFTypes(CFAllocatorRef allocator)
719 {
720 return CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
721 }
722
723 static inline CFMutableDictionaryRef SECWRAPPER_SENTINEL CFDictionaryCreateMutableForCFTypesWith(CFAllocatorRef allocator, ...)
724 {
725 CFMutableDictionaryRef result = CFDictionaryCreateMutableForCFTypes(allocator);
726
727 va_list args;
728 va_start(args, allocator);
729
730 void* key = va_arg(args, void*);
731
732 while (key != NULL) {
733 CFDictionarySetValue(result, key, va_arg(args, void*));
734 key = va_arg(args, void*);
735 };
736
737 return result;
738 }
739
740 //
741 // MARK: CFSet Helpers
742 //
743
744 static inline CFMutableSetRef CFSetCreateMutableForCFTypes(CFAllocatorRef allocator)
745 {
746 return CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks);
747 }
748
749 static inline bool CFSetIsEmpty(CFSetRef set) {
750 return CFSetGetCount(set) == 0;
751 }
752
753 static inline void CFSetForEach(CFSetRef set, void (^operation)(const void *value)) {
754 CFSetApplyFunction(set, apply_block_1, (__SECBRIDGE void *)operation);
755 }
756
757 static inline void CFSetUnion(CFMutableSetRef set, CFSetRef unionWith) {
758 CFSetForEach(unionWith, ^(const void *value) {
759 CFSetSetValue(set, value);
760 });
761 }
762
763 static inline void CFSetSubtract(CFMutableSetRef set, CFSetRef subtract) {
764 CFSetForEach(subtract, ^(const void *value) {
765 CFSetRemoveValue(set, value);
766 });
767 }
768
769 static inline bool CFSetIsSubset(CFSetRef smaller, CFSetRef bigger) {
770 __block bool isSubset = true;
771 CFSetForEach(smaller, ^(const void *value) {
772 if (!CFSetContainsValue(bigger, value)) {
773 isSubset = false;
774 }
775 });
776
777 return isSubset;
778 }
779
780 static inline void CFSetSetValues(CFMutableSetRef set, CFArrayRef valuesToSet) {
781 CFArrayForEach(valuesToSet, ^(const void *value) {
782 CFSetSetValue(set, value);
783 });
784 }
785
786 static inline CFMutableArrayRef CFSetCopyValues(CFSetRef set) {
787 CFMutableArrayRef values = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
788
789 CFSetForEach(set, ^(const void *value) {
790 CFArrayAppendValue(values, value);
791 });
792
793 return values;
794 }
795
796 static inline bool CFSetIntersectionIsEmpty(CFSetRef set1, CFSetRef set2) {
797 __block bool intersectionIsEmpty = true;
798 CFSetForEach(set1, ^(const void *value) {
799 intersectionIsEmpty &= !CFSetContainsValue(set2, value);
800 });
801 return intersectionIsEmpty;
802 }
803
804 static inline bool CFSetIntersects(CFSetRef set1, CFSetRef set2) {
805 return !CFSetIntersectionIsEmpty(set1, set2);
806 }
807
808 static inline CFMutableSetRef CFSetCreateIntersection(CFAllocatorRef allocator, CFSetRef a, CFSetRef b) {
809 CFMutableSetRef result = CFSetCreateMutableCopy(allocator, 0, a);
810
811 CFSetRemoveAllValues(result);
812 CFSetForEach(a, ^(const void *value) {
813 if (CFSetContainsValue(b, value)) {
814 CFSetAddValue(result, value);
815 }
816 });
817
818 return result;
819 }
820
821 static inline CFSetRef CFSetCreateCopyOfArrayForCFTypes(CFArrayRef array) {
822 CFIndex count = CFArrayGetCount(array);
823 const void **values = (const void **)malloc(sizeof(const void *) * count);
824 CFArrayGetValues(array, CFRangeMake(0, count), values);
825 CFSetRef set = CFSetCreate(CFGetAllocator(array), values, count, &kCFTypeSetCallBacks);
826 free(values);
827 return set;
828 }
829
830 static inline void CFSetTransferObject(CFTypeRef object, CFMutableSetRef from, CFMutableSetRef to) {
831 CFSetAddValue(to, object);
832 CFSetRemoveValue(from, object);
833 }
834
835 //
836 // MARK: CFStringXxx Helpers
837 //
838
839 void CFStringArrayPerfromWithDelimeterWithDescription(CFArrayRef strings, CFStringRef start, CFStringRef end, void (^action)(CFStringRef description));
840 void CFStringArrayPerfromWithDescription(CFArrayRef strings, void (^action)(CFStringRef description));
841 void CFStringSetPerformWithDescription(CFSetRef set, void (^action)(CFStringRef description));
842
843 //
844 // MARK: CFDictionary Helpers
845 //
846
847 static inline void CFDictionaryForEach(CFDictionaryRef dictionary, void (^operation)(const void *key, const void *value)) {
848 CFDictionaryApplyFunction(dictionary, apply_block_2, (__SECBRIDGE void *)operation);
849 }
850
851 CFStringRef CFDictionaryCopyCompactDescription(CFDictionaryRef dictionary);
852 CFStringRef CFDictionaryCopySuperCompactDescription(CFDictionaryRef dictionary);
853
854 //
855 // MARK: CFCalendar helpers
856 //
857
858 void SecCFCalendarDoWithZuluCalendar(void(^action)(CFCalendarRef zuluCalendar));
859
860 //
861 // MARK: CFAbsoluteTime helpers
862 //
863
864 static inline CFAbsoluteTime CFAbsoluteTimeForCalendarMoment(CFCalendarRef cal, int year, int month, int day, int hour, int minute, int second) {
865 CFAbsoluteTime at;
866 CFCalendarComposeAbsoluteTime(cal, &at, "yMdHms", year, month, day, hour, minute, second);
867 return at;
868 }
869
870 static inline CFAbsoluteTime CFAbsoluteTimeForCalendarDay(CFCalendarRef cal, int year, int month, int day) {
871 CFAbsoluteTime at;
872 CFCalendarComposeAbsoluteTime(cal, &at, "yMd", year, month, day);
873 return at;
874 }
875
876 static inline CFAbsoluteTime CFAbsoluteTimeForGregorianMoment(CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
877 {
878 CFCalendarRef cal = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar);
879 CFCalendarSetTimeZone(cal, tz);
880 CFAbsoluteTime at = CFAbsoluteTimeForCalendarMoment(cal, year, month, day, hour, minute, second);
881 CFReleaseSafe(cal);
882 return at;
883 }
884
885 static inline CFAbsoluteTime CFAbsoluteTimeForGregorianDay(CFTimeZoneRef tz, int year, int month, int day)
886 {
887 CFCalendarRef cal = CFCalendarCreateWithIdentifier(NULL, kCFGregorianCalendar);
888 CFCalendarSetTimeZone(cal, tz);
889 CFAbsoluteTime at = CFAbsoluteTimeForCalendarDay(cal, year, month, day);
890 CFReleaseSafe(cal);
891 return at;
892 }
893
894 static inline CFAbsoluteTime CFAbsoluteTimeForGregorianZuluMoment(int year, int month, int day, int hour, int minute, int second)
895 {
896 __block CFAbsoluteTime result = 0.0;
897 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
898 result = CFAbsoluteTimeForCalendarMoment(zuluCalendar, year, month, day, hour, minute, second);
899 });
900 return result;
901 }
902
903
904 static inline CFAbsoluteTime CFAbsoluteTimeForGregorianZuluDay(int year, int month, int day)
905 {
906 __block CFAbsoluteTime result = 0.0;
907 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
908 result = CFAbsoluteTimeForCalendarDay(zuluCalendar, year, month, day);
909 });
910 return result;
911 }
912
913
914
915 //
916 // MARK: CFDate Helpers
917 //
918
919 static inline CFDateRef CFDateCreateForGregorianMoment(CFAllocatorRef allocator, CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
920 {
921 return CFDateCreate(allocator, CFAbsoluteTimeForGregorianMoment(tz, year, month, day, hour, minute, second));
922 }
923
924 static inline CFDateRef CFDateCreateForGregorianDay(CFAllocatorRef allocator, CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
925 {
926 return CFDateCreate(allocator, CFAbsoluteTimeForGregorianDay(tz, year, month, day));
927 }
928
929 static inline CFDateRef CFDateCreateForGregorianZuluMoment(CFAllocatorRef allocator, int year, int month, int day, int hour, int minute, int second)
930 {
931 return CFDateCreate(allocator, CFAbsoluteTimeForGregorianZuluMoment(year, month, day, hour, minute, second));
932 }
933
934 static inline CFDateRef CFDateCreateForGregorianZuluDay(CFAllocatorRef allocator, int year, int month, int day)
935 {
936 return CFDateCreate(allocator, CFAbsoluteTimeForGregorianZuluDay(year, month, day));
937 }
938
939 //
940 // MARK: PropertyList Helpers
941 //
942
943 //
944 // Crazy reading and writing stuff
945 //
946
947 static inline void CFPropertyListWriteToFile(CFPropertyListRef plist, CFURLRef file)
948 {
949 CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, file);
950 CFErrorRef error = NULL;
951
952 CFWriteStreamOpen(writeStream);
953 CFPropertyListWrite(plist, writeStream, kCFPropertyListBinaryFormat_v1_0, 0, &error);
954 if (error)
955 secerror("Can't write plist: %@", error);
956
957 CFReleaseNull(error);
958 CFReleaseNull(writeStream);
959 }
960
961 static inline CF_RETURNS_RETAINED CFPropertyListRef CFPropertyListReadFromFile(CFURLRef file)
962 {
963 CFPropertyListRef result = NULL;
964 CFErrorRef error = NULL;
965 CFBooleanRef isRegularFile;
966 if (!CFURLCopyResourcePropertyForKey(file, kCFURLIsRegularFileKey, &isRegularFile, &error)) {
967 secinfo("plist", "file %@: %@", file, error);
968 } else if (CFBooleanGetValue(isRegularFile)) {
969 CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, file);
970 if (readStream) {
971 if (CFReadStreamOpen(readStream)) {
972 CFPropertyListFormat format;
973 result = CFPropertyListCreateWithStream(kCFAllocatorDefault, readStream, 0, kCFPropertyListMutableContainers, &format, &error);
974 if (!result) {
975 secerror("read plist from %@: %@", file, error);
976 }
977 }
978 CFRelease(readStream);
979 }
980 }
981 CFReleaseNull(error);
982
983 return result;
984 }
985
986 __END_DECLS
987
988 #endif /* _SECCFWRAPPERS_H_ */