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