]> git.saurik.com Git - apple/cf.git/blob - CFPlugIn_Factory.c
CF-1151.16.tar.gz
[apple/cf.git] / CFPlugIn_Factory.c
1 /*
2 * Copyright (c) 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 /* CFPlugIn_Factory.c
25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
27 */
28
29 #include "CFBundle_Internal.h"
30 #include "CFInternal.h"
31
32 static CFTypeID __kCFPFactoryTypeID = _kCFRuntimeNotATypeID;
33
34 struct __CFPFactory {
35 CFRuntimeBase _base;
36
37 CFUUIDRef _uuid;
38 Boolean _enabled;
39 char _padding[3];
40
41 CFPlugInFactoryFunction _func;
42
43 CFPlugInRef _plugIn;
44 CFStringRef _funcName;
45
46 CFMutableArrayRef _types;
47 CFLock_t _lock;
48 };
49
50 static void _CFPFactoryDeallocate(CFTypeRef factory);
51
52 static const CFRuntimeClass __CFPFactoryClass = {
53 0,
54 "_CFPFactory",
55 NULL, // init
56 NULL, // copy
57 _CFPFactoryDeallocate,
58 NULL, // equal
59 NULL, // hash
60 NULL, // formatting desc
61 NULL, // debug desc
62 };
63
64 CF_PRIVATE void __CFPFactoryInitialize(void) {
65 static dispatch_once_t initOnce;
66 dispatch_once(&initOnce, ^{ __kCFPFactoryTypeID = _CFRuntimeRegisterClass(&__CFPFactoryClass); });
67 }
68
69 static CFTypeID _CFPFactoryGetTypeID(void) {
70 return __kCFPFactoryTypeID;
71 }
72
73 static CFLock_t CFPlugInGlobalDataLock = CFLockInit;
74 static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactoryRef */
75 static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactoryRef */
76
77 static void _CFPFactoryAddToTable(_CFPFactoryRef factory) {
78 __CFLock(&factory->_lock);
79 CFUUIDRef uuid = (CFUUIDRef)CFRetain(factory->_uuid);
80 CFRetain(factory);
81 __CFUnlock(&factory->_lock);
82
83 __CFLock(&CFPlugInGlobalDataLock);
84 if (!_factoriesByFactoryID) {
85 CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL};
86 _factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks);
87 }
88 CFDictionarySetValue(_factoriesByFactoryID, uuid, factory);
89 __CFUnlock(&CFPlugInGlobalDataLock);
90
91 if (uuid) CFRelease(uuid);
92 CFRelease(factory);
93 }
94
95 static void _CFPFactoryRemoveFromTable(_CFPFactoryRef factory) {
96 __CFLock(&factory->_lock);
97 CFUUIDRef uuid = factory->_uuid;
98 if (uuid) CFRetain(uuid);
99 __CFUnlock(&factory->_lock);
100
101 __CFLock(&CFPlugInGlobalDataLock);
102 if (uuid && _factoriesByTypeID) CFDictionaryRemoveValue(_factoriesByFactoryID, uuid);
103 __CFUnlock(&CFPlugInGlobalDataLock);
104
105 if (uuid) CFRelease(uuid);
106 }
107
108 CF_PRIVATE _CFPFactoryRef _CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled) {
109 _CFPFactoryRef result = NULL;
110
111 __CFLock(&CFPlugInGlobalDataLock);
112 if (_factoriesByFactoryID) {
113 result = (_CFPFactoryRef )CFDictionaryGetValue(_factoriesByFactoryID, factoryID);
114 if (result && result->_enabled != enabled) result = NULL;
115 }
116 __CFUnlock(&CFPlugInGlobalDataLock);
117 return result;
118 }
119
120 static void _CFPFactoryDeallocate(CFTypeRef ty) {
121 SInt32 c;
122 _CFPFactoryRef factory = (_CFPFactoryRef)ty;
123
124 _CFPFactoryRemoveFromTable(factory);
125
126 if (factory->_plugIn) {
127 _CFPlugInRemoveFactory(factory->_plugIn, factory);
128 CFRelease(factory->_plugIn);
129 }
130
131 /* Remove all types for this factory. */
132 c = CFArrayGetCount(factory->_types);
133 while (c-- > 0) _CFPFactoryRemoveType(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c));
134 CFRelease(factory->_types);
135
136 if (factory->_funcName) CFRelease(factory->_funcName);
137 if (factory->_uuid) CFRelease(factory->_uuid);
138 }
139
140 static _CFPFactoryRef _CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factoryID) {
141 _CFPFactoryRef factory;
142 uint32_t size;
143 size = sizeof(struct __CFPFactory) - sizeof(CFRuntimeBase);
144 factory = (_CFPFactoryRef)_CFRuntimeCreateInstance(allocator, _CFPFactoryGetTypeID(), size, NULL);
145 if (!factory) return NULL;
146
147 factory->_uuid = (CFUUIDRef)CFRetain(factoryID);
148 factory->_enabled = true;
149 factory->_types = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
150 factory->_lock = CFLockInit; // WARNING: grab global lock before this lock
151
152 _CFPFactoryAddToTable(factory);
153
154 return factory;
155 }
156
157 CF_PRIVATE _CFPFactoryRef _CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func) {
158 _CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID);
159
160 __CFLock(&factory->_lock);
161 factory->_func = func;
162 factory->_plugIn = NULL;
163 factory->_funcName = NULL;
164 __CFUnlock(&factory->_lock);
165
166 return factory;
167 }
168
169 CF_PRIVATE _CFPFactoryRef _CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName) {
170 _CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID);
171
172 __CFLock(&factory->_lock);
173 factory->_func = NULL;
174 factory->_plugIn = (CFPlugInRef)CFRetain(plugIn);
175 if (plugIn) _CFPlugInAddFactory(plugIn, factory);
176 factory->_funcName = (funcName ? (CFStringRef)CFStringCreateCopy(allocator, funcName) : NULL);
177 __CFUnlock(&factory->_lock);
178
179 return factory;
180 }
181
182 CF_PRIVATE CFUUIDRef _CFPFactoryCopyFactoryID(_CFPFactoryRef factory) {
183 __CFLock(&factory->_lock);
184 CFUUIDRef uuid = factory->_uuid;
185 if (uuid) CFRetain(uuid);
186 __CFUnlock(&factory->_lock);
187 return uuid;
188 }
189
190 CF_PRIVATE CFPlugInRef _CFPFactoryCopyPlugIn(_CFPFactoryRef factory) {
191 __CFLock(&factory->_lock);
192 CFPlugInRef result = factory->_plugIn;
193 if (result) CFRetain(result);
194 __CFUnlock(&factory->_lock);
195 return result;
196 }
197
198 CF_PRIVATE void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactoryRef factory, CFUUIDRef typeID) {
199 void *result = NULL;
200
201 __CFLock(&factory->_lock);
202 if (factory->_enabled) {
203 if (!factory->_func) {
204 factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName);
205 if (!factory->_func) CFLog(__kCFLogPlugIn, CFSTR("Cannot find function pointer %@ for factory %@ in %@"), factory->_funcName, factory->_uuid, factory->_plugIn);
206 }
207 if (factory->_func) {
208 // UPPGOOP
209 CFPlugInFactoryFunction f = factory->_func;
210 __CFUnlock(&factory->_lock);
211 FAULT_CALLBACK((void **)&(f));
212 result = (void *)INVOKE_CALLBACK2(f, allocator, typeID);
213 __CFLock(&factory->_lock);
214 }
215 } else {
216 CFLog(__kCFLogPlugIn, CFSTR("Factory %@ is disabled"), factory->_uuid);
217 }
218 __CFUnlock(&factory->_lock);
219
220 return result;
221 }
222
223 CF_PRIVATE void _CFPFactoryDisable(_CFPFactoryRef factory) {
224 __CFLock(&factory->_lock);
225 factory->_enabled = false;
226 __CFUnlock(&factory->_lock);
227 CFRelease(factory);
228 }
229
230 CF_PRIVATE void _CFPFactoryFlushFunctionCache(_CFPFactoryRef factory) {
231 /* MF:!!! Assert that this factory belongs to a plugIn. */
232 /* This is called by the factory's plugIn when the plugIn unloads its code. */
233 __CFLock(&factory->_lock);
234 factory->_func = NULL;
235 __CFUnlock(&factory->_lock);
236 }
237
238 CF_PRIVATE void _CFPFactoryAddType(_CFPFactoryRef factory, CFUUIDRef typeID) {
239 /* Add the factory to the type's array of factories */
240 __CFLock(&factory->_lock);
241 /* Add the type to the factory's type list */
242 CFArrayAppendValue(factory->_types, typeID);
243 __CFUnlock(&factory->_lock);
244
245 __CFLock(&CFPlugInGlobalDataLock);
246 if (!_factoriesByTypeID) _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
247 CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
248 if (!array) {
249 CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL};
250 // Create this from default allocator
251 array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &_factoryArrayCallbacks);
252 CFDictionarySetValue(_factoriesByTypeID, typeID, array);
253 CFRelease(array);
254 }
255 CFArrayAppendValue(array, factory);
256 __CFUnlock(&CFPlugInGlobalDataLock);
257 }
258
259 CF_PRIVATE void _CFPFactoryRemoveType(_CFPFactoryRef factory, CFUUIDRef typeID) {
260 /* Remove it from the factory's type list */
261 SInt32 idx;
262
263 __CFLock(&factory->_lock);
264 idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
265 if (idx >= 0) CFArrayRemoveValueAtIndex(factory->_types, idx);
266 __CFUnlock(&factory->_lock);
267
268 /* Remove the factory from the type's list of factories */
269 __CFLock(&CFPlugInGlobalDataLock);
270 if (_factoriesByTypeID) {
271 CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
272 if (array) {
273 idx = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), factory);
274 if (idx >= 0) {
275 CFArrayRemoveValueAtIndex(array, idx);
276 if (CFArrayGetCount(array) == 0) CFDictionaryRemoveValue(_factoriesByTypeID, typeID);
277 }
278 }
279 }
280 __CFUnlock(&CFPlugInGlobalDataLock);
281 }
282
283 CF_PRIVATE Boolean _CFPFactorySupportsType(_CFPFactoryRef factory, CFUUIDRef typeID) {
284 SInt32 idx;
285
286 __CFLock(&factory->_lock);
287 idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
288 __CFUnlock(&factory->_lock);
289
290 return (idx >= 0 ? true : false);
291 }
292
293 CF_PRIVATE CFArrayRef _CFPFactoryFindCopyForType(CFUUIDRef typeID) {
294 CFArrayRef result = NULL;
295 __CFLock(&CFPlugInGlobalDataLock);
296 if (_factoriesByTypeID) {
297 result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
298 if (result) CFRetain(result);
299 }
300 __CFUnlock(&CFPlugInGlobalDataLock);
301
302 return result;
303 }
304
305 /* These methods are called by CFPlugInInstance when an instance is created or destroyed. If a factory's instance count goes to 0 and the factory has been disabled, the factory is destroyed. */
306 CF_PRIVATE void _CFPFactoryAddInstance(_CFPFactoryRef factory) {
307 /* MF:!!! Assert that factory is enabled. */
308 CFRetain(factory);
309 __CFLock(&factory->_lock);
310 CFPlugInRef plugin = factory->_plugIn;
311 if (plugin) CFRetain(plugin);
312 __CFUnlock(&factory->_lock);
313 if (plugin) {
314 _CFPlugInAddPlugInInstance(plugin);
315 CFRelease(plugin);
316 }
317 }
318
319 CF_PRIVATE void _CFPFactoryRemoveInstance(_CFPFactoryRef factory) {
320 __CFLock(&factory->_lock);
321 CFPlugInRef plugin = factory->_plugIn;
322 if (plugin) CFRetain(plugin);
323 __CFUnlock(&factory->_lock);
324 if (plugin) {
325 _CFPlugInRemovePlugInInstance(factory->_plugIn);
326 CFRelease(plugin);
327 }
328 CFRelease(factory);
329 }