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