/ CFPlugIn_Factory.c
CFPlugIn_Factory.c
  1  /*
  2   * Copyright (c) 2015 Apple 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  
 24  /*	CFPlugIn_Factory.c
 25  	Copyright (c) 1999-2014, Apple Inc.  All rights reserved.
 26          Responsibility: Tony Parker
 27  */
 28  
 29  #include "CFBundle_Internal.h"
 30  #include "CFInternal.h"
 31  
 32  static CFTypeID __kCFPFactoryTypeID = _kCFRuntimeNotATypeID;
 33  
 34  struct __CFPFactory {
 35      CFRuntimeBase _base;
 36          
 37      CFUUIDRef _uuid;
 38      Boolean _enabled;
 39      char _padding[3];
 40      
 41      CFPlugInFactoryFunction _func;
 42      
 43      CFPlugInRef _plugIn;
 44      CFStringRef _funcName;
 45      
 46      CFMutableArrayRef _types;
 47      CFLock_t _lock;
 48  };
 49  
 50  static void _CFPFactoryDeallocate(CFTypeRef factory);
 51  
 52  static const CFRuntimeClass __CFPFactoryClass = {
 53      0,
 54      "_CFPFactory",
 55      NULL,	// init
 56      NULL,	// copy
 57      _CFPFactoryDeallocate,
 58      NULL,	// equal
 59      NULL,	// hash
 60      NULL,       // formatting desc
 61      NULL,       // debug desc
 62  };
 63  
 64  CF_PRIVATE void __CFPFactoryInitialize(void) {
 65      static dispatch_once_t initOnce;
 66      dispatch_once(&initOnce, ^{ __kCFPFactoryTypeID = _CFRuntimeRegisterClass(&__CFPFactoryClass); });
 67  }
 68  
 69  static CFTypeID _CFPFactoryGetTypeID(void) {
 70      return __kCFPFactoryTypeID;
 71  }
 72  
 73  static CFLock_t CFPlugInGlobalDataLock = CFLockInit;
 74  static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactoryRef */
 75  static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactoryRef */
 76  
 77  static void _CFPFactoryAddToTable(_CFPFactoryRef factory) {
 78      __CFLock(&factory->_lock);
 79      CFUUIDRef uuid = (CFUUIDRef)CFRetain(factory->_uuid);
 80      CFRetain(factory);
 81      __CFUnlock(&factory->_lock);
 82      
 83      __CFLock(&CFPlugInGlobalDataLock);    
 84      if (!_factoriesByFactoryID) {
 85          CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL};
 86          _factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks);
 87      }
 88      CFDictionarySetValue(_factoriesByFactoryID, uuid, factory);
 89      __CFUnlock(&CFPlugInGlobalDataLock);
 90      
 91      if (uuid) CFRelease(uuid);
 92      CFRelease(factory);
 93  }
 94  
 95  static void _CFPFactoryRemoveFromTable(_CFPFactoryRef factory) {
 96      __CFLock(&factory->_lock);
 97      CFUUIDRef uuid = factory->_uuid;
 98      if (uuid) CFRetain(uuid);
 99      __CFUnlock(&factory->_lock);
100      
101      __CFLock(&CFPlugInGlobalDataLock);
102      if (uuid && _factoriesByTypeID) CFDictionaryRemoveValue(_factoriesByFactoryID, uuid);
103      __CFUnlock(&CFPlugInGlobalDataLock);
104      
105      if (uuid) CFRelease(uuid);
106  }
107  
108  CF_PRIVATE _CFPFactoryRef _CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled) {
109      _CFPFactoryRef result = NULL;
110      
111      __CFLock(&CFPlugInGlobalDataLock);
112      if (_factoriesByFactoryID) {
113          result = (_CFPFactoryRef )CFDictionaryGetValue(_factoriesByFactoryID, factoryID);
114          if (result && result->_enabled != enabled) result = NULL;
115      }
116      __CFUnlock(&CFPlugInGlobalDataLock);
117      return result;
118  }
119  
120  static void _CFPFactoryDeallocate(CFTypeRef ty) {
121      SInt32 c;
122      _CFPFactoryRef factory = (_CFPFactoryRef)ty;
123      
124      _CFPFactoryRemoveFromTable(factory);
125  
126      if (factory->_plugIn) {
127          _CFPlugInRemoveFactory(factory->_plugIn, factory);
128          CFRelease(factory->_plugIn);
129      }
130      
131      /* Remove all types for this factory. */
132      c = CFArrayGetCount(factory->_types);
133      while (c-- > 0) _CFPFactoryRemoveType(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c));
134      CFRelease(factory->_types);
135  
136      if (factory->_funcName) CFRelease(factory->_funcName);
137      if (factory->_uuid) CFRelease(factory->_uuid);
138  }
139  
140  static _CFPFactoryRef _CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factoryID) {
141      _CFPFactoryRef factory;
142      uint32_t size;
143      size = sizeof(struct __CFPFactory) - sizeof(CFRuntimeBase);
144      factory = (_CFPFactoryRef)_CFRuntimeCreateInstance(allocator, _CFPFactoryGetTypeID(), size, NULL);
145      if (!factory) return NULL;
146  
147      factory->_uuid = (CFUUIDRef)CFRetain(factoryID);
148      factory->_enabled = true;
149      factory->_types = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
150      factory->_lock = CFLockInit; // WARNING: grab global lock before this lock
151          
152      _CFPFactoryAddToTable(factory);
153  
154      return factory;
155  }
156  
157  CF_PRIVATE _CFPFactoryRef _CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func) {
158      _CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID);
159  
160      __CFLock(&factory->_lock);    
161      factory->_func = func;
162      factory->_plugIn = NULL;
163      factory->_funcName = NULL;
164      __CFUnlock(&factory->_lock);
165  
166      return factory;
167  }
168  
169  CF_PRIVATE _CFPFactoryRef _CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName) {
170      _CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID);
171  
172      __CFLock(&factory->_lock);    
173      factory->_func = NULL;
174      factory->_plugIn = (CFPlugInRef)CFRetain(plugIn);
175      if (plugIn) _CFPlugInAddFactory(plugIn, factory);
176      factory->_funcName = (funcName ? (CFStringRef)CFStringCreateCopy(allocator, funcName) : NULL);
177      __CFUnlock(&factory->_lock);
178  
179      return factory;
180  }
181  
182  CF_PRIVATE CFUUIDRef _CFPFactoryCopyFactoryID(_CFPFactoryRef factory) {
183      __CFLock(&factory->_lock);
184      CFUUIDRef uuid = factory->_uuid;
185      if (uuid) CFRetain(uuid);
186      __CFUnlock(&factory->_lock);
187      return uuid;
188  }
189  
190  CF_PRIVATE CFPlugInRef _CFPFactoryCopyPlugIn(_CFPFactoryRef factory) {
191      __CFLock(&factory->_lock);
192      CFPlugInRef result = factory->_plugIn;
193      if (result) CFRetain(result);
194      __CFUnlock(&factory->_lock);
195      return result;
196  }
197  
198  CF_PRIVATE void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactoryRef factory, CFUUIDRef typeID) {
199      void *result = NULL;
200  
201      __CFLock(&factory->_lock);
202      if (factory->_enabled) {
203          if (!factory->_func) {
204              factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName);
205              if (!factory->_func) CFLog(__kCFLogPlugIn, CFSTR("Cannot find function pointer %@ for factory %@ in %@"), factory->_funcName, factory->_uuid, factory->_plugIn);
206          }
207          if (factory->_func) {
208              // UPPGOOP
209              CFPlugInFactoryFunction f = factory->_func;
210              __CFUnlock(&factory->_lock);
211              FAULT_CALLBACK((void **)&(f));
212              result = (void *)INVOKE_CALLBACK2(f, allocator, typeID);
213              __CFLock(&factory->_lock);
214          }
215      } else {
216          CFLog(__kCFLogPlugIn, CFSTR("Factory %@ is disabled"), factory->_uuid);
217      }    
218      __CFUnlock(&factory->_lock);
219  
220      return result;
221  }
222  
223  CF_PRIVATE void _CFPFactoryDisable(_CFPFactoryRef factory) {
224      __CFLock(&factory->_lock);    
225      factory->_enabled = false;
226      __CFUnlock(&factory->_lock);
227      CFRelease(factory);
228  }
229  
230  CF_PRIVATE void _CFPFactoryFlushFunctionCache(_CFPFactoryRef factory) {
231      /* MF:!!! Assert that this factory belongs to a plugIn. */
232      /* This is called by the factory's plugIn when the plugIn unloads its code. */
233      __CFLock(&factory->_lock);
234      factory->_func = NULL;
235      __CFUnlock(&factory->_lock);
236  }
237  
238  CF_PRIVATE void _CFPFactoryAddType(_CFPFactoryRef factory, CFUUIDRef typeID) {
239      /* Add the factory to the type's array of factories */
240      __CFLock(&factory->_lock);
241      /* Add the type to the factory's type list */
242      CFArrayAppendValue(factory->_types, typeID);
243      __CFUnlock(&factory->_lock);
244  
245      __CFLock(&CFPlugInGlobalDataLock);
246      if (!_factoriesByTypeID) _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
247      CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
248      if (!array) {
249          CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL};
250          // Create this from default allocator
251          array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &_factoryArrayCallbacks);
252          CFDictionarySetValue(_factoriesByTypeID, typeID, array);
253          CFRelease(array);
254      }
255      CFArrayAppendValue(array, factory);
256      __CFUnlock(&CFPlugInGlobalDataLock);
257  }
258  
259  CF_PRIVATE void _CFPFactoryRemoveType(_CFPFactoryRef factory, CFUUIDRef typeID) {
260      /* Remove it from the factory's type list */
261      SInt32 idx;
262  
263      __CFLock(&factory->_lock);
264      idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
265      if (idx >= 0) CFArrayRemoveValueAtIndex(factory->_types, idx);
266      __CFUnlock(&factory->_lock);
267  
268      /* Remove the factory from the type's list of factories */
269      __CFLock(&CFPlugInGlobalDataLock);
270      if (_factoriesByTypeID) {
271          CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
272          if (array) {
273              idx = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), factory);
274              if (idx >= 0) {
275                  CFArrayRemoveValueAtIndex(array, idx);
276                  if (CFArrayGetCount(array) == 0) CFDictionaryRemoveValue(_factoriesByTypeID, typeID);
277              }
278          }
279      }
280      __CFUnlock(&CFPlugInGlobalDataLock);
281  }
282  
283  CF_PRIVATE Boolean _CFPFactorySupportsType(_CFPFactoryRef factory, CFUUIDRef typeID) {
284      SInt32 idx;
285  
286      __CFLock(&factory->_lock);
287      idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
288      __CFUnlock(&factory->_lock);
289      
290      return (idx >= 0 ? true : false);
291  }
292  
293  CF_PRIVATE CFArrayRef _CFPFactoryFindCopyForType(CFUUIDRef typeID) {
294      CFArrayRef result = NULL;
295      __CFLock(&CFPlugInGlobalDataLock);
296      if (_factoriesByTypeID) {
297          result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
298          if (result) CFRetain(result);
299      }
300      __CFUnlock(&CFPlugInGlobalDataLock);
301  
302      return result;
303  }
304  
305  /* These methods are called by CFPlugInInstance when an instance is created or destroyed.  If a factory's instance count goes to 0 and the factory has been disabled, the factory is destroyed. */
306  CF_PRIVATE void _CFPFactoryAddInstance(_CFPFactoryRef factory) {
307      /* MF:!!! Assert that factory is enabled. */
308      CFRetain(factory);
309      __CFLock(&factory->_lock);
310      CFPlugInRef plugin = factory->_plugIn;
311      if (plugin) CFRetain(plugin);
312      __CFUnlock(&factory->_lock);
313      if (plugin) {
314          _CFPlugInAddPlugInInstance(plugin);
315          CFRelease(plugin);
316      }    
317  }
318  
319  CF_PRIVATE void _CFPFactoryRemoveInstance(_CFPFactoryRef factory) {
320      __CFLock(&factory->_lock);
321      CFPlugInRef plugin = factory->_plugIn;
322      if (plugin) CFRetain(plugin);
323      __CFUnlock(&factory->_lock);
324      if (plugin) {
325          _CFPlugInRemovePlugInInstance(factory->_plugIn);
326          CFRelease(plugin);
327      }
328      CFRelease(factory);
329  }