diff options
Diffstat (limited to 'src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp')
-rw-r--r-- | src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp | 547 |
1 files changed, 547 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp new file mode 100644 index 00000000..2d791943 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/glue/nsGenericFactory.cpp @@ -0,0 +1,547 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Pierre Phaneuf <pp@ludusdesign.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +// DO NOT COPY THIS CODE INTO YOUR SOURCE! USE NS_IMPL_NSGETMODULE() + +#include "nsGenericFactory.h" +#include "nsMemory.h" +#include "nsCOMPtr.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" + +#ifdef XPCOM_GLUE +#include "nsXPCOMGlue.h" +#include "nsXPCOMPrivate.h" +#else +#include "nsIInterfaceRequestorUtils.h" +#include "nsINativeComponentLoader.h" +#endif + +nsGenericFactory::nsGenericFactory(const nsModuleComponentInfo *info) + : mInfo(info) +{ + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this); +} + +nsGenericFactory::~nsGenericFactory() +{ + if (mInfo) { + if (mInfo->mFactoryDestructor) + mInfo->mFactoryDestructor(); + if (mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = 0; + } +} + +NS_IMPL_THREADSAFE_ISUPPORTS3(nsGenericFactory, + nsIGenericFactory, + nsIFactory, + nsIClassInfo) + +NS_IMETHODIMP nsGenericFactory::CreateInstance(nsISupports *aOuter, + REFNSIID aIID, void **aResult) +{ + if (mInfo->mConstructor) { + return mInfo->mConstructor(aOuter, aIID, aResult); + } + + return NS_ERROR_FACTORY_NOT_REGISTERED; +} + +NS_IMETHODIMP nsGenericFactory::LockFactory(PRBool aLock) +{ + // XXX do we care if (mInfo->mFlags & THREADSAFE)? + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetInterfaces(PRUint32 *countp, + nsIID* **array) +{ + if (!mInfo->mGetInterfacesProc) { + *countp = 0; + *array = nsnull; + return NS_OK; + } + return mInfo->mGetInterfacesProc(countp, array); +} + +NS_IMETHODIMP nsGenericFactory::GetHelperForLanguage(PRUint32 language, + nsISupports **helper) +{ + if (mInfo->mGetLanguageHelperProc) + return mInfo->mGetLanguageHelperProc(language, helper); + *helper = nsnull; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetContractID(char **aContractID) +{ + if (mInfo->mContractID) { + *aContractID = (char *)nsMemory::Alloc(strlen(mInfo->mContractID) + 1); + if (!*aContractID) + return NS_ERROR_OUT_OF_MEMORY; + strcpy(*aContractID, mInfo->mContractID); + } else { + *aContractID = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassDescription(char * *aClassDescription) +{ + if (mInfo->mDescription) { + *aClassDescription = (char *) + nsMemory::Alloc(strlen(mInfo->mDescription) + 1); + if (!*aClassDescription) + return NS_ERROR_OUT_OF_MEMORY; + strcpy(*aClassDescription, mInfo->mDescription); + } else { + *aClassDescription = nsnull; + } + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassID(nsCID * *aClassID) +{ + *aClassID = + NS_REINTERPRET_CAST(nsCID*, + nsMemory::Clone(&mInfo->mCID, sizeof mInfo->mCID)); + if (! *aClassID) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetClassIDNoAlloc(nsCID *aClassID) +{ + *aClassID = mInfo->mCID; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetImplementationLanguage(PRUint32 *langp) +{ + *langp = nsIProgrammingLanguage::CPLUSPLUS; + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetFlags(PRUint32 *flagsp) +{ + *flagsp = mInfo->mFlags; + return NS_OK; +} + +// nsIGenericFactory: component-info accessors +NS_IMETHODIMP nsGenericFactory::SetComponentInfo(const nsModuleComponentInfo *info) +{ + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = 0; + mInfo = info; + if (mInfo && mInfo->mClassInfoGlobal) + *mInfo->mClassInfoGlobal = NS_STATIC_CAST(nsIClassInfo *, this); + return NS_OK; +} + +NS_IMETHODIMP nsGenericFactory::GetComponentInfo(const nsModuleComponentInfo **infop) +{ + *infop = mInfo; + return NS_OK; +} + +NS_METHOD nsGenericFactory::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + // sorry, aggregation not spoken here. + nsresult res = NS_ERROR_NO_AGGREGATION; + if (outer == NULL) { + nsGenericFactory* factory = new nsGenericFactory; + if (factory != NULL) { + res = factory->QueryInterface(aIID, aInstancePtr); + if (res != NS_OK) + delete factory; + } else { + res = NS_ERROR_OUT_OF_MEMORY; + } + } + return res; +} + +NS_COM nsresult +NS_NewGenericFactory(nsIGenericFactory* *result, + const nsModuleComponentInfo *info) +{ + nsresult rv; + nsIGenericFactory* fact; + rv = nsGenericFactory::Create(NULL, NS_GET_IID(nsIGenericFactory), (void**)&fact); + if (NS_FAILED(rv)) return rv; + rv = fact->SetComponentInfo(info); + if (NS_FAILED(rv)) goto error; + *result = fact; + return rv; + + error: + NS_RELEASE(fact); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +nsGenericModule::nsGenericModule(const char* moduleName, PRUint32 componentCount, + const nsModuleComponentInfo* components, + nsModuleConstructorProc ctor, + nsModuleDestructorProc dtor, + const char** aLibDepends) + : mInitialized(PR_FALSE), + mModuleName(moduleName), + mComponentCount(componentCount), + mComponents(components), + mFactoriesNotToBeRegistered(nsnull), + mCtor(ctor), + mDtor(dtor), + mLibraryDependencies(aLibDepends) +{ +} + +nsGenericModule::~nsGenericModule() +{ + Shutdown(); + +#ifdef XPCOM_GLUE + XPCOMGlueShutdown(); +#endif + +} + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsGenericModule, nsIModule) + +nsresult +nsGenericModule::AddFactoryNode(nsIGenericFactory* fact) +{ + if (!fact) + return NS_ERROR_FAILURE; + + FactoryNode *node = new FactoryNode(fact, mFactoriesNotToBeRegistered); + if (!node) + return NS_ERROR_OUT_OF_MEMORY; + + mFactoriesNotToBeRegistered = node; + return NS_OK; +} + + +// Perform our one-time intialization for this module +nsresult +nsGenericModule::Initialize(nsIComponentManager *compMgr) +{ + nsresult rv; + + if (mInitialized) { + return NS_OK; + } + + if (mCtor) { + rv = mCtor(this); + if (NS_FAILED(rv)) + return rv; + } + + +#ifdef XPCOM_GLUE + rv = XPCOMGlueStartup("."); + if (NS_FAILED(rv)) + return rv; +#endif + + nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(compMgr, &rv); + if (NS_FAILED(rv)) + return rv; + + // Eagerly populate factory/class object hash for entries + // without constructors. If we didn't, the class object would + // never get created. Also create the factory, which doubles + // as the class object, if the EAGER_CLASSINFO flag was given. + // This allows objects to be created (within their modules) + // via operator new rather than CreateInstance, yet still be + // QI'able to nsIClassInfo. + const nsModuleComponentInfo* desc = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + if (!desc->mConstructor || + (desc->mFlags & nsIClassInfo::EAGER_CLASSINFO)) { + nsCOMPtr<nsIGenericFactory> fact; + nsresult rv = NS_NewGenericFactory(getter_AddRefs(fact), desc); + if (NS_FAILED(rv)) return rv; + + // if we don't have a mConstructor, then we should not populate + // the component manager. + if (!desc->mConstructor) { + rv = AddFactoryNode(fact); + } else { + rv = registrar->RegisterFactory(desc->mCID, + desc->mDescription, + desc->mContractID, + fact); + } + if (NS_FAILED(rv)) return rv; + } + desc++; + } + + mInitialized = PR_TRUE; + return NS_OK; +} + +// Shutdown this module, releasing all of the module resources +void +nsGenericModule::Shutdown() +{ + // Free cached factories that were not registered. + FactoryNode* node; + while (mFactoriesNotToBeRegistered) + { + node = mFactoriesNotToBeRegistered->mNext; + delete mFactoriesNotToBeRegistered; + mFactoriesNotToBeRegistered = node; + } + + if (mInitialized) { + mInitialized = PR_FALSE; + + if (mDtor) + mDtor(this); + } +} + +// Create a factory object for creating instances of aClass. +NS_IMETHODIMP +nsGenericModule::GetClassObject(nsIComponentManager *aCompMgr, + const nsCID& aClass, + const nsIID& aIID, + void** r_classObj) +{ + nsresult rv; + + // Defensive programming: Initialize *r_classObj in case of error below + if (!r_classObj) { + return NS_ERROR_INVALID_POINTER; + } + *r_classObj = NULL; + + // Do one-time-only initialization if necessary + if (!mInitialized) { + rv = Initialize(aCompMgr); + if (NS_FAILED(rv)) { + // Initialization failed! yikes! + return rv; + } + } + + // Choose the appropriate factory, based on the desired instance + // class type (aClass). + const nsModuleComponentInfo* desc = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + if (desc->mCID.Equals(aClass)) { + nsCOMPtr<nsIGenericFactory> fact; + rv = NS_NewGenericFactory(getter_AddRefs(fact), desc); + if (NS_FAILED(rv)) return rv; + return fact->QueryInterface(aIID, r_classObj); + } + desc++; + } + // not found in descriptions +#ifndef XPCOM_GLUE +#ifdef DEBUG + char* cs = aClass.ToString(); + fprintf(stderr, "+++ nsGenericModule %s: unable to create factory for %s\n", mModuleName, cs); + // leak until we resolve the nsID Allocator. + // nsCRT::free(cs); +#endif // XXX put in stop-gap so that we don't search for this one again +#endif + return NS_ERROR_FACTORY_NOT_REGISTERED; +} + +NS_IMETHODIMP +nsGenericModule::RegisterSelf(nsIComponentManager *aCompMgr, + nsIFile* aPath, + const char* registryLocation, + const char* componentType) +{ + nsresult rv = NS_OK; + +#ifdef DEBUG + fprintf(stderr, "*** Registering %s components (all right -- a generic module!)\n", mModuleName); +#endif + + const nsModuleComponentInfo* cp = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + // Register the component only if it has a constructor + if (cp->mConstructor) { + nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(aCompMgr, &rv); + if (registrar) + rv = registrar->RegisterFactoryLocation(cp->mCID, + cp->mDescription, + cp->mContractID, + aPath, + registryLocation, + componentType); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: unable to register %s component => %x\n", + mModuleName?mModuleName:"(null)", cp->mDescription?cp->mDescription:"(null)", rv); +#endif + break; + } + } + // Call the registration hook of the component, if any + if (cp->mRegisterSelfProc) + { + rv = cp->mRegisterSelfProc(aCompMgr, aPath, registryLocation, + componentType, cp); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: Register hook for %s component returned error => %x\n", + mModuleName?mModuleName:"(null)", cp->mDescription?cp->mDescription:"(null)", rv); +#endif + break; + } + } + cp++; + } + +#ifndef XPCOM_GLUE + // We want to tell the component loader of any dependencies + // we have so that the loader can resolve them for us. + + nsCOMPtr<nsINativeComponentLoader> loader = do_GetInterface(aCompMgr); + if (loader && mLibraryDependencies) + { + for(int i=0; mLibraryDependencies[i] != nsnull && + mLibraryDependencies[i][0] != '\0'; i++) + { + loader->AddDependentLibrary(aPath, + mLibraryDependencies[i]); + } + loader = nsnull; + } +#endif + + + + return rv; +} + +NS_IMETHODIMP +nsGenericModule::UnregisterSelf(nsIComponentManager* aCompMgr, + nsIFile* aPath, + const char* registryLocation) +{ +#ifdef DEBUG + fprintf(stderr, "*** Unregistering %s components (all right -- a generic module!)\n", mModuleName); +#endif + const nsModuleComponentInfo* cp = mComponents; + for (PRUint32 i = 0; i < mComponentCount; i++) { + // Call the unregistration hook of the component, if any + if (cp->mUnregisterSelfProc) + { + cp->mUnregisterSelfProc(aCompMgr, aPath, registryLocation, cp); + } + + // Unregister the component + nsresult rv; + nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(aCompMgr, &rv); + if (registrar) + rv = registrar->UnregisterFactoryLocation(cp->mCID, aPath); + if (NS_FAILED(rv)) { +#ifdef DEBUG + fprintf(stderr, "nsGenericModule %s: unable to unregister %s component => %x\n", + mModuleName, cp->mDescription, rv); +#endif + } + cp++; + } + + return NS_OK; +} + +NS_IMETHODIMP +nsGenericModule::CanUnload(nsIComponentManager *aCompMgr, PRBool *okToUnload) +{ + if (!okToUnload) { + return NS_ERROR_INVALID_POINTER; + } + *okToUnload = PR_FALSE; + return NS_ERROR_FAILURE; +} + +NS_COM nsresult +NS_NewGenericModule2(nsModuleInfo* info, nsIModule* *result) +{ + nsresult rv = NS_OK; + + // Create and initialize the module instance + nsGenericModule *m = + new nsGenericModule(info->mModuleName, info->mCount, info->mComponents, + info->mCtor, info->mDtor, info->mLibraryDependencies); + + if (!m) + return NS_ERROR_OUT_OF_MEMORY; + + // Increase refcnt and store away nsIModule interface to m in result + NS_ADDREF(*result = m); + return rv; +} + +NS_COM nsresult +NS_NewGenericModule(const char* moduleName, + PRUint32 componentCount, + nsModuleComponentInfo* components, + nsModuleDestructorProc dtor, + nsIModule* *result) +{ + nsModuleInfo info; + memset(&info, 0, sizeof(info)); + + info.mVersion = NS_MODULEINFO_VERSION; + info.mModuleName = moduleName; + info.mComponents = components; + info.mCount = componentCount; + info.mDtor = dtor; + info.mLibraryDependencies = nsnull; + + return NS_NewGenericModule2(&info, result); +} + +//////////////////////////////////////////////////////////////////////////////// |