1 #include <libkern/OSAtomic.h>
2 #include <CoreFoundation/CoreFoundation.h>
4 #include "CoreFoundationBasics.h"
6 #include "TransformFactory.h"
14 const CFStringRef gInternalCFObjectName
= CFSTR("SecTransform Internal Object");
15 const CFStringRef gInternalProtectedCFObjectName
= CFSTR("SecTransform Internal Object (protected)");
17 struct RegisteredClassInfo
19 CFRuntimeClass mClass
;
21 RegisteredClassInfo();
22 void Register(CFStringRef name
);
24 static const RegisteredClassInfo
*Find(CFStringRef name
);
25 static dispatch_queue_t readWriteLock
;
26 static dispatch_once_t initializationGuard
;
27 static CFMutableDictionaryRef registeredInfos
;
30 dispatch_queue_t
RegisteredClassInfo::readWriteLock
;
31 dispatch_once_t
RegisteredClassInfo::initializationGuard
;
32 CFMutableDictionaryRef
RegisteredClassInfo::registeredInfos
;
35 THE FOLLOWING FUNCTION REGISTERS YOUR CLASS. YOU MUST CALL YOUR CLASS INITIALIZER HERE!
38 static CFErrorRef gNoMemory
;
40 CFErrorRef
GetNoMemoryError()
47 CFErrorRef
GetNoMemoryErrorAndRetain()
49 return (CFErrorRef
) CFRetain(gNoMemory
);
54 static void CoreFoundationObjectRegister()
56 static dispatch_once_t gate
= 0;
60 // Init NoMemory here, so other places we can safely return it (otherwise we might
61 // not have enough memory to allocate the CFError)
62 gNoMemory
= CreateGenericErrorRef(kCFErrorDomainPOSIX
, ENOMEM
, "Out of memory.");
64 // only one registration for internal objects, cuts down on how many objects
65 // we register in the CF type table
66 CoreFoundationObject::RegisterObject(gInternalCFObjectName
, false);
67 CoreFoundationObject::RegisterObject(gInternalProtectedCFObjectName
, true);
69 // register any objects which may be exposed as API here
71 // call for externalizable transforms.
72 TransformFactory::Setup();
78 RegisteredClassInfo::RegisteredClassInfo()
80 memset(&mClass
, 0, sizeof(mClass
));
81 dispatch_once(&RegisteredClassInfo::initializationGuard
, ^(void) {
82 RegisteredClassInfo::readWriteLock
= dispatch_queue_create("com.apple.security.transform.cfobject.RegisteredClassInfo", DISPATCH_QUEUE_CONCURRENT
);
83 RegisteredClassInfo::registeredInfos
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, NULL
);
89 CoreFoundationObject::CoreFoundationObject(CFStringRef name
) : mHolder(NULL
), mObjectType(name
)
95 CoreFoundationObject::~CoreFoundationObject()
101 CFHashCode
CoreFoundationObject::Hash()
103 // Valid for address equality only, overload for something else.
104 return (CFHashCode
)mHolder
;
107 void CoreFoundationObject::Finalize()
113 std::string
CoreFoundationObject::FormattingDescription(CFDictionaryRef options
)
115 return "CoreFoundationObject";
120 std::string
CoreFoundationObject::DebugDescription()
122 return "CoreFoundationObject";
127 Boolean
CoreFoundationObject::Equal(const CoreFoundationObject
* obj
)
129 return mHolder
== obj
->mHolder
;
134 static void FinalizeStub(CFTypeRef typeRef
)
136 CoreFoundationHolder::ObjectFromCFType(typeRef
)->Finalize();
141 static Boolean
IsEqualTo(CFTypeRef ref1
, CFTypeRef ref2
)
143 if (CFGetTypeID(ref1
) != CFGetTypeID(ref2
)) {
144 // If ref2 isn't a CoreFoundatonHolder treating
145 // it like one is likely to crash. (One could
146 // argue that we should check to see if ref2
147 // is *any* CoreFoundationHolder registered
152 CoreFoundationHolder
* tr1
= (CoreFoundationHolder
*) ref1
;
153 CoreFoundationHolder
* tr2
= (CoreFoundationHolder
*) ref2
;
154 return tr1
->mObject
->Equal(tr2
->mObject
);
159 static CFHashCode
MakeHash(CFTypeRef typeRef
)
161 CoreFoundationHolder
* tr
= (CoreFoundationHolder
*) typeRef
;
162 return tr
->mObject
->Hash();
167 static CFStringRef
MakeFormattingDescription(CFTypeRef typeRef
, CFDictionaryRef formatOptions
)
170 CoreFoundationHolder
* tr
= (CoreFoundationHolder
*) typeRef
;
171 string desc
= tr
->mObject
->FormattingDescription(formatOptions
);
173 if (desc
.length() == 0)
178 // convert it to a CFString
179 return CFStringCreateWithCString(NULL
, desc
.c_str(), kCFStringEncodingMacRoman
);
183 static CFStringRef
MakeDebugDescription(CFTypeRef typeRef
)
186 CoreFoundationHolder
* tr
= (CoreFoundationHolder
*) typeRef
;
187 string desc
= tr
->mObject
->DebugDescription();
189 if (desc
.length() == 0)
194 // convert it to a CFString
195 return CFStringCreateWithCString(NULL
, desc
.c_str(), kCFStringEncodingMacRoman
);
201 void CoreFoundationObject::RegisterObject(CFStringRef name
, bool protectDelete
)
203 RegisteredClassInfo
*classRecord
= new RegisteredClassInfo
;
205 classRecord
->mClass
.version
= 0;
206 // XXX: this is kind of lame, "name" is almost always a CFSTR, so it would
207 // be best to use the CFStringGetPtr result AND hold a reference to the
208 // name string, but fall back to utf8... (note there is no unRegisterObject)
209 char *utf8_name
= utf8(name
);
210 classRecord
->mClass
.className
= strdup(utf8_name
);
212 classRecord
->mClass
.init
= NULL
;
213 classRecord
->mClass
.copy
= NULL
;
214 classRecord
->mClass
.finalize
= protectDelete
? NULL
: FinalizeStub
;
215 classRecord
->mClass
.equal
= IsEqualTo
;
216 classRecord
->mClass
.hash
= MakeHash
;
217 classRecord
->mClass
.copyFormattingDesc
= MakeFormattingDescription
;
218 classRecord
->mClass
.copyDebugDesc
= MakeDebugDescription
;
219 classRecord
->mClassID
= _CFRuntimeRegisterClass((const CFRuntimeClass
* const)&classRecord
->mClass
);
220 classRecord
->Register(name
);
225 CFTypeID
CoreFoundationObject::FindObjectType(CFStringRef name
)
227 const RegisteredClassInfo
*classInfo
= RegisteredClassInfo::Find(name
);
229 return classInfo
->mClassID
;
231 return _kCFRuntimeNotATypeID
;
235 const RegisteredClassInfo
*RegisteredClassInfo::Find(CFStringRef name
)
237 __block
const RegisteredClassInfo
*ret
= NULL
;
238 dispatch_sync(RegisteredClassInfo::readWriteLock
, ^(void) {
239 ret
= (const RegisteredClassInfo
*)CFDictionaryGetValue(RegisteredClassInfo::registeredInfos
, name
);
245 void RegisteredClassInfo::Register(CFStringRef name
)
247 dispatch_barrier_sync(RegisteredClassInfo::readWriteLock
, ^(void) {
248 CFDictionarySetValue(RegisteredClassInfo::registeredInfos
, name
, this);
252 CFStringRef
CoreFoundationObject::GetTypeAsCFString()
259 CoreFoundationHolder
* CoreFoundationHolder::MakeHolder(CFStringRef name
, CoreFoundationObject
* object
)
261 // setup the CoreFoundation registry, just in case we need it.
263 CoreFoundationObjectRegister();
265 CoreFoundationHolder
* data
= (CoreFoundationHolder
*) _CFRuntimeCreateInstance(kCFAllocatorDefault
,
266 CoreFoundationObject::FindObjectType(name
),
267 sizeof(CoreFoundationHolder
) - sizeof(CFRuntimeBase
),
269 data
->mObject
= object
;
270 object
->SetHolder(data
);
277 CoreFoundationObject
* CoreFoundationHolder::ObjectFromCFType(CFTypeRef type
)
279 return ((CoreFoundationHolder
*) type
)->mObject
;