]> git.saurik.com Git - apple/cf.git/blame - CFPlugIn_PlugIn.c
CF-476.18.tar.gz
[apple/cf.git] / CFPlugIn_PlugIn.c
CommitLineData
9ce05555 1/*
bd5b749c 2 * Copyright (c) 2008 Apple Inc. All rights reserved.
9ce05555
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
9ce05555
A
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_PlugIn.c
bd5b749c 24 Copyright (c) 1999-2007 Apple Inc. All rights reserved.
9ce05555
A
25 Responsibility: Doug Davidson
26*/
27
28#include "CFBundle_Internal.h"
29#include "CFInternal.h"
30
0ae65c4b 31
9ce05555
A
32static void _registerFactory(const void *key, const void *val, void *context) {
33 CFStringRef factoryIDStr = (CFStringRef)key;
34 CFStringRef factoryFuncStr = (CFStringRef)val;
35 CFBundleRef bundle = (CFBundleRef)context;
bd5b749c
A
36 CFUUIDRef factoryID = (CFGetTypeID(factoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(kCFAllocatorSystemDefault, factoryIDStr) : NULL;
37 if (NULL == factoryID) factoryID = (CFUUIDRef)CFRetain(factoryIDStr);
9ce05555
A
38 if (CFGetTypeID(factoryFuncStr) != CFStringGetTypeID() || CFStringGetLength(factoryFuncStr) <= 0) factoryFuncStr = NULL;
39 CFPlugInRegisterFactoryFunctionByName(factoryID, bundle, factoryFuncStr);
40 if (NULL != factoryID) CFRelease(factoryID);
41}
42
43static void _registerType(const void *key, const void *val, void *context) {
44 CFStringRef typeIDStr = (CFStringRef)key;
45 CFArrayRef factoryIDStrArray = (CFArrayRef)val;
46 CFBundleRef bundle = (CFBundleRef)context;
47 SInt32 i, c = (CFGetTypeID(factoryIDStrArray) == CFArrayGetTypeID()) ? CFArrayGetCount(factoryIDStrArray) : 0;
48 CFStringRef curFactoryIDStr;
bd5b749c 49 CFUUIDRef typeID = (CFGetTypeID(typeIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(kCFAllocatorSystemDefault, typeIDStr) : NULL;
9ce05555 50 CFUUIDRef curFactoryID;
bd5b749c 51 if (NULL == typeID) typeID = (CFUUIDRef)CFRetain(typeIDStr);
9ce05555
A
52 if (0 == c && (CFGetTypeID(factoryIDStrArray) != CFArrayGetTypeID())) {
53 curFactoryIDStr = (CFStringRef)val;
54 curFactoryID = (CFGetTypeID(curFactoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(CFGetAllocator(bundle), curFactoryIDStr) : NULL;
bd5b749c 55 if (NULL == curFactoryID) curFactoryID = (CFUUIDRef)CFRetain(curFactoryIDStr);
9ce05555
A
56 CFPlugInRegisterPlugInType(curFactoryID, typeID);
57 if (NULL != curFactoryID) CFRelease(curFactoryID);
58 } else for (i=0; i<c; i++) {
59 curFactoryIDStr = (CFStringRef)CFArrayGetValueAtIndex(factoryIDStrArray, i);
60 curFactoryID = (CFGetTypeID(curFactoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(CFGetAllocator(bundle), curFactoryIDStr) : NULL;
bd5b749c 61 if (NULL == curFactoryID) curFactoryID = (CFUUIDRef)CFRetain(curFactoryIDStr);
9ce05555
A
62 CFPlugInRegisterPlugInType(curFactoryID, typeID);
63 if (NULL != curFactoryID) CFRelease(curFactoryID);
64 }
65 if (NULL != typeID) CFRelease(typeID);
66}
67
d8925383
A
68__private_extern__ Boolean _CFBundleNeedsInitPlugIn(CFBundleRef bundle) {
69 Boolean result = false;
70 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle), factoryDict;
71 CFStringRef tempStr;
72 if (infoDict) {
bd5b749c 73 factoryDict = (CFDictionaryRef)CFDictionaryGetValue(infoDict, kCFPlugInFactoriesKey);
d8925383 74 if (factoryDict != NULL && CFGetTypeID(factoryDict) == CFDictionaryGetTypeID()) result = true;
bd5b749c 75 tempStr = (CFStringRef)CFDictionaryGetValue(infoDict, kCFPlugInDynamicRegistrationKey);
d8925383
A
76 if (tempStr != NULL && CFGetTypeID(tempStr) == CFStringGetTypeID() && CFStringCompare(tempStr, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) result = true;
77 }
78 return result;
79}
80
9ce05555
A
81__private_extern__ void _CFBundleInitPlugIn(CFBundleRef bundle) {
82 CFArrayCallBacks _pluginFactoryArrayCallbacks = {0, NULL, NULL, NULL, NULL};
83 Boolean doDynamicReg = false;
84 CFDictionaryRef infoDict;
85 CFDictionaryRef factoryDict;
86 CFDictionaryRef typeDict;
87 CFStringRef tempStr;
88
89 infoDict = CFBundleGetInfoDictionary(bundle);
90 if (infoDict == NULL) {
91 return;
92 }
bd5b749c 93 factoryDict = (CFDictionaryRef)CFDictionaryGetValue(infoDict, kCFPlugInFactoriesKey);
9ce05555 94 if (factoryDict != NULL && CFGetTypeID(factoryDict) != CFDictionaryGetTypeID()) factoryDict = NULL;
bd5b749c 95 tempStr = (CFStringRef)CFDictionaryGetValue(infoDict, kCFPlugInDynamicRegistrationKey);
9ce05555
A
96 if (tempStr != NULL && CFGetTypeID(tempStr) == CFStringGetTypeID() && CFStringCompare(tempStr, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
97 doDynamicReg = true;
98 }
99 if (!factoryDict && !doDynamicReg) {
100 // This is not a plugIn.
101 return;
102 }
103
104 /* loadOnDemand is true by default if the plugIn does not do dynamic registration. It is false, by default if it does do dynamic registration. The dynamic register function can set this. */
105 __CFBundleGetPlugInData(bundle)->_isPlugIn = true;
106 __CFBundleGetPlugInData(bundle)->_loadOnDemand = true;
107 __CFBundleGetPlugInData(bundle)->_isDoingDynamicRegistration = false;
108 __CFBundleGetPlugInData(bundle)->_instanceCount = 0;
109
110 __CFBundleGetPlugInData(bundle)->_factories = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &_pluginFactoryArrayCallbacks);
111
112 /* Now do the registration */
113
114 /* First do static registrations, if any. */
115 if (factoryDict != NULL) {
116 CFDictionaryApplyFunction(factoryDict, _registerFactory, bundle);
117 }
bd5b749c 118 typeDict = (CFDictionaryRef)CFDictionaryGetValue(infoDict, kCFPlugInTypesKey);
9ce05555
A
119 if (typeDict != NULL && CFGetTypeID(typeDict) != CFDictionaryGetTypeID()) typeDict = NULL;
120 if (typeDict != NULL) {
121 CFDictionaryApplyFunction(typeDict, _registerType, bundle);
122 }
123
0ae65c4b 124 /* Now set key for dynamic registration if necessary */
9ce05555 125 if (doDynamicReg) {
0ae65c4b
A
126 CFDictionarySetValue((CFMutableDictionaryRef)infoDict, CFSTR("CFPlugInNeedsDynamicRegistration"), CFSTR("YES"));
127 if (CFBundleIsExecutableLoaded(bundle)) _CFBundlePlugInLoaded(bundle);
128 }
129}
130
131__private_extern__ void _CFBundlePlugInLoaded(CFBundleRef bundle) {
132 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle);
133 CFStringRef tempStr;
134 CFPlugInDynamicRegisterFunction func = NULL;
135
136 if (!__CFBundleGetPlugInData(bundle)->_isPlugIn || __CFBundleGetPlugInData(bundle)->_isDoingDynamicRegistration || !infoDict || !CFBundleIsExecutableLoaded(bundle)) return;
137
bd5b749c 138 tempStr = (CFStringRef)CFDictionaryGetValue(infoDict, CFSTR("CFPlugInNeedsDynamicRegistration"));
0ae65c4b
A
139 if (tempStr != NULL && CFGetTypeID(tempStr) == CFStringGetTypeID() && CFStringCompare(tempStr, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
140 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, CFSTR("CFPlugInNeedsDynamicRegistration"));
bd5b749c 141 tempStr = (CFStringRef)CFDictionaryGetValue(infoDict, kCFPlugInDynamicRegisterFunctionKey);
9ce05555
A
142 if (tempStr == NULL || CFGetTypeID(tempStr) != CFStringGetTypeID() || CFStringGetLength(tempStr) <= 0) {
143 tempStr = CFSTR("CFPlugInDynamicRegister");
144 }
145 __CFBundleGetPlugInData(bundle)->_loadOnDemand = false;
0ae65c4b 146 __CFBundleGetPlugInData(bundle)->_isDoingDynamicRegistration = true;
9ce05555 147
0ae65c4b
A
148 /* Find the symbol and call it. */
149 func = (CFPlugInDynamicRegisterFunction)CFBundleGetFunctionPointerForName(bundle, tempStr);
150 if (func) {
151 func(bundle);
152 // MF:!!! Unload function is never called. Need to deal with this!
153 }
9ce05555 154
0ae65c4b
A
155 __CFBundleGetPlugInData(bundle)->_isDoingDynamicRegistration = false;
156 if (__CFBundleGetPlugInData(bundle)->_loadOnDemand && (__CFBundleGetPlugInData(bundle)->_instanceCount == 0)) {
157 /* Unload now if we can/should. */
158 CFBundleUnloadExecutable(bundle);
9ce05555 159 }
0ae65c4b
A
160 } else {
161 CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, CFSTR("CFPlugInNeedsDynamicRegistration"));
9ce05555
A
162 }
163}
164
165__private_extern__ void _CFBundleDeallocatePlugIn(CFBundleRef bundle) {
166 if (__CFBundleGetPlugInData(bundle)->_isPlugIn) {
167 SInt32 c;
168
169 /* Go through factories disabling them. Disabling these factories should cause them to dealloc since we wouldn't be deallocating if any of the factories had outstanding instances. So go backwards. */
170 c = CFArrayGetCount(__CFBundleGetPlugInData(bundle)->_factories);
171 while (c--) {
172 _CFPFactoryDisable((_CFPFactory *)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(bundle)->_factories, c));
173 }
174 CFRelease(__CFBundleGetPlugInData(bundle)->_factories);
175
176 __CFBundleGetPlugInData(bundle)->_isPlugIn = false;
177 }
178}
179
bd5b749c 180CFTypeID CFPlugInGetTypeID(void) {
9ce05555
A
181 return CFBundleGetTypeID();
182}
183
184CFPlugInRef CFPlugInCreate(CFAllocatorRef allocator, CFURLRef plugInURL) {
0ae65c4b
A
185 CFBundleRef bundle = CFBundleCreate(allocator, plugInURL);
186 return (CFPlugInRef)bundle;
9ce05555
A
187}
188
189CFBundleRef CFPlugInGetBundle(CFPlugInRef plugIn) {
190 return (CFBundleRef)plugIn;
191}
192
193void CFPlugInSetLoadOnDemand(CFPlugInRef plugIn, Boolean flag) {
194 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) {
195 __CFBundleGetPlugInData(plugIn)->_loadOnDemand = flag;
196 if (__CFBundleGetPlugInData(plugIn)->_loadOnDemand && !__CFBundleGetPlugInData(plugIn)->_isDoingDynamicRegistration && (__CFBundleGetPlugInData(plugIn)->_instanceCount == 0)) {
197 /* Unload now if we can/should. */
198 /* If we are doing dynamic registration currently, do not unload. The unloading will happen when dynamic registration is done, if necessary. */
199 CFBundleUnloadExecutable(plugIn);
200 } else if (!__CFBundleGetPlugInData(plugIn)->_loadOnDemand) {
201 /* Make sure we're loaded now. */
202 CFBundleLoadExecutable(plugIn);
203 }
204 }
205}
206
207Boolean CFPlugInIsLoadOnDemand(CFPlugInRef plugIn) {
208 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) {
209 return __CFBundleGetPlugInData(plugIn)->_loadOnDemand;
210 } else {
211 return false;
212 }
213}
214
215__private_extern__ void _CFPlugInWillUnload(CFPlugInRef plugIn) {
216 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) {
217 SInt32 c = CFArrayGetCount(__CFBundleGetPlugInData(plugIn)->_factories);
218 /* First, flush all the function pointers that may be cached by our factories. */
219 while (c--) {
220 _CFPFactoryFlushFunctionCache((_CFPFactory *)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(plugIn)->_factories, c));
221 }
222 }
223}
224
225__private_extern__ void _CFPlugInAddPlugInInstance(CFPlugInRef plugIn) {
226 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) {
227 if ((__CFBundleGetPlugInData(plugIn)->_instanceCount == 0) && (__CFBundleGetPlugInData(plugIn)->_loadOnDemand)) {
228 /* Make sure we are not scheduled for unloading */
229 _CFBundleUnscheduleForUnloading(CFPlugInGetBundle(plugIn));
230 }
231 __CFBundleGetPlugInData(plugIn)->_instanceCount++;
232 /* Instances also retain the CFBundle */
233 CFRetain(plugIn);
234 }
235}
236
237__private_extern__ void _CFPlugInRemovePlugInInstance(CFPlugInRef plugIn) {
238 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) {
239 /* MF:!!! Assert that instanceCount > 0. */
240 __CFBundleGetPlugInData(plugIn)->_instanceCount--;
241 if ((__CFBundleGetPlugInData(plugIn)->_instanceCount == 0) && (__CFBundleGetPlugInData(plugIn)->_loadOnDemand)) {
242 // We unload the code lazily because the code that caused this function to be called is probably code from the plugin itself. If we unload now, we will hose things.
243 //CFBundleUnloadExecutable(plugIn);
244 _CFBundleScheduleForUnloading(CFPlugInGetBundle(plugIn));
245 }
246 /* Instances also retain the CFPlugIn */
247 /* MF:!!! This will cause immediate unloading if it was the last ref on the plugin. */
248 CFRelease(plugIn);
249 }
250}
251
252__private_extern__ void _CFPlugInAddFactory(CFPlugInRef plugIn, _CFPFactory *factory) {
253 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) {
254 CFArrayAppendValue(__CFBundleGetPlugInData(plugIn)->_factories, factory);
255 }
256}
257
258__private_extern__ void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory) {
259 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) {
260 SInt32 idx = CFArrayGetFirstIndexOfValue(__CFBundleGetPlugInData(plugIn)->_factories, CFRangeMake(0, CFArrayGetCount(__CFBundleGetPlugInData(plugIn)->_factories)), factory);
261 if (idx >= 0) {
262 CFArrayRemoveValueAtIndex(__CFBundleGetPlugInData(plugIn)->_factories, idx);
263 }
264 }
265}