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