2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Doug Davidson
30 #include "CFBundle_Internal.h"
31 #include "CFInternal.h"
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
);
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
);
66 if (NULL
!= typeID
) CFRelease(typeID
);
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
;
77 infoDict
= CFBundleGetInfoDictionary(bundle
);
78 if (infoDict
== NULL
) {
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
) {
87 if (!factoryDict
&& !doDynamicReg
) {
88 // This is not a plugIn.
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;
98 __CFBundleGetPlugInData(bundle
)->_factories
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &_pluginFactoryArrayCallbacks
);
100 /* Now do the registration */
102 /* First do static registrations, if any. */
103 if (factoryDict
!= NULL
) {
104 CFDictionaryApplyFunction(factoryDict
, _registerFactory
, bundle
);
106 typeDict
= CFDictionaryGetValue(infoDict
, kCFPlugInTypesKey
);
107 if (typeDict
!= NULL
&& CFGetTypeID(typeDict
) != CFDictionaryGetTypeID()) typeDict
= NULL
;
108 if (typeDict
!= NULL
) {
109 CFDictionaryApplyFunction(typeDict
, _registerType
, bundle
);
112 /* Now do dynamic registration if necessary */
114 tempStr
= CFDictionaryGetValue(infoDict
, kCFPlugInDynamicRegisterFunctionKey
);
115 if (tempStr
== NULL
|| CFGetTypeID(tempStr
) != CFStringGetTypeID() || CFStringGetLength(tempStr
) <= 0) {
116 tempStr
= CFSTR("CFPlugInDynamicRegister");
118 __CFBundleGetPlugInData(bundle
)->_loadOnDemand
= false;
120 if (CFBundleLoadExecutable(bundle
)) {
121 CFPlugInDynamicRegisterFunction func
= NULL
;
123 __CFBundleGetPlugInData(bundle
)->_isDoingDynamicRegistration
= true;
125 /* Find the symbol and call it. */
126 func
= (CFPlugInDynamicRegisterFunction
)CFBundleGetFunctionPointerForName(bundle
, tempStr
);
129 // MF:!!! Unload function is never called. Need to deal with this!
132 __CFBundleGetPlugInData(bundle
)->_isDoingDynamicRegistration
= false;
133 if (__CFBundleGetPlugInData(bundle
)->_loadOnDemand
&& (__CFBundleGetPlugInData(bundle
)->_instanceCount
== 0)) {
134 /* Unload now if we can/should. */
135 CFBundleUnloadExecutable(bundle
);
141 __private_extern__
void _CFBundleDeallocatePlugIn(CFBundleRef bundle
) {
142 if (__CFBundleGetPlugInData(bundle
)->_isPlugIn
) {
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
);
148 _CFPFactoryDisable((_CFPFactory
*)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(bundle
)->_factories
, c
));
150 CFRelease(__CFBundleGetPlugInData(bundle
)->_factories
);
152 __CFBundleGetPlugInData(bundle
)->_isPlugIn
= false;
156 UInt32
CFPlugInGetTypeID(void) {
157 return CFBundleGetTypeID();
160 CFPlugInRef
CFPlugInCreate(CFAllocatorRef allocator
, CFURLRef plugInURL
) {
161 return (CFPlugInRef
)CFBundleCreate(allocator
, plugInURL
);
164 CFBundleRef
CFPlugInGetBundle(CFPlugInRef plugIn
) {
165 return (CFBundleRef
)plugIn
;
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
);
182 Boolean
CFPlugInIsLoadOnDemand(CFPlugInRef plugIn
) {
183 if (__CFBundleGetPlugInData(plugIn
)->_isPlugIn
) {
184 return __CFBundleGetPlugInData(plugIn
)->_loadOnDemand
;
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. */
195 _CFPFactoryFlushFunctionCache((_CFPFactory
*)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(plugIn
)->_factories
, c
));
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
));
206 __CFBundleGetPlugInData(plugIn
)->_instanceCount
++;
207 /* Instances also retain the CFBundle */
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
));
221 /* Instances also retain the CFPlugIn */
222 /* MF:!!! This will cause immediate unloading if it was the last ref on the plugin. */
227 __private_extern__
void _CFPlugInAddFactory(CFPlugInRef plugIn
, _CFPFactory
*factory
) {
228 if (__CFBundleGetPlugInData(plugIn
)->_isPlugIn
) {
229 CFArrayAppendValue(__CFBundleGetPlugInData(plugIn
)->_factories
, factory
);
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
);
237 CFArrayRemoveValueAtIndex(__CFBundleGetPlugInData(plugIn
)->_factories
, idx
);