/* * Copyright (c) 2005 Apple Computer, 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 1999-2002, Apple, Inc. All rights reserved. Responsibility: Doug Davidson */ #include "CFBundle_Internal.h" #include "CFInternal.h" static CFSpinLock_t CFPlugInGlobalDataLock = 0; 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(NULL, 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, 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) ? CFRetain(__CFGetDefaultAllocator()) : CFRetain(allocator)); factory = CFAllocatorAllocate(allocator, size, 0); if (NULL == factory) { CFRelease(allocator); return NULL; } factory->_allocator = allocator; factory->_uuid = 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 ? 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 = 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 defined(__MACH__) && defined(__ppc__) 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 } if (factory->_func) { #if 1 // UPPGOOP FAULT_CALLBACK((void **)&(factory->_func)); result = (void *)INVOKE_CALLBACK2(factory->_func, allocator, typeID); #else result = factory->_func(allocator, typeID); #endif } } 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(NULL, 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(NULL, 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 = 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); } }