blob: 1801707f3e85f5765855727f3e95bb795f6f1650 [file] [log] [blame]
/*
* 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);
}
}