2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Doug Davidson
28 #include "CFBundle_Internal.h"
29 #include "CFInternal.h"
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
);
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
);
64 if (NULL
!= typeID
) CFRelease(typeID
);
67 __private_extern__ Boolean
_CFBundleNeedsInitPlugIn(CFBundleRef bundle
) {
68 Boolean result
= false;
69 CFDictionaryRef infoDict
= CFBundleGetInfoDictionary(bundle
), factoryDict
;
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;
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
;
88 infoDict
= CFBundleGetInfoDictionary(bundle
);
89 if (infoDict
== NULL
) {
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
) {
98 if (!factoryDict
&& !doDynamicReg
) {
99 // This is not a plugIn.
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;
109 __CFBundleGetPlugInData(bundle
)->_factories
= CFArrayCreateMutable(CFGetAllocator(bundle
), 0, &_pluginFactoryArrayCallbacks
);
111 /* Now do the registration */
113 /* First do static registrations, if any. */
114 if (factoryDict
!= NULL
) {
115 CFDictionaryApplyFunction(factoryDict
, _registerFactory
, bundle
);
117 typeDict
= CFDictionaryGetValue(infoDict
, kCFPlugInTypesKey
);
118 if (typeDict
!= NULL
&& CFGetTypeID(typeDict
) != CFDictionaryGetTypeID()) typeDict
= NULL
;
119 if (typeDict
!= NULL
) {
120 CFDictionaryApplyFunction(typeDict
, _registerType
, bundle
);
123 /* Now do dynamic registration if necessary */
125 tempStr
= CFDictionaryGetValue(infoDict
, kCFPlugInDynamicRegisterFunctionKey
);
126 if (tempStr
== NULL
|| CFGetTypeID(tempStr
) != CFStringGetTypeID() || CFStringGetLength(tempStr
) <= 0) {
127 tempStr
= CFSTR("CFPlugInDynamicRegister");
129 __CFBundleGetPlugInData(bundle
)->_loadOnDemand
= false;
131 if (CFBundleLoadExecutable(bundle
)) {
132 CFPlugInDynamicRegisterFunction func
= NULL
;
134 __CFBundleGetPlugInData(bundle
)->_isDoingDynamicRegistration
= true;
136 /* Find the symbol and call it. */
137 func
= (CFPlugInDynamicRegisterFunction
)CFBundleGetFunctionPointerForName(bundle
, tempStr
);
140 // MF:!!! Unload function is never called. Need to deal with this!
143 __CFBundleGetPlugInData(bundle
)->_isDoingDynamicRegistration
= false;
144 if (__CFBundleGetPlugInData(bundle
)->_loadOnDemand
&& (__CFBundleGetPlugInData(bundle
)->_instanceCount
== 0)) {
145 /* Unload now if we can/should. */
146 CFBundleUnloadExecutable(bundle
);
152 __private_extern__
void _CFBundleDeallocatePlugIn(CFBundleRef bundle
) {
153 if (__CFBundleGetPlugInData(bundle
)->_isPlugIn
) {
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
);
159 _CFPFactoryDisable((_CFPFactory
*)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(bundle
)->_factories
, c
));
161 CFRelease(__CFBundleGetPlugInData(bundle
)->_factories
);
163 __CFBundleGetPlugInData(bundle
)->_isPlugIn
= false;
167 UInt32
CFPlugInGetTypeID(void) {
168 return CFBundleGetTypeID();
171 CFPlugInRef
CFPlugInCreate(CFAllocatorRef allocator
, CFURLRef plugInURL
) {
172 return (CFPlugInRef
)CFBundleCreate(allocator
, plugInURL
);
175 CFBundleRef
CFPlugInGetBundle(CFPlugInRef plugIn
) {
176 return (CFBundleRef
)plugIn
;
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
);
193 Boolean
CFPlugInIsLoadOnDemand(CFPlugInRef plugIn
) {
194 if (__CFBundleGetPlugInData(plugIn
)->_isPlugIn
) {
195 return __CFBundleGetPlugInData(plugIn
)->_loadOnDemand
;
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. */
206 _CFPFactoryFlushFunctionCache((_CFPFactory
*)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(plugIn
)->_factories
, c
));
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
));
217 __CFBundleGetPlugInData(plugIn
)->_instanceCount
++;
218 /* Instances also retain the CFBundle */
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
));
232 /* Instances also retain the CFPlugIn */
233 /* MF:!!! This will cause immediate unloading if it was the last ref on the plugin. */
238 __private_extern__
void _CFPlugInAddFactory(CFPlugInRef plugIn
, _CFPFactory
*factory
) {
239 if (__CFBundleGetPlugInData(plugIn
)->_isPlugIn
) {
240 CFArrayAppendValue(__CFBundleGetPlugInData(plugIn
)->_factories
, factory
);
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
);
248 CFArrayRemoveValueAtIndex(__CFBundleGetPlugInData(plugIn
)->_factories
, idx
);