#ifndef _SECCFOBJECT_H
#define _SECCFOBJECT_H
#include <CoreFoundation/CFRuntime.h>
#include <new>
#include "threading.h"
#if( __cplusplus <= 201103L)
#include <stdatomic.h>
#endif
namespace Security {
class CFClass;
#define SECCFFUNCTIONS_BASE(OBJTYPE, APIPTR) \
\
operator APIPTR() const \
{ return (APIPTR)(this->operator CFTypeRef()); } \
\
OBJTYPE *retain() \
{ SecCFObject::handle(true); return this; } \
APIPTR handle(bool retain = true) \
{ return (APIPTR)SecCFObject::handle(retain); }
#define SECCFFUNCTIONS_CREATABLE(OBJTYPE, APIPTR, CFCLASS) \
SECCFFUNCTIONS_BASE(OBJTYPE, APIPTR)\
\
void *operator new(size_t size) throw(std::bad_alloc) \
{ return SecCFObject::allocate(size, CFCLASS); }
#define SECCFFUNCTIONS(OBJTYPE, APIPTR, ERRCODE, CFCLASS) \
SECCFFUNCTIONS_CREATABLE(OBJTYPE, APIPTR, CFCLASS) \
\
static OBJTYPE *required(APIPTR ptr) \
{ if (OBJTYPE *p = dynamic_cast<OBJTYPE *>(SecCFObject::required(ptr, ERRCODE))) \
return p; else MacOSError::throwMe(ERRCODE); } \
\
static OBJTYPE *optional(APIPTR ptr) \
{ if (SecCFObject *p = SecCFObject::optional(ptr)) \
if (OBJTYPE *pp = dynamic_cast<OBJTYPE *>(p)) return pp; else MacOSError::throwMe(ERRCODE); \
else return NULL; }
#define SECALIGNUP(SIZE, ALIGNMENT) (((SIZE - 1) & ~(ALIGNMENT - 1)) + ALIGNMENT)
struct SecRuntimeBase: CFRuntimeBase
{
atomic_flag isOld;
};
class SecCFObject
{
private:
void *operator new(size_t) throw(std::bad_alloc);
static const size_t kAlignedRuntimeSize = SECALIGNUP(sizeof(SecRuntimeBase), 4);
uint32_t mRetainCount;
OSSpinLock mRetainSpinLock;
public:
bool isNew()
{
SecRuntimeBase *base = reinterpret_cast<SecRuntimeBase *>(reinterpret_cast<uint8_t *>(this) - kAlignedRuntimeSize);
return !atomic_flag_test_and_set(&(base->isOld));
}
static SecCFObject *optional(CFTypeRef) throw();
static SecCFObject *required(CFTypeRef, OSStatus error);
static void *allocate(size_t size, const CFClass &cfclass) throw(std::bad_alloc);
SecCFObject();
virtual ~SecCFObject();
uint32_t updateRetainCount(intptr_t direction, uint32_t *oldCount);
uint32_t getRetainCount() {return updateRetainCount(0, NULL);}
static void operator delete(void *object) throw();
virtual operator CFTypeRef() const throw()
{
return reinterpret_cast<CFTypeRef>(reinterpret_cast<const uint8_t *>(this) - kAlignedRuntimeSize);
}
CFTypeRef handle(bool retain = true) throw();
virtual bool equal(SecCFObject &other);
virtual CFHashCode hash();
virtual CFStringRef copyFormattingDesc(CFDictionaryRef dict);
virtual CFStringRef copyDebugDesc();
virtual void aboutToDestruct();
virtual Mutex* getMutexForObject() const;
virtual bool mayDelete();
};
class SecPointerBase
{
public:
SecPointerBase() : ptr(NULL)
{}
SecPointerBase(const SecPointerBase& p);
SecPointerBase(SecCFObject *p);
~SecPointerBase();
SecPointerBase& operator = (const SecPointerBase& p);
protected:
void assign(SecCFObject * p);
void copy(SecCFObject * p);
SecCFObject *ptr;
};
template <class T>
class SecPointer : public SecPointerBase
{
public:
SecPointer() : SecPointerBase() {}
SecPointer(const SecPointer& p) : SecPointerBase(p) {}
SecPointer(T *p): SecPointerBase(p) {}
SecPointer &operator =(T *p) { this->assign(p); return *this; }
SecPointer &take(T *p) { this->copy(p); return *this; }
T *yield() { T *result = static_cast<T *>(ptr); ptr = NULL; return result; }
T* get () const { return static_cast<T*>(ptr); } operator T * () const { return static_cast<T*>(ptr); }
T * operator -> () const { return static_cast<T*>(ptr); }
T & operator * () const { return *static_cast<T*>(ptr); }
};
template <class T>
bool operator <(const SecPointer<T> &r1, const SecPointer<T> &r2)
{
T *p1 = r1.get(), *p2 = r2.get();
return p1 && p2 ? *p1 < *p2 : p1 < p2;
}
template <class T>
bool operator ==(const SecPointer<T> &r1, const SecPointer<T> &r2)
{
T *p1 = r1.get(), *p2 = r2.get();
return p1 && p2 ? *p1 == *p2 : p1 == p2;
}
template <class T>
bool operator !=(const SecPointer<T> &r1, const SecPointer<T> &r2)
{
T *p1 = r1.get(), *p2 = r2.get();
return p1 && p2 ? *p1 != *p2 : p1 != p2;
}
}
#endif