1/*
2 * Copyright (c) 2000-2004,2011,2013-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#ifndef _SECCFOBJECT_H
27#define _SECCFOBJECT_H
28
29#include <CoreFoundation/CFRuntime.h>
30#include <new>
31#include "threading.h"
32
33namespace Security {
34
35class CFClass;
36
37#define SECCFFUNCTIONS(OBJTYPE, APIPTR, ERRCODE, CFCLASS) \
38\
39void *operator new(size_t size) throw(std::bad_alloc) \
40{ return SecCFObject::allocate(size, CFCLASS); } \
41\
42operator APIPTR() const \
43{ return (APIPTR)(this->operator CFTypeRef()); } \
44\
45OBJTYPE *retain() \
46{ SecCFObject::handle(true); return this; } \
47APIPTR handle(bool retain = true) \
48{ return (APIPTR)SecCFObject::handle(retain); } \
49\
50static OBJTYPE *required(APIPTR ptr) \
51{ if (OBJTYPE *p = dynamic_cast<OBJTYPE *>(SecCFObject::required(ptr, ERRCODE))) \
52	return p; else MacOSError::throwMe(ERRCODE); } \
53\
54static OBJTYPE *optional(APIPTR ptr) \
55{ if (SecCFObject *p = SecCFObject::optional(ptr)) \
56	if (OBJTYPE *pp = dynamic_cast<OBJTYPE *>(p)) return pp; else MacOSError::throwMe(ERRCODE); \
57  else return NULL; }
58
59#define SECALIGNUP(SIZE, ALIGNMENT) (((SIZE - 1) & ~(ALIGNMENT - 1)) + ALIGNMENT)
60
61struct SecRuntimeBase: CFRuntimeBase
62{
63	bool isNew;
64};
65
66class SecCFObject
67{
68private:
69	void *operator new(size_t) throw(std::bad_alloc);
70
71	// Align up to a multiple of 16 bytes
72	static const size_t kAlignedRuntimeSize = SECALIGNUP(sizeof(SecRuntimeBase), 4);
73
74    uint32_t mRetainCount;
75    OSSpinLock mRetainSpinLock;
76
77public:
78	// For use by SecPointer only. Returns true once the first time it's called after the object has been created.
79	bool isNew()
80	{
81		SecRuntimeBase *base = reinterpret_cast<SecRuntimeBase *>(reinterpret_cast<uint8_t *>(this) - kAlignedRuntimeSize);
82		bool isNew = base->isNew;
83		base->isNew = false;
84		return isNew;
85	}
86
87	static SecCFObject *optional(CFTypeRef) throw();
88	static SecCFObject *required(CFTypeRef, OSStatus error);
89	static void *allocate(size_t size, const CFClass &cfclass) throw(std::bad_alloc);
90
91    SecCFObject();
92	virtual ~SecCFObject();
93    uint32_t updateRetainCount(intptr_t direction, uint32_t *oldCount);
94    uint32_t getRetainCount() {return updateRetainCount(0, NULL);}
95
96	static void operator delete(void *object) throw();
97	operator CFTypeRef() const throw()
98	{
99		return reinterpret_cast<CFTypeRef>(reinterpret_cast<const uint8_t *>(this) - kAlignedRuntimeSize);
100	}
101
102	// This bumps up the retainCount by 1, by calling CFRetain(), iff retain is true
103	CFTypeRef handle(bool retain = true) throw();
104
105    virtual bool equal(SecCFObject &other);
106    virtual CFHashCode hash();
107	virtual CFStringRef copyFormattingDesc(CFDictionaryRef dict);
108	virtual CFStringRef copyDebugDesc();
109	virtual void aboutToDestruct();
110	virtual Mutex* getMutexForObject();
111    virtual bool mayDelete();
112};
113
114//
115// A pointer type for SecCFObjects.
116// T must be derived from SecCFObject.
117//
118class SecPointerBase
119{
120public:
121	SecPointerBase() : ptr(NULL)
122	{}
123	SecPointerBase(const SecPointerBase& p);
124	SecPointerBase(SecCFObject *p);
125	~SecPointerBase();
126	SecPointerBase& operator = (const SecPointerBase& p);
127
128protected:
129 	void assign(SecCFObject * p);
130	void copy(SecCFObject * p);
131	SecCFObject *ptr;
132};
133
134template <class T>
135class SecPointer : public SecPointerBase
136{
137public:
138	SecPointer() : SecPointerBase() {}
139	SecPointer(const SecPointer& p) : SecPointerBase(p) {}
140	SecPointer(T *p): SecPointerBase(p) {}
141	SecPointer &operator =(T *p) { this->assign(p); return *this; }
142	SecPointer &take(T *p) { this->copy(p); return *this; }
143	T *yield() { T *result = static_cast<T *>(ptr); ptr = NULL; return result; }
144
145	// dereference operations
146    T* get () const				{ return static_cast<T*>(ptr); }	// mimic auto_ptr
147	operator T * () const		{ return static_cast<T*>(ptr); }
148	T * operator -> () const	{ return static_cast<T*>(ptr); }
149	T & operator * () const		{ return *static_cast<T*>(ptr); }
150};
151
152template <class T>
153bool operator <(const SecPointer<T> &r1, const SecPointer<T> &r2)
154{
155	T *p1 = r1.get(), *p2 = r2.get();
156	return p1 && p2 ? *p1 < *p2 : p1 < p2;
157}
158
159template <class T>
160bool operator ==(const SecPointer<T> &r1, const SecPointer<T> &r2)
161{
162	T *p1 = r1.get(), *p2 = r2.get();
163	return p1 && p2 ? *p1 == *p2 : p1 == p2;
164}
165
166template <class T>
167bool operator !=(const SecPointer<T> &r1, const SecPointer<T> &r2)
168{
169	T *p1 = r1.get(), *p2 = r2.get();
170	return p1 && p2 ? *p1 != *p2 : p1 != p2;
171}
172
173} // end namespace Security
174
175
176#endif
177