| /* |
| * Copyright (c) 2008-2009 Brent Fulgham <bfulgham@gmail.org>. All rights reserved. |
| * |
| * This source code is a modified version of the CoreFoundation sources released by Apple Inc. under |
| * the terms of the APSL version 2.0 (see below). |
| * |
| * For information about changes from the original Apple source release can be found by reviewing the |
| * source control system for the project at https://sourceforge.net/svn/?group_id=246198. |
| * |
| * The original license information is as follows: |
| * |
| * 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); |
| } |
| } |