]> git.saurik.com Git - apple/cf.git/blob - CFPlugIn_Factory.c
CF-476.17.tar.gz
[apple/cf.git] / CFPlugIn_Factory.c
1 /*
2 * Copyright (c) 2008 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 /* CFPlugIn_Factory.c
24 Copyright (c) 1999-2007 Apple Inc. All rights reserved.
25 Responsibility: Doug Davidson
26 */
27
28 #include "CFBundle_Internal.h"
29 #include "CFInternal.h"
30
31 static CFSpinLock_t CFPlugInGlobalDataLock = CFSpinLockInit;
32 static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactory */
33 static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactory */
34
35 static void _CFPFactoryAddToTable(_CFPFactory *factory) {
36 __CFSpinLock(&CFPlugInGlobalDataLock);
37 if (_factoriesByFactoryID == NULL) {
38 CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL};
39 // Use default allocator
40 _factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks);
41 }
42 CFDictionarySetValue(_factoriesByFactoryID, factory->_uuid, factory);
43 __CFSpinUnlock(&CFPlugInGlobalDataLock);
44 }
45
46 static void _CFPFactoryRemoveFromTable(_CFPFactory *factory) {
47 __CFSpinLock(&CFPlugInGlobalDataLock);
48 if (_factoriesByFactoryID != NULL) {
49 CFDictionaryRemoveValue(_factoriesByFactoryID, factory->_uuid);
50 }
51 __CFSpinUnlock(&CFPlugInGlobalDataLock);
52 }
53
54 __private_extern__ _CFPFactory *_CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled) {
55 _CFPFactory *result = NULL;
56
57 __CFSpinLock(&CFPlugInGlobalDataLock);
58 if (_factoriesByFactoryID != NULL) {
59 result = (_CFPFactory *)CFDictionaryGetValue(_factoriesByFactoryID, factoryID);
60 if (result && result->_enabled != enabled) {
61 result = NULL;
62 }
63 }
64 __CFSpinUnlock(&CFPlugInGlobalDataLock);
65 return result;
66 }
67
68 static void _CFPFactoryDeallocate(_CFPFactory *factory) {
69 CFAllocatorRef allocator = factory->_allocator;
70 SInt32 c;
71
72 _CFPFactoryRemoveFromTable(factory);
73
74 if (factory->_plugIn) {
75 _CFPlugInRemoveFactory(factory->_plugIn, factory);
76 }
77
78 /* Remove all types for this factory. */
79 c = CFArrayGetCount(factory->_types);
80 while (c--) {
81 _CFPFactoryRemoveType(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c));
82 }
83 CFRelease(factory->_types);
84
85 if (factory->_funcName) {
86 CFRelease(factory->_funcName);
87 }
88
89 if (factory->_uuid) {
90 CFRelease(factory->_uuid);
91 }
92
93 CFAllocatorDeallocate(allocator, factory);
94 CFRelease(allocator);
95 }
96
97 static _CFPFactory *_CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factoryID) {
98 _CFPFactory *factory;
99 UInt32 size;
100 size = sizeof(_CFPFactory);
101 allocator = ((NULL == allocator) ? (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator()) : (CFAllocatorRef)CFRetain(allocator));
102 factory = (_CFPFactory *)CFAllocatorAllocate(allocator, size, 0);
103 if (NULL == factory) {
104 CFRelease(allocator);
105 return NULL;
106 }
107
108 factory->_allocator = allocator;
109
110 factory->_uuid = (CFUUIDRef)CFRetain(factoryID);
111 factory->_enabled = true;
112 factory->_instanceCount = 0;
113
114 _CFPFactoryAddToTable(factory);
115
116 factory->_types = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
117
118 return factory;
119 }
120
121 __private_extern__ _CFPFactory *_CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func) {
122 _CFPFactory *factory = _CFPFactoryCommonCreate(allocator, factoryID);
123
124 factory->_func = func;
125 factory->_plugIn = NULL;
126 factory->_funcName = NULL;
127
128 return factory;
129 }
130
131 __private_extern__ _CFPFactory *_CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName) {
132 _CFPFactory *factory = _CFPFactoryCommonCreate(allocator, factoryID);
133
134 factory->_func = NULL;
135 factory->_plugIn = plugIn;
136 if (plugIn) {
137 _CFPlugInAddFactory(plugIn, factory);
138 }
139 factory->_funcName = (funcName ? (CFStringRef)CFStringCreateCopy(allocator, funcName) : NULL);
140
141 return factory;
142 }
143
144 __private_extern__ CFUUIDRef _CFPFactoryGetFactoryID(_CFPFactory *factory) {
145 return factory->_uuid;
146 }
147
148 __private_extern__ CFPlugInRef _CFPFactoryGetPlugIn(_CFPFactory *factory) {
149 return factory->_plugIn;
150 }
151
152 __private_extern__ void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactory *factory, CFUUIDRef typeID) {
153 void *result = NULL;
154 if (factory->_enabled) {
155 if (factory->_func == NULL) {
156 factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName);
157 if (factory->_func == NULL) {
158 CFLog(__kCFLogPlugIn, CFSTR("Cannot find function pointer %@ for factory %@ in %@"), factory->_funcName, factory->_uuid, factory->_plugIn);
159 }
160 #if BINARY_SUPPORT_CFM
161 else {
162 // return values from CFBundleGetFunctionPointerForName will always be dyld, but
163 // we must force-fault them because pointers to glue code do not fault correctly
164 factory->_func = (void *)((uint32_t)(factory->_func) | 0x1);
165 }
166 #endif /* BINARY_SUPPORT_CFM */
167 }
168 if (factory->_func) {
169 // UPPGOOP
170 FAULT_CALLBACK((void **)&(factory->_func));
171 result = (void *)INVOKE_CALLBACK2(factory->_func, allocator, typeID);
172 }
173 } else {
174 CFLog(__kCFLogPlugIn, CFSTR("Factory %@ is disabled"), factory->_uuid);
175 }
176 return result;
177 }
178
179 __private_extern__ void _CFPFactoryDisable(_CFPFactory *factory) {
180 factory->_enabled = false;
181 if (factory->_instanceCount == 0) {
182 _CFPFactoryDeallocate(factory);
183 }
184 }
185
186 __private_extern__ Boolean _CFPFactoryIsEnabled(_CFPFactory *factory) {
187 return factory->_enabled;
188 }
189
190 __private_extern__ void _CFPFactoryFlushFunctionCache(_CFPFactory *factory) {
191 /* MF:!!! Assert that this factory belongs to a plugIn. */
192 /* This is called by the factory's plugIn when the plugIn unloads its code. */
193 factory->_func = NULL;
194 }
195
196 __private_extern__ void _CFPFactoryAddType(_CFPFactory *factory, CFUUIDRef typeID) {
197 CFMutableArrayRef array;
198
199 /* Add the type to the factory's type list */
200 CFArrayAppendValue(factory->_types, typeID);
201
202 /* Add the factory to the type's array of factories */
203 __CFSpinLock(&CFPlugInGlobalDataLock);
204 if (_factoriesByTypeID == NULL) {
205 // Create this from default allocator
206 _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
207 }
208 array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
209 if (array == NULL) {
210 CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL};
211 // Create this from default allocator
212 array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &_factoryArrayCallbacks);
213 CFDictionarySetValue(_factoriesByTypeID, typeID, array);
214 CFRelease(array);
215 }
216 CFArrayAppendValue(array, factory);
217 __CFSpinUnlock(&CFPlugInGlobalDataLock);
218 }
219
220 __private_extern__ void _CFPFactoryRemoveType(_CFPFactory *factory, CFUUIDRef typeID) {
221 /* Remove it from the factory's type list */
222 SInt32 idx;
223
224 idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
225 if (idx >=0) {
226 CFArrayRemoveValueAtIndex(factory->_types, idx);
227 }
228
229 /* Remove the factory from the type's list of factories */
230 __CFSpinLock(&CFPlugInGlobalDataLock);
231 if (_factoriesByTypeID != NULL) {
232 CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
233 if (array != NULL) {
234 idx = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), factory);
235 if (idx >=0) {
236 CFArrayRemoveValueAtIndex(array, idx);
237 if (CFArrayGetCount(array) == 0) {
238 CFDictionaryRemoveValue(_factoriesByTypeID, typeID);
239 }
240 }
241 }
242 }
243 __CFSpinUnlock(&CFPlugInGlobalDataLock);
244 }
245
246 __private_extern__ Boolean _CFPFactorySupportsType(_CFPFactory *factory, CFUUIDRef typeID) {
247 SInt32 idx;
248
249 idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
250 return ((idx >= 0) ? true : false);
251 }
252
253 __private_extern__ CFArrayRef _CFPFactoryFindForType(CFUUIDRef typeID) {
254 CFArrayRef result = NULL;
255
256 __CFSpinLock(&CFPlugInGlobalDataLock);
257 if (_factoriesByTypeID != NULL) {
258 result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
259 }
260 __CFSpinUnlock(&CFPlugInGlobalDataLock);
261
262 return result;
263 }
264
265 /* 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. */
266 __private_extern__ void _CFPFactoryAddInstance(_CFPFactory *factory) {
267 /* MF:!!! Assert that factory is enabled. */
268 factory->_instanceCount++;
269 if (factory->_plugIn) {
270 _CFPlugInAddPlugInInstance(factory->_plugIn);
271 }
272 }
273
274 __private_extern__ void _CFPFactoryRemoveInstance(_CFPFactory *factory) {
275 /* MF:!!! Assert that _instanceCount > 0. */
276 factory->_instanceCount--;
277 if (factory->_plugIn) {
278 _CFPlugInRemovePlugInInstance(factory->_plugIn);
279 }
280 if ((factory->_instanceCount == 0) && (!factory->_enabled)) {
281 _CFPFactoryDeallocate(factory);
282 }
283 }