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