1/* 2 * Copyright (c) 2000-2004,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// 26//CoreFoundation related utilities 27// 28#ifndef _H_CFUTILITIES 29#define _H_CFUTILITIES 30 31#include <security_utilities/utilities.h> 32#include <security_utilities/globalizer.h> 33#include <CoreFoundation/CoreFoundation.h> 34#include <algorithm> 35#include <Security/SecBase.h> 36#undef check 37 38 39namespace Security { 40 41 42// 43// Traits of popular CF types 44// 45template <class CFType> struct CFTraits { }; 46 47template <> struct CFTraits<CFTypeRef> { 48 static bool check(CFTypeRef ref) { return true; } 49}; 50 51#define __SEC_CFTYPE(name) \ 52 template <> struct CFTraits<name##Ref> { \ 53 static CFTypeID cfid() { return name##GetTypeID(); } \ 54 static bool check(CFTypeRef ref) { return CFGetTypeID(ref) == cfid(); } \ 55 }; 56 57__SEC_CFTYPE(CFNull) 58__SEC_CFTYPE(CFBoolean) 59__SEC_CFTYPE(CFNumber) 60__SEC_CFTYPE(CFString) 61__SEC_CFTYPE(CFData) 62__SEC_CFTYPE(CFDate) 63__SEC_CFTYPE(CFURL) 64__SEC_CFTYPE(CFBundle) 65__SEC_CFTYPE(CFArray) 66__SEC_CFTYPE(CFDictionary) 67__SEC_CFTYPE(CFSet) 68 69 70// 71// Initialize-only self-releasing CF object handler (lightweight). 72// 73template <class CFType> class CFRef { 74public: 75 CFRef() : mRef(NULL) { } 76 CFRef(CFType ref) : mRef(ref) { } 77 ~CFRef() { this->release(); } 78 CFRef(const CFRef &ref) : mRef(ref) {} 79 template <class _T> CFRef(const CFRef<_T> &ref) : mRef(ref) {} 80 81 CFRef(CFTypeRef ref, OSStatus err) 82 : mRef(CFType(ref)) 83 { 84 if (ref && !CFTraits<CFType>::check(ref)) 85 MacOSError::throwMe(err); 86 } 87 88 CFRef &take(CFType ref) 89 { this->release(); mRef = ref; return *this; } 90 91 CFType yield() 92 { CFType r = mRef; mRef = NULL; return r; } 93 94 CFRef &operator = (CFType ref) 95 { if (ref) CFRetain(ref); return take(ref); } 96 97 CFRef &operator = (const CFRef &ref) 98 { if (ref) CFRetain(ref); return take(ref); } 99 100 // take variant for when newly created CFType is returned 101 // via a ptr-to-CFType argument. 102 CFType *take() 103 { if (mRef) CFRelease(mRef); mRef = NULL; return &mRef; } 104 105 operator CFType () const { return mRef; } 106 operator bool () const { return mRef != NULL; } 107 bool operator ! () const { return mRef == NULL; } 108 109 CFType get() const { return mRef; } 110 111 CFType &aref() 112 { take(NULL); return mRef; } 113 114 CFType retain() const 115 { if (mRef) CFRetain(mRef); return mRef; } 116 117 void release() const 118 { if (mRef) CFRelease(mRef); } 119 120 template <class NewType> 121 bool is() const { return CFTraits<NewType>::check(mRef); } 122 123 template <class OldType> 124 static CFType check(OldType cf, OSStatus err) 125 { 126 if (cf && !CFTraits<CFType>::check(cf)) 127 MacOSError::throwMe(err); 128 return CFType(cf); 129 } 130 131 template <class NewType> 132 NewType as() const { return NewType(mRef); } 133 134 template <class NewType> 135 NewType as(OSStatus err) const { return CFRef<NewType>::check(mRef, err); } 136 137private: 138 CFType mRef; 139}; 140 141 142template <class CFType> class CFCopyRef : public CFRef<CFType> { 143 typedef CFRef<CFType> _Base; 144public: 145 CFCopyRef() { } 146 CFCopyRef(CFType ref) : _Base(ref) { this->retain(); } 147 CFCopyRef(const CFCopyRef &ref) : _Base(ref) { this->retain(); } 148 template <class _T> CFCopyRef(const CFRef<_T> &ref) : _Base(ref) { this->retain(); } 149 CFCopyRef(CFTypeRef ref, OSStatus err) : _Base(ref, err) { this->retain(); } 150 151 CFCopyRef &take(CFType ref) 152 { _Base::take(ref); return *this; } 153 154 CFCopyRef &operator = (CFType ref) 155 { if (ref) CFRetain(ref); return take(ref); } 156 157 CFCopyRef &operator = (const CFCopyRef &ref) 158 { _Base::operator = (ref); return *this; } 159 160 template <class _T> CFCopyRef &operator = (const CFRef<_T> &ref) 161 { _Base::operator = (ref); return *this; } 162}; 163 164 165// 166// A simple function that turns a non-array CFTypeRef into 167// an array of one with that element. This will retain its argument 168// (directly or indirectly). 169// 170inline CFArrayRef cfArrayize(CFTypeRef arrayOrItem) 171{ 172 if (arrayOrItem == NULL) 173 return NULL; // NULL is NULL 174 else if (CFGetTypeID(arrayOrItem) == CFArrayGetTypeID()) { 175 CFRetain(arrayOrItem); 176 return CFArrayRef(arrayOrItem); // already an array 177 } else { 178 return CFArrayCreate(NULL, 179 (const void **)&arrayOrItem, 1, &kCFTypeArrayCallBacks); 180 } 181} 182 183 184// 185// An empty CFArray. 186// Since CFArrays are type-neutral, a single immutable empty array will 187// serve for all uses. So keep it. 188// 189struct CFEmptyArray { 190 operator CFArrayRef () { return mArray; } 191 CFEmptyArray(); 192private: 193 CFArrayRef mArray; 194}; 195 196extern ModuleNexus<CFEmptyArray> cfEmptyArray; 197 198 199// 200// Translate CFStringRef or CFURLRef to (UTF8-encoded) C++ string. 201// If release==true, a CFRelease will be performed on the CFWhatever argument 202// whether the call succeeds or not(!). 203// 204string cfString(CFStringRef str); // extract UTF8 string 205string cfString(CFURLRef url); // path of file: URL (only) 206string cfString(CFBundleRef bundle); // path to bundle root 207 208string cfStringRelease(CFStringRef str CF_CONSUMED); // extract UTF8 string 209string cfStringRelease(CFURLRef url CF_CONSUMED); // path of file: URL (only) 210string cfStringRelease(CFBundleRef bundle CF_CONSUMED); // path to bundle root 211 212 213string cfString(CFTypeRef anything, OSStatus err); // dynamic form; throws err on NULL 214 215 216// 217// Handle CFNumberRefs. 218// This is nasty because CFNumber does not support unsigned types, and there's really no portably-safe 219// way of working around this. So the handling of unsigned numbers is "almost correct." 220// 221template <class Number> 222struct CFNumberTraits; 223 224template <> struct CFNumberTraits<char> { 225 static const CFNumberType cfnType = kCFNumberCharType; 226 typedef char ValueType; 227}; 228template <> struct CFNumberTraits<short> { 229 static const CFNumberType cfnType = kCFNumberShortType; 230 typedef short ValueType; 231}; 232template <> struct CFNumberTraits<int> { 233 static const CFNumberType cfnType = kCFNumberIntType; 234 typedef int ValueType; 235}; 236template <> struct CFNumberTraits<long> { 237 static const CFNumberType cfnType = kCFNumberLongType; 238 typedef long ValueType; 239}; 240template <> struct CFNumberTraits<long long> { 241 static const CFNumberType cfnType = kCFNumberLongLongType; 242 typedef long long ValueType; 243}; 244template <> struct CFNumberTraits<float> { 245 static const CFNumberType cfnType = kCFNumberFloatType; 246 typedef float ValueType; 247}; 248template <> struct CFNumberTraits<double> { 249 static const CFNumberType cfnType = kCFNumberDoubleType; 250 typedef double ValueType; 251}; 252 253template <> struct CFNumberTraits<unsigned char> { 254 static const CFNumberType cfnType = kCFNumberIntType; 255 typedef int ValueType; 256}; 257template <> struct CFNumberTraits<unsigned short> { 258 static const CFNumberType cfnType = kCFNumberIntType; 259 typedef int ValueType; 260}; 261template <> struct CFNumberTraits<unsigned int> { 262 static const CFNumberType cfnType = kCFNumberLongLongType; 263 typedef long long ValueType; 264}; 265template <> struct CFNumberTraits<unsigned long> { 266 static const CFNumberType cfnType = kCFNumberLongLongType; 267 typedef long long ValueType; 268}; 269template <> struct CFNumberTraits<unsigned long long> { 270 static const CFNumberType cfnType = kCFNumberLongLongType; 271 typedef long long ValueType; 272}; 273 274template <class Number> 275Number cfNumber(CFNumberRef number) 276{ 277 typename CFNumberTraits<Number>::ValueType value; 278 if (CFNumberGetValue(number, CFNumberTraits<Number>::cfnType, &value)) 279 return (Number)value; 280 else 281 CFError::throwMe(); 282} 283 284template <class Number> 285Number cfNumber(CFNumberRef number, Number defaultValue) 286{ 287 typename CFNumberTraits<Number>::ValueType value; 288 if (CFNumberGetValue(number, CFNumberTraits<Number>::cfnType, &value)) 289 return value; 290 else 291 return defaultValue; 292} 293 294template <class Number> 295CFNumberRef makeCFNumber(Number value) 296{ 297 typename CFNumberTraits<Number>::ValueType cfValue = value; 298 return CFNumberCreate(NULL, CFNumberTraits<Number>::cfnType, &cfValue); 299} 300 301// legacy form 302inline uint32_t cfNumber(CFNumberRef number) { return cfNumber<uint32_t>(number); } 303 304 305// 306// Translate strings into CFStrings 307// 308inline CFStringRef makeCFString(const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8) 309{ 310 return s ? CFStringCreateWithCString(NULL, s, encoding) : NULL; 311} 312 313inline CFStringRef makeCFString(const string &s, CFStringEncoding encoding = kCFStringEncodingUTF8) 314{ 315 return CFStringCreateWithCString(NULL, s.c_str(), encoding); 316} 317 318inline CFStringRef makeCFString(CFDataRef data, CFStringEncoding encoding = kCFStringEncodingUTF8) 319{ 320 return CFStringCreateFromExternalRepresentation(NULL, data, encoding); 321} 322 323 324// 325// Create CFURL objects from various sources 326// 327CFURLRef makeCFURL(const char *s, bool isDirectory = false, CFURLRef base = NULL); 328CFURLRef makeCFURL(CFStringRef s, bool isDirectory = false, CFURLRef base = NULL); 329 330inline CFURLRef makeCFURL(const string &s, bool isDirectory = false, CFURLRef base = NULL) 331{ 332 return makeCFURL(s.c_str(), isDirectory, base); 333} 334 335 336// 337// Make temporary CF objects. 338// 339class CFTempString : public CFRef<CFStringRef> { 340public: 341 template <class Source> 342 CFTempString(Source s) : CFRef<CFStringRef>(makeCFString(s)) { } 343}; 344 345class CFTempURL : public CFRef<CFURLRef> { 346public: 347 template <class Source> 348 CFTempURL(Source s, bool isDirectory = false, CFURLRef base = NULL) 349 : CFRef<CFURLRef>(makeCFURL(s, isDirectory, base)) { } 350}; 351 352 353// 354// A temporary CFNumber 355// 356class CFTempNumber : public CFRef<CFNumberRef> { 357public: 358 template <class Value> 359 CFTempNumber(Value value) : CFRef<CFNumberRef>(makeCFNumber(value)) { } 360}; 361 362 363// 364// A temporary CFData. 365// 366class CFTempData : public CFRef<CFDataRef> { 367public: 368 CFTempData(const void *data, size_t length) 369 : CFRef<CFDataRef>(CFDataCreate(NULL, (const UInt8 *)data, length)) { } 370 371 template <class Dataoid> 372 CFTempData(const Dataoid &dataoid) 373 : CFRef<CFDataRef>(CFDataCreate(NULL, (const UInt8 *)dataoid.data(), dataoid.length())) { } 374}; 375 376class CFTempDataWrap : public CFRef<CFDataRef> { 377public: 378 CFTempDataWrap(const void *data, size_t length) 379 : CFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)data, length, kCFAllocatorNull)) { } 380 381 template <class Dataoid> 382 CFTempDataWrap(const Dataoid &dataoid) 383 : CFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)dataoid.data(), dataoid.length(), kCFAllocatorNull)) { } 384}; 385 386 387// 388// Create CFData objects from various sources. 389// 390inline CFDataRef makeCFData(const void *data, size_t size) 391{ 392 return CFDataCreate(NULL, (const UInt8 *)data, size); 393} 394 395inline CFDataRef makeCFData(CFDictionaryRef dictionary) 396{ 397 return CFPropertyListCreateXMLData(NULL, dictionary); 398} 399 400template <class Data> 401inline CFDataRef makeCFData(const Data &source) 402{ 403 return CFDataCreate(NULL, reinterpret_cast<const UInt8 *>(source.data()), source.length()); 404} 405 406inline CFDataRef makeCFDataMalloc(const void *data, size_t size) 407{ 408 return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)data, size, kCFAllocatorMalloc); 409} 410 411template <class Data> 412inline CFDataRef makeCFDataMalloc(const Data &source) 413{ 414 return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)source.data(), source.length(), kCFAllocatorMalloc); 415} 416 417 418// 419// Create a CFDataRef from malloc'ed data, exception-safely 420// 421class CFMallocData { 422public: 423 CFMallocData(size_t size) 424 : mData(::malloc(size)), mSize(size) 425 { 426 if (!mData) 427 UnixError::throwMe(); 428 } 429 430 ~CFMallocData() 431 { 432 if (mData) 433 ::free(mData); 434 } 435 436 template <class T> 437 operator T * () 438 { return static_cast<T *>(mData); } 439 440 operator CFDataRef (); 441 442 void *data() { return mData; } 443 const void *data() const { return mData; } 444 size_t length() const { return mSize; } 445 446private: 447 void *mData; 448 size_t mSize; 449}; 450 451 452// 453// Make CFDictionaries from stuff 454// 455CFDictionaryRef makeCFDictionary(unsigned count, ...); // key/value pairs 456CFMutableDictionaryRef makeCFMutableDictionary(); // empty 457CFMutableDictionaryRef makeCFMutableDictionary(unsigned count, ...); // (count) key/value pairs 458CFMutableDictionaryRef makeCFMutableDictionary(CFDictionaryRef dict); // copy of dictionary 459 460CFDictionaryRef makeCFDictionaryFrom(CFDataRef data) CF_RETURNS_RETAINED;// interpret plist form 461CFDictionaryRef makeCFDictionaryFrom(const void *data, size_t length) CF_RETURNS_RETAINED; // ditto 462 463 464// 465// Parsing out a CFDictionary without losing your lunch 466// 467class CFDictionary : public CFCopyRef<CFDictionaryRef> { 468 typedef CFCopyRef<CFDictionaryRef> _Base; 469public: 470 CFDictionary(CFDictionaryRef ref, OSStatus error) : _Base(ref), mDefaultError(error) 471 { if (!ref) MacOSError::throwMe(error); } 472 CFDictionary(CFTypeRef ref, OSStatus error) : _Base(ref, error), mDefaultError(error) 473 { if (!ref) MacOSError::throwMe(error); } 474 CFDictionary(OSStatus error) : _Base(NULL), mDefaultError(error) { } 475 476 using CFCopyRef<CFDictionaryRef>::get; 477 478 CFTypeRef get(CFStringRef key) { return CFDictionaryGetValue(*this, key); } 479 CFTypeRef get(const char *key) { return CFDictionaryGetValue(*this, CFTempString(key)); } 480 481 template <class CFType> 482 CFType get(CFStringRef key, OSStatus err = errSecSuccess) const 483 { 484 CFTypeRef elem = CFDictionaryGetValue(*this, key); 485 return CFRef<CFType>::check(elem, err ? err : mDefaultError); 486 } 487 488 template <class CFType> 489 CFType get(const char *key, OSStatus err = errSecSuccess) const 490 { return get<CFType>(CFTempString(key), err); } 491 492 void apply(CFDictionaryApplierFunction func, void *context) 493 { return CFDictionaryApplyFunction(*this, func, context); } 494 495private: 496 template <class T> 497 struct Applier { 498 T *object; 499 void (T::*func)(CFTypeRef key, CFTypeRef value); 500 static void apply(CFTypeRef key, CFTypeRef value, void *context) 501 { Applier *me = (Applier *)context; return ((me->object)->*(me->func))(key, value); } 502 }; 503 504 template <class Key, class Value> 505 struct BlockApplier { 506 void (^action)(Key key, Value value); 507 static void apply(CFTypeRef key, CFTypeRef value, void* context) 508 { BlockApplier *me = (BlockApplier *)context; return me->action(Key(key), Value(value)); } 509 }; 510 511public: 512 template <class T> 513 void apply(T *object, void (T::*func)(CFTypeRef key, CFTypeRef value)) 514 { Applier<T> app; app.object = object; app.func = func; return apply(app.apply, &app); } 515 516 template <class Key = CFTypeRef, class Value = CFTypeRef> 517 void apply(void (^action)(Key key, Value value)) 518 { BlockApplier<Key, Value> app; app.action = action; return apply(app.apply, &app); } 519 520private: 521 OSStatus mDefaultError; 522}; 523 524 525// 526// CFURLAccess wrappers for specific purposes 527// 528CFDataRef cfLoadFile(CFURLRef url); 529CFDataRef cfLoadFile(int fd, size_t bytes); 530inline CFDataRef cfLoadFile(CFStringRef path) { return cfLoadFile(CFTempURL(path)); } 531inline CFDataRef cfLoadFile(const std::string &path) { return cfLoadFile(CFTempURL(path)); } 532inline CFDataRef cfLoadFile(const char *path) { return cfLoadFile(CFTempURL(path)); } 533 534 535// 536// Internally used STL adapters. Should probably be in utilities.h. 537// 538template <class Self> 539Self projectPair(const Self &me) 540{ return me; } 541 542template <class First, class Second> 543Second projectPair(const pair<First, Second> &me) 544{ return me.second; } 545 546 547// 548// A CFToVector turns a CFArrayRef of items into a flat 549// C vector of some type, using a conversion function 550// (from CFTypeRef) specified. As a special bonus, if 551// you provide a CFTypeRef (other than CFArrayRef), it 552// will be transparently handled as an array-of-one. 553// The array will be automatically released on destruction 554// of the CFToVector object. Any internal structure shared 555// with the CFTypeRef inputs will be left alone. 556// 557template <class VectorBase, class CFRefType, VectorBase convert(CFRefType)> 558class CFToVector { 559public: 560 CFToVector(CFArrayRef arrayRef); 561 ~CFToVector() { delete[] mVector; } 562 operator UInt32 () const { return mCount; } 563 operator VectorBase *() const { return mVector; } 564 bool empty() const { return mCount == 0; } 565 566 VectorBase *begin() const { return mVector; } 567 VectorBase *end() const { return mVector + mCount; } 568 569 VectorBase &operator [] (UInt32 ix) const { assert(ix < mCount); return mVector[ix]; } 570 571private: 572 VectorBase *mVector; 573 UInt32 mCount; 574}; 575 576template <class VectorBase, class CFRefType, VectorBase convert(CFRefType)> 577CFToVector<VectorBase, CFRefType, convert>::CFToVector(CFArrayRef arrayRef) 578{ 579 if (arrayRef == NULL) { 580 mCount = 0; 581 mVector = NULL; 582 } else { 583 mCount = (UInt32)CFArrayGetCount(arrayRef); 584 mVector = new VectorBase[mCount]; 585 for (UInt32 n = 0; n < mCount; n++) 586 mVector[n] = convert(CFRefType(CFArrayGetValueAtIndex(arrayRef, n))); 587 } 588} 589 590 591// 592// Make CFArrays from stuff. 593// 594template <class Iterator, class Generator> 595inline CFArrayRef makeCFArray(Generator &generate, Iterator first, Iterator last) 596{ 597 // how many elements? 598 size_t size = distance(first, last); 599 600 // do the CFArrayCreate tango 601 auto_array<CFTypeRef> vec(size); 602 for (UInt32 n = 0; n < size; n++) 603 vec[n] = generate(projectPair(*first++)); 604 assert(first == last); 605 return CFArrayCreate(NULL, (const void **)vec.get(), size, &kCFTypeArrayCallBacks); 606} 607 608template <class Container, class Generator> 609inline CFArrayRef makeCFArray(Generator &generate, const Container &container) 610{ 611 return makeCFArray(generate, container.begin(), container.end()); 612} 613 614CFArrayRef makeCFArray(CFIndex count, ...) CF_RETURNS_RETAINED; 615CFMutableArrayRef makeCFMutableArray(CFIndex count, ...) CF_RETURNS_RETAINED; 616 617 618} // end namespace Security 619 620#endif //_H_CFUTILITIES 621