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