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