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