#ifndef _H_CFUTILITIES
#define _H_CFUTILITIES
#include <security_utilities/utilities.h>
#include <security_utilities/globalizer.h>
#include <CoreFoundation/CoreFoundation.h>
#include <algorithm>
#undef check
namespace Security {
template <class CFType> struct CFTraits { };
template <> struct CFTraits<CFTypeRef> {
static bool check(CFTypeRef ref) { return true; }
};
#define __SEC_CFTYPE(name) \
template <> struct CFTraits<name##Ref> { \
static CFTypeID cfid() { return name##GetTypeID(); } \
static bool check(CFTypeRef ref) { return CFGetTypeID(ref) == cfid(); } \
};
__SEC_CFTYPE(CFNull)
__SEC_CFTYPE(CFBoolean)
__SEC_CFTYPE(CFNumber)
__SEC_CFTYPE(CFString)
__SEC_CFTYPE(CFData)
__SEC_CFTYPE(CFDate)
__SEC_CFTYPE(CFURL)
__SEC_CFTYPE(CFBundle)
__SEC_CFTYPE(CFArray)
__SEC_CFTYPE(CFDictionary)
__SEC_CFTYPE(CFSet)
template <class CFType> class CFRef {
public:
CFRef() : mRef(NULL) { }
CFRef(CFType ref) : mRef(ref) { }
~CFRef() { this->release(); }
CFRef(const CFRef &ref) : mRef(ref) {}
template <class _T> CFRef(const CFRef<_T> &ref) : mRef(ref) {}
CFRef(CFTypeRef ref, OSStatus err)
: mRef(CFType(ref))
{
if (ref && !CFTraits<CFType>::check(ref))
MacOSError::throwMe(err);
}
CFRef &take(CFType ref)
{ this->release(); mRef = ref; return *this; }
CFType yield()
{ CFType r = mRef; mRef = NULL; return r; }
CFRef &operator = (CFType ref)
{ if (ref) CFRetain(ref); return take(ref); }
CFRef &operator = (const CFRef &ref)
{ if (ref) CFRetain(ref); return take(ref); }
CFType *take()
{ if (mRef) CFRelease(mRef); mRef = NULL; return &mRef; }
operator CFType () const { return mRef; }
operator bool () const { return mRef != NULL; }
bool operator ! () const { return mRef == NULL; }
CFType get() const { return mRef; }
CFType &aref()
{ take(NULL); return mRef; }
CFType retain() const
{ if (mRef) CFRetain(mRef); return mRef; }
void release() const
{ if (mRef) CFRelease(mRef); }
template <class NewType>
bool is() const { return CFTraits<NewType>::check(mRef); }
template <class OldType>
static CFType check(OldType cf, OSStatus err)
{
if (cf && !CFTraits<CFType>::check(cf))
MacOSError::throwMe(err);
return CFType(cf);
}
template <class NewType>
NewType as() const { return NewType(mRef); }
template <class NewType>
NewType as(OSStatus err) const { return CFRef<NewType>::check(mRef, err); }
private:
CFType mRef;
};
template <class CFType> class CFCopyRef : public CFRef<CFType> {
typedef CFRef<CFType> _Base;
public:
CFCopyRef() { }
CFCopyRef(CFType ref) : _Base(ref) { this->retain(); }
CFCopyRef(const CFCopyRef &ref) : _Base(ref) { this->retain(); }
template <class _T> CFCopyRef(const CFRef<_T> &ref) : _Base(ref) { this->retain(); }
CFCopyRef(CFTypeRef ref, OSStatus err) : _Base(ref, err) { this->retain(); }
CFCopyRef &take(CFType ref)
{ _Base::take(ref); return *this; }
CFCopyRef &operator = (CFType ref)
{ if (ref) CFRetain(ref); return take(ref); }
CFCopyRef &operator = (const CFCopyRef &ref)
{ _Base::operator = (ref); return *this; }
template <class _T> CFCopyRef &operator = (const CFRef<_T> &ref)
{ _Base::operator = (ref); return *this; }
};
inline CFArrayRef cfArrayize(CFTypeRef arrayOrItem)
{
if (arrayOrItem == NULL)
return NULL; else if (CFGetTypeID(arrayOrItem) == CFArrayGetTypeID()) {
CFRetain(arrayOrItem);
return CFArrayRef(arrayOrItem); } else {
return CFArrayCreate(NULL,
(const void **)&arrayOrItem, 1, &kCFTypeArrayCallBacks);
}
}
struct CFEmptyArray {
operator CFArrayRef () { return mArray; }
CFEmptyArray();
private:
CFArrayRef mArray;
};
extern ModuleNexus<CFEmptyArray> cfEmptyArray;
string cfString(CFStringRef str); string cfString(CFURLRef url); string cfString(CFBundleRef bundle);
string cfStringRelease(CFStringRef str CF_CONSUMED); string cfStringRelease(CFURLRef url CF_CONSUMED); string cfStringRelease(CFBundleRef bundle CF_CONSUMED);
string cfString(CFTypeRef anything, OSStatus err);
template <class Number>
struct CFNumberTraits;
template <> struct CFNumberTraits<char> {
static const CFNumberType cfnType = kCFNumberCharType;
typedef char ValueType;
};
template <> struct CFNumberTraits<short> {
static const CFNumberType cfnType = kCFNumberShortType;
typedef short ValueType;
};
template <> struct CFNumberTraits<int> {
static const CFNumberType cfnType = kCFNumberIntType;
typedef int ValueType;
};
template <> struct CFNumberTraits<long> {
static const CFNumberType cfnType = kCFNumberLongType;
typedef long ValueType;
};
template <> struct CFNumberTraits<long long> {
static const CFNumberType cfnType = kCFNumberLongLongType;
typedef long long ValueType;
};
template <> struct CFNumberTraits<float> {
static const CFNumberType cfnType = kCFNumberFloatType;
typedef float ValueType;
};
template <> struct CFNumberTraits<double> {
static const CFNumberType cfnType = kCFNumberDoubleType;
typedef double ValueType;
};
template <> struct CFNumberTraits<unsigned char> {
static const CFNumberType cfnType = kCFNumberIntType;
typedef int ValueType;
};
template <> struct CFNumberTraits<unsigned short> {
static const CFNumberType cfnType = kCFNumberIntType;
typedef int ValueType;
};
template <> struct CFNumberTraits<unsigned int> {
static const CFNumberType cfnType = kCFNumberLongLongType;
typedef long long ValueType;
};
template <> struct CFNumberTraits<unsigned long> {
static const CFNumberType cfnType = kCFNumberLongLongType;
typedef long long ValueType;
};
template <> struct CFNumberTraits<unsigned long long> {
static const CFNumberType cfnType = kCFNumberLongLongType;
typedef long long ValueType;
};
template <class Number>
Number cfNumber(CFNumberRef number)
{
typename CFNumberTraits<Number>::ValueType value;
if (CFNumberGetValue(number, CFNumberTraits<Number>::cfnType, &value))
return value;
else
CFError::throwMe();
}
template <class Number>
Number cfNumber(CFNumberRef number, Number defaultValue)
{
typename CFNumberTraits<Number>::ValueType value;
if (CFNumberGetValue(number, CFNumberTraits<Number>::cfnType, &value))
return value;
else
return defaultValue;
}
template <class Number>
CFNumberRef makeCFNumber(Number value)
{
typename CFNumberTraits<Number>::ValueType cfValue = value;
return CFNumberCreate(NULL, CFNumberTraits<Number>::cfnType, &cfValue);
}
inline uint32_t cfNumber(CFNumberRef number) { return cfNumber<uint32_t>(number); }
inline CFStringRef makeCFString(const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8)
{
return s ? CFStringCreateWithCString(NULL, s, encoding) : NULL;
}
inline CFStringRef makeCFString(const string &s, CFStringEncoding encoding = kCFStringEncodingUTF8)
{
return CFStringCreateWithCString(NULL, s.c_str(), encoding);
}
inline CFStringRef makeCFString(CFDataRef data, CFStringEncoding encoding = kCFStringEncodingUTF8)
{
return CFStringCreateFromExternalRepresentation(NULL, data, encoding);
}
CFURLRef makeCFURL(const char *s, bool isDirectory = false, CFURLRef base = NULL);
CFURLRef makeCFURL(CFStringRef s, bool isDirectory = false, CFURLRef base = NULL);
inline CFURLRef makeCFURL(const string &s, bool isDirectory = false, CFURLRef base = NULL)
{
return makeCFURL(s.c_str(), isDirectory, base);
}
class CFTempString : public CFRef<CFStringRef> {
public:
template <class Source>
CFTempString(Source s) : CFRef<CFStringRef>(makeCFString(s)) { }
};
class CFTempURL : public CFRef<CFURLRef> {
public:
template <class Source>
CFTempURL(Source s, bool isDirectory = false, CFURLRef base = NULL)
: CFRef<CFURLRef>(makeCFURL(s, isDirectory, base)) { }
};
class CFTempNumber : public CFRef<CFNumberRef> {
public:
template <class Value>
CFTempNumber(Value value) : CFRef<CFNumberRef>(makeCFNumber(value)) { }
};
class CFTempData : public CFRef<CFDataRef> {
public:
CFTempData(const void *data, size_t length)
: CFRef<CFDataRef>(CFDataCreate(NULL, (const UInt8 *)data, length)) { }
template <class Dataoid>
CFTempData(const Dataoid &dataoid)
: CFRef<CFDataRef>(CFDataCreate(NULL, (const UInt8 *)dataoid.data(), dataoid.length())) { }
};
class CFTempDataWrap : public CFRef<CFDataRef> {
public:
CFTempDataWrap(const void *data, size_t length)
: CFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)data, length, kCFAllocatorNull)) { }
template <class Dataoid>
CFTempDataWrap(const Dataoid &dataoid)
: CFRef<CFDataRef>(CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)dataoid.data(), dataoid.length(), kCFAllocatorNull)) { }
};
inline CFDataRef makeCFData(const void *data, size_t size)
{
return CFDataCreate(NULL, (const UInt8 *)data, size);
}
inline CFDataRef makeCFData(CFDictionaryRef dictionary)
{
return CFPropertyListCreateXMLData(NULL, dictionary);
}
template <class Data>
inline CFDataRef makeCFData(const Data &source)
{
return CFDataCreate(NULL, reinterpret_cast<const UInt8 *>(source.data()), source.length());
}
inline CFDataRef makeCFDataMalloc(const void *data, size_t size)
{
return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)data, size, kCFAllocatorMalloc);
}
template <class Data>
inline CFDataRef makeCFDataMalloc(const Data &source)
{
return CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)source.data(), source.length(), kCFAllocatorMalloc);
}
class CFMallocData {
public:
CFMallocData(size_t size)
: mData(::malloc(size)), mSize(size)
{
if (!mData)
UnixError::throwMe();
}
~CFMallocData()
{
if (mData)
::free(mData);
}
template <class T>
operator T * ()
{ return static_cast<T *>(mData); }
operator CFDataRef ();
void *data() { return mData; }
const void *data() const { return mData; }
size_t length() const { return mSize; }
private:
void *mData;
size_t mSize;
};
CFDictionaryRef makeCFDictionary(unsigned count, ...); CFMutableDictionaryRef makeCFMutableDictionary(); CFMutableDictionaryRef makeCFMutableDictionary(unsigned count, ...); CFMutableDictionaryRef makeCFMutableDictionary(CFDictionaryRef dict);
CFDictionaryRef makeCFDictionaryFrom(CFDataRef data) CF_RETURNS_RETAINED;CFDictionaryRef makeCFDictionaryFrom(const void *data, size_t length) CF_RETURNS_RETAINED;
class CFDictionary : public CFCopyRef<CFDictionaryRef> {
typedef CFCopyRef<CFDictionaryRef> _Base;
public:
CFDictionary(CFDictionaryRef ref, OSStatus error) : _Base(ref), mDefaultError(error)
{ if (!ref) MacOSError::throwMe(error); }
CFDictionary(CFTypeRef ref, OSStatus error) : _Base(ref, error), mDefaultError(error)
{ if (!ref) MacOSError::throwMe(error); }
CFDictionary(OSStatus error) : _Base(NULL), mDefaultError(error) { }
using CFCopyRef<CFDictionaryRef>::get;
CFTypeRef get(CFStringRef key) { return CFDictionaryGetValue(*this, key); }
CFTypeRef get(const char *key) { return CFDictionaryGetValue(*this, CFTempString(key)); }
template <class CFType>
CFType get(CFStringRef key, OSStatus err = noErr) const
{
CFTypeRef elem = CFDictionaryGetValue(*this, key);
return CFRef<CFType>::check(elem, err ? err : mDefaultError);
}
template <class CFType>
CFType get(const char *key, OSStatus err = noErr) const
{ return get<CFType>(CFTempString(key), err); }
void apply(CFDictionaryApplierFunction func, void *context)
{ return CFDictionaryApplyFunction(*this, func, context); }
private:
template <class T>
struct Applier {
T *object;
void (T::*func)(CFTypeRef key, CFTypeRef value);
static void apply(CFTypeRef key, CFTypeRef value, void *context)
{ Applier *me = (Applier *)context; return ((me->object)->*(me->func))(key, value); }
};
public:
template <class T>
void apply(T *object, void (T::*func)(CFTypeRef key, CFTypeRef value))
{ Applier<T> app; app.object = object; app.func = func; return apply(app.apply, &app); }
private:
OSStatus mDefaultError;
};
CFDataRef cfLoadFile(CFURLRef url);
inline CFDataRef cfLoadFile(CFStringRef path) { return cfLoadFile(CFTempURL(path)); }
inline CFDataRef cfLoadFile(const std::string &path) { return cfLoadFile(CFTempURL(path)); }
inline CFDataRef cfLoadFile(const char *path) { return cfLoadFile(CFTempURL(path)); }
template <class Self>
Self projectPair(const Self &me)
{ return me; }
template <class First, class Second>
Second projectPair(const pair<First, Second> &me)
{ return me.second; }
template <class VectorBase, class CFRefType, VectorBase convert(CFRefType)>
class CFToVector {
public:
CFToVector(CFArrayRef arrayRef);
~CFToVector() { delete[] mVector; }
operator UInt32 () const { return mCount; }
operator VectorBase *() const { return mVector; }
bool empty() const { return mCount == 0; }
VectorBase *begin() const { return mVector; }
VectorBase *end() const { return mVector + mCount; }
VectorBase &operator [] (UInt32 ix) const { assert(ix < mCount); return mVector[ix]; }
private:
VectorBase *mVector;
UInt32 mCount;
};
template <class VectorBase, class CFRefType, VectorBase convert(CFRefType)>
CFToVector<VectorBase, CFRefType, convert>::CFToVector(CFArrayRef arrayRef)
{
if (arrayRef == NULL) {
mCount = 0;
mVector = NULL;
} else {
mCount = CFArrayGetCount(arrayRef);
mVector = new VectorBase[mCount];
for (UInt32 n = 0; n < mCount; n++)
mVector[n] = convert(CFRefType(CFArrayGetValueAtIndex(arrayRef, n)));
}
}
template <class Iterator, class Generator>
inline CFArrayRef makeCFArray(Generator &generate, Iterator first, Iterator last)
{
size_t size = distance(first, last);
auto_array<CFTypeRef> vec(size);
for (UInt32 n = 0; n < size; n++)
vec[n] = generate(projectPair(*first++));
assert(first == last);
return CFArrayCreate(NULL, (const void **)vec.get(), size, &kCFTypeArrayCallBacks);
}
template <class Container, class Generator>
inline CFArrayRef makeCFArray(Generator &generate, const Container &container)
{
return makeCFArray(generate, container.begin(), container.end());
}
CFArrayRef makeCFArray(CFIndex count, ...) CF_RETURNS_RETAINED;
CFMutableArrayRef makeCFMutableArray(CFIndex count, ...) CF_RETURNS_RETAINED;
}
#endif //_H_CFUTILITIES