2 * Copyright (c) 2000-2004 Apple Computer, 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>
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
))
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
= kCFStringEncodingUTF8
)
310 return s
? CFStringCreateWithCString(NULL
, s
, encoding
) : NULL
;
313 inline CFStringRef
makeCFString(const string
&s
, CFStringEncoding encoding
= kCFStringEncodingUTF8
)
315 return CFStringCreateWithCString(NULL
, s
.c_str(), encoding
);
318 inline CFStringRef
makeCFString(CFDataRef data
, CFStringEncoding encoding
= kCFStringEncodingUTF8
)
320 return CFStringCreateFromExternalRepresentation(NULL
, data
, encoding
);
325 // Create CFURL objects from various sources
327 CFURLRef
makeCFURL(const char *s
, bool isDirectory
= false, CFURLRef base
= NULL
);
328 CFURLRef
makeCFURL(CFStringRef s
, bool isDirectory
= false, CFURLRef base
= NULL
);
330 inline CFURLRef
makeCFURL(const string
&s
, bool isDirectory
= false, CFURLRef base
= NULL
)
332 return makeCFURL(s
.c_str(), isDirectory
, base
);
337 // Make temporary CF objects.
339 class CFTempString
: public CFRef
<CFStringRef
> {
341 template <class Source
>
342 CFTempString(Source s
) : CFRef
<CFStringRef
>(makeCFString(s
)) { }
345 class CFTempURL
: public CFRef
<CFURLRef
> {
347 template <class Source
>
348 CFTempURL(Source s
, bool isDirectory
= false, CFURLRef base
= NULL
)
349 : CFRef
<CFURLRef
>(makeCFURL(s
, isDirectory
, base
)) { }
354 // A temporary CFNumber
356 class CFTempNumber
: public CFRef
<CFNumberRef
> {
358 template <class Value
>
359 CFTempNumber(Value value
) : CFRef
<CFNumberRef
>(makeCFNumber(value
)) { }
364 // A temporary CFData.
366 class CFTempData
: public CFRef
<CFDataRef
> {
368 CFTempData(const void *data
, size_t length
)
369 : CFRef
<CFDataRef
>(CFDataCreate(NULL
, (const UInt8
*)data
, length
)) { }
371 template <class Dataoid
>
372 CFTempData(const Dataoid
&dataoid
)
373 : CFRef
<CFDataRef
>(CFDataCreate(NULL
, (const UInt8
*)dataoid
.data(), dataoid
.length())) { }
376 class CFTempDataWrap
: public CFRef
<CFDataRef
> {
378 CFTempDataWrap(const void *data
, size_t length
)
379 : CFRef
<CFDataRef
>(CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)data
, length
, kCFAllocatorNull
)) { }
381 template <class Dataoid
>
382 CFTempDataWrap(const Dataoid
&dataoid
)
383 : CFRef
<CFDataRef
>(CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)dataoid
.data(), dataoid
.length(), kCFAllocatorNull
)) { }
388 // Create CFData objects from various sources.
390 inline CFDataRef
makeCFData(const void *data
, size_t size
)
392 return CFDataCreate(NULL
, (const UInt8
*)data
, size
);
395 inline CFDataRef
makeCFData(CFDictionaryRef dictionary
)
397 return CFPropertyListCreateXMLData(NULL
, dictionary
);
400 template <class Data
>
401 inline CFDataRef
makeCFData(const Data
&source
)
403 return CFDataCreate(NULL
, reinterpret_cast<const UInt8
*>(source
.data()), source
.length());
406 inline CFDataRef
makeCFDataMalloc(const void *data
, size_t size
)
408 return CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)data
, size
, kCFAllocatorMalloc
);
411 template <class Data
>
412 inline CFDataRef
makeCFDataMalloc(const Data
&source
)
414 return CFDataCreateWithBytesNoCopy(NULL
, (const UInt8
*)source
.data(), source
.length(), kCFAllocatorMalloc
);
419 // Create a CFDataRef from malloc'ed data, exception-safely
423 CFMallocData(size_t size
)
424 : mData(::malloc(size
)), mSize(size
)
427 UnixError::throwMe();
438 { return static_cast<T
*>(mData
); }
440 operator CFDataRef ();
442 void *data() { return mData
; }
443 const void *data() const { return mData
; }
444 size_t length() const { return mSize
; }
453 // Make CFDictionaries from stuff
455 CFDictionaryRef
makeCFDictionary(unsigned count
, ...); // key/value pairs
456 CFMutableDictionaryRef
makeCFMutableDictionary(); // empty
457 CFMutableDictionaryRef
makeCFMutableDictionary(unsigned count
, ...); // (count) key/value pairs
458 CFMutableDictionaryRef
makeCFMutableDictionary(CFDictionaryRef dict
); // copy of dictionary
460 CFDictionaryRef
makeCFDictionaryFrom(CFDataRef data
) CF_RETURNS_RETAINED
;// interpret plist form
461 CFDictionaryRef
makeCFDictionaryFrom(const void *data
, size_t length
) CF_RETURNS_RETAINED
; // ditto
465 // Parsing out a CFDictionary without losing your lunch
467 class CFDictionary
: public CFCopyRef
<CFDictionaryRef
> {
468 typedef CFCopyRef
<CFDictionaryRef
> _Base
;
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
) { }
476 using CFCopyRef
<CFDictionaryRef
>::get
;
478 CFTypeRef
get(CFStringRef key
) { return CFDictionaryGetValue(*this, key
); }
479 CFTypeRef
get(const char *key
) { return CFDictionaryGetValue(*this, CFTempString(key
)); }
481 template <class CFType
>
482 CFType
get(CFStringRef key
, OSStatus err
= noErr
) const
484 CFTypeRef elem
= CFDictionaryGetValue(*this, key
);
485 return CFRef
<CFType
>::check(elem
, err
? err
: mDefaultError
);
488 template <class CFType
>
489 CFType
get(const char *key
, OSStatus err
= noErr
) const
490 { return get
<CFType
>(CFTempString(key
), err
); }
492 void apply(CFDictionaryApplierFunction func
, void *context
)
493 { return CFDictionaryApplyFunction(*this, func
, context
); }
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
); }
506 void apply(T
*object
, void (T::*func
)(CFTypeRef key
, CFTypeRef value
))
507 { Applier
<T
> app
; app
.object
= object
; app
.func
= func
; return apply(app
.apply
, &app
); }
510 OSStatus mDefaultError
;
515 // CFURLAccess wrappers for specific purposes
517 CFDataRef
cfLoadFile(CFURLRef url
);
518 inline CFDataRef
cfLoadFile(CFStringRef path
) { return cfLoadFile(CFTempURL(path
)); }
519 inline CFDataRef
cfLoadFile(const std::string
&path
) { return cfLoadFile(CFTempURL(path
)); }
520 inline CFDataRef
cfLoadFile(const char *path
) { return cfLoadFile(CFTempURL(path
)); }
524 // Internally used STL adapters. Should probably be in utilities.h.
526 template <class Self
>
527 Self
projectPair(const Self
&me
)
530 template <class First
, class Second
>
531 Second
projectPair(const pair
<First
, Second
> &me
)
532 { return me
.second
; }
536 // A CFToVector turns a CFArrayRef of items into a flat
537 // C vector of some type, using a conversion function
538 // (from CFTypeRef) specified. As a special bonus, if
539 // you provide a CFTypeRef (other than CFArrayRef), it
540 // will be transparently handled as an array-of-one.
541 // The array will be automatically released on destruction
542 // of the CFToVector object. Any internal structure shared
543 // with the CFTypeRef inputs will be left alone.
545 template <class VectorBase
, class CFRefType
, VectorBase
convert(CFRefType
)>
548 CFToVector(CFArrayRef arrayRef
);
549 ~CFToVector() { delete[] mVector
; }
550 operator UInt32 () const { return mCount
; }
551 operator VectorBase
*() const { return mVector
; }
552 bool empty() const { return mCount
== 0; }
554 VectorBase
*begin() const { return mVector
; }
555 VectorBase
*end() const { return mVector
+ mCount
; }
557 VectorBase
&operator [] (UInt32 ix
) const { assert(ix
< mCount
); return mVector
[ix
]; }
564 template <class VectorBase
, class CFRefType
, VectorBase
convert(CFRefType
)>
565 CFToVector
<VectorBase
, CFRefType
, convert
>::CFToVector(CFArrayRef arrayRef
)
567 if (arrayRef
== NULL
) {
571 mCount
= CFArrayGetCount(arrayRef
);
572 mVector
= new VectorBase
[mCount
];
573 for (UInt32 n
= 0; n
< mCount
; n
++)
574 mVector
[n
] = convert(CFRefType(CFArrayGetValueAtIndex(arrayRef
, n
)));
580 // Make CFArrays from stuff.
582 template <class Iterator
, class Generator
>
583 inline CFArrayRef
makeCFArray(Generator
&generate
, Iterator first
, Iterator last
)
585 // how many elements?
586 size_t size
= distance(first
, last
);
588 // do the CFArrayCreate tango
589 auto_array
<CFTypeRef
> vec(size
);
590 for (UInt32 n
= 0; n
< size
; n
++)
591 vec
[n
] = generate(projectPair(*first
++));
592 assert(first
== last
);
593 return CFArrayCreate(NULL
, (const void **)vec
.get(), size
, &kCFTypeArrayCallBacks
);
596 template <class Container
, class Generator
>
597 inline CFArrayRef
makeCFArray(Generator
&generate
, const Container
&container
)
599 return makeCFArray(generate
, container
.begin(), container
.end());
602 CFArrayRef
makeCFArray(CFIndex count
, ...) CF_RETURNS_RETAINED
;
603 CFMutableArrayRef
makeCFMutableArray(CFIndex count
, ...) CF_RETURNS_RETAINED
;
606 } // end namespace Security
608 #endif //_H_CFUTILITIES