2 * Copyright (c) 2000-2004,2011-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 //CoreFoundation related utilities
28 #ifndef _H_CFUTILITIES
29 #define _H_CFUTILITIES
31 #include <security_utilities/utilities.h>
32 #include <security_utilities/globalizer.h>
33 #include <CoreFoundation/CoreFoundation.h>
35 #include <Security/SecBase.h>
43 // Traits of popular CF types
45 template <class CFType
> struct CFTraits
{ };
47 template <> struct CFTraits
<CFTypeRef
> {
48 static bool check(CFTypeRef ref
) { return true; }
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(); } \
58 __SEC_CFTYPE(CFBoolean
)
59 __SEC_CFTYPE(CFNumber
)
60 __SEC_CFTYPE(CFString
)
64 __SEC_CFTYPE(CFBundle
)
66 __SEC_CFTYPE(CFDictionary
)
71 // Initialize-only self-releasing CF object handler (lightweight).
73 template <class CFType
> class CFRef
{
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
) {}
81 CFRef(CFTypeRef ref
, OSStatus err
)
84 if (ref
&& !CFTraits
<CFType
>::check(ref
))
85 MacOSError::throwMe(err
);
88 CFRef
&take(CFType ref
)
89 { this->release(); mRef
= ref
; return *this; }
92 { CFType r
= mRef
; mRef
= NULL
; return r
; }
94 CFRef
&operator = (CFType ref
)
95 { if (ref
) CFRetain(ref
); return take(ref
); }
97 CFRef
&operator = (const CFRef
&ref
)
98 { if (ref
) CFRetain(ref
); return take(ref
); }
100 // take variant for when newly created CFType is returned
101 // via a ptr-to-CFType argument.
103 { if (mRef
) CFRelease(mRef
); mRef
= NULL
; return &mRef
; }
105 operator CFType () const { return mRef
; }
106 operator bool () const { return mRef
!= NULL
; }
107 bool operator ! () const { return mRef
== NULL
; }
109 CFType
get() const { return mRef
; }
112 { take(NULL
); return mRef
; }
114 CFType
retain() const
115 { if (mRef
) CFRetain(mRef
); return mRef
; }
118 { if (mRef
) CFRelease(mRef
); }
120 template <class NewType
>
121 bool is() const { return CFTraits
<NewType
>::check(mRef
); }
123 template <class OldType
>
124 static CFType
check(OldType cf
, OSStatus err
)
126 if (cf
&& !CFTraits
<CFType
>::check(cf
))
127 MacOSError::throwMe(err
);
131 template <class NewType
>
132 NewType
as() const { return NewType(mRef
); }
134 template <class NewType
>
135 NewType
as(OSStatus err
) const { return CFRef
<NewType
>::check(mRef
, err
); }
142 template <class CFType
> class CFCopyRef
: public CFRef
<CFType
> {
143 typedef CFRef
<CFType
> _Base
;
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(); }
151 CFCopyRef
&take(CFType ref
)
152 { _Base::take(ref
); return *this; }
154 CFCopyRef
&operator = (CFType ref
)
155 { if (ref
) CFRetain(ref
); return take(ref
); }
157 CFCopyRef
&operator = (const CFCopyRef
&ref
)
158 { _Base::operator = (ref
); return *this; }
160 template <class _T
> CFCopyRef
&operator = (const CFRef
<_T
> &ref
)
161 { _Base::operator = (ref
); return *this; }
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).
170 inline CFArrayRef
cfArrayize(CFTypeRef arrayOrItem
)
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
178 return CFArrayCreate(NULL
,
179 (const void **)&arrayOrItem
, 1, &kCFTypeArrayCallBacks
);
186 // Since CFArrays are type-neutral, a single immutable empty array will
187 // serve for all uses. So keep it.
189 struct CFEmptyArray
{
190 operator CFArrayRef () { return mArray
; }
196 extern ModuleNexus
<CFEmptyArray
> cfEmptyArray
;
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(!).
204 string
cfString(CFStringRef str
); // extract UTF8 string
205 string
cfString(CFURLRef url
); // path of file: URL (only)
206 string
cfString(CFBundleRef bundle
); // path to bundle root
208 string
cfStringRelease(CFStringRef str CF_CONSUMED
); // extract UTF8 string
209 string
cfStringRelease(CFURLRef url CF_CONSUMED
); // path of file: URL (only)
210 string
cfStringRelease(CFBundleRef bundle CF_CONSUMED
); // path to bundle root
213 string
cfString(CFTypeRef anything
, OSStatus err
); // dynamic form; throws err on NULL
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."
221 template <class Number
>
222 struct CFNumberTraits
;
224 template <> struct CFNumberTraits
<char> {
225 static const CFNumberType cfnType
= kCFNumberCharType
;
226 typedef char ValueType
;
228 template <> struct CFNumberTraits
<short> {
229 static const CFNumberType cfnType
= kCFNumberShortType
;
230 typedef short ValueType
;
232 template <> struct CFNumberTraits
<int> {
233 static const CFNumberType cfnType
= kCFNumberIntType
;
234 typedef int ValueType
;
236 template <> struct CFNumberTraits
<long> {
237 static const CFNumberType cfnType
= kCFNumberLongType
;
238 typedef long ValueType
;
240 template <> struct CFNumberTraits
<long long> {
241 static const CFNumberType cfnType
= kCFNumberLongLongType
;
242 typedef long long ValueType
;
244 template <> struct CFNumberTraits
<float> {
245 static const CFNumberType cfnType
= kCFNumberFloatType
;
246 typedef float ValueType
;
248 template <> struct CFNumberTraits
<double> {
249 static const CFNumberType cfnType
= kCFNumberDoubleType
;
250 typedef double ValueType
;
253 template <> struct CFNumberTraits
<unsigned char> {
254 static const CFNumberType cfnType
= kCFNumberIntType
;
255 typedef int ValueType
;
257 template <> struct CFNumberTraits
<unsigned short> {
258 static const CFNumberType cfnType
= kCFNumberIntType
;
259 typedef int ValueType
;
261 template <> struct CFNumberTraits
<unsigned int> {
262 static const CFNumberType cfnType
= kCFNumberLongLongType
;
263 typedef long long ValueType
;
265 template <> struct CFNumberTraits
<unsigned long> {
266 static const CFNumberType cfnType
= kCFNumberLongLongType
;
267 typedef long long ValueType
;
269 template <> struct CFNumberTraits
<unsigned long long> {
270 static const CFNumberType cfnType
= kCFNumberLongLongType
;
271 typedef long long ValueType
;
274 template <class Number
>
275 Number
cfNumber(CFNumberRef number
)
277 typename CFNumberTraits
<Number
>::ValueType value
;
278 if (CFNumberGetValue(number
, CFNumberTraits
<Number
>::cfnType
, &value
))
279 return (Number
)value
;
284 template <class Number
>
285 Number
cfNumber(CFNumberRef number
, Number defaultValue
)
287 typename CFNumberTraits
<Number
>::ValueType value
;
288 if (CFNumberGetValue(number
, CFNumberTraits
<Number
>::cfnType
, &value
))
294 template <class Number
>
295 CFNumberRef
makeCFNumber(Number value
)
297 typename CFNumberTraits
<Number
>::ValueType cfValue
= value
;
298 return CFNumberCreate(NULL
, CFNumberTraits
<Number
>::cfnType
, &cfValue
);
302 inline uint32_t cfNumber(CFNumberRef number
) { return cfNumber
<uint32_t>(number
); }
306 // Translate strings into CFStrings
308 inline CFStringRef
makeCFString(const char *s
, CFStringEncoding encoding
)
310 return s
? CFStringCreateWithCString(NULL
, s
, encoding
) : NULL
;
313 inline CFStringRef
makeCFString(const char *s
)
317 CFStringRef result
= CFStringCreateWithCString(NULL
, s
, kCFStringEncodingUTF8
);
318 if (result
== NULL
) {
319 result
= CFStringCreateWithCString(NULL
, s
, kCFStringEncodingASCII
);
326 inline CFStringRef
makeCFString(const string
&s
, CFStringEncoding encoding
)
328 return makeCFString(s
.c_str(), encoding
);
331 inline CFStringRef
makeCFString(const string
&s
)
333 return makeCFString(s
.c_str());
336 inline CFStringRef
makeCFString(CFDataRef data
, CFStringEncoding encoding
= kCFStringEncodingUTF8
)
338 return CFStringCreateFromExternalRepresentation(NULL
, data
, encoding
);
343 // Create CFURL objects from various sources
345 CFURLRef CF_RETURNS_RETAINED
makeCFURL(const char *s
, bool isDirectory
= false, CFURLRef base
= NULL
);
346 CFURLRef CF_RETURNS_RETAINED
makeCFURL(CFStringRef s
, bool isDirectory
= false, CFURLRef base
= NULL
);
348 inline CFURLRef
makeCFURL(const string
&s
, bool isDirectory
= false, CFURLRef base
= NULL
)
350 return makeCFURL(s
.c_str(), isDirectory
, base
);
355 // Make temporary CF objects.
357 class CFTempString
: public CFRef
<CFStringRef
> {
359 template <class Source
>
360 CFTempString(Source s
) : CFRef
<CFStringRef
>(makeCFString(s
)) { }
363 class CFTempURL
: public CFRef
<CFURLRef
> {
365 template <class Source
>
366 CFTempURL(Source s
, bool isDirectory
= false, CFURLRef base
= NULL
)
367 : CFRef
<CFURLRef
>(makeCFURL(s
, isDirectory
, base
)) { }
372 // A temporary CFNumber
374 class CFTempNumber
: public CFRef
<CFNumberRef
> {
376 template <class Value
>
377 CFTempNumber(Value value
) : CFRef
<CFNumberRef
>(makeCFNumber(value
)) { }
382 // A temporary CFData.
384 class CFTempData
: public CFRef
<CFDataRef
> {
386 CFTempData(const void *data
, size_t length
)
387 : CFRef
<CFDataRef
>(CFDataCreate(NULL
, (const UInt8
*)data
, length
)) { }
389 template <class Dataoid
>
390 CFTempData(const Dataoid
&dataoid
)
391 : CFRef
<CFDataRef
>(CFDataCreate(NULL
, (const UInt8
*)dataoid
.data(), dataoid
.length())) { }
394 class CFTempDataWrap
: public CFRef
<CFDataRef
> {
396 CFTempDataWrap(const void *data
, size_t length
)
397 : CFRef
<CFDataRef
>(CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)data
, length
, kCFAllocatorNull
)) { }
399 template <class Dataoid
>
400 CFTempDataWrap(const Dataoid
&dataoid
)
401 : CFRef
<CFDataRef
>(CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)dataoid
.data(), dataoid
.length(), kCFAllocatorNull
)) { }
406 // Create CFData objects from various sources.
408 inline CFDataRef
makeCFData(const void *data
, size_t size
)
410 return CFDataCreate(NULL
, (const UInt8
*)data
, size
);
413 inline CFDataRef
makeCFData(CFDictionaryRef dictionary
)
415 return CFPropertyListCreateData(NULL
, dictionary
, kCFPropertyListXMLFormat_v1_0
, 0, NULL
);
418 inline CFDataRef
makeCFData(CFArrayRef array
)
420 return CFPropertyListCreateData(NULL
, array
, kCFPropertyListXMLFormat_v1_0
, 0, NULL
);
423 template <class Data
>
424 inline CFDataRef
makeCFData(const Data
&source
)
426 return CFDataCreate(NULL
, reinterpret_cast<const UInt8
*>(source
.data()), source
.length());
429 inline CFDataRef
makeCFDataMalloc(const void *data
, size_t size
)
431 return CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)data
, size
, kCFAllocatorMalloc
);
434 template <class Data
>
435 inline CFDataRef
makeCFDataMalloc(const Data
&source
)
437 return CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)source
.data(), source
.length(), kCFAllocatorMalloc
);
442 // Create a CFDataRef from malloc'ed data, exception-safely
446 CFMallocData(size_t size
)
447 : mData(::malloc(size
)), mSize(size
)
450 UnixError::throwMe();
461 { return static_cast<T
*>(mData
); }
463 operator CFDataRef ();
465 void *data() { return mData
; }
466 const void *data() const { return mData
; }
467 size_t length() const { return mSize
; }
476 // Make CFDictionaries from stuff
478 CFDictionaryRef
makeCFDictionary(unsigned count
, ...) CF_RETURNS_RETAINED
; // key/value pairs
479 CFMutableDictionaryRef
makeCFMutableDictionary() CF_RETURNS_RETAINED
; // empty
480 CFMutableDictionaryRef
makeCFMutableDictionary(unsigned count
, ...) CF_RETURNS_RETAINED
; // (count) key/value pairs
481 CFMutableDictionaryRef
makeCFMutableDictionary(CFDictionaryRef dict
) CF_RETURNS_RETAINED
; // copy of dictionary
483 CFDictionaryRef
makeCFDictionaryFrom(CFDataRef data
) CF_RETURNS_RETAINED
;// interpret plist form
484 CFDictionaryRef
makeCFDictionaryFrom(const void *data
, size_t length
) CF_RETURNS_RETAINED
; // ditto
488 // Parsing out a CFDictionary without losing your lunch
490 class CFDictionary
: public CFCopyRef
<CFDictionaryRef
> {
491 typedef CFCopyRef
<CFDictionaryRef
> _Base
;
493 CFDictionary(CFDictionaryRef ref
, OSStatus error
) : _Base(ref
), mDefaultError(error
)
494 { if (!ref
) MacOSError::throwMe(error
); }
495 CFDictionary(CFTypeRef ref
, OSStatus error
) : _Base(ref
, error
), mDefaultError(error
)
496 { if (!ref
) MacOSError::throwMe(error
); }
497 CFDictionary(OSStatus error
) : _Base(NULL
), mDefaultError(error
) { }
499 using CFCopyRef
<CFDictionaryRef
>::get
;
501 CFTypeRef
get(CFStringRef key
) { return CFDictionaryGetValue(*this, key
); }
502 CFTypeRef
get(const char *key
) { return CFDictionaryGetValue(*this, CFTempString(key
)); }
504 template <class CFType
>
505 CFType
get(CFStringRef key
, OSStatus err
= errSecSuccess
) const
507 CFTypeRef elem
= CFDictionaryGetValue(*this, key
);
508 return CFRef
<CFType
>::check(elem
, err
? err
: mDefaultError
);
511 template <class CFType
>
512 CFType
get(const char *key
, OSStatus err
= errSecSuccess
) const
513 { return get
<CFType
>(CFTempString(key
), err
); }
515 void apply(CFDictionaryApplierFunction func
, void *context
)
516 { return CFDictionaryApplyFunction(*this, func
, context
); }
522 void (T::*func
)(CFTypeRef key
, CFTypeRef value
);
523 static void apply(CFTypeRef key
, CFTypeRef value
, void *context
)
524 { Applier
*me
= (Applier
*)context
; return ((me
->object
)->*(me
->func
))(key
, value
); }
527 template <class Key
, class Value
>
528 struct BlockApplier
{
529 void (^action
)(Key key
, Value value
);
530 static void apply(CFTypeRef key
, CFTypeRef value
, void* context
)
531 { BlockApplier
*me
= (BlockApplier
*)context
; return me
->action(Key(key
), Value(value
)); }
536 void apply(T
*object
, void (T::*func
)(CFTypeRef key
, CFTypeRef value
))
537 { Applier
<T
> app
; app
.object
= object
; app
.func
= func
; return apply(app
.apply
, &app
); }
539 template <class Key
= CFTypeRef
, class Value
= CFTypeRef
>
540 void apply(void (^action
)(Key key
, Value value
))
541 { BlockApplier
<Key
, Value
> app
; app
.action
= action
; return apply(app
.apply
, &app
); }
544 OSStatus mDefaultError
;
549 // Apply a block to a dictionary
551 typedef void (^CFDictionaryApplierBlock
)(const void *, const void *);
552 void cfDictionaryApplyBlock(CFDictionaryRef source
, CFDictionaryApplierBlock block
);
557 // CFURLAccess wrappers for specific purposes
558 // cfLoadFile family will use mmap(2) when appropriate
559 // cfReadFile will read the data into memory
560 // cfMapFile will mmap(2) the file
562 CFDataRef CF_RETURNS_RETAINED
cfLoadFile(CFURLRef url
);
563 CFDataRef CF_RETURNS_RETAINED
cfLoadFile(int fd
, size_t bytes
);
564 inline CFDataRef CF_RETURNS_RETAINED
cfLoadFile(CFStringRef path
) { return cfLoadFile(CFTempURL(path
)); }
565 inline CFDataRef CF_RETURNS_RETAINED
cfLoadFile(const std::string
&path
) { return cfLoadFile(CFTempURL(path
)); }
566 inline CFDataRef CF_RETURNS_RETAINED
cfLoadFile(const char *path
) { return cfLoadFile(CFTempURL(path
)); }
569 CFDataRef
cfReadFile(CFURLRef url
) CF_RETURNS_RETAINED
;
570 CFDataRef
cfReadFile(int fd
, size_t bytes
) CF_RETURNS_RETAINED
;
571 inline CFDataRef
cfReadFile(CFStringRef path
) { return cfReadFile(CFTempURL(path
)); }
572 inline CFDataRef
cfReadFile(const std::string
&path
) { return cfReadFile(CFTempURL(path
)); }
573 inline CFDataRef
cfReadFile(const char *path
) { return cfReadFile(CFTempURL(path
)); }
575 CFDataRef
cfMapFile(CFURLRef url
) CF_RETURNS_RETAINED
;
576 CFDataRef
cfMapFile(int fd
, size_t bytes
) CF_RETURNS_RETAINED
;
577 inline CFDataRef
cfMapFile(CFStringRef path
) { return cfMapFile(CFTempURL(path
)); }
578 inline CFDataRef
cfMapFile(const std::string
&path
) { return cfMapFile(CFTempURL(path
)); }
579 inline CFDataRef
cfMapFile(const char *path
) { return cfMapFile(CFTempURL(path
)); }
583 // Internally used STL adapters. Should probably be in utilities.h.
585 template <class Self
>
586 Self
projectPair(const Self
&me
)
589 template <class First
, class Second
>
590 Second
projectPair(const pair
<First
, Second
> &me
)
591 { return me
.second
; }
595 // A CFToVector turns a CFArrayRef of items into a flat
596 // C vector of some type, using a conversion function
597 // (from CFTypeRef) specified. As a special bonus, if
598 // you provide a CFTypeRef (other than CFArrayRef), it
599 // will be transparently handled as an array-of-one.
600 // The array will be automatically released on destruction
601 // of the CFToVector object. Any internal structure shared
602 // with the CFTypeRef inputs will be left alone.
604 template <class VectorBase
, class CFRefType
, VectorBase
convert(CFRefType
)>
607 CFToVector(CFArrayRef arrayRef
);
608 ~CFToVector() { delete[] mVector
; }
609 operator UInt32 () const { return mCount
; }
610 operator VectorBase
*() const { return mVector
; }
611 bool empty() const { return mCount
== 0; }
613 VectorBase
*begin() const { return mVector
; }
614 VectorBase
*end() const { return mVector
+ mCount
; }
616 VectorBase
&operator [] (UInt32 ix
) const { assert(ix
< mCount
); return mVector
[ix
]; }
623 template <class VectorBase
, class CFRefType
, VectorBase
convert(CFRefType
)>
624 CFToVector
<VectorBase
, CFRefType
, convert
>::CFToVector(CFArrayRef arrayRef
)
626 if (arrayRef
== NULL
) {
630 mCount
= (UInt32
)CFArrayGetCount(arrayRef
);
631 mVector
= new VectorBase
[mCount
];
632 for (UInt32 n
= 0; n
< mCount
; n
++)
633 mVector
[n
] = convert(CFRefType(CFArrayGetValueAtIndex(arrayRef
, n
)));
639 // Make CFArrays from stuff.
641 template <class Iterator
, class Generator
>
642 inline CFArrayRef CF_RETURNS_RETAINED
makeCFArrayFrom(const Generator
&generate
, Iterator first
, Iterator last
)
644 // how many elements?
645 size_t size
= distance(first
, last
);
647 // do the CFArrayCreate tango
648 auto_array
<CFTypeRef
> vec(size
);
649 for (UInt32 n
= 0; n
< size
; n
++)
650 vec
[n
] = generate(projectPair(*first
++));
651 assert(first
== last
);
652 return CFArrayCreate(NULL
, (const void **)vec
.get(), size
, &kCFTypeArrayCallBacks
);
655 template <class Container
, class Generator
>
656 inline CFArrayRef
makeCFArrayFrom(const Generator
&generate
, const Container
&container
)
658 return makeCFArrayFrom(generate
, container
.begin(), container
.end());
661 CFArrayRef
makeCFArray(CFIndex count
, ...) CF_RETURNS_RETAINED
;
662 CFMutableArrayRef
makeCFMutableArray(CFIndex count
, ...) CF_RETURNS_RETAINED
;
666 // Apply a block to aa array
668 typedef void (^CFArrayApplierBlock
)(const void *value
);
669 void cfArrayApplyBlock(CFArrayRef array
, CFRange range
, CFArrayApplierBlock block
);
670 void cfArrayApplyBlock(CFArrayRef array
, CFArrayApplierBlock block
);
673 } // end namespace Security
675 #endif //_H_CFUTILITIES