--- /dev/null
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* CFPlugIn_Factory.c
+ Copyright (c) 1999-2007 Apple Inc. All rights reserved.
+ Responsibility: Doug Davidson
+*/
+
+#include "CFBundle_Internal.h"
+#include "CFInternal.h"
+
+static CFSpinLock_t CFPlugInGlobalDataLock = CFSpinLockInit;
+static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactory */
+static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactory */
+
+static void _CFPFactoryAddToTable(_CFPFactory *factory) {
+ __CFSpinLock(&CFPlugInGlobalDataLock);
+ if (_factoriesByFactoryID == NULL) {
+ CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL};
+ // Use default allocator
+ _factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks);
+ }
+ CFDictionarySetValue(_factoriesByFactoryID, factory->_uuid, factory);
+ __CFSpinUnlock(&CFPlugInGlobalDataLock);
+}
+
+static void _CFPFactoryRemoveFromTable(_CFPFactory *factory) {
+ __CFSpinLock(&CFPlugInGlobalDataLock);
+ if (_factoriesByFactoryID != NULL) {
+ CFDictionaryRemoveValue(_factoriesByFactoryID, factory->_uuid);
+ }
+ __CFSpinUnlock(&CFPlugInGlobalDataLock);
+}
+
+__private_extern__ _CFPFactory *_CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled) {
+ _CFPFactory *result = NULL;
+
+ __CFSpinLock(&CFPlugInGlobalDataLock);
+ if (_factoriesByFactoryID != NULL) {
+ result = (_CFPFactory *)CFDictionaryGetValue(_factoriesByFactoryID, factoryID);
+ if (result && result->_enabled != enabled) {
+ result = NULL;
+ }
+ }
+ __CFSpinUnlock(&CFPlugInGlobalDataLock);
+ return result;
+}
+
+static void _CFPFactoryDeallocate(_CFPFactory *factory) {
+ CFAllocatorRef allocator = factory->_allocator;
+ SInt32 c;
+
+ _CFPFactoryRemoveFromTable(factory);
+
+ if (factory->_plugIn) {
+ _CFPlugInRemoveFactory(factory->_plugIn, factory);
+ }
+
+ /* Remove all types for this factory. */
+ c = CFArrayGetCount(factory->_types);
+ while (c--) {
+ _CFPFactoryRemoveType(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c));
+ }
+ CFRelease(factory->_types);
+
+ if (factory->_funcName) {
+ CFRelease(factory->_funcName);
+ }
+
+ if (factory->_uuid) {
+ CFRelease(factory->_uuid);
+ }
+
+ CFAllocatorDeallocate(allocator, factory);
+ CFRelease(allocator);
+}
+
+static _CFPFactory *_CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factoryID) {
+ _CFPFactory *factory;
+ UInt32 size;
+ size = sizeof(_CFPFactory);
+ allocator = ((NULL == allocator) ? (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator()) : (CFAllocatorRef)CFRetain(allocator));
+ factory = (_CFPFactory *)CFAllocatorAllocate(allocator, size, 0);
+ if (NULL == factory) {
+ CFRelease(allocator);
+ return NULL;
+ }
+
+ factory->_allocator = allocator;
+
+ factory->_uuid = (CFUUIDRef)CFRetain(factoryID);
+ factory->_enabled = true;
+ factory->_instanceCount = 0;
+
+ _CFPFactoryAddToTable(factory);
+
+ factory->_types = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
+
+ return factory;
+}
+
+__private_extern__ _CFPFactory *_CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func) {
+ _CFPFactory *factory = _CFPFactoryCommonCreate(allocator, factoryID);
+
+ factory->_func = func;
+ factory->_plugIn = NULL;
+ factory->_funcName = NULL;
+
+ return factory;
+}
+
+__private_extern__ _CFPFactory *_CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName) {
+ _CFPFactory *factory = _CFPFactoryCommonCreate(allocator, factoryID);
+
+ factory->_func = NULL;
+ factory->_plugIn = plugIn;
+ if (plugIn) {
+ _CFPlugInAddFactory(plugIn, factory);
+ }
+ factory->_funcName = (funcName ? (CFStringRef)CFStringCreateCopy(allocator, funcName) : NULL);
+
+ return factory;
+}
+
+__private_extern__ CFUUIDRef _CFPFactoryGetFactoryID(_CFPFactory *factory) {
+ return factory->_uuid;
+}
+
+__private_extern__ CFPlugInRef _CFPFactoryGetPlugIn(_CFPFactory *factory) {
+ return factory->_plugIn;
+}
+
+__private_extern__ void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactory *factory, CFUUIDRef typeID) {
+ void *result = NULL;
+ if (factory->_enabled) {
+ if (factory->_func == NULL) {
+ factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName);
+ if (factory->_func == NULL) {
+ CFLog(__kCFLogPlugIn, CFSTR("Cannot find function pointer %@ for factory %@ in %@"), factory->_funcName, factory->_uuid, factory->_plugIn);
+ }
+#if BINARY_SUPPORT_CFM
+ else {
+ // return values from CFBundleGetFunctionPointerForName will always be dyld, but
+ // we must force-fault them because pointers to glue code do not fault correctly
+ factory->_func = (void *)((uint32_t)(factory->_func) | 0x1);
+ }
+#endif /* BINARY_SUPPORT_CFM */
+ }
+ if (factory->_func) {
+ // UPPGOOP
+ FAULT_CALLBACK((void **)&(factory->_func));
+ result = (void *)INVOKE_CALLBACK2(factory->_func, allocator, typeID);
+ }
+ } else {
+ CFLog(__kCFLogPlugIn, CFSTR("Factory %@ is disabled"), factory->_uuid);
+ }
+ return result;
+}
+
+__private_extern__ void _CFPFactoryDisable(_CFPFactory *factory) {
+ factory->_enabled = false;
+ if (factory->_instanceCount == 0) {
+ _CFPFactoryDeallocate(factory);
+ }
+}
+
+__private_extern__ Boolean _CFPFactoryIsEnabled(_CFPFactory *factory) {
+ return factory->_enabled;
+}
+
+__private_extern__ void _CFPFactoryFlushFunctionCache(_CFPFactory *factory) {
+ /* MF:!!! Assert that this factory belongs to a plugIn. */
+ /* This is called by the factory's plugIn when the plugIn unloads its code. */
+ factory->_func = NULL;
+}
+
+__private_extern__ void _CFPFactoryAddType(_CFPFactory *factory, CFUUIDRef typeID) {
+ CFMutableArrayRef array;
+
+ /* Add the type to the factory's type list */
+ CFArrayAppendValue(factory->_types, typeID);
+
+ /* Add the factory to the type's array of factories */
+ __CFSpinLock(&CFPlugInGlobalDataLock);
+ if (_factoriesByTypeID == NULL) {
+ // Create this from default allocator
+ _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ }
+ array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
+ if (array == NULL) {
+ CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL};
+ // Create this from default allocator
+ array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &_factoryArrayCallbacks);
+ CFDictionarySetValue(_factoriesByTypeID, typeID, array);
+ CFRelease(array);
+ }
+ CFArrayAppendValue(array, factory);
+ __CFSpinUnlock(&CFPlugInGlobalDataLock);
+}
+
+__private_extern__ void _CFPFactoryRemoveType(_CFPFactory *factory, CFUUIDRef typeID) {
+ /* Remove it from the factory's type list */
+ SInt32 idx;
+
+ idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
+ if (idx >=0) {
+ CFArrayRemoveValueAtIndex(factory->_types, idx);
+ }
+
+ /* Remove the factory from the type's list of factories */
+ __CFSpinLock(&CFPlugInGlobalDataLock);
+ if (_factoriesByTypeID != NULL) {
+ CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
+ if (array != NULL) {
+ idx = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), factory);
+ if (idx >=0) {
+ CFArrayRemoveValueAtIndex(array, idx);
+ if (CFArrayGetCount(array) == 0) {
+ CFDictionaryRemoveValue(_factoriesByTypeID, typeID);
+ }
+ }
+ }
+ }
+ __CFSpinUnlock(&CFPlugInGlobalDataLock);
+}
+
+__private_extern__ Boolean _CFPFactorySupportsType(_CFPFactory *factory, CFUUIDRef typeID) {
+ SInt32 idx;
+
+ idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID);
+ return ((idx >= 0) ? true : false);
+}
+
+__private_extern__ CFArrayRef _CFPFactoryFindForType(CFUUIDRef typeID) {
+ CFArrayRef result = NULL;
+
+ __CFSpinLock(&CFPlugInGlobalDataLock);
+ if (_factoriesByTypeID != NULL) {
+ result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID);
+ }
+ __CFSpinUnlock(&CFPlugInGlobalDataLock);
+
+ return result;
+}
+
+/* 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. */
+__private_extern__ void _CFPFactoryAddInstance(_CFPFactory *factory) {
+ /* MF:!!! Assert that factory is enabled. */
+ factory->_instanceCount++;
+ if (factory->_plugIn) {
+ _CFPlugInAddPlugInInstance(factory->_plugIn);
+ }
+}
+
+__private_extern__ void _CFPFactoryRemoveInstance(_CFPFactory *factory) {
+ /* MF:!!! Assert that _instanceCount > 0. */
+ factory->_instanceCount--;
+ if (factory->_plugIn) {
+ _CFPlugInRemovePlugInInstance(factory->_plugIn);
+ }
+ if ((factory->_instanceCount == 0) && (!factory->_enabled)) {
+ _CFPFactoryDeallocate(factory);
+ }
+}