]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | #include <libkern/OSAtomic.h> |
2 | #include <CoreFoundation/CoreFoundation.h> | |
3 | ||
4 | #include "CoreFoundationBasics.h" | |
5 | #include "Block.h" | |
6 | #include "TransformFactory.h" | |
7 | #include "Utilities.h" | |
8 | #include "syslog.h" | |
9 | #include "misc.h" | |
10 | ||
11 | using namespace std; | |
12 | ||
13 | ||
14 | const CFStringRef gInternalCFObjectName = CFSTR("SecTransform Internal Object"); | |
15 | const CFStringRef gInternalProtectedCFObjectName = CFSTR("SecTransform Internal Object (protected)"); | |
16 | ||
17 | struct RegisteredClassInfo | |
18 | { | |
19 | CFRuntimeClass mClass; | |
20 | CFTypeID mClassID; | |
21 | RegisteredClassInfo(); | |
22 | void Register(CFStringRef name); | |
23 | ||
24 | static const RegisteredClassInfo *Find(CFStringRef name); | |
25 | static dispatch_queue_t readWriteLock; | |
26 | static dispatch_once_t initializationGuard; | |
27 | static CFMutableDictionaryRef registeredInfos; | |
28 | }; | |
29 | ||
30 | dispatch_queue_t RegisteredClassInfo::readWriteLock; | |
31 | dispatch_once_t RegisteredClassInfo::initializationGuard; | |
32 | CFMutableDictionaryRef RegisteredClassInfo::registeredInfos; | |
33 | ||
34 | /* | |
35 | THE FOLLOWING FUNCTION REGISTERS YOUR CLASS. YOU MUST CALL YOUR CLASS INITIALIZER HERE! | |
36 | */ | |
37 | ||
38 | static CFErrorRef gNoMemory; | |
39 | ||
40 | CFErrorRef GetNoMemoryError() | |
41 | { | |
42 | return gNoMemory; | |
43 | } | |
44 | ||
45 | ||
46 | ||
47 | CFErrorRef GetNoMemoryErrorAndRetain() | |
48 | { | |
49 | return (CFErrorRef) CFRetain(gNoMemory); | |
50 | } | |
51 | ||
52 | ||
53 | ||
54 | static void CoreFoundationObjectRegister() | |
55 | { | |
56 | static dispatch_once_t gate = 0; | |
57 | ||
58 | dispatch_once(&gate, | |
59 | ^{ | |
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."); | |
63 | ||
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); | |
68 | ||
69 | // register any objects which may be exposed as API here | |
70 | ||
71 | // call for externalizable transforms. | |
72 | TransformFactory::Setup(); | |
73 | }); | |
74 | } | |
75 | ||
76 | ||
77 | ||
78 | RegisteredClassInfo::RegisteredClassInfo() | |
79 | { | |
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); | |
84 | }); | |
85 | } | |
86 | ||
87 | ||
88 | ||
89 | CoreFoundationObject::CoreFoundationObject(CFStringRef name) : mHolder(NULL), mObjectType(name) | |
90 | { | |
91 | } | |
92 | ||
93 | ||
94 | ||
95 | CoreFoundationObject::~CoreFoundationObject() | |
96 | { | |
97 | } | |
98 | ||
99 | ||
100 | ||
101 | CFHashCode CoreFoundationObject::Hash() | |
102 | { | |
103 | // Valid for address equality only, overload for something else. | |
104 | return (CFHashCode)mHolder; | |
105 | } | |
106 | ||
107 | void CoreFoundationObject::Finalize() | |
108 | { | |
109 | delete this; | |
110 | } | |
111 | ||
112 | ||
113 | std::string CoreFoundationObject::FormattingDescription(CFDictionaryRef options) | |
114 | { | |
115 | return "CoreFoundationObject"; | |
116 | } | |
117 | ||
118 | ||
119 | ||
120 | std::string CoreFoundationObject::DebugDescription() | |
121 | { | |
122 | return "CoreFoundationObject"; | |
123 | } | |
124 | ||
125 | ||
126 | ||
127 | Boolean CoreFoundationObject::Equal(const CoreFoundationObject* obj) | |
128 | { | |
129 | return mHolder == obj->mHolder; | |
130 | } | |
131 | ||
132 | ||
133 | ||
134 | static void FinalizeStub(CFTypeRef typeRef) | |
135 | { | |
136 | CoreFoundationHolder::ObjectFromCFType(typeRef)->Finalize(); | |
137 | } | |
138 | ||
139 | ||
140 | ||
141 | static Boolean IsEqualTo(CFTypeRef ref1, CFTypeRef ref2) | |
142 | { | |
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 | |
148 | // type) | |
149 | return false; | |
150 | } | |
151 | ||
152 | CoreFoundationHolder* tr1 = (CoreFoundationHolder*) ref1; | |
153 | CoreFoundationHolder* tr2 = (CoreFoundationHolder*) ref2; | |
154 | return tr1->mObject->Equal(tr2->mObject); | |
155 | } | |
156 | ||
157 | ||
158 | ||
159 | static CFHashCode MakeHash(CFTypeRef typeRef) | |
160 | { | |
161 | CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef; | |
162 | return tr->mObject->Hash(); | |
163 | } | |
164 | ||
165 | ||
166 | ||
167 | static CFStringRef MakeFormattingDescription(CFTypeRef typeRef, CFDictionaryRef formatOptions) | |
168 | { | |
169 | // get the string | |
170 | CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef; | |
171 | string desc = tr->mObject->FormattingDescription(formatOptions); | |
172 | ||
173 | if (desc.length() == 0) | |
174 | { | |
175 | return NULL; | |
176 | } | |
177 | ||
178 | // convert it to a CFString | |
179 | return CFStringCreateWithCString(NULL, desc.c_str(), kCFStringEncodingMacRoman); | |
180 | } | |
181 | ||
182 | ||
183 | static CFStringRef MakeDebugDescription(CFTypeRef typeRef) | |
184 | { | |
185 | // get the string | |
186 | CoreFoundationHolder* tr = (CoreFoundationHolder*) typeRef; | |
187 | string desc = tr->mObject->DebugDescription(); | |
188 | ||
189 | if (desc.length() == 0) | |
190 | { | |
191 | return NULL; | |
192 | } | |
193 | ||
194 | // convert it to a CFString | |
195 | return CFStringCreateWithCString(NULL, desc.c_str(), kCFStringEncodingMacRoman); | |
196 | } | |
197 | ||
198 | ||
199 | ||
200 | ||
201 | void CoreFoundationObject::RegisterObject(CFStringRef name, bool protectDelete) | |
202 | { | |
203 | RegisteredClassInfo *classRecord = new RegisteredClassInfo; | |
204 | ||
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); | |
211 | free(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); | |
221 | } | |
222 | ||
223 | ||
224 | ||
225 | CFTypeID CoreFoundationObject::FindObjectType(CFStringRef name) | |
226 | { | |
227 | const RegisteredClassInfo *classInfo = RegisteredClassInfo::Find(name); | |
228 | if (classInfo) { | |
229 | return classInfo->mClassID; | |
230 | } else { | |
231 | return _kCFRuntimeNotATypeID; | |
232 | } | |
233 | } | |
234 | ||
235 | const RegisteredClassInfo *RegisteredClassInfo::Find(CFStringRef name) | |
236 | { | |
237 | __block const RegisteredClassInfo *ret = NULL; | |
238 | dispatch_sync(RegisteredClassInfo::readWriteLock, ^(void) { | |
239 | ret = (const RegisteredClassInfo *)CFDictionaryGetValue(RegisteredClassInfo::registeredInfos, name); | |
240 | }); | |
241 | ||
242 | return ret; | |
243 | } | |
244 | ||
245 | void RegisteredClassInfo::Register(CFStringRef name) | |
246 | { | |
247 | dispatch_barrier_sync(RegisteredClassInfo::readWriteLock, ^(void) { | |
248 | CFDictionarySetValue(RegisteredClassInfo::registeredInfos, name, this); | |
249 | }); | |
250 | } | |
251 | ||
252 | CFStringRef CoreFoundationObject::GetTypeAsCFString() | |
253 | { | |
254 | return mObjectType; | |
255 | } | |
256 | ||
257 | ||
258 | ||
259 | CoreFoundationHolder* CoreFoundationHolder::MakeHolder(CFStringRef name, CoreFoundationObject* object) | |
260 | { | |
261 | // setup the CoreFoundation registry, just in case we need it. | |
262 | ||
263 | CoreFoundationObjectRegister(); | |
264 | ||
265 | CoreFoundationHolder* data = (CoreFoundationHolder*) _CFRuntimeCreateInstance(kCFAllocatorDefault, | |
266 | CoreFoundationObject::FindObjectType(name), | |
267 | sizeof(CoreFoundationHolder) - sizeof(CFRuntimeBase), | |
268 | NULL); | |
269 | data->mObject = object; | |
270 | object->SetHolder(data); | |
271 | ||
272 | return data; | |
273 | } | |
274 | ||
275 | ||
276 | ||
277 | CoreFoundationObject* CoreFoundationHolder::ObjectFromCFType(CFTypeRef type) | |
278 | { | |
279 | return ((CoreFoundationHolder*) type)->mObject; | |
280 | } | |
281 | ||
282 | ||
283 |