From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- src/libs/xpcom18a4/xpcom/components/.cvsignore | 1 + src/libs/xpcom18a4/xpcom/components/Makefile.in | 107 + .../xpcom/components/nsCategoryManager.cpp | 799 +++++ .../xpcom18a4/xpcom/components/nsCategoryManager.h | 159 + .../xpcom/components/nsCategoryManagerUtils.h | 88 + .../xpcom/components/nsComponentManager.cpp | 3794 ++++++++++++++++++++ .../xpcom/components/nsComponentManager.h | 339 ++ .../components/nsComponentManagerObsolete.cpp | 271 ++ .../xpcom/components/nsComponentManagerObsolete.h | 185 + .../xpcom/components/nsComponentManagerUtils.h | 196 + .../xpcom/components/nsICategoryManager.idl | 101 + .../xpcom18a4/xpcom/components/nsIClassInfo.idl | 132 + .../xpcom/components/nsIComponentLoader.idl | 109 + .../xpcom/components/nsIComponentLoaderManager.idl | 72 + .../xpcom/components/nsIComponentManager.idl | 111 + .../components/nsIComponentManagerObsolete.idl | 351 ++ .../xpcom/components/nsIComponentManagerUtils.h | 43 + .../xpcom/components/nsIComponentRegistrar.idl | 243 ++ src/libs/xpcom18a4/xpcom/components/nsIFactory.idl | 79 + src/libs/xpcom18a4/xpcom/components/nsIModule.idl | 115 + .../xpcom/components/nsINativeComponentLoader.idl | 70 + .../xpcom/components/nsIServiceManager.idl | 119 + .../xpcom/components/nsIServiceManagerObsolete.h | 250 ++ .../xpcom/components/nsIServiceManagerUtils.h | 185 + src/libs/xpcom18a4/xpcom/components/nsModule.h | 58 + .../xpcom/components/nsNativeComponentLoader.cpp | 1150 ++++++ .../xpcom/components/nsNativeComponentLoader.h | 84 + .../xpcom/components/nsObsoleteModuleLoading.h | 27 + .../xpcom/components/nsServiceManagerObsolete.cpp | 155 + .../xpcom18a4/xpcom/components/nsStaticComponent.h | 52 + .../xpcom/components/nsStaticComponentLoader.cpp | 317 ++ src/libs/xpcom18a4/xpcom/components/xcDll.cpp | 457 +++ src/libs/xpcom18a4/xpcom/components/xcDll.h | 121 + 33 files changed, 10340 insertions(+) create mode 100644 src/libs/xpcom18a4/xpcom/components/.cvsignore create mode 100644 src/libs/xpcom18a4/xpcom/components/Makefile.in create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManager.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIFactory.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIModule.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsModule.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h create mode 100644 src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/xcDll.cpp create mode 100644 src/libs/xpcom18a4/xpcom/components/xcDll.h (limited to 'src/libs/xpcom18a4/xpcom/components') diff --git a/src/libs/xpcom18a4/xpcom/components/.cvsignore b/src/libs/xpcom18a4/xpcom/components/.cvsignore new file mode 100644 index 00000000..f3c7a7c5 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/.cvsignore @@ -0,0 +1 @@ +Makefile diff --git a/src/libs/xpcom18a4/xpcom/components/Makefile.in b/src/libs/xpcom18a4/xpcom/components/Makefile.in new file mode 100644 index 00000000..68614854 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/Makefile.in @@ -0,0 +1,107 @@ +# +# ***** 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): +# +# 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 ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = xpcom +XPIDL_MODULE = xpcom_components +LIBRARY_NAME = xpcomcomponents_s +GRE_MODULE = 1 + +REQUIRES = string \ + $(NULL) + +CPPSRCS = \ + nsCategoryManager.cpp \ + nsComponentManager.cpp \ + nsComponentManagerObsolete.cpp \ + nsNativeComponentLoader.cpp \ + nsServiceManagerObsolete.cpp \ + xcDll.cpp \ + $(NULL) + +ifdef MOZ_STATIC_COMPONENT_LOADER +CPPSRCS += nsStaticComponentLoader.cpp +endif + +EXPORTS = \ + nsCategoryManagerUtils.h \ + nsComponentManagerUtils.h \ + nsComponentManagerObsolete.h \ + nsIServiceManagerUtils.h \ + nsIServiceManagerObsolete.h \ + nsModule.h \ + nsNativeComponentLoader.h \ + nsStaticComponent.h \ + nsObsoleteModuleLoading.h \ + xcDll.h \ + $(NULL) + +XPIDLSRCS = \ + nsIComponentLoader.idl \ + nsIComponentLoaderManager.idl \ + nsIComponentManagerObsolete.idl \ + nsINativeComponentLoader.idl \ + $(NULL) + +SDK_XPIDLSRCS = \ + nsIClassInfo.idl \ + nsIComponentRegistrar.idl \ + nsIFactory.idl \ + nsIModule.idl \ + nsIServiceManager.idl \ + nsIComponentManager.idl \ + nsICategoryManager.idl \ + $(NULL) + +EXPORTS := $(addprefix $(srcdir)/, $(EXPORTS)) + +LOCAL_INCLUDES = -I$(srcdir)/../base -I$(srcdir)/../thread -I$(srcdir)/../ds -I.. + +# we don't want the shared lib, but we want to force the creation of a static lib. +FORCE_STATIC_LIB = 1 + +# Force use of PIC +FORCE_USE_PIC = 1 +include $(topsrcdir)/config/rules.mk + +DEFINES += -D_IMPL_NS_COM -DEXPORT_XPTI_API diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp new file mode 100644 index 00000000..d7202bdb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.cpp @@ -0,0 +1,799 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Scott Collins + * + * 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 ***** */ + +#define PL_ARENA_CONST_ALIGN_MASK 7 + +#include "nsICategoryManager.h" +#include "nsCategoryManager.h" + +#include "plarena.h" +#include "prio.h" +#include "prprf.h" +#include "prlock.h" +#include "nsCOMPtr.h" +#include "nsTHashtable.h" +#include "nsClassHashtable.h" +#include "nsIFactory.h" +#include "nsIStringEnumerator.h" +#include "nsSupportsPrimitives.h" +#include "nsIServiceManagerUtils.h" +#include "nsIObserver.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsEnumeratorUtils.h" + +class nsIComponentLoaderManager; + +/* + CategoryDatabase + contains 0 or more 1-1 mappings of string to Category + each Category contains 0 or more 1-1 mappings of string keys to string values + + In other words, the CategoryDatabase is a tree, whose root is a hashtable. + Internal nodes (or Categories) are hashtables. Leaf nodes are strings. + + The leaf strings are allocated in an arena, because we assume they're not + going to change much ;) +*/ + +#define NS_CATEGORYMANAGER_ARENA_SIZE (1024 * 8) + +// pulled in from nsComponentManager.cpp +char* ArenaStrdup(const char* s, PLArenaPool* aArena); + +// +// BaseStringEnumerator is subclassed by EntryEnumerator and +// CategoryEnumerator +// +class BaseStringEnumerator + : public nsISimpleEnumerator, + nsIUTF8StringEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSISIMPLEENUMERATOR + NS_DECL_NSIUTF8STRINGENUMERATOR + +protected: + BaseStringEnumerator() + : mArray(nsnull), + mCount(0), + mSimpleCurItem(0), + mStringCurItem(0) { } + + // A virtual destructor is needed here because subclasses of + // BaseStringEnumerator do not implement their own Release() method. + + virtual ~BaseStringEnumerator() + { + if (mArray) + delete[] mArray; + } + + const char** mArray; + PRUint32 mCount; + PRUint32 mSimpleCurItem; + PRUint32 mStringCurItem; +}; + +NS_IMPL_ISUPPORTS2(BaseStringEnumerator, nsISimpleEnumerator, nsIUTF8StringEnumerator) + +NS_IMETHODIMP +BaseStringEnumerator::HasMoreElements(PRBool *_retval) +{ + *_retval = (mSimpleCurItem < mCount); + + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::GetNext(nsISupports **_retval) +{ + if (mSimpleCurItem >= mCount) + return NS_ERROR_FAILURE; + + nsSupportsDependentCString* str = + new nsSupportsDependentCString(mArray[mSimpleCurItem++]); + if (!str) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = str; + NS_ADDREF(*_retval); + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::HasMore(PRBool *_retval) +{ + *_retval = (mStringCurItem < mCount); + + return NS_OK; +} + +NS_IMETHODIMP +BaseStringEnumerator::GetNext(nsACString& _retval) +{ + if (mStringCurItem >= mCount) + return NS_ERROR_FAILURE; + + _retval = nsDependentCString(mArray[mStringCurItem++]); + return NS_OK; +} + + +// +// EntryEnumerator is the wrapper that allows nsICategoryManager::EnumerateCategory +// +class EntryEnumerator + : public BaseStringEnumerator +{ +public: + static EntryEnumerator* Create(nsTHashtable& aTable); + +private: + static PLDHashOperator PR_CALLBACK + enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg); +}; + + +PLDHashOperator PR_CALLBACK +EntryEnumerator::enumfunc_createenumerator(CategoryLeaf* aLeaf, void* userArg) +{ + EntryEnumerator* mythis = NS_STATIC_CAST(EntryEnumerator*, userArg); + mythis->mArray[mythis->mCount++] = aLeaf->GetKey(); + + return PL_DHASH_NEXT; +} + +EntryEnumerator* +EntryEnumerator::Create(nsTHashtable& aTable) +{ + EntryEnumerator* enumObj = new EntryEnumerator(); + if (!enumObj) + return nsnull; + + enumObj->mArray = new char const* [aTable.Count()]; + if (!enumObj->mArray) { + delete enumObj; + return nsnull; + } + + aTable.EnumerateEntries(enumfunc_createenumerator, enumObj); + + return enumObj; +} + + +// +// CategoryNode implementations +// + +CategoryNode* +CategoryNode::Create(PLArenaPool* aArena) +{ + CategoryNode* node = new(aArena) CategoryNode(); + if (!node) + return nsnull; + + if (!node->mTable.Init()) { + delete node; + return nsnull; + } + + node->mLock = PR_NewLock(); + if (!node->mLock) { + delete node; + return nsnull; + } + + return node; +} + +CategoryNode::~CategoryNode() +{ + if (mLock) + PR_DestroyLock(mLock); +} + +void* +CategoryNode::operator new(size_t aSize, PLArenaPool* aArena) +{ + void* p; + PL_ARENA_ALLOCATE(p, aArena, aSize); + return p; +} + +NS_METHOD +CategoryNode::GetLeaf(const char* aEntryName, + char** _retval) +{ + PR_Lock(mLock); + nsresult rv = NS_ERROR_NOT_AVAILABLE; + CategoryLeaf* ent = + mTable.GetEntry(aEntryName); + + // we only want the non-persistent value + if (ent && ent->nonpValue) { + *_retval = nsCRT::strdup(ent->nonpValue); + if (*_retval) + rv = NS_OK; + } + PR_Unlock(mLock); + + return rv; +} + +NS_METHOD +CategoryNode::AddLeaf(const char* aEntryName, + const char* aValue, + PRBool aPersist, + PRBool aReplace, + char** _retval, + PLArenaPool* aArena) +{ + PR_Lock(mLock); + CategoryLeaf* leaf = + mTable.GetEntry(aEntryName); + + nsresult rv = NS_OK; + if (leaf) { + //if the entry was found, aReplace must be specified + if (!aReplace && (leaf->nonpValue || (aPersist && leaf->pValue ))) + rv = NS_ERROR_INVALID_ARG; + } else { + const char* arenaEntryName = ArenaStrdup(aEntryName, aArena); + if (!arenaEntryName) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + leaf = mTable.PutEntry(arenaEntryName); + if (!leaf) + rv = NS_ERROR_OUT_OF_MEMORY; + } + } + + if (NS_SUCCEEDED(rv)) { + const char* arenaValue = ArenaStrdup(aValue, aArena); + if (!arenaValue) { + rv = NS_ERROR_OUT_OF_MEMORY; + } else { + leaf->nonpValue = arenaValue; + if (aPersist) + leaf->pValue = arenaValue; + } + } + + PR_Unlock(mLock); + return rv; +} + +NS_METHOD +CategoryNode::DeleteLeaf(const char* aEntryName, + PRBool aDontPersist) +{ + // we don't throw any errors, because it normally doesn't matter + // and it makes JS a lot cleaner + PR_Lock(mLock); + + if (aDontPersist) { + // we can just remove the entire hash entry without introspection + mTable.RemoveEntry(aEntryName); + } else { + // if we are keeping the persistent value, we need to look at + // the contents of the current entry + CategoryLeaf* leaf = mTable.GetEntry(aEntryName); + if (leaf) { + if (leaf->pValue) { + leaf->nonpValue = nsnull; + } else { + // if there is no persistent value, just remove the entry + mTable.RawRemoveEntry(leaf); + } + } + } + PR_Unlock(mLock); + + return NS_OK; +} + +NS_METHOD +CategoryNode::Enumerate(nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + EntryEnumerator* enumObj = EntryEnumerator::Create(mTable); + PR_Unlock(mLock); + + if (!enumObj) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = enumObj; + NS_ADDREF(*_retval); + return NS_OK; +} + +struct persistent_userstruct { + PRFileDesc* fd; + const char* categoryName; + PRBool success; +}; + +PLDHashOperator PR_CALLBACK +enumfunc_pentries(CategoryLeaf* aLeaf, void* userArg) +{ + persistent_userstruct* args = + NS_STATIC_CAST(persistent_userstruct*, userArg); + + PLDHashOperator status = PL_DHASH_NEXT; + + if (aLeaf->pValue) { + if (PR_fprintf(args->fd, + "%s,%s,%s\n", + args->categoryName, + aLeaf->GetKey(), + aLeaf->pValue) == (PRUint32) -1) { + args->success = PR_FALSE; + status = PL_DHASH_STOP; + } + } + + return status; +} + +PRBool +CategoryNode::WritePersistentEntries(PRFileDesc* fd, const char* aCategoryName) +{ + persistent_userstruct args = { + fd, + aCategoryName, + PR_TRUE + }; + + PR_Lock(mLock); + mTable.EnumerateEntries(enumfunc_pentries, &args); + PR_Unlock(mLock); + + return args.success; +} + + +// +// CategoryEnumerator class +// + +class CategoryEnumerator + : public BaseStringEnumerator +{ +public: + static CategoryEnumerator* Create(nsClassHashtable& aTable); + +private: + static PLDHashOperator PR_CALLBACK + enumfunc_createenumerator(const char* aStr, + CategoryNode* aNode, + void* userArg); +}; + +CategoryEnumerator* +CategoryEnumerator::Create(nsClassHashtable& aTable) +{ + CategoryEnumerator* enumObj = new CategoryEnumerator(); + if (!enumObj) + return nsnull; + + enumObj->mArray = new const char* [aTable.Count()]; + if (!enumObj->mArray) { + delete enumObj; + return nsnull; + } + + aTable.EnumerateRead(enumfunc_createenumerator, enumObj); + + return enumObj; +} + +PLDHashOperator PR_CALLBACK +CategoryEnumerator::enumfunc_createenumerator(const char* aStr, CategoryNode* aNode, void* userArg) +{ + CategoryEnumerator* mythis = NS_STATIC_CAST(CategoryEnumerator*, userArg); + + // if a category has no entries, we pretend it doesn't exist + if (aNode->Count()) + mythis->mArray[mythis->mCount++] = aStr; + + return PL_DHASH_NEXT; +} + + +// +// nsCategoryManager implementations +// + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsCategoryManager, nsICategoryManager) + +nsCategoryManager* +nsCategoryManager::Create() +{ + nsCategoryManager* manager = new nsCategoryManager(); + + if (!manager) + return nsnull; + + PL_INIT_ARENA_POOL(&(manager->mArena), "CategoryManagerArena", + NS_CATEGORYMANAGER_ARENA_SIZE); // this never fails + + if (!manager->mTable.Init()) { + delete manager; + return nsnull; + } + + manager->mLock = PR_NewLock(); + + if (!manager->mLock) { + delete manager; + return nsnull; + } + + return manager; +} + +nsCategoryManager::~nsCategoryManager() +{ + if (mLock) + PR_DestroyLock(mLock); + + // the hashtable contains entries that must be deleted before the arena is + // destroyed, or else you will have PRLocks undestroyed and other Really + // Bad Stuff (TM) + mTable.Clear(); + + PL_FinishArenaPool(&mArena); +} + +inline CategoryNode* +nsCategoryManager::get_category(const char* aName) { + CategoryNode* node; + if (!mTable.Get(aName, &node)) { + return nsnull; + } + return node; +} + +NS_IMETHODIMP +nsCategoryManager::GetCategoryEntry( const char *aCategoryName, + const char *aEntryName, + char **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + NS_ENSURE_ARG_POINTER(_retval); + + nsresult status = NS_ERROR_NOT_AVAILABLE; + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (category) { + status = category->GetLeaf(aEntryName, _retval); + } + + return status; +} + +NS_IMETHODIMP +nsCategoryManager::AddCategoryEntry( const char *aCategoryName, + const char *aEntryName, + const char *aValue, + PRBool aPersist, + PRBool aReplace, + char **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + NS_ENSURE_ARG_POINTER(aValue); + + // Before we can insert a new entry, we'll need to + // find the |CategoryNode| to put it in... + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + + if (!category) { + // That category doesn't exist yet; let's make it. + category = CategoryNode::Create(&mArena); + + char* categoryName = ArenaStrdup(aCategoryName, &mArena); + mTable.Put(categoryName, category); + } + PR_Unlock(mLock); + + if (!category) + return NS_ERROR_OUT_OF_MEMORY; + + return category->AddLeaf(aEntryName, + aValue, + aPersist, + aReplace, + _retval, + &mArena); +} + +NS_IMETHODIMP +nsCategoryManager::DeleteCategoryEntry( const char *aCategoryName, + const char *aEntryName, + PRBool aDontPersist) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(aEntryName); + + /* + Note: no errors are reported since failure to delete + probably won't hurt you, and returning errors seriously + inconveniences JS clients + */ + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (!category) + return NS_OK; + + return category->DeleteLeaf(aEntryName, + aDontPersist); +} + +NS_IMETHODIMP +nsCategoryManager::DeleteCategory( const char *aCategoryName ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + + // the categories are arena-allocated, so we don't + // actually delete them. We just remove all of the + // leaf nodes. + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (category) + category->Clear(); + + return NS_OK; +} + +NS_IMETHODIMP +nsCategoryManager::EnumerateCategory( const char *aCategoryName, + nsISimpleEnumerator **_retval ) +{ + NS_ENSURE_ARG_POINTER(aCategoryName); + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + CategoryNode* category = get_category(aCategoryName); + PR_Unlock(mLock); + + if (!category) { + return NS_NewEmptyEnumerator(_retval); + } + + return category->Enumerate(_retval); +} + +NS_IMETHODIMP +nsCategoryManager::EnumerateCategories(nsISimpleEnumerator **_retval) +{ + NS_ENSURE_ARG_POINTER(_retval); + + PR_Lock(mLock); + CategoryEnumerator* enumObj = CategoryEnumerator::Create(mTable); + PR_Unlock(mLock); + + if (!enumObj) + return NS_ERROR_OUT_OF_MEMORY; + + *_retval = enumObj; + NS_ADDREF(*_retval); + return NS_OK; +} + +struct writecat_struct { + PRFileDesc* fd; + PRBool success; +}; + +PLDHashOperator PR_CALLBACK +enumfunc_categories(const char* aKey, CategoryNode* aCategory, void* userArg) +{ + writecat_struct* args = NS_STATIC_CAST(writecat_struct*, userArg); + + PLDHashOperator result = PL_DHASH_NEXT; + + if (!aCategory->WritePersistentEntries(args->fd, aKey)) { + args->success = PR_FALSE; + result = PL_DHASH_STOP; + } + + return result; +} + +NS_METHOD +nsCategoryManager::WriteCategoryManagerToRegistry(PRFileDesc* fd) +{ + writecat_struct args = { + fd, + PR_TRUE + }; + + PR_Lock(mLock); + mTable.EnumerateRead(enumfunc_categories, &args); + PR_Unlock(mLock); + + if (!args.success) { + return NS_ERROR_UNEXPECTED; + } + + return NS_OK; +} + +class nsCategoryManagerFactory : public nsIFactory + { + public: + nsCategoryManagerFactory() { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIFACTORY + }; + +NS_IMPL_ISUPPORTS1(nsCategoryManagerFactory, nsIFactory) + +NS_IMETHODIMP +nsCategoryManagerFactory::CreateInstance( nsISupports* aOuter, const nsIID& aIID, void** aResult ) + { + NS_ENSURE_ARG_POINTER(aResult); + + *aResult = 0; + + nsresult status = NS_OK; + if ( aOuter ) + status = NS_ERROR_NO_AGGREGATION; + else + { + nsCategoryManager* raw_category_manager = nsCategoryManager::Create(); + nsCOMPtr new_category_manager = raw_category_manager; + if ( new_category_manager ) + status = new_category_manager->QueryInterface(aIID, aResult); + else + status = NS_ERROR_OUT_OF_MEMORY; + } + + return status; + } + +NS_IMETHODIMP +nsCategoryManagerFactory::LockFactory( PRBool ) + { + // Not implemented... + return NS_OK; + } + +nsresult +NS_CategoryManagerGetFactory( nsIFactory** aFactory ) + { + // assert(aFactory); + + nsresult status; + + *aFactory = 0; + nsIFactory* new_factory = NS_STATIC_CAST(nsIFactory*, new nsCategoryManagerFactory); + if (new_factory) + { + *aFactory = new_factory; + NS_ADDREF(*aFactory); + status = NS_OK; + } + else + status = NS_ERROR_OUT_OF_MEMORY; + + return status; + } + + + +/* + * CreateServicesFromCategory() + * + * Given a category, this convenience functions enumerates the category and + * creates a service of every CID or ContractID registered under the category. + * If observerTopic is non null and the service implements nsIObserver, + * this will attempt to notify the observer with the origin, observerTopic string + * as parameter. + */ +NS_COM nsresult +NS_CreateServicesFromCategory(const char *category, + nsISupports *origin, + const char *observerTopic) +{ + nsresult rv = NS_OK; + + int nFailed = 0; + nsCOMPtr categoryManager = + do_GetService("@mozilla.org/categorymanager;1", &rv); + if (!categoryManager) return rv; + + nsCOMPtr enumerator; + rv = categoryManager->EnumerateCategory(category, + getter_AddRefs(enumerator)); + if (NS_FAILED(rv)) return rv; + + nsCOMPtr entry; + while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(entry)))) { + // From here on just skip any error we get. + nsCOMPtr catEntry = do_QueryInterface(entry, &rv); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + nsCAutoString entryString; + rv = catEntry->GetData(entryString); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + nsXPIDLCString contractID; + rv = categoryManager->GetCategoryEntry(category,entryString.get(), getter_Copies(contractID)); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + + nsCOMPtr instance = do_GetService(contractID, &rv); + if (NS_FAILED(rv)) { + nFailed++; + continue; + } + + if (observerTopic) { + // try an observer, if it implements it. + nsCOMPtr observer = do_QueryInterface(instance, &rv); + if (NS_SUCCEEDED(rv) && observer) + observer->Observe(origin, observerTopic, EmptyString().get()); + } + } + return (nFailed ? NS_ERROR_FAILURE : NS_OK); +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h new file mode 100644 index 00000000..a5cdb59a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManager.h @@ -0,0 +1,159 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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): + * + * 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 ***** */ + + +#ifndef NSCATEGORYMANAGER_H +#define NSCATEGORYMANAGER_H + +#include "prio.h" +#include "prlock.h" +#include "plarena.h" +#include "nsClassHashtable.h" +#include "nsICategoryManager.h" + +#define NS_CATEGORYMANAGER_CLASSNAME "Category Manager" + +/* 16d222a6-1dd2-11b2-b693-f38b02c021b2 */ +#define NS_CATEGORYMANAGER_CID \ +{ 0x16d222a6, 0x1dd2, 0x11b2, \ + {0xb6, 0x93, 0xf3, 0x8b, 0x02, 0xc0, 0x21, 0xb2} } + +/** + * a "leaf-node", managed by the nsCategoryNode hashtable. + * + * we need to keep a "persistent value" (which will be written to the registry) + * and a non-persistent value (for the current runtime): these are usually + * the same, except when aPersist==PR_FALSE. The strings are permanently arena- + * allocated, and will never go away. + */ +class CategoryLeaf : public nsDepCharHashKey +{ +public: + CategoryLeaf(const char* aKey) + : nsDepCharHashKey(aKey), + pValue(nsnull), + nonpValue(nsnull) { } + const char* pValue; + const char* nonpValue; +}; + + +/** + * CategoryNode keeps a hashtable of it's entries. + * the CategoryNode itself is permanently allocated in + * the arena. + */ +class CategoryNode +{ +public: + NS_METHOD GetLeaf(const char* aEntryName, + char** _retval); + + NS_METHOD AddLeaf(const char* aEntryName, + const char* aValue, + PRBool aPersist, + PRBool aReplace, + char** _retval, + PLArenaPool* aArena); + + NS_METHOD DeleteLeaf(const char* aEntryName, + PRBool aDontPersist); + + void Clear() { + PR_Lock(mLock); + mTable.Clear(); + PR_Unlock(mLock); + } + + PRUint32 Count() { + PR_Lock(mLock); + PRUint32 tCount = mTable.Count(); + PR_Unlock(mLock); + return tCount; + } + + NS_METHOD Enumerate(nsISimpleEnumerator** _retval); + + PRBool WritePersistentEntries(PRFileDesc* fd, const char* aCategoryName); + + // CategoryNode is arena-allocated, with the strings + static CategoryNode* Create(PLArenaPool* aArena); + ~CategoryNode(); + void operator delete(void*) { } + +private: + CategoryNode() : mLock(nsnull) { } + void* operator new(size_t aSize, PLArenaPool* aArena); + + nsTHashtable mTable; + PRLock* mLock; +}; + + +/** + * The main implementation of nsICategoryManager. + * + * This implementation is thread-safe. + */ +class nsCategoryManager + : public nsICategoryManager +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICATEGORYMANAGER + + /** + * Write the categories to the XPCOM persistent registry. + * This is to be used by nsComponentManagerImpl (and NO ONE ELSE). + */ + NS_METHOD WriteCategoryManagerToRegistry(PRFileDesc* fd); + + nsCategoryManager() : mLock(nsnull) { } +private: + friend class nsCategoryManagerFactory; + static nsCategoryManager* Create(); + + ~nsCategoryManager(); + + CategoryNode* get_category(const char* aName); + + PLArenaPool mArena; + nsClassHashtable mTable; + PRLock* mLock; +}; + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h new file mode 100644 index 00000000..54a9fcec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsCategoryManagerUtils.h @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 8; 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): + * + * 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 ***** */ + +#ifndef nsCategoryManagerUtils_h__ +#define nsCategoryManagerUtils_h__ + +#include "nsICategoryManager.h" +#include "nsCOMPtr.h" + +NS_COM nsresult +NS_CreateServicesFromCategory(const char *category, + nsISupports *origin, + const char *observerTopic); + +class NS_COM nsCreateInstanceFromCategory : public nsCOMPtr_helper +{ +public: + nsCreateInstanceFromCategory(const char *aCategory, const char *aEntry, + nsISupports *aOuter, nsresult *aErrorPtr) + : mCategory(aCategory), + mEntry(aEntry), + mErrorPtr(aErrorPtr) + { + // nothing else to do; + } + virtual nsresult NS_FASTCALL operator()( const nsIID& aIID, void** aInstancePtr) const; + +private: + const char *mCategory; // Do not free. This char * is not owned. + const char *mEntry; // Do not free. This char * is not owned. + + nsISupports *mOuter; + nsresult *mErrorPtr; + +}; + +inline +const nsCreateInstanceFromCategory +do_CreateInstanceFromCategory( const char *aCategory, const char *aEntry, + nsresult *aErrorPtr = 0) +{ + return nsCreateInstanceFromCategory(aCategory, aEntry, 0, aErrorPtr); +} + +inline +const nsCreateInstanceFromCategory +do_CreateInstanceFromCategory( const char *aCategory, const char *aEntry, + nsISupports *aOuter, nsresult *aErrorPtr = 0) +{ + return nsCreateInstanceFromCategory(aCategory, aEntry, aOuter, aErrorPtr); +} + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp new file mode 100644 index 00000000..980b0565 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.cpp @@ -0,0 +1,3794 @@ +/* -*- 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): + * + * 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 ***** + * + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ +#include +#include "nscore.h" +#include "nsISupports.h" +#include "nspr.h" +#include "nsCRT.h" // for atoll +// Arena used by component manager for storing contractid string, dll +// location strings and small objects +// CAUTION: Arena align mask needs to be defined before including plarena.h +// currently from nsComponentManager.h +#define PL_ARENA_CONST_ALIGN_MASK 7 +#define NS_CM_BLOCK_SIZE (1024 * 8) + +#include "nsAutoLock.h" +#include "nsCOMPtr.h" +#include "nsComponentManager.h" +#include "nsComponentManagerObsolete.h" +#include "nsDirectoryService.h" +#include "nsDirectoryServiceDefs.h" +#include "nsCategoryManager.h" +#include "nsCategoryManagerUtils.h" +#include "nsIComponentLoader.h" +#include "nsIEnumerator.h" +#include "nsIInterfaceInfoManager.h" +#include "nsIModule.h" +#include "nsIObserverService.h" +#include "nsISimpleEnumerator.h" +#include "nsXPCOM.h" +#include "nsISupportsPrimitives.h" +#include "nsLocalFile.h" +#include "nsNativeComponentLoader.h" +#include "nsReadableUtils.h" +#include "nsString.h" +#include "nsXPIDLString.h" +#include "prcmon.h" +#include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself... + +#include "nsInt64.h" +#include "nsManifestLineReader.h" + +#include NEW_H // for placement new + + +#ifdef XP_BEOS +#include +#include +#endif + +#include "prlog.h" + +PRLogModuleInfo* nsComponentManagerLog = nsnull; + +#if 0 || defined (DEBUG_timeless) + #define SHOW_DENIED_ON_SHUTDOWN + #define SHOW_CI_ON_EXISTING_SERVICE + #define XPCOM_CHECK_PENDING_CIDS +#endif + +// Loader Types +#define NS_LOADER_DATA_ALLOC_STEP 6 + +// Bloated registry buffer size to improve startup performance -- needs to +// be big enough to fit the entire file into memory or it'll thrash. +// 512K is big enough to allow for some future growth in the registry. +#define BIG_REGISTRY_BUFLEN (512*1024) + +// Common Key Names +const char classIDKeyName[]="classID"; +const char classesKeyName[]="contractID"; +const char componentLoadersKeyName[]="componentLoaders"; +const char componentsKeyName[]="components"; +const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components"; +const char xpcomKeyName[]="software/mozilla/XPCOM"; + +// Common Value Names +const char classIDValueName[]="ClassID"; +const char classNameValueName[]="ClassName"; +const char componentCountValueName[]="ComponentsCount"; +const char componentTypeValueName[]="ComponentType"; +const char contractIDValueName[]="ContractID"; +const char fileSizeValueName[]="FileSize"; +const char inprocServerValueName[]="InprocServer"; +const char lastModValueName[]="LastModTimeStamp"; +const char nativeComponentType[]="application/x-mozilla-native"; +const char staticComponentType[]="application/x-mozilla-static"; +const char versionValueName[]="VersionString"; + +const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:"; +const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:"; +const static char XPCOM_GRECOMPONENT_PREFIX[] = "gre:"; + +static const char gIDFormat[] = + "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"; + + +#define NS_EMPTY_IID \ +{ \ + 0x00000000, \ + 0x0000, \ + 0x0000, \ + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \ +} + +NS_DEFINE_CID(kEmptyCID, NS_EMPTY_IID); +NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID); + +#define UID_STRING_LENGTH 39 + +// Set to true from NS_ShutdownXPCOM. +extern PRBool gXPCOMShuttingDown; + +static void GetIDString(const nsID& aCID, char buf[UID_STRING_LENGTH]) +{ + PR_snprintf(buf, UID_STRING_LENGTH, gIDFormat, + aCID.m0, (PRUint32) aCID.m1, (PRUint32) aCID.m2, + (PRUint32) aCID.m3[0], (PRUint32) aCID.m3[1], + (PRUint32) aCID.m3[2], (PRUint32) aCID.m3[3], + (PRUint32) aCID.m3[4], (PRUint32) aCID.m3[5], + (PRUint32) aCID.m3[6], (PRUint32) aCID.m3[7]); +} + +nsresult +nsCreateInstanceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const +{ + /* + * If I were a real man, I would consolidate this with + * nsGetServiceFromContractID::operator(). + */ + nsresult rv; + nsXPIDLCString value; + nsCOMPtr compMgr; + nsCOMPtr catman = + do_GetService(kCategoryManagerCID, &rv); + + if (NS_FAILED(rv)) goto error; + + if (!mCategory || !mEntry) { + // when categories have defaults, use that for null mEntry + rv = NS_ERROR_NULL_POINTER; + goto error; + } + + /* find the contractID for category.entry */ + rv = catman->GetCategoryEntry(mCategory, mEntry, + getter_Copies(value)); + if (NS_FAILED(rv)) goto error; + if (!value) { + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + goto error; + } + NS_GetComponentManager(getter_AddRefs(compMgr)); + if (!compMgr) + return NS_ERROR_FAILURE; + compMgr->CreateInstanceByContractID(value, + mOuter, + aIID, + aInstancePtr); + if (NS_FAILED(rv)) { + error: + *aInstancePtr = 0; + } + + *mErrorPtr = rv; + return rv; +} + + +nsresult +nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const +{ + nsresult rv; + nsXPIDLCString value; + nsCOMPtr catman = + do_GetService(kCategoryManagerCID, &rv); + if (NS_FAILED(rv)) goto error; + if (!mCategory || !mEntry) { + // when categories have defaults, use that for null mEntry + rv = NS_ERROR_NULL_POINTER; + goto error; + } + /* find the contractID for category.entry */ + rv = catman->GetCategoryEntry(mCategory, mEntry, + getter_Copies(value)); + if (NS_FAILED(rv)) goto error; + if (!value) { + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + goto error; + } + if (mServiceManager) { + rv = mServiceManager->GetServiceByContractID(value, aIID, (void**)aInstancePtr); + } else { + nsCOMPtr mgr; + NS_GetServiceManager(getter_AddRefs(mgr)); + if (mgr) + rv = mgr->GetServiceByContractID(value, aIID, (void**)aInstancePtr); + } + if (NS_FAILED(rv)) { + error: + *aInstancePtr = 0; + } + *mErrorPtr = rv; + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// +// Arena helper functions +//////////////////////////////////////////////////////////////////////////////// +char * +ArenaStrndup(const char *s, PRUint32 len, PLArenaPool *arena) +{ + void *mem; + // Include trailing null in the len + PL_ARENA_ALLOCATE(mem, arena, len+1); + if (mem) + memcpy(mem, s, len+1); + return NS_STATIC_CAST(char *, mem); +} + +char* +ArenaStrdup(const char *s, PLArenaPool *arena) +{ + return ArenaStrndup(s, strlen(s), arena); +} + +//////////////////////////////////////////////////////////////////////////////// +// Hashtable Callbacks +//////////////////////////////////////////////////////////////////////////////// + +PRBool PR_CALLBACK +nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure); + +PR_STATIC_CALLBACK(const void *) +factory_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + + return &entry->mFactoryEntry->mCid; +} + +PR_STATIC_CALLBACK(PLDHashNumber) +factory_HashKey(PLDHashTable *aTable, const void *aKey) +{ + const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey); + + return cidp->m0; +} + +PR_STATIC_CALLBACK(PRBool) +factory_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr, + const void *aKey) +{ + const nsFactoryTableEntry* entry = + NS_STATIC_CAST(const nsFactoryTableEntry*, aHdr); + const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey); + + return (entry->mFactoryEntry->mCid).Equals(*cidp); +} + +PR_STATIC_CALLBACK(void) +factory_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + entry->mFactoryEntry->~nsFactoryEntry(); + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps factory_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + factory_GetKey, + factory_HashKey, + factory_MatchEntry, + PL_DHashMoveEntryStub, + factory_ClearEntry, + PL_DHashFinalizeStub, +}; + +PR_STATIC_CALLBACK(void) +contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + if (entry->mFactoryEntry->mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY && + entry->mFactoryEntry->mCid.Equals(kEmptyCID)) { + // this object is owned by the hash. + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + entry->mFactoryEntry->~nsFactoryEntry(); + } + + // contractIDs are arena allocated. No need to free them. + + PL_DHashClearEntryStub(aTable, aHdr); +} + +static const PLDHashTableOps contractID_DHashTableOps = { + PL_DHashAllocTable, + PL_DHashFreeTable, + PL_DHashGetKeyStub, + PL_DHashStringKey, + PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, + contractID_ClearEntry, + PL_DHashFinalizeStub, +}; + +//////////////////////////////////////////////////////////////////////////////// +// nsFactoryEntry +//////////////////////////////////////////////////////////////////////////////// + +MOZ_DECL_CTOR_COUNTER(nsFactoryEntry) +nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, + const char *aLocation, + PRUint32 locationlen, + int aType, + class nsFactoryEntry* parent) +: mCid(aClass), mTypeIndex(aType), mParent(parent) +{ + // Arena allocate the location string + mLocation = ArenaStrndup(aLocation, locationlen, &nsComponentManagerImpl::gComponentManager->mArena); +} + +nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, + nsIFactory *aFactory, + class nsFactoryEntry* parent) +: mCid(aClass), mTypeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY), mParent(parent) +{ + mFactory = aFactory; + mLocation = nsnull; +} + +// nsFactoryEntry is usually arena allocated including the strings it +// holds. So we call destructor by hand. +nsFactoryEntry::~nsFactoryEntry(void) +{ + // Release the reference to the factory + mFactory = nsnull; + + // Release any service reference + mServiceObject = nsnull; + + // nsFactoryEntry is arena allocated. So we dont delete it. + // We call the destructor by hand. + if (mParent) + mParent->~nsFactoryEntry(); +} + +nsresult +nsFactoryEntry::ReInit(const nsCID &aClass, const char *aLocation, int aType) +{ + NS_ENSURE_TRUE(mTypeIndex != NS_COMPONENT_TYPE_FACTORY_ONLY, NS_ERROR_INVALID_ARG); + // cid has to match + // SERVICE_ONLY entries can be promoted to an entry of another type + NS_ENSURE_TRUE((mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || mCid.Equals(aClass)), + NS_ERROR_INVALID_ARG); + + // Arena allocate the location string + mLocation = ArenaStrdup(aLocation, &nsComponentManagerImpl::gComponentManager->mArena); + + mTypeIndex = aType; + return NS_OK; +} + +//////////////////////////////////////////////////////////////////////////////// +// Hashtable Enumeration +//////////////////////////////////////////////////////////////////////////////// +typedef NS_CALLBACK(EnumeratorConverter)(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, + nsISupports **retval); + +class PLDHashTableEnumeratorImpl : public nsIBidirectionalEnumerator, + public nsISimpleEnumerator +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIENUMERATOR + NS_DECL_NSIBIDIRECTIONALENUMERATOR + NS_DECL_NSISIMPLEENUMERATOR + + PLDHashTableEnumeratorImpl(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData); + PRInt32 Count() { return mCount; } +private: + PLDHashTableEnumeratorImpl(); /* no implementation */ + + ~PLDHashTableEnumeratorImpl(); + NS_IMETHODIMP ReleaseElements(); + + nsVoidArray mElements; + PRInt32 mCount, mCurrent; + PRMonitor* mMonitor; + + struct Closure { + PRBool succeeded; + EnumeratorConverter converter; + void *data; + PLDHashTableEnumeratorImpl *impl; + }; + + static PLDHashOperator PR_CALLBACK Enumerator(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *data); +}; + +// static +PLDHashOperator PR_CALLBACK +PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *data) +{ + Closure *c = NS_REINTERPRET_CAST(Closure *, data); + nsISupports *converted; + if (NS_FAILED(c->converter(table, hdr, c->data, &converted)) || + !c->impl->mElements.AppendElement(converted)) { + c->succeeded = PR_FALSE; + return PL_DHASH_STOP; + } + + c->succeeded = PR_TRUE; + return PL_DHASH_NEXT; +} + +PLDHashTableEnumeratorImpl::PLDHashTableEnumeratorImpl(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData) +: mCurrent(0) +{ + mMonitor = nsAutoMonitor::NewMonitor("PLDHashTableEnumeratorImpl"); + NS_ASSERTION(mMonitor, "NULL Monitor"); + + nsAutoMonitor mon(mMonitor); + + Closure c = { PR_FALSE, converter, converterData, this }; + mCount = PL_DHashTableEnumerate(table, Enumerator, &c); + if (!c.succeeded) { + ReleaseElements(); + mCount = 0; + } +} + +NS_IMPL_ISUPPORTS3(PLDHashTableEnumeratorImpl, + nsIBidirectionalEnumerator, + nsIEnumerator, + nsISimpleEnumerator) + +PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl() +{ + (void) ReleaseElements(); + + // Destroy the Lock + if (mMonitor) + nsAutoMonitor::DestroyMonitor(mMonitor); +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::ReleaseElements() +{ + for (PRInt32 i = 0; i < mCount; i++) { + nsISupports *supports = NS_REINTERPRET_CAST(nsISupports *, + mElements[i]); + NS_IF_RELEASE(supports); + } + return NS_OK; +} + +NS_IMETHODIMP +PL_NewDHashTableEnumerator(PLDHashTable *table, + EnumeratorConverter converter, + void *converterData, + PLDHashTableEnumeratorImpl **retval) +{ + PLDHashTableEnumeratorImpl *impl = + new PLDHashTableEnumeratorImpl(table, converter, converterData); + + if (!impl) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ADDREF(impl); + + if (impl->Count() == -1) { + // conversion failed + NS_RELEASE(impl); + return NS_ERROR_FAILURE; + } + + *retval = impl; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::First() +{ + if (!mCount) + return NS_ERROR_FAILURE; + + mCurrent = 0; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Last() +{ + if (!mCount) + return NS_ERROR_FAILURE; + mCurrent = mCount - 1; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Prev() +{ + if (!mCurrent) + return NS_ERROR_FAILURE; + + mCurrent--; + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::Next() +{ + // If empty or we're past the end, or we are at the end return error + if (!mCount || (mCurrent == mCount) || (++mCurrent == mCount)) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::CurrentItem(nsISupports **retval) +{ + if (!mCount || mCurrent == mCount) + return NS_ERROR_FAILURE; + + *retval = NS_REINTERPRET_CAST(nsISupports *, mElements[mCurrent]); + if (*retval) + NS_ADDREF(*retval); + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::IsDone() +{ + if (!mCount || (mCurrent == mCount)) + return NS_OK; + + return NS_ENUMERATOR_FALSE; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::HasMoreElements(PRBool *_retval) +{ + if (!mCount || (mCurrent == mCount)) + *_retval = PR_FALSE; + else + *_retval = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP +PLDHashTableEnumeratorImpl::GetNext(nsISupports **_retval) +{ + nsresult rv = Next(); + if (NS_FAILED(rv)) return rv; + + return CurrentItem(_retval); +} + +static NS_IMETHODIMP +ConvertFactoryEntryToCID(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, nsISupports **retval) +{ + nsresult rv; + nsCOMPtr wrapper; + + nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data); + + rv = cm->CreateInstanceByContractID(NS_SUPPORTS_ID_CONTRACTID, nsnull, + NS_GET_IID(nsISupportsID), getter_AddRefs(wrapper)); + + NS_ENSURE_SUCCESS(rv, rv); + + const nsFactoryTableEntry *entry = + NS_REINTERPRET_CAST(const nsFactoryTableEntry *, hdr); + if (entry) { + nsFactoryEntry *fe = entry->mFactoryEntry; + + wrapper->SetData(&fe->mCid); + *retval = wrapper; + NS_ADDREF(*retval); + return NS_OK; + } + *retval = nsnull; + + return rv; +} + +static NS_IMETHODIMP +ConvertContractIDKeyToString(PLDHashTable *table, + const PLDHashEntryHdr *hdr, + void *data, nsISupports **retval) +{ + nsresult rv; + nsCOMPtr wrapper; + + nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data); + + rv = cm->CreateInstanceByContractID(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull, + NS_GET_IID(nsISupportsCString), getter_AddRefs(wrapper)); + + NS_ENSURE_SUCCESS(rv, rv); + + const nsContractIDTableEntry *entry = + NS_REINTERPRET_CAST(const nsContractIDTableEntry *, hdr); + + wrapper->SetData(nsDependentCString(entry->mContractID, + entry->mContractIDLen)); + *retval = wrapper; + NS_ADDREF(*retval); + return NS_OK; +} + +// this is safe to call during InitXPCOM +static nsresult GetLocationFromDirectoryService(const char* prop, + nsIFile** aDirectory) +{ + nsCOMPtr directoryService; + nsDirectoryService::Create(nsnull, + NS_GET_IID(nsIProperties), + getter_AddRefs(directoryService)); + + if (!directoryService) + return NS_ERROR_FAILURE; + + return directoryService->Get(prop, + NS_GET_IID(nsIFile), + (void**)aDirectory); +} + + +//////////////////////////////////////////////////////////////////////////////// +// nsComponentManagerImpl +//////////////////////////////////////////////////////////////////////////////// + + +nsComponentManagerImpl::nsComponentManagerImpl() + : + mMon(NULL), + mNativeComponentLoader(0), +#ifdef ENABLE_STATIC_COMPONENT_LOADER + mStaticComponentLoader(0), +#endif + mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED), + mLoaderData(nsnull), + mRegistryDirty(PR_FALSE) +{ + mFactories.ops = nsnull; + mContractIDs.ops = nsnull; +} + +nsresult nsComponentManagerImpl::Init(void) +{ + PR_ASSERT(mShuttingDown != NS_SHUTDOWN_INPROGRESS); + if (mShuttingDown == NS_SHUTDOWN_INPROGRESS) + return NS_ERROR_FAILURE; + + mShuttingDown = NS_SHUTDOWN_NEVERHAPPENED; + + if (nsComponentManagerLog == nsnull) + { + nsComponentManagerLog = PR_NewLogModule("nsComponentManager"); + } + + // Initialize our arena + PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE); + + if (!mFactories.ops) { + if (!PL_DHashTableInit(&mFactories, &factory_DHashTableOps, + 0, sizeof(nsFactoryTableEntry), + 1024)) { + mFactories.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + // Minimum alpha uses k=2 because nsFactoryTableEntry saves two + // words compared to what a chained hash table requires. + PL_DHashTableSetAlphaBounds(&mFactories, + 0.875, + PL_DHASH_MIN_ALPHA(&mFactories, 2)); + } + + if (!mContractIDs.ops) { + if (!PL_DHashTableInit(&mContractIDs, &contractID_DHashTableOps, + 0, sizeof(nsContractIDTableEntry), + 1024)) { + mContractIDs.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + + // Minimum alpha uses k=1 because nsContractIDTableEntry saves one + // word compared to what a chained hash table requires. +#if 0 + PL_DHashTableSetAlphaBounds(&mContractIDs, + 0.875, + PL_DHASH_MIN_ALPHA(&mContractIDs, 1)); +#endif + } + if (mMon == nsnull) { + mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl"); + if (mMon == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + } + + if (mNativeComponentLoader == nsnull) { + /* Create the NativeComponentLoader */ + mNativeComponentLoader = new nsNativeComponentLoader(); + if (!mNativeComponentLoader) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(mNativeComponentLoader); + + nsresult rv = mNativeComponentLoader->Init(this, nsnull); + if (NS_FAILED(rv)) + return rv; + } + + // Add predefined loaders + mLoaderData = (nsLoaderdata *) PR_Malloc(sizeof(nsLoaderdata) * NS_LOADER_DATA_ALLOC_STEP); + if (!mLoaderData) + return NS_ERROR_OUT_OF_MEMORY; + mMaxNLoaderData = NS_LOADER_DATA_ALLOC_STEP; + + mNLoaderData = NS_COMPONENT_TYPE_NATIVE; + mLoaderData[mNLoaderData].type = PL_strdup(nativeComponentType); + mLoaderData[mNLoaderData].loader = mNativeComponentLoader; + NS_ADDREF(mLoaderData[mNLoaderData].loader); + mNLoaderData++; + +#ifdef ENABLE_STATIC_COMPONENT_LOADER + if (mStaticComponentLoader == nsnull) { + extern nsresult NS_NewStaticComponentLoader(nsIComponentLoader **); + NS_NewStaticComponentLoader(&mStaticComponentLoader); + if (!mStaticComponentLoader) + return NS_ERROR_OUT_OF_MEMORY; + } + + mLoaderData[mNLoaderData].type = PL_strdup(staticComponentType); + mLoaderData[mNLoaderData].loader = mStaticComponentLoader; + NS_ADDREF(mLoaderData[mNLoaderData].loader); + mNLoaderData++; + + if (mStaticComponentLoader) { + /* Init the static loader */ + mStaticComponentLoader->Init(this, nsnull); + } +#endif + GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_DIR, getter_AddRefs(mComponentsDir)); + if (!mComponentsDir) + return NS_ERROR_OUT_OF_MEMORY; + + nsCAutoString componentDescriptor; + nsresult rv = mComponentsDir->GetNativePath(componentDescriptor); + if (NS_FAILED(rv)) + return rv; + + mComponentsOffset = componentDescriptor.Length(); + + GetLocationFromDirectoryService(NS_GRE_COMPONENT_DIR, getter_AddRefs(mGREComponentsDir)); + if (mGREComponentsDir) { + nsresult rv = mGREComponentsDir->GetNativePath(componentDescriptor); + if (NS_FAILED(rv)) { + NS_WARNING("No GRE component manager"); + return rv; + } + mGREComponentsOffset = componentDescriptor.Length(); + } + + GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_REGISTRY_FILE, + getter_AddRefs(mRegistryFile)); + + if(!mRegistryFile) { + NS_WARNING("No Component Registry file was found in the directory service"); + return NS_ERROR_FAILURE; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsComponentManager: Initialized.")); + + return NS_OK; +} + +PRIntn PR_CALLBACK AutoRegEntryDestroy(nsHashKey *aKey, void *aData, void* aClosure) +{ + delete (AutoRegEntry*)aData; + return kHashEnumerateNext; +} + +nsresult nsComponentManagerImpl::Shutdown(void) +{ + PR_ASSERT(mShuttingDown == NS_SHUTDOWN_NEVERHAPPENED); + if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED) + return NS_ERROR_FAILURE; + + mShuttingDown = NS_SHUTDOWN_INPROGRESS; + + // Shutdown the component manager + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown.")); + + PRInt32 i; + + // Write out our component data file. + if (mRegistryDirty) { + nsresult rv = WritePersistentRegistry(); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Could not write out perisistant registry.")); +#ifdef DEBUG + printf("Could not write out perisistant registry!\n"); +#endif + } + } + + mAutoRegEntries.Reset(AutoRegEntryDestroy); + + // Release all cached factories + if (mContractIDs.ops) { + PL_DHashTableFinish(&mContractIDs); + mContractIDs.ops = nsnull; + } + if (mFactories.ops) { + PL_DHashTableFinish(&mFactories); + mFactories.ops = nsnull; + } + // Unload libraries + UnloadLibraries(nsnull, NS_Shutdown); + + // delete arena for strings and small objects + PL_FinishArenaPool(&mArena); + + mComponentsDir = 0; + + mCategoryManager = 0; + + // Release all the component data - loaders and type strings + for (i=0; i < mNLoaderData; i++) { + NS_IF_RELEASE(mLoaderData[i].loader); + PL_strfree((char *)mLoaderData[i].type); + } + PR_Free(mLoaderData); + mLoaderData = nsnull; + + // we have an extra reference on this one, which is probably a good thing + NS_IF_RELEASE(mNativeComponentLoader); +#ifdef ENABLE_STATIC_COMPONENT_LOADER + NS_IF_RELEASE(mStaticComponentLoader); +#endif + + mShuttingDown = NS_SHUTDOWN_COMPLETE; + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete.")); + + return NS_OK; +} + +nsComponentManagerImpl::~nsComponentManagerImpl() +{ + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction.")); + + if (mShuttingDown != NS_SHUTDOWN_COMPLETE) + Shutdown(); + + if (mMon) { + nsAutoMonitor::DestroyMonitor(mMon); + } + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed.")); +} + +NS_IMPL_THREADSAFE_ISUPPORTS8(nsComponentManagerImpl, + nsIComponentManager, + nsIServiceManager, + nsISupportsWeakReference, + nsIInterfaceRequestor, + nsIComponentRegistrar, + nsIServiceManagerObsolete, + nsIComponentManagerObsolete, + nsIComponentLoaderManager) + + +nsresult +nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result) +{ + if (uuid.Equals(NS_GET_IID(nsINativeComponentLoader))) + { + if (!mNativeComponentLoader) + return NS_ERROR_NOT_INITIALIZED; + + return mNativeComponentLoader->QueryInterface(uuid, result); + } + + NS_WARNING("This isn't supported"); + // fall through to QI as anything QIable is a superset of what can be + // got via the GetInterface() + return QueryInterface(uuid, result); +} + +//////////////////////////////////////////////////////////////////////////////// +// nsComponentManagerImpl: Platform methods +//////////////////////////////////////////////////////////////////////////////// + +#define PERSISTENT_REGISTRY_VERSION_MINOR 5 +#define PERSISTENT_REGISTRY_VERSION_MAJOR 0 + + +AutoRegEntry::AutoRegEntry(const nsACString& name, PRInt64* modDate) : + mName(ToNewCString(name)), + mNameLen(name.Length()), + mData(nsnull), + mModDate(*modDate) +{ +} + +AutoRegEntry::~AutoRegEntry() +{ + if (mName) PL_strfree(mName); + if (mData) PL_strfree(mData); +} + +PRBool +AutoRegEntry::Modified(PRInt64 *date) +{ + return !LL_EQ(*date, mModDate); +} + +void +AutoRegEntry::SetOptionalData(const char* data) +{ + if (mData) + PL_strfree(mData); + + if (!data) { + mData = nsnull; + return; + } + + mData = PL_strdup(data); +} + +static +PRBool ReadSectionHeader(nsManifestLineReader& reader, const char *token) +{ + while (1) + { + if (*reader.LinePtr() == '[') + { + char* p = reader.LinePtr() + (reader.LineLength() - 1); + if (*p != ']') + break; + *p = 0; + + char* values[1]; + int lengths[1]; + if (2 != reader.ParseLine(values, lengths, 1)) + break; + + // ignore the leading '[' + if (0 != PL_strcmp(values[0]+1, token)) + break; + + return PR_TRUE; + } + + if (!reader.NextLine()) + break; + } + return PR_FALSE; +} + +nsresult +nsComponentManagerImpl::ReadPersistentRegistry() +{ + + // populate Category Manager. need to get this early so that we don't get + // skipped by 'goto out' + nsresult rv = GetService(kCategoryManagerCID, + NS_GET_IID(nsICategoryManager), + getter_AddRefs(mCategoryManager)); + if (NS_FAILED(rv)) + return rv; + + nsAutoMonitor mon(mMon); + nsManifestLineReader reader; + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; // this should have been set by Init(). + + PRFileDesc* fd = nsnull; + + // Set From Init + if (!mRegistryFile) { + return NS_ERROR_FILE_NOT_FOUND; + } + + nsCOMPtr file; + mRegistryFile->Clone(getter_AddRefs(file)); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr localFile(do_QueryInterface(file)); + + rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd); + if (NS_FAILED(rv)) + return rv; + + PRInt64 fileSize; + rv = localFile->GetFileSize(&fileSize); + if (NS_FAILED(rv)) + { + PR_Close(fd); + return rv; + } + + PRInt32 flen = nsInt64(fileSize); + if (flen == 0) + { + PR_Close(fd); + NS_WARNING("Persistent Registry Empty!"); + return NS_OK; // ERROR CONDITION + } + + char* registry = new char[flen+1]; + if (!registry) + goto out; + + if (flen > PR_Read(fd, registry, flen)) + { + rv = NS_ERROR_FAILURE; + goto out; + } + registry[flen] = '\0'; + + reader.Init(registry, flen); + + if (ReadSectionHeader(reader, "HEADER")) + goto out; + + if (!reader.NextLine()) + goto out; + + char* values[6]; + int lengths[6]; + + // VersionLiteral,major,minor + if (3 != reader.ParseLine(values, lengths, 3)) + goto out; + + // VersionLiteral + if (!nsDependentCString(values[0], lengths[0]).EqualsLiteral("Version")) + goto out; + + // major + if (PERSISTENT_REGISTRY_VERSION_MAJOR != atoi(values[1])) + goto out; + + // minor + if (PERSISTENT_REGISTRY_VERSION_MINOR != atoi(values[2])) + goto out; + + if (ReadSectionHeader(reader, "COMPONENTS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //name,last_modification_date[,optionaldata] + int parts = reader.ParseLine(values, lengths, 3); + if (2 > parts) + break; + + PRInt64 a = nsCRT::atoll(values[1]); + AutoRegEntry *entry = + new AutoRegEntry(nsDependentCString(values[0], lengths[0]), &a); + + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + if (parts == 3) + entry->SetOptionalData(values[2]); + + nsCStringKey key((const char*)values[0]); + mAutoRegEntries.Put(&key, entry); + } + + if (ReadSectionHeader(reader, "CLASSIDS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + // cid,contract_id,type,class_name,inproc_server + if (5 != reader.ParseLine(values, lengths, 5)) + break; + + nsCID aClass; + if (!aClass.Parse(values[0])) + continue; + + int loadertype = GetLoaderType(values[2]); + if (loadertype < 0) { + rv = AddLoaderType(values[2], &loadertype); + if (NS_FAILED(rv)) + continue; + } + + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + nsFactoryEntry *entry = new (mem) nsFactoryEntry(aClass, values[4], lengths[4], loadertype); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, + &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + + } + + if (ReadSectionHeader(reader, "CONTRACTIDS")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //contractID,cid + if (2 != reader.ParseLine(values, lengths, 2)) + break; + + nsCID aClass; + if (!aClass.Parse(values[1])) + continue; + + + //need to find the location for this cid. + nsFactoryEntry *cidEntry = GetFactoryEntry(aClass); + if (!cidEntry || cidEntry->mTypeIndex < 0) + continue; //what should we really do? + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, + values[0], + PL_DHASH_ADD)); + if (!contractIDTableEntry) { + continue; + } + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = ArenaStrndup(values[0], lengths[0], &mArena); + contractIDTableEntry->mContractIDLen = lengths[0]; + } + + contractIDTableEntry->mFactoryEntry = cidEntry; + } + +#ifdef XPCOM_CHECK_PENDING_CIDS + { +/* + * If you get Asserts when you define SHOW_CI_ON_EXISTING_SERVICE and want to + * track down their cause, then you should add the contracts listed by the + * assertion to abusedContracts. The next time you run your xpcom app, xpcom + * will assert the first time the object associated with the contract is + * instantiated (which in many cases is the source of the problem). + * + * If you're doing this then you might want to NOP and soft breakpoint the + * lines labeled: NOP_AND_BREAK. + * + * Otherwise XPCOM will refuse to create the object for the caller, which + * while reasonable at some level, will almost certainly cause the app to + * stop functioning normally. + */ + static char abusedContracts[][128] = { + /*// Example contracts: + "@mozilla.org/rdf/container;1", + "@mozilla.org/intl/charsetalias;1", + "@mozilla.org/locale/win32-locale;1", + "@mozilla.org/widget/lookandfeel/win;1", + // */ + { 0 } + }; + for (int i=0; abusedContracts[i] && *abusedContracts[i]; i++) { + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, abusedContracts[i], + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + AddPendingCID(entry->mCid); + } + } + } +#endif + + if (ReadSectionHeader(reader, "CATEGORIES")) + goto out; + + while (1) + { + if (!reader.NextLine()) + break; + + //type,name,value + if (3 != reader.ParseLine(values, lengths, 3)) + break; + + mCategoryManager->AddCategoryEntry(values[0], + values[1], + values[2], + PR_TRUE, + PR_TRUE, + 0); + } + + mRegistryDirty = PR_FALSE; +out: + if (fd) + PR_Close(fd); + + if (registry) + delete [] registry; + + return rv; +} + +struct PersistentWriterArgs +{ + PRFileDesc *mFD; + nsLoaderdata *mLoaderData; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +ContractIDWriter(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg) +{ + char *contractID = ((nsContractIDTableEntry*)hdr)->mContractID; + nsFactoryEntry *factoryEntry = ((nsContractIDTableEntry*)hdr)->mFactoryEntry; + + // for now, we only save out the top most parent. + while (factoryEntry->mParent) + factoryEntry = factoryEntry->mParent; + + if (factoryEntry->mTypeIndex < 0) + return PL_DHASH_NEXT; + + PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD; + + char cidString[UID_STRING_LENGTH]; + GetIDString(factoryEntry->mCid, cidString); + PR_fprintf(fd, "%s,%s\n", contractID, cidString); // what if this fails? + return PL_DHASH_NEXT; +} + +PR_STATIC_CALLBACK(PLDHashOperator) +ClassIDWriter(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, + void *arg) +{ + nsFactoryEntry *factoryEntry = ((nsFactoryTableEntry*)hdr)->mFactoryEntry; + PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD; + nsLoaderdata *loaderData = ((PersistentWriterArgs*)arg)->mLoaderData; + + // for now, we only save out the top most parent. + while (factoryEntry->mParent) + factoryEntry = factoryEntry->mParent; + + if (factoryEntry->mTypeIndex < 0) { + return PL_DHASH_NEXT; + } + + char cidString[UID_STRING_LENGTH]; + GetIDString(factoryEntry->mCid, cidString); + + char *contractID = nsnull, *className = nsnull; + + nsCOMPtr classInfo = do_QueryInterface(factoryEntry->mFactory); + if (classInfo) + { + classInfo->GetContractID(&contractID); + classInfo->GetClassDescription(&className); + } + + const char * loaderName = nsnull; + if (factoryEntry->mTypeIndex) + loaderName = loaderData[factoryEntry->mTypeIndex].type; + + char* location = factoryEntry->mLocation; + + // cid,contract_id,type,class_name,inproc_server + PR_fprintf(fd, + "%s,%s,%s,%s,%s\n", + cidString, + (contractID ? contractID : ""), + (loaderName ? loaderName : ""), + (className ? className : ""), + (location ? location : "")); + + if (contractID) + PR_Free(contractID); + if (className) + PR_Free(className); + + return PL_DHASH_NEXT; +} + +PRIntn PR_CALLBACK +AutoRegEntryWriter(nsHashKey *aKey, void *aData, void* aClosure) +{ + PRFileDesc* fd = (PRFileDesc*) aClosure; + AutoRegEntry* entry = (AutoRegEntry*) aData; + + const char* extraData = entry->GetOptionalData(); + const char *fmt; + if (extraData) + fmt = "%s,%lld,%s\n"; + else + fmt = "%s,%lld\n"; + PR_fprintf(fd, fmt, entry->GetName().get(), entry->GetDate(), extraData); + + return PR_TRUE; +} + +nsresult +nsComponentManagerImpl::WritePersistentRegistry() +{ + if (!mRegistryFile) + return NS_ERROR_FAILURE; // this should have been set by Init(). + + nsCOMPtr file; + mRegistryFile->Clone(getter_AddRefs(file)); + if (!file) + return NS_ERROR_OUT_OF_MEMORY; + + nsCOMPtr localFile(do_QueryInterface(file)); + + nsCAutoString originalLeafName; + localFile->GetNativeLeafName(originalLeafName); + + nsCAutoString leafName; + leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp")); + + localFile->SetNativeLeafName(leafName); + + PRFileDesc* fd = nsnull; + nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd); + if (NS_FAILED(rv)) + return rv; + + if (PR_fprintf(fd, "Generated File. Do not edit.\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + if (PR_fprintf(fd, "\n[HEADER]\nVersion,%d,%d\n", + PERSISTENT_REGISTRY_VERSION_MAJOR, + PERSISTENT_REGISTRY_VERSION_MINOR) == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + if (PR_fprintf(fd, "\n[COMPONENTS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + mAutoRegEntries.Enumerate(AutoRegEntryWriter, (void*)fd); + + PersistentWriterArgs args; + args.mFD = fd; + args.mLoaderData = mLoaderData; + + if (PR_fprintf(fd, "\n[CLASSIDS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + PL_DHashTableEnumerate(&mFactories, ClassIDWriter, (void*)&args); + + if (PR_fprintf(fd, "\n[CONTRACTIDS]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + PL_DHashTableEnumerate(&mContractIDs, ContractIDWriter, (void*)&args); + + if (PR_fprintf(fd, "\n[CATEGORIES]\n") == (PRUint32) -1) { + rv = NS_ERROR_UNEXPECTED; + goto out; + } + + + if (!mCategoryManager) { + NS_WARNING("Could not access category manager. Will not be able to save categories!"); + rv = NS_ERROR_UNEXPECTED; + } else { + rv = mCategoryManager->WriteCategoryManagerToRegistry(fd); + } + +out: + if (fd) + PR_Close(fd); + + // don't create the file is there was a problem???? + NS_ENSURE_SUCCESS(rv, rv); + + if (!mRegistryFile) + return NS_ERROR_NOT_INITIALIZED; + + PRBool exists; + if(NS_FAILED(mRegistryFile->Exists(&exists))) + return PR_FALSE; + + if(exists && NS_FAILED(mRegistryFile->Remove(PR_FALSE))) + return PR_FALSE; + + nsCOMPtr parent; + mRegistryFile->GetParent(getter_AddRefs(parent)); + + rv = localFile->MoveToNative(parent, originalLeafName); + mRegistryDirty = PR_FALSE; + + return rv; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Hash Functions +//////////////////////////////////////////////////////////////////////////////// +nsresult +nsComponentManagerImpl::HashContractID(const char *aContractID, + PRUint32 aContractIDLen, + nsFactoryEntry *fe) +{ + if(!aContractID || !aContractIDLen) + return NS_ERROR_NULL_POINTER; + + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_ADD)); + if (!contractIDTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + NS_ASSERTION(!contractIDTableEntry->mContractID || !strcmp(contractIDTableEntry->mContractID, aContractID), "contractid conflict"); + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = ArenaStrndup(aContractID, aContractIDLen, &mArena); + contractIDTableEntry->mContractIDLen = aContractIDLen; + } + + contractIDTableEntry->mFactoryEntry = fe; + + return NS_OK; +} + +/** + * LoadFactory() + * + * Given a FactoryEntry, this loads the dll if it has to, find the NSGetFactory + * symbol, calls the routine to create a new factory and returns it to the + * caller. + * + * No attempt is made to store the factory in any form anywhere. + */ +nsresult +nsComponentManagerImpl::LoadFactory(nsFactoryEntry *aEntry, + nsIFactory **aFactory) +{ + + if (!aFactory) + return NS_ERROR_NULL_POINTER; + *aFactory = nsnull; + + nsresult rv; + rv = aEntry->GetFactory(aFactory, this); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsComponentManager: FAILED to load factory from %s (%s)\n", + (const char *)aEntry->mLocation, mLoaderData[aEntry->mTypeIndex].type)); + return rv; + } + + return NS_OK; +} + +nsFactoryEntry * +nsComponentManagerImpl::GetFactoryEntry(const char *aContractID, + PRUint32 aContractIDLen) +{ + nsFactoryEntry *fe = nsnull; + { + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + fe = contractIDTableEntry->mFactoryEntry; + } + } //exit monitor + + return fe; +} + + +nsFactoryEntry * +nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass) +{ + nsFactoryEntry *entry = nsnull; + { + nsAutoMonitor mon(mMon); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + } // exit monitor + + return entry; +} + + +/** + * FindFactory() + * + * Given a classID, this finds the factory for this CID by first searching the + * local CID<->factory mapping. Next it searches for a Dll that implements + * this classID and calls LoadFactory() to create the factory. + * + * Again, no attempt is made at storing the factory. + */ +nsresult +nsComponentManagerImpl::FindFactory(const nsCID &aClass, + nsIFactory **aFactory) +{ + PR_ASSERT(aFactory != nsnull); + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + return entry->GetFactory(aFactory, this); +} + + +nsresult +nsComponentManagerImpl::FindFactory(const char *contractID, + PRUint32 aContractIDLen, + nsIFactory **aFactory) +{ + PR_ASSERT(aFactory != nsnull); + + nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + return entry->GetFactory(aFactory, this); +} + +/** + * GetClassObject() + * + * Given a classID, this finds the singleton ClassObject that implements the CID. + * Returns an interface of type aIID off the singleton classobject. + */ +nsresult +nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult) +{ + nsresult rv; + + nsCOMPtr factory; + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) + { + char *buf = aClass.ToString(); + PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf); + if (buf) + PR_Free(buf); + } +#endif + + PR_ASSERT(aResult != nsnull); + + rv = FindFactory(aClass, getter_AddRefs(factory)); + if (NS_FAILED(rv)) return rv; + + rv = factory->QueryInterface(aIID, aResult); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + + +nsresult +nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID, + const nsIID &aIID, + void **aResult) +{ + nsresult rv; + + nsCOMPtr factory; + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG)) + { + PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID); + } +#endif + + PR_ASSERT(aResult != nsnull); + + rv = FindFactory(contractID, strlen(contractID), getter_AddRefs(factory)); + if (NS_FAILED(rv)) return rv; + + rv = factory->QueryInterface(aIID, aResult); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + +/** + * ContractIDToClassID() + * + * Mapping function from a ContractID to a classID. Directly talks to the registry. + * + */ +nsresult +nsComponentManagerImpl::ContractIDToClassID(const char *aContractID, nsCID *aClass) +{ + NS_PRECONDITION(aContractID != nsnull, "null ptr"); + if (!aContractID) + return NS_ERROR_NULL_POINTER; + + NS_PRECONDITION(aClass != nsnull, "null ptr"); + if (!aClass) + return NS_ERROR_NULL_POINTER; + + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; + + nsFactoryEntry *fe = GetFactoryEntry(aContractID, strlen(aContractID)); + if (fe) { + *aClass = fe->mCid; + rv = NS_OK; + } +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) { + char *buf = 0; + if (NS_SUCCEEDED(rv)) + buf = aClass->ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID, + NS_SUCCEEDED(rv) ? buf : "[FAILED]")); + if (buf) + PR_Free(buf); + } +#endif + return rv; +} + +/** + * CLSIDToContractID() + * + * Translates a classID to a {ContractID, Class Name}. Does direct registry + * access to do the translation. + * + * NOTE: Since this isn't heavily used, we arent caching this. + */ +nsresult +nsComponentManagerImpl::CLSIDToContractID(const nsCID &aClass, + char* *aClassName, + char* *aContractID) +{ + NS_WARNING("Need to implement CLSIDToContractID"); + + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CLSIDToContractID(%s)->%s", buf, + NS_SUCCEEDED(rv) ? *aContractID : "[FAILED]")); + if (buf) + PR_Free(buf); + } +#endif + return rv; +} + +#ifdef XPCOM_CHECK_PENDING_CIDS + +// This method must be called from within the mMon monitor +nsresult +nsComponentManagerImpl::AddPendingCID(const nsCID &aClass) +{ + int max = mPendingCIDs.Count(); + for (int index = 0; index < max; index++) + { + nsCID *cidp = (nsCID*) mPendingCIDs.ElementAt(index); + NS_ASSERTION(cidp, "Bad CID in pending list"); + if (cidp->Equals(aClass)) { + nsXPIDLCString cid; + cid.Adopt(aClass.ToString()); + nsCAutoString message; + message = NS_LITERAL_CSTRING("Creation of \"") + + cid + NS_LITERAL_CSTRING("\" in progress (Reentrant GS - see bug 194568)"); + // Note that you may see this assertion by near-simultaneous + // calls to GetService on multiple threads. + NS_WARNING(message.get()); + return NS_ERROR_NOT_AVAILABLE; + } + } + mPendingCIDs.AppendElement((void*)&aClass); + return NS_OK; +} + +// This method must be called from within the mMon monitor +void +nsComponentManagerImpl::RemovePendingCID(const nsCID &aClass) +{ + mPendingCIDs.RemoveElement((void*)&aClass); +} +#endif +/** + * CreateInstance() + * + * Create an instance of an object that implements an interface and belongs + * to the implementation aClass using the factory. The factory is immediately + * released and not held onto for any longer. + */ +nsresult +nsComponentManagerImpl::CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + // test this first, since there's no point in creating a component during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Creating new instance on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + if (aResult == nsnull) + { + return NS_ERROR_NULL_POINTER; + } + *aResult = nsnull; + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + +#ifdef SHOW_CI_ON_EXISTING_SERVICE + if (entry->mServiceObject) { + nsXPIDLCString cid; + cid.Adopt(aClass.ToString()); + nsCAutoString message; + message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") + + cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!"); + NS_ERROR(message.get()); + } +#endif + + nsIFactory *factory = nsnull; + nsresult rv = entry->GetFactory(&factory, this); + + if (NS_SUCCEEDED(rv)) + { + rv = factory->CreateInstance(aDelegate, aIID, aResult); + NS_RELEASE(factory); + } + else + { + // Translate error values + rv = NS_ERROR_FACTORY_NOT_REGISTERED; + } + +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CreateInstance(%s) %s", buf, + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + if (buf) + PR_Free(buf); + } +#endif + + return rv; +} + +/** + * CreateInstanceByContractID() + * + * A variant of CreateInstance() that creates an instance of the object that + * implements the interface aIID and whose implementation has a contractID aContractID. + * + * This is only a convenience routine that turns around can calls the + * CreateInstance() with classid and iid. + */ +nsresult +nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + // test this first, since there's no point in creating a component during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Creating new instance on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + if (aResult == nsnull) + { + return NS_ERROR_NULL_POINTER; + } + *aResult = nsnull; + + nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID)); + + if (!entry) + return NS_ERROR_FACTORY_NOT_REGISTERED; + +#ifdef SHOW_CI_ON_EXISTING_SERVICE + if (entry->mServiceObject) { + nsCAutoString message; + message = + NS_LITERAL_CSTRING("You are calling CreateInstance \"") + + nsDependentCString(aContractID) + + NS_LITERAL_CSTRING("\" when a service for this CID already exists! " + "Add it to abusedContracts to track down the service consumer."); + NS_ERROR(message.get()); + } +#endif + + nsIFactory *factory = nsnull; + nsresult rv = entry->GetFactory(&factory, this); + + if (NS_SUCCEEDED(rv)) + { + + rv = factory->CreateInstance(aDelegate, aIID, aResult); + NS_RELEASE(factory); + } + else + { + // Translate error values + if (rv != NS_ERROR_SOCKET_FAIL) + rv = NS_ERROR_FACTORY_NOT_REGISTERED; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID, + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + + return rv; +} + +// Service Manager Impl +static +PLDHashOperator PR_CALLBACK +FreeServiceFactoryEntryEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + factoryEntry->mServiceObject = nsnull; + return PL_DHASH_NEXT; +} + +static +PLDHashOperator PR_CALLBACK +FreeServiceContractIDEntryEnumerate(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + factoryEntry->mServiceObject = nsnull; + return PL_DHASH_NEXT; +} + +nsresult +nsComponentManagerImpl::FreeServices() +{ + NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services"); + + if (!gXPCOMShuttingDown) + return NS_ERROR_FAILURE; + + if (mContractIDs.ops) { + PL_DHashTableEnumerate(&mContractIDs, FreeServiceContractIDEntryEnumerate, nsnull); + } + + + if (mFactories.ops) { + PL_DHashTableEnumerate(&mFactories, FreeServiceFactoryEntryEnumerate, nsnull); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const nsCID& aClass, + const nsIID& aIID, + void* *result) +{ + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Getting service on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsAutoMonitor mon(mMon); + + nsresult rv = NS_OK; + nsIDKey key(aClass); + nsFactoryEntry* entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && entry->mServiceObject) { + return entry->mServiceObject->QueryInterface(aIID, result); + } + +#ifdef XPCOM_CHECK_PENDING_CIDS + rv = AddPendingCID(aClass); + if (NS_FAILED(rv)) + return rv; // NOP_AND_BREAK +#endif + nsCOMPtr service; + // We need to not be holding the service manager's monitor while calling + // CreateInstance, because it invokes user code which could try to re-enter + // the service manager: + mon.Exit(); + + rv = CreateInstance(aClass, nsnull, aIID, getter_AddRefs(service)); + + mon.Enter(); + +#ifdef XPCOM_CHECK_PENDING_CIDS + RemovePendingCID(aClass); +#endif + + if (NS_FAILED(rv)) + return rv; + + if (!entry) { // second hash lookup for GetService + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here"); + if (!entry) return NS_ERROR_FAILURE; + } + + entry->mServiceObject = service; + *result = service.get(); + NS_ADDREF(NS_STATIC_CAST(nsISupports*, (*result))); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService) +{ + nsAutoMonitor mon(mMon); + + // check to see if we have a factory entry for the service + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + if (!entry) { // XXXdougt - should we require that all services register factories?? probably not. + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + entry = new (mem) nsFactoryEntry(aClass, nsnull); + + entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_ADD)); + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + } + else { + if (entry->mServiceObject) + return NS_ERROR_FAILURE; + } + + entry->mServiceObject = aService; + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterService(const nsCID& aClass) +{ + nsresult rv = NS_OK; + + nsFactoryEntry* entry = nsnull; + + nsAutoMonitor mon(mMon); + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (!entry || !entry->mServiceObject) + return NS_ERROR_SERVICE_NOT_AVAILABLE; + + entry->mServiceObject = nsnull; + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterService(const char* aContractID, nsISupports* aService) +{ + + nsAutoMonitor mon(mMon); + + // check to see if we have a factory entry for the service + PRUint32 contractIDLen = strlen(aContractID); + nsFactoryEntry *entry = GetFactoryEntry(aContractID, contractIDLen); + + if (!entry) { // XXXdougt - should we require that all services register factories?? probably not. + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + entry = new (mem) nsFactoryEntry(kEmptyCID, nsnull); + + entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY; + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_ADD)); + if (!contractIDTableEntry) { + delete entry; + return NS_ERROR_OUT_OF_MEMORY; + } + + if (!contractIDTableEntry->mContractID) { + contractIDTableEntry->mContractID = + ArenaStrndup(aContractID, contractIDLen, &mArena); + + contractIDTableEntry->mContractIDLen = contractIDLen; + } + + contractIDTableEntry->mFactoryEntry = entry; + } + else { + if (entry->mServiceObject) + return NS_ERROR_FAILURE; + } + + entry->mServiceObject = aService; + return NS_OK; +} + + +NS_IMETHODIMP +nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass, + const nsIID& aIID, + PRBool *result) +{ + // Now we want to get the service if we already got it. If not, we dont want + // to create an instance of it. mmh! + + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString cid, iid; + cid.Adopt(aClass.ToString()); + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Checking for service on shutdown. Denied.\n" + " CID: %s\n IID: %s\n", cid.get(), iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + nsFactoryEntry* entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && entry->mServiceObject) { + nsCOMPtr service; + rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service)); + *result = (service!=nsnull); + } + return rv; + +} + +NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID, + const nsIID& aIID, + PRBool *result) +{ + // Now we want to get the service if we already got it. If not, we dont want + // to create an instance of it. mmh! + + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Checking for service on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE; + nsFactoryEntry *entry = nsnull; + { + nsAutoMonitor mon(mMon); + + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + } // exit monitor + + if (entry && entry->mServiceObject) { + nsCOMPtr service; + rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service)); + *result = (service!=nsnull); + } + return rv; +} + + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterService(const char* aContractID) +{ + nsresult rv = NS_OK; + + nsAutoMonitor mon(mMon); + + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + + if (!entry || !entry->mServiceObject) + return NS_ERROR_SERVICE_NOT_AVAILABLE; + + entry->mServiceObject = nsnull; + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetServiceByContractID(const char* aContractID, + const nsIID& aIID, + void* *result) +{ + // test this first, since there's no point in returning a service during + // shutdown -- whether it's available or not would depend on the order it + // occurs in the list + if (gXPCOMShuttingDown) { + // When processing shutdown, dont process new GetService() requests +#ifdef SHOW_DENIED_ON_SHUTDOWN + nsXPIDLCString iid; + iid.Adopt(aIID.ToString()); + fprintf(stderr, "Getting service on shutdown. Denied.\n" + " ContractID: %s\n IID: %s\n", aContractID, iid.get()); +#endif /* SHOW_DENIED_ON_SHUTDOWN */ + return NS_ERROR_UNEXPECTED; + } + + nsAutoMonitor mon(mMon); + + nsresult rv = NS_OK; + nsFactoryEntry *entry = nsnull; + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + + if (entry) { + if (entry->mServiceObject) { + return entry->mServiceObject->QueryInterface(aIID, result); + } +#ifdef XPCOM_CHECK_PENDING_CIDS + rv = AddPendingCID(entry->mCid); + if (NS_FAILED(rv)) + return rv; // NOP_AND_BREAK +#endif + } + + nsCOMPtr service; + // We need to not be holding the service manager's monitor while calling + // CreateInstance, because it invokes user code which could try to re-enter + // the service manager: + mon.Exit(); + + rv = CreateInstanceByContractID(aContractID, nsnull, aIID, getter_AddRefs(service)); + + mon.Enter(); + +#ifdef XPCOM_CHECK_PENDING_CIDS + if (entry) + RemovePendingCID(entry->mCid); +#endif + + if (NS_FAILED(rv)) + return rv; + + if (!entry) { // second hash lookup for GetService + nsContractIDTableEntry* contractIDTableEntry = + NS_STATIC_CAST(nsContractIDTableEntry*, + PL_DHashTableOperate(&mContractIDs, aContractID, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) { + entry = contractIDTableEntry->mFactoryEntry; + } + NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here"); + if (!entry) return NS_ERROR_FAILURE; + } + + entry->mServiceObject = service; + *result = service.get(); + NS_ADDREF(NS_STATIC_CAST(nsISupports*, *result)); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + return GetService(aClass, aIID, (void**)result); +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + return GetServiceByContractID(aContractID, aIID, (void**)result); +} + + +NS_IMETHODIMP +nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +/* + * I want an efficient way to allocate a buffer to the right size + * and stick the prefix and dllName in, then be able to hand that buffer + * off to the FactoryEntry. Is that so wrong? + * + * *regName is allocated on success. + * + * This should live in nsNativeComponentLoader.cpp, I think. + */ +static nsresult +MakeRegistryName(const char *aDllName, const char *prefix, char **regName) +{ + char *registryName; + + PRUint32 len = strlen(prefix); + + PRUint32 registryNameLen = strlen(aDllName) + len; + registryName = (char *)nsMemory::Alloc(registryNameLen + 1); + + // from here on it, we want len sans terminating NUL + + if (!registryName) + return NS_ERROR_OUT_OF_MEMORY; + + memcpy(registryName, prefix, len); + strcpy(registryName + len, aDllName); + registryName[registryNameLen] = '\0'; + *regName = registryName; + +#ifdef DEBUG_shaver_off + fprintf(stderr, "MakeRegistryName(%s, %s, &[%s])\n", + aDllName, prefix, *regName); +#endif + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec, + char **aRegistryName) +{ + nsresult rv; + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + if (!aSpec) { + *aRegistryName = PL_strdup(""); + return NS_OK; + } + + + // First check to see if this component is in the application + // components directory + PRBool containedIn; + mComponentsDir->Contains(aSpec, PR_TRUE, &containedIn); + + nsCAutoString nativePathString; + + if (containedIn){ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + + const char* relativeLocation = nativePathString.get() + mComponentsOffset + 1; + return MakeRegistryName(relativeLocation, XPCOM_RELCOMPONENT_PREFIX, aRegistryName); + } + + // Next check to see if this component is in the GRE + // components directory + + mGREComponentsDir->Contains(aSpec, PR_TRUE, &containedIn); + + if (containedIn){ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + + const char* relativeLocation = nativePathString.get() + mGREComponentsOffset + 1; + return MakeRegistryName(relativeLocation, XPCOM_GRECOMPONENT_PREFIX, aRegistryName); + } + + /* absolute names include volume info on Mac, so persistent descriptor */ + rv = aSpec->GetNativePath(nativePathString); + if (NS_FAILED(rv)) + return rv; + return MakeRegistryName(nativePathString.get(), XPCOM_ABSCOMPONENT_PREFIX, aRegistryName); +} + +nsresult +nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation, + nsIFile **aSpec) +{ + // i18n: assuming aLocation is encoded for the current locale + + nsresult rv; + if (!aLocation || !aSpec) + return NS_ERROR_NULL_POINTER; + + /* abs:/full/path/to/libcomponent.so */ + if (!strncmp(aLocation, XPCOM_ABSCOMPONENT_PREFIX, 4)) { + + nsLocalFile* file = new nsLocalFile; + if (!file) return NS_ERROR_FAILURE; + + rv = file->InitWithNativePath(nsDependentCString((char *)aLocation + 4)); + file->QueryInterface(NS_GET_IID(nsILocalFile), (void**)aSpec); + return rv; + } + + if (!strncmp(aLocation, XPCOM_RELCOMPONENT_PREFIX, 4)) { + + if (!mComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + nsILocalFile* file = nsnull; + rv = mComponentsDir->Clone((nsIFile**)&file); + + if (NS_FAILED(rv)) return rv; + + rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4)); + *aSpec = file; + return rv; + } + + if (!strncmp(aLocation, XPCOM_GRECOMPONENT_PREFIX, 4)) { + + if (!mGREComponentsDir) + return NS_ERROR_NOT_INITIALIZED; + + nsILocalFile* file = nsnull; + rv = mGREComponentsDir->Clone((nsIFile**)&file); + + if (NS_FAILED(rv)) return rv; + + rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4)); + *aSpec = file; + return rv; + } + + *aSpec = nsnull; + return NS_ERROR_INVALID_ARG; +} + +/** + * RegisterFactory() + * + * Register a factory to be responsible for creation of implementation of + * classID aClass. Plus creates as association of aClassName and aContractID + * to the classID. If replace is PR_TRUE, we replace any existing registrations + * with this one. + * + * Once registration is complete, we add the class to the factories cache + * that we maintain. The factories cache is the ONLY place where these + * registrations are ever kept. + * + * The other RegisterFunctions create a loader mapping and persistent + * location, but we just slam it into the cache here. And we don't call the + * loader's OnRegister function, either. + */ +nsresult +nsComponentManagerImpl::RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace) +{ + nsAutoMonitor mon(mMon); +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: RegisterFactory(%s, %s)", buf, + (aContractID ? aContractID : "(null)"))); + if (buf) + PR_Free(buf); + } +#endif + nsFactoryEntry *entry = nsnull; + nsFactoryTableEntry* factoryTableEntry = NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, + &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + + if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) { + entry = factoryTableEntry->mFactoryEntry; + } + + if (entry && !aReplace) + { + // Already registered + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tFactory already registered.")); + return NS_ERROR_FACTORY_EXISTS; + } + + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + entry = new (mem) nsFactoryEntry(aClass, aFactory, entry); + + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + + // Update the ContractID->CLSID Map + if (aContractID) { + nsresult rv = HashContractID(aContractID, strlen(aContractID), entry); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tFactory register succeeded. " + "Hashing contractid (%s) FAILED.", aContractID)); + return rv; + } + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tFactory register succeeded contractid=%s.", + aContractID ? aContractID : "")); + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aPersistentDescriptor, + PRBool aReplace, + PRBool aPersist) +{ + return RegisterComponentCommon(aClass, aClassName, + aContractID, + aContractID ? strlen(aContractID) : 0, + aPersistentDescriptor, + aPersistentDescriptor ? + strlen(aPersistentDescriptor) : 0, + aReplace, aPersist, + nativeComponentType); +} + +nsresult +nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aSpec, + const char *aLocation, + PRBool aReplace, + PRBool aPersist, + const char *aType) +{ + return RegisterComponentCommon(aClass, aClassName, + aContractID, + aContractID ? strlen(aContractID) : 0, + aLocation, + aLocation ? strlen(aLocation) : 0, + aReplace, aPersist, + aType); +} + +/* + * Register a component, using whatever they stuck in the nsIFile. + */ +nsresult +nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrarySpec, + PRBool aReplace, + PRBool aPersist) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + rv = RegisterComponentWithType(aClass, aClassName, + aContractID, + aLibrarySpec, + registryName, + aReplace, aPersist, + nativeComponentType); + return rv; +} + +nsresult +nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aDllName, + PRBool aReplace, + PRBool aPersist) +{ + // deprecated and obsolete. + return NS_ERROR_NOT_IMPLEMENTED; +} + +/* + * Add a component to the known universe of components. + + * Once we enter this function, we own aRegistryName, and must free it + * or hand it to nsFactoryEntry. Common exit point ``out'' helps keep us + * sane. + */ + +nsresult +nsComponentManagerImpl::RegisterComponentCommon(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + PRUint32 aContractIDLen, + const char *aRegistryName, + PRUint32 aRegistryNameLen, + PRBool aReplace, + PRBool aPersist, + const char *aType) +{ + nsIDKey key(aClass); + nsAutoMonitor mon(mMon); + + nsFactoryEntry *entry = GetFactoryEntry(aClass); + + // Normalize proid and classname + const char *contractID = (aContractID && *aContractID) ? aContractID : nsnull; + const char *className = (aClassName && *aClassName) ? aClassName : nsnull; +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)", + buf, + contractID ? contractID : "(null)", + aRegistryName, aType)); + if (buf) + PR_Free(buf); + } +#endif + if (entry && !aReplace) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tFactory already registered.")); + return NS_ERROR_FACTORY_EXISTS; + } + + int typeIndex = GetLoaderType(aType); + + nsCOMPtr loader; + nsresult rv = GetLoaderForType(typeIndex, getter_AddRefs(loader)); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tgetting loader for %s FAILED\n", aType)); + return rv; + } + + if (entry) { + entry->ReInit(aClass, aRegistryName, typeIndex); + } + else { + + // Arena allocate the nsFactoryEntry + void *mem; + PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry)); + if (!mem) + return NS_ERROR_OUT_OF_MEMORY; + + mRegistryDirty = PR_TRUE; + entry = new (mem) nsFactoryEntry(aClass, + aRegistryName, aRegistryNameLen, + typeIndex); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + nsFactoryTableEntry* factoryTableEntry = + NS_STATIC_CAST(nsFactoryTableEntry*, + PL_DHashTableOperate(&mFactories, &aClass, + PL_DHASH_ADD)); + + if (!factoryTableEntry) + return NS_ERROR_OUT_OF_MEMORY; + + factoryTableEntry->mFactoryEntry = entry; + } + + // Update the ContractID->CLSID Map + if (contractID) { + rv = HashContractID(contractID, aContractIDLen, entry); + if (NS_FAILED(rv)) { + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("\t\tHashContractID(%s) FAILED\n", contractID)); + return rv; + } + } + return rv; +} + + +nsresult +nsComponentManagerImpl::GetLoaderForType(int aType, + nsIComponentLoader **aLoader) +{ + nsresult rv; + + // Make sure we have a valid type + if (aType < 0 || aType >= mNLoaderData) + return NS_ERROR_INVALID_ARG; + + *aLoader = mLoaderData[aType].loader; + if (*aLoader) { + NS_ADDREF(*aLoader); + return NS_OK; + } + + nsCOMPtr loader; + loader = do_GetServiceFromCategory("component-loader", mLoaderData[aType].type, &rv); + if (NS_FAILED(rv)) + return rv; + + rv = loader->Init(this, nsnull); + + if (NS_SUCCEEDED(rv)) { + mLoaderData[aType].loader = loader; + NS_ADDREF(mLoaderData[aType].loader); + *aLoader = loader; + NS_ADDREF(*aLoader); + } + return rv; +} + + + +// Convert a loader type string into an index into the component data +// array. Empty loader types are converted to NATIVE. Returns -1 if +// loader type cannot be determined. +int +nsComponentManagerImpl::GetLoaderType(const char *typeStr) +{ + if (!typeStr || !*typeStr) { + // Empty type strings are NATIVE + return NS_COMPONENT_TYPE_NATIVE; + } + + for (int i=NS_COMPONENT_TYPE_NATIVE; i= 0) { + *aTypeIndex = typeIndex; + return NS_OK; + } + + // Add the loader type + if (mNLoaderData >= mMaxNLoaderData) { + NS_ASSERTION(mNLoaderData == mMaxNLoaderData, + "Memory corruption. nsComponentManagerImpl::mLoaderData array overrun."); + // Need to increase our loader array + nsLoaderdata *new_mLoaderData = (nsLoaderdata *) PR_Realloc(mLoaderData, (mMaxNLoaderData + NS_LOADER_DATA_ALLOC_STEP) * sizeof(nsLoaderdata)); + if (!new_mLoaderData) + return NS_ERROR_OUT_OF_MEMORY; + mLoaderData = new_mLoaderData; + mMaxNLoaderData += NS_LOADER_DATA_ALLOC_STEP; + } + + typeIndex = mNLoaderData; + mLoaderData[typeIndex].type = PL_strdup(typeStr); + if (!mLoaderData[typeIndex].type) { + // mmh! no memory. return failure. + return NS_ERROR_OUT_OF_MEMORY; + } + mLoaderData[typeIndex].loader = nsnull; + mNLoaderData++; + + *aTypeIndex = typeIndex; + return NS_OK; +} + +typedef struct +{ + const nsCID* cid; + const char* regName; + nsIFactory* factory; +} UnregisterConditions; + +static PLDHashOperator PR_CALLBACK +DeleteFoundCIDs(PLDHashTable *aTable, + PLDHashEntryHdr *aHdr, + PRUint32 aNumber, + void *aData) +{ + nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr); + + if (!entry->mFactoryEntry) + return PL_DHASH_NEXT; + + UnregisterConditions* data = (UnregisterConditions*)aData; + + nsFactoryEntry* factoryEntry = entry->mFactoryEntry; + if (data->cid->Equals(factoryEntry->mCid) && + ((data->regName && !PL_strcasecmp(factoryEntry->mLocation, data->regName)) || + (data->factory && data->factory == factoryEntry->mFactory.get()))) + return PL_DHASH_REMOVE; + + return PL_DHASH_NEXT; +} + +void +nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName) +{ + UnregisterConditions aData; + aData.cid = aClass; + aData.regName = registryName; + aData.factory = nsnull; + PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData); + +} + +void +nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory) +{ + UnregisterConditions aData; + aData.cid = aClass; + aData.regName = nsnull; + aData.factory = factory; + PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData); +} + +nsresult +nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory) +{ +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: UnregisterFactory(%s)", buf)); + if (buf) + PR_Free(buf); + } +#endif + nsFactoryEntry *old; + + // first delete all contract id entries that are registered with this cid. + DeleteContractIDEntriesByCID(&aClass, aFactory); + + // next check to see if there is a CID registered + nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED; + old = GetFactoryEntry(aClass); + + if (old && (old->mFactory.get() == aFactory)) + { + nsAutoMonitor mon(mMon); + PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE); + rv = NS_OK; + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("\t\tUnregisterFactory() %s", + NS_SUCCEEDED(rv) ? "succeeded" : "FAILED")); + return rv; +} + +nsresult +nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass, + const char *registryName) +{ +#ifdef PR_LOGGING + if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) + { + char *buf = aClass.ToString(); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: UnregisterComponent(%s)", buf)); + if (buf) + PR_Free(buf); + } +#endif + + NS_ENSURE_ARG_POINTER(registryName); + nsFactoryEntry *old; + + // first delete all contract id entries that are registered with this cid. + DeleteContractIDEntriesByCID(&aClass, registryName); + + // next check to see if there is a CID registered + old = GetFactoryEntry(aClass); + if (old && old->mLocation && !PL_strcasecmp(old->mLocation, registryName)) + { + nsAutoMonitor mon(mMon); + PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE); + } + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: Factory unregister(%s) succeeded.", registryName)); + + return NS_OK; +} + +nsresult +nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName)); + if (NS_FAILED(rv)) return rv; + return UnregisterComponent(aClass, registryName); +} + +// XXX Need to pass in aWhen and servicemanager +nsresult +nsComponentManagerImpl::FreeLibraries(void) +{ + return UnloadLibraries(NS_STATIC_CAST(nsIServiceManager*, this), NS_Timer); // XXX when +} + +// Private implementation of unloading libraries +nsresult +nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr, PRInt32 aWhen) +{ + nsresult rv = NS_OK; + + nsAutoMonitor mon(mMon); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsComponentManager: Unloading Libraries.")); + + // UnloadAll the loaders + /* iterate over all known loaders and ask them to autoregister. */ + // Skip mNativeComponentLoader + for (int i=NS_COMPONENT_TYPE_NATIVE + 1; iUnloadAll(aWhen); + if (NS_FAILED(rv)) + break; + } + } + + // UnloadAll the native loader + rv = mNativeComponentLoader->UnloadAll(aWhen); + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +/** + * AutoRegister(RegistrationInstant, const char *directory) + * + * Given a directory in the following format, this will ensure proper registration + * of all components. No default directory is looked at. + * + * Directory and fullname are what NSPR will accept. For eg. + * WIN y:/home/dp/mozilla/dist/bin + * UNIX /home/dp/mozilla/dist/bin + * MAC /Hard drive/mozilla/dist/apprunner + * + * This will take care not loading already registered dlls, finding and + * registering new dlls, re-registration of modified dlls + * + */ + +nsresult +nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec) +{ + return AutoRegisterImpl(when, inDirSpec); +} + +nsresult +nsComponentManagerImpl::AutoRegisterImpl(PRInt32 when, + nsIFile *inDirSpec, + PRBool fileIsCompDir) +{ + nsCOMPtr dir; + nsresult rv; + +#ifdef DEBUG + // testing release behaviour + if (getenv("XPCOM_NO_AUTOREG")) + return NS_OK; +#endif + if (inDirSpec) + { + // Use supplied components' directory + dir = inDirSpec; + } + else + { + mComponentsDir->Clone(getter_AddRefs(dir)); + if (!dir) + return NS_ERROR_NOT_INITIALIZED; + } + + nsCOMPtr iim = + dont_AddRef(XPTI_GetInterfaceInfoManager()); + + if (!iim) + return NS_ERROR_UNEXPECTED; + + // Notify observers of xpcom autoregistration start + NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + nsnull, + "start"); + + /* do the native loader first, so we can find other loaders */ + rv = mNativeComponentLoader->AutoRegisterComponents((PRInt32)when, dir); + if (NS_FAILED(rv)) return rv; + +#ifdef ENABLE_STATIC_COMPONENT_LOADER + rv = mStaticComponentLoader->AutoRegisterComponents((PRInt32)when, inDirSpec); + if (NS_FAILED(rv)) return rv; +#endif + + /* do InterfaceInfoManager after native loader so it can use components. */ + rv = iim->AutoRegisterInterfaces(); + if (NS_FAILED(rv)) return rv; + + if (!mCategoryManager) { + NS_WARNING("mCategoryManager is null"); + return NS_ERROR_UNEXPECTED; + } + + nsCOMPtr loaderEnum; + rv = mCategoryManager->EnumerateCategory("component-loader", + getter_AddRefs(loaderEnum)); + if (NS_FAILED(rv)) return rv; + + PRBool hasMore; + while (NS_SUCCEEDED(loaderEnum->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr supports; + if (NS_FAILED(loaderEnum->GetNext(getter_AddRefs(supports)))) + continue; + + nsCOMPtr supStr = do_QueryInterface(supports); + if (!supStr) + continue; + + nsCAutoString loaderType; + if (NS_FAILED(supStr->GetData(loaderType))) + continue; + + // We depend on the loader being created. Add the loader type and + // create the loader object too. + nsCOMPtr loader; + int typeIndex; + rv = AddLoaderType(loaderType.get(), &typeIndex); + if (NS_FAILED(rv)) + return rv; + GetLoaderForType(typeIndex, getter_AddRefs(loader)); + } + + rv = AutoRegisterNonNativeComponents(dir.get()); + + // Notify observers of xpcom autoregistration completion + NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + nsnull, + "end"); + + if (mRegistryDirty) + FlushPersistentStore(PR_TRUE); + return rv; +} + +nsresult +nsComponentManagerImpl::AutoRegisterNonNativeComponents(nsIFile* spec) +{ + nsresult rv = NS_OK; + nsCOMPtr directory = spec; + + if (!directory) { + mComponentsDir->Clone(getter_AddRefs(directory)); + if (!directory) + return NS_ERROR_NOT_INITIALIZED; + } + + for (int i = 1; i < mNLoaderData; i++) { + if (!mLoaderData[i].loader) { + rv = GetLoaderForType(i, &mLoaderData[i].loader); + if (NS_FAILED(rv)) + continue; + } + rv = mLoaderData[i].loader->AutoRegisterComponents(0, directory); + if (NS_FAILED(rv)) + break; + } + + if (NS_SUCCEEDED(rv)) + { + PRBool registered; + do { + registered = PR_FALSE; + for (int i = 0; i < mNLoaderData; i++) { + PRBool b = PR_FALSE; + if (mLoaderData[i].loader) { + rv = mLoaderData[i].loader->RegisterDeferredComponents(0, &b); + if (NS_FAILED(rv)) + continue; + registered |= b; + } + } + } while (NS_SUCCEEDED(rv) && registered); + } + return rv; +} +nsresult +nsComponentManagerImpl::AutoRegisterComponent(PRInt32 when, + nsIFile *component) +{ + nsresult rv = NS_OK, res = NS_ERROR_FACTORY_NOT_REGISTERED; + /* + * Do we have to give the native loader first crack at it? + * I vote ``no''. + */ + for (int i = 0; i < mNLoaderData; i++) { + PRBool didRegister; + if (!mLoaderData[i].loader) { + nsCOMPtr loader; + rv = GetLoaderForType(i, getter_AddRefs(loader)); + if (NS_FAILED(rv)) + continue; + // |GetLoaderForType| has filled in |mLoaderData[i].loader|: + NS_ASSERTION(loader == mLoaderData[i].loader, "oops"); + } + rv = mLoaderData[i].loader->AutoRegisterComponent((int)when, component, &didRegister); + if (NS_FAILED(rv)) { + res = rv; + } else if (didRegister) { + return rv; + } + } + return res; +} + +nsresult +nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 when, + nsIFile *component) +{ + nsresult rv = NS_OK; + for (int i = 0; i < mNLoaderData; i++) { + PRBool didUnRegister; + if (!mLoaderData[i].loader) { + rv = GetLoaderForType(i, &mLoaderData[i].loader); + if (NS_FAILED(rv)) + continue; + } + rv = mLoaderData[i].loader->AutoUnregisterComponent(when, component, &didUnRegister); + if (NS_SUCCEEDED(rv) && didUnRegister) { + // we need to remove this file from our list of known libraries. + RemoveFileInfo(component, nsnull); + mRegistryDirty = PR_TRUE; + break; + } + } + return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK; +} + +nsresult +nsComponentManagerImpl::IsRegistered(const nsCID &aClass, + PRBool *aRegistered) +{ + if (!aRegistered) + { + NS_ASSERTION(0, "null ptr"); + return NS_ERROR_NULL_POINTER; + } + *aRegistered = (nsnull != GetFactoryEntry(aClass)); + return NS_OK; +} + +nsresult +nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + { + return NS_ERROR_NULL_POINTER; + } + *aEnumerator = nsnull; + + nsresult rv; + + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mFactories, + ConvertFactoryEntryToCID, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum); + return NS_OK; +} + +nsresult +nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + { + return NS_ERROR_NULL_POINTER; + } + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mContractIDs, + ConvertContractIDKeyToString, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum); + return NS_OK; +} + +// nsIComponentRegistrar + +NS_IMETHODIMP +nsComponentManagerImpl::AutoRegister(nsIFile *aSpec) +{ + if (aSpec == nsnull) + return AutoRegisterImpl(0, aSpec); + + PRBool directory; + aSpec->IsDirectory(&directory); + + if (directory) + return AutoRegisterImpl(0, aSpec, PR_FALSE); + + return AutoRegisterComponent(0, aSpec); +} + +NS_IMETHODIMP +nsComponentManagerImpl::AutoUnregister(nsIFile *aSpec) +{ + // unregistering a complete directory is not implmeneted yet...FIX + if (aSpec == nsnull) + return NS_ERROR_NOT_IMPLEMENTED; + + PRBool directory; + aSpec->IsDirectory(&directory); + + if (directory) + return NS_ERROR_NOT_IMPLEMENTED; + + return AutoUnregisterComponent(0, aSpec); +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterFactory(const nsCID & aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory) +{ + return RegisterFactory(aClass, + aClassName, + aContractID, + aFactory, + PR_TRUE); +} + +NS_IMETHODIMP +nsComponentManagerImpl::RegisterFactoryLocation(const nsCID & aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aFile, + const char *loaderStr, + const char *aType) +{ + nsXPIDLCString registryName; + + if (!loaderStr) + { + nsresult rv = RegistryLocationForSpec(aFile, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + } + + nsresult rv; + rv = RegisterComponentWithType(aClass, + aClassName, + aContractID, + aFile, + (loaderStr ? loaderStr : registryName.get()), + PR_TRUE, + PR_TRUE, + (aType ? aType : nativeComponentType)); + return rv; +} + +NS_IMETHODIMP +nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID & aClass, + nsIFile *aFile) +{ + return UnregisterComponentSpec(aClass, aFile); +} + +NS_IMETHODIMP +nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass, + PRBool *_retval) +{ + return IsRegistered(aClass, _retval); +} + +NS_IMETHODIMP +nsComponentManagerImpl::IsContractIDRegistered(const char *aClass, + PRBool *_retval) +{ + nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass)); + + if (entry) + *_retval = PR_TRUE; + else + *_retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + + if (!aEnumerator) + return NS_ERROR_NULL_POINTER; + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mFactories, + ConvertFactoryEntryToCID, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator) +{ + NS_ASSERTION(aEnumerator != nsnull, "null ptr"); + if (!aEnumerator) + return NS_ERROR_NULL_POINTER; + + *aEnumerator = nsnull; + + nsresult rv; + PLDHashTableEnumeratorImpl *aEnum; + rv = PL_NewDHashTableEnumerator(&mContractIDs, + ConvertContractIDKeyToString, + (void*)this, + &aEnum); + if (NS_FAILED(rv)) + return rv; + + *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::CIDToContractID(const nsCID & aClass, + char **_retval) +{ + return CLSIDToContractID(aClass, + nsnull, + _retval); +} + +NS_IMETHODIMP +nsComponentManagerImpl::ContractIDToCID(const char *aContractID, + nsCID * *_retval) +{ + *_retval = (nsCID*) nsMemory::Alloc(sizeof(nsCID)); + if (!*_retval) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = ContractIDToClassID(aContractID, *_retval); + if (NS_FAILED(rv)) { + nsMemory::Free(*_retval); + *_retval = nsnull; + } + return rv; +} + +// end nsIComponentRegistrar + + + + +NS_IMETHODIMP +nsComponentManagerImpl::HasFileChanged(nsIFile *file, const char *loaderString, PRInt64 modDate, PRBool *_retval) +{ + *_retval = PR_TRUE; + + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + if (entry) + *_retval = entry->Modified(&modDate); + else + *_retval = PR_TRUE; + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::SaveFileInfo(nsIFile *file, const char *loaderString, PRInt64 modDate) +{ + mRegistryDirty = PR_TRUE; + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + // check to see if exists in the array before adding it so that we don't have dups. + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + + if (entry) + { + entry->SetDate(&modDate); + return NS_OK; + } + + entry = new AutoRegEntry(registryName, &modDate); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + mAutoRegEntries.Put(&key, entry); + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::RemoveFileInfo(nsIFile *file, const char *loaderString) +{ + mRegistryDirty = PR_TRUE; + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Remove(&key); + if (entry) + delete entry; + + return NS_OK; +} + +NS_IMETHODIMP +nsComponentManagerImpl::GetOptionalData(nsIFile *file, + const char *loaderString, + char **_retval) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + if (!entry) { + return NS_ERROR_NOT_INITIALIZED; + } + const char* opData = entry->GetOptionalData(); + + if (opData) + *_retval = ToNewCString(nsDependentCString(opData)); + else + *_retval = nsnull; + return NS_OK; + } + +NS_IMETHODIMP +nsComponentManagerImpl::SetOptionalData(nsIFile *file, + const char *loaderString, + const char *data) +{ + nsXPIDLCString registryName; + nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(registryName); + AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key); + + if (!entry) { + PRInt64 zero = LL_Zero(); + entry = new AutoRegEntry(registryName, &zero); + if (!entry) + return NS_ERROR_OUT_OF_MEMORY; + + mAutoRegEntries.Put(&key, entry); + } + + entry->SetOptionalData(data); + + return NS_OK; + } + + +NS_IMETHODIMP +nsComponentManagerImpl::FlushPersistentStore(PRBool now) +{ + mRegistryDirty = PR_TRUE; + if (now) + return WritePersistentRegistry(); + + return NS_OK; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Static Access Functions +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_GetGlobalComponentManager(nsIComponentManager* *result) +{ +#ifdef DEBUG_dougt + // NS_WARNING("DEPRECATED FUNCTION: Use NS_GetComponentManager"); +#endif + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_SUCCEEDED(rv)) + { + // NO ADDREF since this is never intended to be released. + // See nsComponentManagerObsolete.h for the reason for such + // casting uglyness + *result = (nsIComponentManager*)(void*)(nsIComponentManagerObsolete*) nsComponentManagerImpl::gComponentManager; + } + + return rv; +} + +NS_COM nsresult +NS_GetComponentManager(nsIComponentManager* *result) +{ + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + if (NS_FAILED(rv)) + return rv; + } + + *result = NS_STATIC_CAST(nsIComponentManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + +NS_COM nsresult +NS_GetServiceManager(nsIServiceManager* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { +#ifdef VBOX + // While XPCOM might need initialization, we're not in a position + // to pass the right values to this call. This is actually triggered + // on object destruction, so there is no point in re-initializing, + // and actually the attempt would lead to nested calls to + // xptiInterfaceInfoManager::BuildFileSearchPath, which it detects + // as unsafe in debug builds. Just fail, no real problem. +#ifdef DEBUG + printf("NS_GetServiceManager: no current instance, suppressed XPCOM initialization!\n"); +#endif + rv = NS_ERROR_SERVICE_NOT_AVAILABLE; +#else /* !VBOX */ + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); +#endif /* !VBOX */ + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIServiceManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + + +NS_COM nsresult +NS_GetComponentRegistrar(nsIComponentRegistrar* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIComponentRegistrar*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} + + +// nsIComponentLoaderManager is not frozen, but is defined here +// so that I can use it internally in xpcom. +nsresult +NS_GetComponentLoaderManager(nsIComponentLoaderManager* *result) +{ + nsresult rv = NS_OK; + + if (nsComponentManagerImpl::gComponentManager == NULL) + { + // XPCOM needs initialization. + rv = NS_InitXPCOM2(nsnull, nsnull, nsnull); + } + + if (NS_FAILED(rv)) + return rv; + + *result = NS_STATIC_CAST(nsIComponentLoaderManager*, + nsComponentManagerImpl::gComponentManager); + NS_IF_ADDREF(*result); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h new file mode 100644 index 00000000..df128125 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManager.h @@ -0,0 +1,339 @@ +/* -*- Mode: C++; tab-width: 8; 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): + * + * 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 ***** */ + +#ifndef nsComponentManager_h__ +#define nsComponentManager_h__ + +#include "nsXPCOM.h" + +#include "nsIComponentLoader.h" +#include "xpcom-private.h" +#include "nsNativeComponentLoader.h" +#include "nsIComponentManager.h" +#include "nsIComponentRegistrar.h" +#include "nsIComponentManagerObsolete.h" +#include "nsIComponentLoaderManager.h" +#include "nsCategoryManager.h" +#include "nsIServiceManager.h" +#include "nsIFactory.h" +#include "nsIInterfaceRequestor.h" +#include "nsIInterfaceRequestorUtils.h" +#include "pldhash.h" +#include "prtime.h" +#include "prmon.h" +#include "nsCOMPtr.h" +#include "nsWeakReference.h" +#include "nsXPIDLString.h" +#include "nsIFile.h" +#include "plarena.h" + +class nsFactoryEntry; +class nsDll; +class nsIServiceManager; + + +// Predefined loader types. Do not change the numbers. +// NATIVE should be 0 as it is being used as the first array index. +#define NS_COMPONENT_TYPE_NATIVE 0 +#define NS_COMPONENT_TYPE_FACTORY_ONLY -1 +// this define means that the factory entry only has a ContractID +// to service mapping and has no cid mapping. +#define NS_COMPONENT_TYPE_SERVICE_ONLY -2 + + +#ifdef DEBUG +#define XPCOM_CHECK_PENDING_CIDS +#endif +//////////////////////////////////////////////////////////////////////////////// + +// Array of Loaders and their type strings +struct nsLoaderdata { + nsIComponentLoader *loader; + const char *type; +}; + +class nsComponentManagerImpl + : public nsIComponentManager, + public nsIServiceManager, + public nsIComponentRegistrar, + public nsSupportsWeakReference, + public nsIInterfaceRequestor, + public nsIComponentLoaderManager, + public nsIServiceManagerObsolete, + public nsIComponentManagerObsolete +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIINTERFACEREQUESTOR + // Since the nsIComponentManagerObsolete and nsIComponentManager share some of the + // same interface function names, we have to manually define the functions here. + // The only function that is in nsIComponentManagerObsolete and is in nsIComponentManager + // is GetClassObjectContractID. + // + // nsIComponentManager function not in nsIComponentManagerObsolete: + NS_IMETHOD GetClassObjectByContractID(const char *aContractID, + const nsIID &aIID, + void **_retval); + + + NS_DECL_NSICOMPONENTMANAGEROBSOLETE + + // Since the nsIComponentManagerObsolete and nsIComponentRegistrar share some of the + // same interface function names, we have to manually define the functions here. + // the only function that is shared is UnregisterFactory + NS_IMETHOD AutoRegister(nsIFile *aSpec); + NS_IMETHOD AutoUnregister(nsIFile *aSpec); + NS_IMETHOD RegisterFactory(const nsCID & aClass, const char *aClassName, const char *aContractID, nsIFactory *aFactory); + // NS_IMETHOD UnregisterFactory(const nsCID & aClass, nsIFactory *aFactory); + NS_IMETHOD RegisterFactoryLocation(const nsCID & aClass, const char *aClassName, const char *aContractID, nsIFile *aFile, const char *loaderStr, const char *aType); + NS_IMETHOD UnregisterFactoryLocation(const nsCID & aClass, nsIFile *aFile); + NS_IMETHOD IsCIDRegistered(const nsCID & aClass, PRBool *_retval); + NS_IMETHOD IsContractIDRegistered(const char *aClass, PRBool *_retval); + NS_IMETHOD EnumerateCIDs(nsISimpleEnumerator **_retval); + NS_IMETHOD EnumerateContractIDs(nsISimpleEnumerator **_retval); + NS_IMETHOD CIDToContractID(const nsCID & aClass, char **_retval); + NS_IMETHOD ContractIDToCID(const char *aContractID, nsCID * *_retval); + + NS_DECL_NSISERVICEMANAGER + NS_DECL_NSISERVICEMANAGEROBSOLETE + NS_DECL_NSICOMPONENTLOADERMANAGER + + // nsComponentManagerImpl methods: + nsComponentManagerImpl(); + + static nsComponentManagerImpl* gComponentManager; + nsresult Init(void); + + nsresult WritePersistentRegistry(); + nsresult ReadPersistentRegistry(); + + nsresult Shutdown(void); + + nsresult FreeServices(); + + nsresult + NS_GetService(const char *aContractID, const nsIID& aIID, PRBool aDontCreate, nsISupports** result); + + nsresult RegisterComponentCommon(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + PRUint32 aContractIDLen, + const char *aRegistryName, + PRUint32 aRegistryNameLen, + PRBool aReplace, PRBool aPersist, + const char *aType); + nsresult GetLoaderForType(int aType, + nsIComponentLoader **aLoader); + nsresult FindFactory(const char *contractID, PRUint32 aContractIDLen, nsIFactory **aFactory) ; + nsresult LoadFactory(nsFactoryEntry *aEntry, nsIFactory **aFactory); + + nsFactoryEntry *GetFactoryEntry(const char *aContractID, + PRUint32 aContractIDLen); + nsFactoryEntry *GetFactoryEntry(const nsCID &aClass); + + nsresult SyncComponentsInDir(PRInt32 when, nsIFile *dirSpec); + nsresult SelfRegisterDll(nsDll *dll); + nsresult SelfUnregisterDll(nsDll *dll); + nsresult HashContractID(const char *acontractID, PRUint32 aContractIDLen, + nsFactoryEntry *fe_ptr); + + void DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName); + void DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory); + + nsresult UnloadLibraries(nsIServiceManager *servmgr, PRInt32 when); + + // Convert a loader type string into an index into the loader data + // array. Empty loader types are converted to NATIVE. Returns -1 if + // loader type cannot be determined. + int GetLoaderType(const char *typeStr); + + // Add a loader type if not already known. Out the typeIndex + // if the loader type is either added or already there; + // returns NS_OK or an error on failure. + nsresult AddLoaderType(const char *typeStr, int *typeIndex); + + int GetLoaderCount() { return mNLoaderData + 1; } + + // registers only the files in spec's location by loaders other than the + // native loader. This is an optimization method only. + nsresult AutoRegisterNonNativeComponents(nsIFile* spec); + + nsresult AutoRegisterImpl(PRInt32 when, nsIFile *inDirSpec, PRBool fileIsCompDir=PR_TRUE); + nsresult RemoveEntries(nsIFile* file); + + PLDHashTable mFactories; + PLDHashTable mContractIDs; + PRMonitor* mMon; + + nsNativeComponentLoader *mNativeComponentLoader; +#ifdef ENABLE_STATIC_COMPONENT_LOADER + nsIComponentLoader *mStaticComponentLoader; +#endif + nsCOMPtr mComponentsDir; + PRInt32 mComponentsOffset; + + nsCOMPtr mGREComponentsDir; + PRInt32 mGREComponentsOffset; + + nsCOMPtr mRegistryFile; + + // Shutdown + #define NS_SHUTDOWN_NEVERHAPPENED 0 + #define NS_SHUTDOWN_INPROGRESS 1 + #define NS_SHUTDOWN_COMPLETE 2 + PRUint32 mShuttingDown; + + nsLoaderdata *mLoaderData; + int mNLoaderData; + int mMaxNLoaderData; + + PRBool mRegistryDirty; + nsHashtable mAutoRegEntries; + nsCOMPtr mCategoryManager; + + PLArenaPool mArena; + +#ifdef XPCOM_CHECK_PENDING_CIDS + nsresult AddPendingCID(const nsCID &aClass); + void RemovePendingCID(const nsCID &aClass); + + nsVoidArray mPendingCIDs; +#endif + +private: + ~nsComponentManagerImpl(); +}; + + +#define NS_MAX_FILENAME_LEN 1024 + +#define NS_ERROR_IS_DIR NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 24) + +//////////////////////////////////////////////////////////////////////////////// +/** + * Class: nsFactoryEntry() + * + * There are two types of FactoryEntries. + * + * 1. {CID, dll} mapping. + * Factory is a consequence of the dll. These can be either session + * specific or persistent based on whether we write this + * to the registry or not. + * + * 2. {CID, factory} mapping + * These are strictly session specific and in memory only. + */ + +class nsFactoryEntry { +public: + nsFactoryEntry(const nsCID &aClass, + const char *location, PRUint32 locationlen, int aType, class nsFactoryEntry* parent = nsnull); + nsFactoryEntry(const nsCID &aClass, nsIFactory *aFactory, class nsFactoryEntry* parent = nsnull); + ~nsFactoryEntry(); + + nsresult ReInit(const nsCID &aClass, const char *location, int aType); + + nsresult GetFactory(nsIFactory **aFactory, + nsComponentManagerImpl * mgr) { + if (mFactory) { + *aFactory = mFactory.get(); + NS_ADDREF(*aFactory); + return NS_OK; + } + + if (mTypeIndex < 0) + return NS_ERROR_FAILURE; + + nsresult rv; + nsCOMPtr loader; + rv = mgr->GetLoaderForType(mTypeIndex, getter_AddRefs(loader)); + if(NS_FAILED(rv)) + return rv; + + rv = loader->GetFactory(mCid, mLocation, mgr->mLoaderData[mTypeIndex].type, aFactory); + if (NS_SUCCEEDED(rv)) + mFactory = do_QueryInterface(*aFactory); + return rv; + } + + nsCID mCid; + nsCOMPtr mFactory; + // This is an index into the mLoaderData array that holds the type string and the loader + int mTypeIndex; + nsCOMPtr mServiceObject; + char* mLocation; + class nsFactoryEntry* mParent; +}; + +//////////////////////////////////////////////////////////////////////////////// + +struct nsFactoryTableEntry : public PLDHashEntryHdr { + nsFactoryEntry *mFactoryEntry; +}; + +struct nsContractIDTableEntry : public PLDHashEntryHdr { + char *mContractID; + PRUint32 mContractIDLen; + nsFactoryEntry *mFactoryEntry; +}; + + +class AutoRegEntry +{ +public: + AutoRegEntry(const nsACString& name, PRInt64* modDate); + ~AutoRegEntry(); + + const nsDependentCString GetName() + { return nsDependentCString(mName, mNameLen); } + PRInt64 GetDate() {return mModDate;} + void SetDate(PRInt64 *date) { mModDate = *date;} + PRBool Modified(PRInt64 *date); + + // this is the optional field line in the compreg.dat. + // it must not contain any comma's and it must be null terminated. + char* GetOptionalData() {return mData;}; + void SetOptionalData(const char* data); + +private: + char* mName; + PRUint32 mNameLen; + char* mData; + PRInt64 mModDate; +}; +#endif // nsComponentManager_h__ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp new file mode 100644 index 00000000..fca77cf7 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.cpp @@ -0,0 +1,271 @@ + +/* ***** 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 XPCOM. + * + * 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): + * + * 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 ***** */ + +//////////////////////////////////////////////////////////////////////////////// +// Global Static Component Manager Methods +// (for when you need to link with xpcom) + +#include "nsIComponentManagerObsolete.h" +#include "nsComponentManagerObsolete.h" + + +nsresult +nsComponentManager::Initialize(void) +{ + return NS_OK; +} + +nsresult +nsComponentManager::FindFactory(const nsCID &aClass, + nsIFactory **aFactory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->FindFactory(aClass, aFactory); +} + +nsresult +nsComponentManager::GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->GetClassObject(aClass, aIID, aResult); +} + +nsresult +nsComponentManager::ContractIDToClassID(const char *aContractID, + nsCID *aClass) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->ContractIDToClassID(aContractID, aClass); +} + +nsresult +nsComponentManager::CLSIDToContractID(nsCID *aClass, + char* *aClassName, + char* *aContractID) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CLSIDToContractID(*aClass, aClassName, aContractID); +} + +nsresult +nsComponentManager::CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CreateInstance(aClass, aDelegate, aIID, aResult); +} + +nsresult +nsComponentManager::CreateInstance(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->CreateInstanceByContractID(aContractID, aDelegate, aIID, aResult); +} + +nsresult +nsComponentManager::RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterFactory(aClass, aClassName, aContractID, + aFactory, aReplace); +} + +nsresult +nsComponentManager::RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aLibraryPersistentDescriptor, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponent(aClass, aClassName, aContractID, + aLibraryPersistentDescriptor, aReplace, aPersist); +} + +nsresult +nsComponentManager::RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrary, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponentSpec(aClass, aClassName, aContractID, + aLibrary, aReplace, aPersist); +} + +nsresult +nsComponentManager::RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *adllName, + PRBool aReplace, + PRBool aPersist) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->RegisterComponentLib(aClass, aClassName, aContractID, + adllName, aReplace, aPersist); +} + +nsresult +nsComponentManager::UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterFactory(aClass, aFactory); +} + +nsresult +nsComponentManager::UnregisterComponent(const nsCID &aClass, + const char *aLibrary) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterComponent(aClass, aLibrary); +} + +nsresult +nsComponentManager::UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->UnregisterComponentSpec(aClass, aLibrarySpec); +} + +nsresult +nsComponentManager::FreeLibraries(void) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->FreeLibraries(); +} + +nsresult +nsComponentManager::AutoRegister(PRInt32 when, nsIFile *directory) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoRegister(when, directory); +} + +nsresult +nsComponentManager::AutoRegisterComponent(PRInt32 when, + nsIFile *fullname) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoRegisterComponent(when, fullname); +} + +nsresult +nsComponentManager::AutoUnregisterComponent(PRInt32 when, + nsIFile *fullname) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->AutoUnregisterComponent(when, fullname); +} + +nsresult +nsComponentManager::IsRegistered(const nsCID &aClass, + PRBool *aRegistered) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->IsRegistered(aClass, aRegistered); +} + +nsresult +nsComponentManager::EnumerateCLSIDs(nsIEnumerator** aEnumerator) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->EnumerateCLSIDs(aEnumerator); +} + +nsresult +nsComponentManager::EnumerateContractIDs(nsIEnumerator** aEnumerator) +{ + nsIComponentManagerObsolete* cm; + nsresult rv = NS_GetGlobalComponentManager((nsIComponentManager**)&cm); + if (NS_FAILED(rv)) return rv; + return cm->EnumerateContractIDs(aEnumerator); +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h new file mode 100644 index 00000000..dfcde87a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerObsolete.h @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 2; 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 XPCOM. + * + * 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): + * + * 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 ***** */ +#ifndef nsComponentManagerObsolete_h___ +#define nsComponentManagerObsolete_h___ + +#include "nsIComponentManager.h" +#include "nsIComponentManagerObsolete.h" + +class nsIEnumerator; +class nsIFactory; +class nsIFile; +//////////////////////////////////////////////////////////////////// +// +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +// +// Functions, classes, interfaces and types in this file are +// obsolete. Use at your own risk. +// Please see nsIComponentManager.idl for the supported interface +// to the component manager. +// +//////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////// +// God save me from this evilness. Below is a very bad +// function. Its out var is really a nsIComponentManagerObsolete +// but it has been cast to a nsIComponentManager. +// The reason for such uglyness is that this function is require for +// backward compatiblity of some plugins. This funciton will +// be removed at some point. +//////////////////////////////////////////////////////////////////// + +extern NS_COM nsresult +NS_GetGlobalComponentManager(nsIComponentManager* *result); + + + + +class NS_COM nsComponentManager { +public: + static nsresult Initialize(void); + + // Finds a factory for a specific class ID + static nsresult FindFactory(const nsCID &aClass, + nsIFactory **aFactory); + + // Get the singleton class object that implements the CID aClass + static nsresult GetClassObject(const nsCID &aClass, const nsIID &aIID, + void **aResult); + + // Finds a class ID for a specific Program ID + static nsresult ContractIDToClassID(const char *aContractID, + nsCID *aClass); + + // Finds a Program ID for a specific class ID + // caller frees the result with delete[] + static nsresult CLSIDToContractID(nsCID *aClass, + char* *aClassName, + char* *aContractID); + + // Creates a class instance for a specific class ID + static nsresult CreateInstance(const nsCID &aClass, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult); + + // Convenience routine, creates a class instance for a specific ContractID + static nsresult CreateInstance(const char *aContractID, + nsISupports *aDelegate, + const nsIID &aIID, + void **aResult); + + // Manually registry a factory for a class + static nsresult RegisterFactory(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory *aFactory, + PRBool aReplace); + + // Manually register a dynamically loaded component. + // The libraryPersistentDescriptor is what gets passed to the library + // self register function from ComponentManager. The format of this string + // is the same as nsIFile::GetPath() + // + // This function will go away in favour of RegisterComponentSpec. In fact, + // it internally turns around and calls RegisterComponentSpec. + static nsresult RegisterComponent(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *aLibraryPersistentDescriptor, + PRBool aReplace, + PRBool aPersist); + + // Register a component using its FileSpec as its identification + // This is the more prevalent use. + static nsresult RegisterComponentSpec(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFile *aLibrary, + PRBool aReplace, + PRBool aPersist); + + // Register a component using its dllName. This could be a dll name with + // no path so that LD_LIBRARY_PATH on unix or PATH on win can load it. Or + // this could be a code fragment name on the Mac. + static nsresult RegisterComponentLib(const nsCID &aClass, + const char *aClassName, + const char *aContractID, + const char *adllName, + PRBool aReplace, + PRBool aPersist); + + + // Manually unregister a factory for a class + static nsresult UnregisterFactory(const nsCID &aClass, + nsIFactory *aFactory); + + // Manually unregister a dynamically loaded component + static nsresult UnregisterComponent(const nsCID &aClass, + const char *aLibrary); + + // Manually unregister a dynamically loaded component + static nsresult UnregisterComponentSpec(const nsCID &aClass, + nsIFile *aLibrarySpec); + + // Unload dynamically loaded factories that are not in use + static nsresult FreeLibraries(void); + ////////////////////////////////////////////////////////////////////////////// + // DLL registration support + + // If directory is NULL, then AutoRegister will try registering components + // in the default components directory. + static nsresult AutoRegister(PRInt32 when, nsIFile* directory); + static nsresult AutoRegisterComponent(PRInt32 when, nsIFile *component); + static nsresult AutoUnregisterComponent(PRInt32 when, nsIFile *component); + + // Is the given CID currently registered? + static nsresult IsRegistered(const nsCID &aClass, + PRBool *aRegistered); + + // Get an enumeration of all the CIDs + static nsresult EnumerateCLSIDs(nsIEnumerator** aEmumerator); + + // Get an enumeration of all the ContractIDs + static nsresult EnumerateContractIDs(nsIEnumerator** aEmumerator); + +}; + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h new file mode 100644 index 00000000..cda56416 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsComponentManagerUtils.h @@ -0,0 +1,196 @@ +/* -*- 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): + * + * 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 ***** */ + +#ifndef nsComponentManagerUtils_h__ +#define nsComponentManagerUtils_h__ + +/* + * Do not include this file directly. Instead, + * |#include "nsIComponentManager.h"|. + */ + +#ifndef nsCOMPtr_h__ +#include "nsCOMPtr.h" +#endif + +#ifndef nsComponentManagerObsolete_h___ +#include "nsComponentManagerObsolete.h" +#endif + +#define NS_COMPONENTMANAGER_CID \ +{ /* 91775d60-d5dc-11d2-92fb-00e09805570f */ \ + 0x91775d60, \ + 0xd5dc, \ + 0x11d2, \ + {0x92, 0xfb, 0x00, 0xe0, 0x98, 0x05, 0x57, 0x0f} \ +} + +class NS_COM nsCreateInstanceByCID : public nsCOMPtr_helper +{ +public: + nsCreateInstanceByCID( const nsCID& aCID, nsISupports* aOuter, nsresult* aErrorPtr ) + : mCID(aCID), + mOuter(aOuter), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + +private: + const nsCID& mCID; + nsISupports* mOuter; + nsresult* mErrorPtr; +}; + +class NS_COM nsCreateInstanceByContractID : public nsCOMPtr_helper +{ +public: + nsCreateInstanceByContractID( const char* aContractID, nsISupports* aOuter, nsresult* aErrorPtr ) + : mContractID(aContractID), + mOuter(aOuter), + mErrorPtr(aErrorPtr) + { + // nothing else to do here + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + +private: + const char* mContractID; + nsISupports* mOuter; + nsresult* mErrorPtr; +}; + +inline +const nsCreateInstanceByCID +do_CreateInstance( const nsCID& aCID, nsresult* error = 0 ) +{ + return nsCreateInstanceByCID(aCID, 0, error); +} + +inline +const nsCreateInstanceByCID +do_CreateInstance( const nsCID& aCID, nsISupports* aOuter, nsresult* error = 0 ) +{ + return nsCreateInstanceByCID(aCID, aOuter, error); +} + +inline +const nsCreateInstanceByContractID +do_CreateInstance( const char* aContractID, nsresult* error = 0 ) +{ + return nsCreateInstanceByContractID(aContractID, 0, error); +} + +inline +const nsCreateInstanceByContractID +do_CreateInstance( const char* aContractID, nsISupports* aOuter, nsresult* error = 0 ) +{ + return nsCreateInstanceByContractID(aContractID, aOuter, error); +} + +// type-safe shortcuts for calling |CreateInstance| +template +inline +nsresult +CallCreateInstance( const nsCID &aClass, + nsISupports *aDelegate, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aClass, aDelegate, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const nsCID &aClass, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aClass, nsnull, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const char *aContractID, + nsISupports *aDelegate, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aContractID, + aDelegate, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallCreateInstance( const char *aContractID, + DestinationType** aDestination ) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsComponentManager::CreateInstance(aContractID, nsnull, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +/* keys for registry use */ +extern const char xpcomKeyName[]; +extern const char xpcomComponentsKeyName[]; +extern const char lastModValueName[]; +extern const char fileSizeValueName[]; +extern const char nativeComponentType[]; +extern const char staticComponentType[]; + +#endif /* nsComponentManagerUtils_h__ */ + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl b/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl new file mode 100644 index 00000000..509f7870 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsICategoryManager.idl @@ -0,0 +1,101 @@ +/* -*- 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): + * + * 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 ***** */ + +#include "nsISupports.idl" +#include "nsISimpleEnumerator.idl" + +/* + * nsICategoryManager + * @status FROZEN + */ + +[scriptable, uuid(3275b2cd-af6d-429a-80d7-f0c5120342ac)] +interface nsICategoryManager : nsISupports +{ + /** + * Get the value for the given category's entry. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry you're looking for ("http") + * @return The value. + */ + string getCategoryEntry(in string aCategory, in string aEntry); + + /** + * Add an entry to a category. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry to be added ("http") + * @param aValue The value for the entry ("moz.httprulez.1") + * @param aPersist Should this data persist between invocations? + * @param aReplace Should we replace an existing entry? + * @return Previous entry, if any + */ + string addCategoryEntry(in string aCategory, in string aEntry, + in string aValue, in boolean aPersist, + in boolean aReplace); + + /** + * Delete an entry from the category. + * @param aCategory The name of the category ("protocol") + * @param aEntry The entry to be added ("http") + * @param aPersist Delete persistent data from registry, if present? + */ + void deleteCategoryEntry(in string aCategory, in string aEntry, + in boolean aPersist); + + /** + * Delete a category and all entries. + * @param aCategory The category to be deleted. + */ + void deleteCategory(in string aCategory); + + /** + * Enumerate the entries in a category. + * @param aCategory The category to be enumerated. + * @return a simple enumerator, each result QIs to + * nsISupportsCString. + */ + nsISimpleEnumerator enumerateCategory(in string aCategory); + + /** + * Enumerate all existing categories + * @param aCategory The category to be enumerated. + * @return a simple enumerator, each result QIs to + * nsISupportsCString. + */ + nsISimpleEnumerator enumerateCategories(); +}; + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl b/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl new file mode 100644 index 00000000..e934057c --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIClassInfo.idl @@ -0,0 +1,132 @@ +/* -*- Mode: C++; tab-width: 8; 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 Communicator client code, released + * March 31, 1998. + * + * 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): + * John Bandhauer + * + * 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 ***** */ + +#include "nsISupports.idl" +#include "nsIProgrammingLanguage.idl" + +/** + * Provides information about a specific implementation class + * @status FROZEN + */ + +[scriptable, uuid(986c11d0-f340-11d4-9075-0010a4e73d9a)] +interface nsIClassInfo : nsISupports +{ + /** + * Get an ordered list of the interface ids that instances of the class + * promise to implement. Note that nsISupports is an implicit member + * of any such list and need not be included. + * + * Should set *count = 0 and *array = null and return NS_OK if getting the + * list is not supported. + */ + void getInterfaces(out PRUint32 count, + [array, size_is(count), retval] out nsIIDPtr array); + + /** + * Get a language mapping specific helper object that may assist in using + * objects of this class in a specific lanaguage. For instance, if asked + * for the helper for nsIProgrammingLanguage::JAVASCRIPT this might return + * an object that can be QI'd into the nsIXPCScriptable interface to assist + * XPConnect in supplying JavaScript specific behavior to callers of the + * instance object. + * + * see: nsIProgrammingLanguage.idl + * + * Should return null if no helper available for given language. + */ + nsISupports getHelperForLanguage(in PRUint32 language); + + /** + * A contract ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|), or null. + */ + readonly attribute string contractID; + + /** + * A human readable string naming the class, or null. + */ + readonly attribute string classDescription; + + /** + * A class ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|), or null. + */ + readonly attribute nsCIDPtr classID; + + /** + * Return language type from list in nsIProgrammingLanguage + */ + + readonly attribute PRUint32 implementationLanguage; + + /** + * Bitflags for 'flags' attribute. + */ + const PRUint32 SINGLETON = 1 << 0; + const PRUint32 THREADSAFE = 1 << 1; + const PRUint32 MAIN_THREAD_ONLY = 1 << 2; + const PRUint32 DOM_OBJECT = 1 << 3; + const PRUint32 PLUGIN_OBJECT = 1 << 4; + const PRUint32 EAGER_CLASSINFO = 1 << 5; + /** + * 'flags' attribute bitflag: whether objects of this type implement + * nsIContent. + */ + const PRUint32 CONTENT_NODE = 1 << 6; + + // The high order bit is RESERVED for consumers of these flags. + // No implementor of this interface should ever return flags + // with this bit set. + const PRUint32 RESERVED = 1 << 31; + + + readonly attribute PRUint32 flags; + + /** + * Also a class ID through which an instance of this class can be created + * (or accessed as a service, if |flags & SINGLETON|). If the class does + * not have a CID, it should return NS_ERROR_NOT_AVAILABLE. This attribute + * exists so C++ callers can avoid allocating and freeing a CID, as would + * happen if they used classID. + */ + [notxpcom] readonly attribute nsCID classIDNoAlloc; + +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl new file mode 100644 index 00000000..d1b4be6e --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoader.idl @@ -0,0 +1,109 @@ +/* -*- 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): + * + * 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 ***** */ + +#include "nsISupports.idl" +#include "nsIFactory.idl" +#include "nsIFile.idl" +#include "nsIComponentManager.idl" + +[object, uuid(c073cfc0-567c-11d3-aec1-0000f8e25c06)] +interface nsIComponentLoader : nsISupports { + + /** + * Get the factory for a given component. + */ + nsIFactory getFactory(in nsIIDRef aCID, in string aLocation, + in string aType); + + /** + * Initialize the loader. + * + * We use nsISupports here because nsIRegistry isn't IDLized yet. + */ + void init(in nsIComponentManager aCompMgr, in nsISupports aRegistry); + + /** + * Called when a component of the appropriate type is registered, + * to give the component loader an opportunity to do things like + * annotate the registry and such. + */ + void onRegister(in nsIIDRef aCID, in string aType, + in string aClassName, in string aContractID, + in string aLocation, in boolean aReplace, + in boolean aPersist); + + /** + * When is AutoRegistration occuring? + */ + const long Startup = 0; + const long Component = 1; + const long Timer = 2; + + /** + * AutoRegister components in the given directory. + */ + void autoRegisterComponents(in long aWhen, in nsIFile aDirectory); + + /** + * AutoRegister the given component. + * + * Returns true if the component was registered, false if it couldn't + * attempt to register the component (wrong type) and ``throws'' an + * NS_FAILED code if there was an error during registration. + */ + boolean autoRegisterComponent(in long aWhen, in nsIFile aComponent); + + /** + * AutoUnregister the given component. + * Returns true if the component was unregistered, false if it coudln't + * attempt to unregister the component (not found, wrong type). + */ + boolean autoUnregisterComponent(in long aWhen, in nsIFile aComponent); + + /** + * Register any deferred (NS_ERROR_FACTORY_REGISTER_AGAIN) components. + * Return registered-any-components? + */ + boolean registerDeferredComponents(in long aWhen); + + /** + * Unload all components that are willing. + */ + void unloadAll(in long aWhen); + +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl new file mode 100644 index 00000000..9f1784d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentLoaderManager.idl @@ -0,0 +1,72 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +/** + * The nsIComponentRegistrar interface. + * @status EXPERIMENTAL + * + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + * USE AT YOUR OWN RISK + */ + +#include "nsISupports.idl" + +interface nsIFile; + +[uuid(fce83d37-a3c0-4e09-ad9f-6842a984dbdf)] +interface nsIComponentLoaderManager : nsISupports +{ + boolean hasFileChanged(in nsIFile file, in string loaderString, in PRInt64 modDate); + void saveFileInfo(in nsIFile file, in string loaderString, in PRInt64 modDate); + void removeFileInfo(in nsIFile file, in string loaderString); + void flushPersistentStore(in boolean now); + + string getOptionalData(in nsIFile file, in string loaderString); + void setOptionalData(in nsIFile file, in string loaderString, in string value); +}; + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl new file mode 100644 index 00000000..20661803 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManager.idl @@ -0,0 +1,111 @@ +/* -*- Mode: IDL; 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): + * + * 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 ***** */ + +/** + * The nsIComponentManager interface. + * @status FROZEN + */ + +#include "nsISupports.idl" + +interface nsIFactory; + +[scriptable, uuid(a88e5a60-205a-4bb1-94e1-2628daf51eae)] +interface nsIComponentManager : nsISupports +{ + /** + * getClassObject + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + void getClassObject(in nsCIDRef aClass, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * getClassObjectByContractID + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + void getClassObjectByContractID(in string aContractID, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + + /** + * createInstance + * + * Create an instance of the CID aClass and return the interface aIID. + * + * @param aClass : ClassID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + void createInstance(in nsCIDRef aClass, + in nsISupports aDelegate, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * createInstanceByContractID + * + * Create an instance of the CID that implements aContractID and return the + * interface aIID. + * + * @param aContractID : aContractID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + void createInstanceByContractID(in string aContractID, + in nsISupports aDelegate, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); +}; + + +%{ C++ +#ifndef MOZILLA_STRICT_API +#include "nsComponentManagerUtils.h" +#include "nsComponentManagerObsolete.h" +#endif +%} C++ diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl new file mode 100644 index 00000000..ac5f7975 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerObsolete.idl @@ -0,0 +1,351 @@ +/* -*- 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): + * + * 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 ***** */ + +#include "nsISupports.idl" +#include "nsIFactory.idl" + +interface nsIFile; +interface nsIEnumerator; + +[scriptable, uuid(8458a740-d5dc-11d2-92fb-00e09805570f)] +interface nsIComponentManagerObsolete : nsISupports +{ + /** + * findFactory + * + * Returns the factory object that can be used to create instances of + * CID aClass + * + * @param aClass The classid of the factory that is being requested + */ + nsIFactory findFactory(in nsCIDRef aClass); + + /** + * getClassObject + * + * @param aClass : CID of the class whose class object is requested + * @param aIID : IID of an interface that the class object is known to + * to implement. nsISupports and nsIFactory are known to + * be implemented by the class object. + */ + [noscript] voidPtr getClassObject(in nsCIDRef aClass, in nsIIDRef aIID); + + /** + * contractIDToClassID + * + * Get the ClassID for a given ContractID. Many ClassIDs may implement a + * ContractID. In such a situation, this returns the preferred ClassID, which + * happens to be the last registered ClassID. + * + * @param aContractID : Contractid for which ClassID is requested + * @return aClass : ClassID return + */ + [notxpcom] nsresult contractIDToClassID(in string aContractID, out nsCID aClass); + + /** + * classIDToContractid + * + * Get the ContractID for a given ClassID. A ClassIDs may implement multiple + * ContractIDs. This function return the last registered ContractID. + * + * @param aClass : ClassID for which ContractID is requested. + * @return aClassName : returns class name asssociated with aClass + * @return : ContractID last registered for aClass + */ + string CLSIDToContractID(in nsCIDRef aClass, out string aClassName); + + /** + * createInstance + * + * Create an instance of the CID aClass and return the interface aIID. + * + * @param aClass : ClassID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + [noscript] voidPtr createInstance(in nsCIDRef aClass, + in nsISupports aDelegate, + in nsIIDRef aIID); + + /** + * createInstanceByContractID + * + * Create an instance of the CID that implements aContractID and return the + * interface aIID. This is a convenience function that effectively does + * ContractIDToClassID() followed by CreateInstance(). + * + * @param aContractID : aContractID of object instance requested + * @param aDelegate : Used for aggregation + * @param aIID : IID of interface requested + */ + [noscript] voidPtr createInstanceByContractID(in string aContractID, + in nsISupports aDelegate, + in nsIIDRef IID); + /** + * registryLocationForSpec + * + * Given a file specification, return the registry representation of + * the filename. Files that are found relative to the components + * directory will have a registry representation + * "rel:" while filenames that are not, will have + * "abs:". + */ + string registryLocationForSpec(in nsIFile aSpec); + + /** + * specForRegistyLocation + * + * Create a file specification for the registry representation (rel:/abs:) + * got via registryLocationForSpec. + */ + nsIFile specForRegistryLocation(in string aLocation); + + /** + * registerFactory + * + * Register a factory and ContractID associated with CID aClass + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFactory : Factory that will be registered for CID aClass + * @param aReplace : Boolean that indicates whether to replace a previous + * registration for the CID aClass. + */ + void registerFactory(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFactory aFactory, + in boolean aReplace); + + /** + * registerComponent + * + * Register a native dll module via its registry representation as returned + * by registryLocationForSpec() as the container of CID implemenation + * aClass and associate aContractID and aClassName to the CID aClass. Native + * dll component type is assumed. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aLocation : Location of module (dll). Format of this is the + * registry representation as returned by + * registryLocationForSpec() + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponent(in nsCIDRef aClass, in string aClassName, + in string aContractID, in string aLocation, + in boolean aReplace, in boolean aPersist); + + /** + * registerComponentWithType + * + * Register a module's location via its registry representation + * as returned by registryLocationForSpec() as the container of CID implemenation + * aClass of type aType and associate aContractID and aClassName to the CID aClass. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aSpec : Filename spec for module's location. + * @param aLocation : Location of module of type aType. Format of this string + * is the registry representation as returned by + * registryLocationForSpec() + * @param aReplace : Boolean that indicates whether to replace a previous + * loader registration for aClass. + * @param aPersist : Remember this registration across sessions. + * @param aType : Component Type of CID aClass. + */ + void registerComponentWithType(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFile aSpec, + in string aLocation, in boolean aReplace, + in boolean aPersist, in string aType); + + /** + * registerComponentSpec + * + * Register a native dll module via its file specification as the container + * of CID implemenation aClass and associate aContractID and aClassName to the + * CID aClass. Native dll component type is assumed. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aLibrary : File specification Location of module (dll). + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponentSpec(in nsCIDRef aClass, in string aClassName, + in string aContractID, in nsIFile aLibrary, + in boolean aReplace, in boolean aPersist); + + /** + * registerComponentLib + * + * Register a native dll module via its dll name (not full path) as the + * container of CID implemenation aClass and associate aContractID and aClassName + * to the CID aClass. Native dll component type is assumed and the system + * services will be used to load this dll. + * + * @param aClass : CID implemenation contained in module + * @param aClassName : Class name associated with CID aClass + * @param aContractID : ContractID associated with CID aClass + * @param aDllNameLocation : Dll name of module. + * @param aReplace : Boolean that indicates whether to replace a previous + * module registration for aClass. + * @param aPersist : Remember this registration across sessions. + */ + void registerComponentLib(in nsCIDRef aClass, in string aClassName, + in string aContractID, in string aDllName, + in boolean aReplace, in boolean aPersist); + + /** + * unregisterFactory + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : ClassID being unregistered + * @param aFactory : Factory previously registered to create instances of + * ClassID aClass. + */ + void unregisterFactory(in nsCIDRef aClass, in nsIFactory aFactory); + + /** + * unregisterComponent + * + * Disassociate module aLocation represented as registry location as returned + * by registryLocationForSpec() as containing ClassID aClass. + * + * @param aClass : ClassID being unregistered + * @param aLocation : Location of module. Format of this is the registry + * representation as returned by registryLocationForSpec(). + * Components of any type will be unregistered. + */ + void unregisterComponent(in nsCIDRef aClass, in string aLocation); + + /** + * unregisterComponentSpec + * + * Disassociate module references by file specification aLibrarySpec as + * containing ClassID aClass. + */ + void unregisterComponentSpec(in nsCIDRef aClass, in nsIFile aLibrarySpec); + + /** + * freeLibraries + * + * Enumerates all loaded modules and unloads unused modules. + */ + void freeLibraries(); + + /** + * ID values for 'when' + */ + const long NS_Startup = 0; + const long NS_Script = 1; + const long NS_Timer = 2; + const long NS_Shutdown = 3; + + /** + * autoRegister + * + * Enumerates directory looking for modules of all types and registers + * modules who have changed (modtime or size) since the last time + * autoRegister() was invoked. + * + * @param when : ID values of when the call is being made. + * @param directory : Directory the will be enumerated. + */ + void autoRegister(in long when, in nsIFile directory); + + /** + * autoRegisterComponent + * + * Loads module using appropriate loader and gives it an opportunity to + * register its CIDs if module's modtime or size changed since the last + * time this was called. + * + * @param when : ID values of when the call is being made. + * @param aFileLocation : File specification of module. + */ + void autoRegisterComponent(in long when, in nsIFile aFileLocation); + + /** + * autoUnregisterComponent + * + * Loads module using approriate loader and gives it an opportunity to + * unregister its CIDs + */ + void autoUnregisterComponent(in long when, in nsIFile aFileLocation); + + /** + * isRegistered + * + * Returns true if a factory or module is registered for CID aClass. + * + * @param aClass : ClassID queried for registeration + * @return : true if a factory or module is registered for CID aClass. + * false otherwise. + */ + boolean isRegistered(in nsCIDRef aClass); + + /** + * enumerateCLSIDs + * + * Enumerate the list of all registered ClassIDs. + * + * @return : enumerator for ClassIDs. + */ + nsIEnumerator enumerateCLSIDs(); + + /** + * enumerateContractIDs + * + * Enumerate the list of all registered ContractIDs. + * + * @return : enumerator for ContractIDs. + */ + nsIEnumerator enumerateContractIDs(); +}; + +%{ C++ +/* include after the class def'n, because it needs to see it. */ +#include "nsComponentManagerUtils.h" +%} C++ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h new file mode 100644 index 00000000..a21ee7e3 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentManagerUtils.h @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 2; 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 XPCOM. + * + * 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): + * + * 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 ***** */ + +#ifndef nsIComponentManagerUtils_h__ +#define nsIComponentManagerUtils_h__ + + + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl b/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl new file mode 100644 index 00000000..2a4a55db --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIComponentRegistrar.idl @@ -0,0 +1,243 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + +/** + * The nsIComponentRegistrar interface. + * @status FROZEN + */ + +#include "nsISupports.idl" + +interface nsIFile; +interface nsIFactory; +interface nsISimpleEnumerator; + +[scriptable, uuid(2417cbfe-65ad-48a6-b4b6-eb84db174392)] +interface nsIComponentRegistrar : nsISupports +{ + /** + * autoRegister + * + * Register a component file or all component files in a directory. + * + * Component files must have an associated loader and export the required + * symbols which this loader defines. For example, if the given file is a + * native library (which is built into XPCOM), it must export the symbol + * "NSGetModule". Other loaders may have different semantics. + * + * This method may only be called from the main thread. + * + * @param aSpec : Filename spec for component file's location. If aSpec + * is a directory, then every component file in the + * directory will be registered. + * If the aSpec is null, then the application component's + * directory as defined by NS_XPCOM_COMPONENT_DIR will be + * registered (see nsIDirectoryService.idl) + * + * @return NS_OK : Registration was successful. + * NS_ERROR: Method failure. + */ + void autoRegister(in nsIFile aSpec); + + /** + * autoUnregister + * + * Unregister a component file or all component files in a directory. + * This method may only be called from the main thread. + * + * @param aSpec : Filename spec for component file's location. If aSpec + * is a directory, the every component file in the directory + * will be registered. + * If aSpec is null, then the application component's + * directory as defined by NS_XPCOM_COMPONENT_DIR will be + * registered. (see nsIDirectoryService.idl) + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void autoUnregister(in nsIFile aSpec); + + + /** + * registerFactory + * + * Register a factory with a given ContractID, CID and Class Name. + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFactory : Factory that will be registered for CID aClass + * + * @return NS_OK Registration was successful. + * NS_ERROR* method failure. + */ + void registerFactory(in nsCIDRef aClass, + in string aClassName, + in string aContractID, + in nsIFactory aFactory); + + /** + * unregisterFactory + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : CID being unregistered + * @param aFactory : Factory previously registered to create instances of + * CID aClass. + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void unregisterFactory(in nsCIDRef aClass, + in nsIFactory aFactory); + + /** + * registerFactoryLocation + * + * Register a factory with a given ContractID, CID and Class Name + * + * @param aClass : CID of object + * @param aClassName : Class Name of CID + * @param aContractID : ContractID associated with CID aClass + * @param aFile : Component File. This file must have an associated + * loader and export the required symbols which this + * loader specifies. + * @param aLoaderStr : Opaque loader specific string. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * @param aType : Component Type of CID aClass. This value is + * passed into the nsIModule's registerSelf + * callback and must be fowarded unmodified when + * registering factories via their location. + * + * @return NS_OK Registration was successful. + * NS_ERROR* Method failure. + */ + void registerFactoryLocation(in nsCIDRef aClass, + in string aClassName, + in string aContractID, + in nsIFile aFile, + in string aLoaderStr, + in string aType); + + /** + * unregisterFactoryLocation + * + * Unregister a factory associated with CID aClass. + * + * @param aClass : CID being unregistered + * @param aFile : Component File previously registered + * + * @return NS_OK Unregistration was successful. + * NS_ERROR* Method failure. + */ + void unregisterFactoryLocation(in nsCIDRef aClass, + in nsIFile aFile); + + /** + * isCIDRegistered + * + * Returns true if a factory is registered for the CID. + * + * @param aClass : CID queried for registeration + * @return : true if a factory is registered for CID + * false otherwise. + */ + boolean isCIDRegistered(in nsCIDRef aClass); + + /** + * isContractIDRegistered + * + * Returns true if a factory is registered for the contract id. + * + * @param aClass : contract id queried for registeration + * @return : true if a factory is registered for contract id + * false otherwise. + */ + boolean isContractIDRegistered(in string aContractID); + + /** + * enumerateCIDs + * + * Enumerate the list of all registered CIDs. + * + * @return : enumerator for CIDs. Elements of the enumeration can be QI'ed + * for the nsISupportsID interface. From the nsISupportsID, you + * can obtain the actual CID. + */ + nsISimpleEnumerator enumerateCIDs(); + + /** + * enumerateContractIDs + * + * Enumerate the list of all registered ContractIDs. + * + * @return : enumerator for ContractIDs. Elements of the enumeration can be + * QI'ed for the nsISupportsCString interface. From the + * nsISupportsCString interface, you can obtain the actual + * Contract ID string. + */ + nsISimpleEnumerator enumerateContractIDs(); + + /** + * CIDToContractID + * + * Returns the Contract ID for a given CID, if one exists and is registered. + * + * @return : Contract ID. + */ + string CIDToContractID(in nsCIDRef aClass); + + /** + * contractIDToCID + * + * Returns the CID for a given Contract ID, if one exists and is registered. + * + * @return : Contract ID. + */ + nsCIDPtr contractIDToCID(in string aContractID); + +}; + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl b/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl new file mode 100644 index 00000000..bda0b43a --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIFactory.idl @@ -0,0 +1,79 @@ +/* -*- Mode: IDL; 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): + * + * 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 ***** */ + +#include "nsISupports.idl" + +/** + * A class factory allows the creation of nsISupports derived + * components without specifying a concrete base class. + * + * @status FROZEN + */ + +[scriptable, object, uuid(00000001-0000-0000-c000-000000000046)] +interface nsIFactory : nsISupports { + /** + * Creates an instance of a component. + * + * @param aOuter Pointer to a component that wishes to be aggregated + * in the resulting instance. This will be nsnull if no + * aggregation is requested. + * @param iid The IID of the interface being requested in + * the component which is being currently created. + * @param result [out] Pointer to the newly created instance, if successful. + * @return NS_OK - Component successfully created and the interface + * being requested was successfully returned in result. + * NS_NOINTERFACE - Interface not accessible. + * NS_ERROR_NO_AGGREGATION - if an 'outer' object is supplied, but the + * component is not aggregatable. + * NS_ERROR* - Method failure. + */ + void createInstance(in nsISupports aOuter, in nsIIDRef iid, + [retval, iid_is(iid)] out nsQIResult result); + + /** + * LockFactory provides the client a way to keep the component + * in memory until it is finished with it. The client can call + * LockFactory(PR_TRUE) to lock the factory and LockFactory(PR_FALSE) + * to release the factory. + * + * @param lock - Must be PR_TRUE or PR_FALSE + * @return NS_OK - If the lock operation was successful. + * NS_ERROR* - Method failure. + */ + void lockFactory(in PRBool lock); +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIModule.idl b/src/libs/xpcom18a4/xpcom/components/nsIModule.idl new file mode 100644 index 00000000..a71b9b13 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIModule.idl @@ -0,0 +1,115 @@ +/* -*- 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): + * + * 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 ***** */ + +#include "nsISupports.idl" + +interface nsIFile; +interface nsIComponentManager; + +/** + * The nsIModule interface. + * @status FROZEN + */ + +[scriptable, uuid(7392D032-5371-11d3-994E-00805FD26FEE)] +interface nsIModule : nsISupports +{ + /** + * Object Instance Creation + * + * Obtains a Class Object from a nsIModule for a given CID and IID pair. + * This class object can either be query to a nsIFactory or a may be + * query to a nsIClassInfo. + * + * @param aCompMgr : The global component manager + * @param aClass : ClassID of object instance requested + * @param aIID : IID of interface requested + * + */ + void getClassObject(in nsIComponentManager aCompMgr, + in nsCIDRef aClass, + in nsIIDRef aIID, + [retval, iid_is(aIID)] out nsQIResult aResult); + + + /** + * One time registration callback + * + * When the nsIModule is discovered, this method will be + * called so that any setup registration can be preformed. + * + * @param aCompMgr : The global component manager + * @param aLocation : The location of the nsIModule on disk + * @param aLoaderStr: Opaque loader specific string + * @param aType : Loader Type being used to load this module + */ + void registerSelf(in nsIComponentManager aCompMgr, + in nsIFile aLocation, + in string aLoaderStr, + in string aType); + /** + * One time unregistration callback + * + * When the nsIModule is being unregistered, this method will be + * called so that any unregistration can be preformed + * + * @param aCompMgr : The global component manager + * @param aLocation : The location of the nsIModule on disk + * @param aLoaderStr : Opaque loader specific string + * + */ + void unregisterSelf(in nsIComponentManager aCompMgr, + in nsIFile aLocation, + in string aLoaderStr); + + /** + * Module load management + * + * @param aCompMgr : The global component manager + * + * @return indicates to the caller if the module can be unloaded. + * Returning PR_TRUE isn't a guarantee that the module will be + * unloaded. It constitues only willingness of the module to be + * unloaded. It is very important to ensure that no outstanding + * references to the module's code/data exist before returning + * PR_TRUE. + * Returning PR_FALSE guaratees that the module wont be unloaded. + */ + boolean canUnload(in nsIComponentManager aCompMgr); +}; + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl b/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl new file mode 100644 index 00000000..c5d18111 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsINativeComponentLoader.idl @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 8; 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) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#include "nsISupports.idl" + +interface nsIFile; + +[uuid(10d1a2a2-d816-458d-a4c3-0805ff0f7b31)] +interface nsINativeComponentLoader : nsISupports +{ + + /** + * addDependentLibrary + * + * This method informs the native component loader that the + * given component library referenced by |aFile| requires + * symbols that can be found in the library named |aLibName|. + * + * The native component loader is expected to resolve these + * external symobls prior to loading the component library. + * + * @param aFile + * The native component file location that is declaring a + * a dependency. This file is expected to be a DSO/DLL. + * + * @param aLibName + * This is a name of a library that the component requires. + * This file name is found in either the GRE bin directory + * or the application's bin directory. Full file path are + * also accepted. Passing nsnull for the |aLibName| will + * clear all dependencies. Note that non null aLibName + * values are expected to be in the native charset. + */ + + void addDependentLibrary(in nsIFile aFile, in string aLibName); +}; diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl b/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl new file mode 100644 index 00000000..200c2a69 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManager.idl @@ -0,0 +1,119 @@ +/* ***** 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 XPCOM. + * + * The Initial Developer of the Original Code is Netscape Communications. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either 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 ***** */ + + +#include "nsISupports.idl" + +/** + * The nsIServiceManager manager interface provides a means to obtain + * global services in an application. The service manager depends on the + * repository to find and instantiate factories to obtain services. + * + * Users of the service manager must first obtain a pointer to the global + * service manager by calling NS_GetServiceManager. After that, + * they can request specific services by calling GetService. When they are + * finished they can NS_RELEASE() the service as usual. + * + * A user of a service may keep references to particular services indefinitely + * and only must call Release when it shuts down. + * + * @status FROZEN + */ + +[scriptable, uuid(8bb35ed9-e332-462d-9155-4a002ab5c958)] +interface nsIServiceManager : nsISupports +{ + /** + * getServiceByContractID + * + * Returns the instance that implements aClass or aContractID and the + * interface aIID. This may result in the instance being created. + * + * @param aClass or aContractID : aClass or aContractID of object + * instance requested + * @param aIID : IID of interface requested + * @param result : resulting service + */ + void getService(in nsCIDRef aClass, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + void getServiceByContractID(in string aContractID, + in nsIIDRef aIID, + [iid_is(aIID),retval] out nsQIResult result); + + /** + * isServiceInstantiated + * + * isServiceInstantiated will return a true if the service has already + * been created, otherwise false + * + * @param aClass or aContractID : aClass or aContractID of object + * instance requested + * @param aIID : IID of interface requested + * @param aIID : IID of interface requested + */ + boolean isServiceInstantiated(in nsCIDRef aClass, in nsIIDRef aIID); + boolean isServiceInstantiatedByContractID(in string aContractID, in nsIIDRef aIID); +}; + + +%{C++ +#define NS_ERROR_SERVICE_NOT_AVAILABLE NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_XPCOM, 22) +/** + * @status DEPRECATED + */ +#define NS_ERROR_SERVICE_NOT_FOUND NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 22) +/** + * @status DEPRECATED + */ +#define NS_ERROR_SERVICE_IN_USE NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_XPCOM, 23) + +// Observing xpcom startup. If you component has not been created, it will be. +#define NS_XPCOM_STARTUP_OBSERVER_ID "xpcom-startup" + +// Observing xpcom shutdown +#define NS_XPCOM_SHUTDOWN_OBSERVER_ID "xpcom-shutdown" + +// Observing xpcom autoregistration. Topics will be 'start' and 'stop'. +#define NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID "xpcom-autoregistration" + +#ifndef MOZILLA_STRICT_API +#include "nsXPCOM.h" +#include "nsIServiceManagerUtils.h" +#include "nsIServiceManagerObsolete.h" +#endif +%} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h new file mode 100644 index 00000000..dc229c76 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerObsolete.h @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 2; 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 XPCOM. + * + * 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): + * + * 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 ***** */ + +#ifndef nsIServiceManagerObsolete_h___ +#define nsIServiceManagerObsolete_h___ + +//////////////////////////////////////////////////////////////////// +// +// WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING +// +// Functions, classes, interfaces and types in this file are +// obsolete. Use at your own risk. +// Please see nsIServiceManager.idl for the supported interface +// to the service manager. +// +//////////////////////////////////////////////////////////////////// + +#include "nsIComponentManager.h" +#include "nsID.h" + +#ifndef nsCOMPtr_h___ +#include "nsCOMPtr.h" +#endif + +class nsIServiceManager; +class nsIShutdownListener; +class nsIDirectoryServiceProvider; + +class nsServiceManagerObsolete; + +#define NS_ISERVICEMANAGER_OBSOLETE_IID \ +{ /* cf0df3b0-3401-11d2-8163-006008119d7a */ \ + 0xcf0df3b0, \ + 0x3401, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +/** + * The nsIServiceManagerObsolete manager is obsolete. Please refer + * to nsIServiceManager. + */ +class nsIServiceManagerObsolete : public nsISupports { +public: + + NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISERVICEMANAGER_OBSOLETE_IID); + + /** + * RegisterService may be called explicitly to register a service + * with the service manager. If a service is not registered explicitly, + * the component manager will be used to create an instance according + * to the class ID specified. + */ + NS_IMETHOD + RegisterService(const nsCID& aClass, nsISupports* aService) = 0; + + /** + * Requests a service to be shut down, possibly unloading its DLL. + * + * @returns NS_OK - if shutdown was successful and service was unloaded, + * @returns NS_ERROR_SERVICE_NOT_FOUND - if shutdown failed because + * the service was not currently loaded + * @returns NS_ERROR_SERVICE_IN_USE - if shutdown failed because some + * user of the service wouldn't voluntarily release it by using + * a shutdown listener. + */ + NS_IMETHOD + UnregisterService(const nsCID& aClass) = 0; + + NS_IMETHOD + GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + NS_IMETHOD + ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + //////////////////////////////////////////////////////////////////////////// + // let's do it again, this time with ContractIDs... + + NS_IMETHOD + RegisterService(const char* aContractID, nsISupports* aService) = 0; + + NS_IMETHOD + UnregisterService(const char* aContractID) = 0; + + NS_IMETHOD + GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull) = 0; + + /* OBSOLETE */ + NS_IMETHOD + ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull) = 0; + +}; + +// Interface to Global Services +class NS_COM nsServiceManager { +public: + + static nsresult + RegisterService(const nsCID& aClass, nsISupports* aService); + + static nsresult + UnregisterService(const nsCID& aClass); + + static nsresult + GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull); + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + static nsresult + ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull); + + //////////////////////////////////////////////////////////////////////////// + // let's do it again, this time with ContractIDs... + + static nsresult + RegisterService(const char* aContractID, nsISupports* aService); + + static nsresult + UnregisterService(const char* aContractID); + + static nsresult + GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener = nsnull); + + /* OBSOLETE: use NS_RELEASE(service) instead. */ + static nsresult + ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener = nsnull); + + + //////////////////////////////////////////////////////////////////////////// + // These methods return really nsIServiceManagerObsolete, but they are + // statically cast to nsIServiceManager to preserve backwards compatiblity. + static nsresult GetGlobalServiceManager(nsIServiceManager* *result); + static nsresult ShutdownGlobalServiceManager(nsIServiceManager* *result); +}; + + +#define NS_DECL_NSISERVICEMANAGEROBSOLETE \ + NS_IMETHOD RegisterService(const nsCID& aClass, nsISupports* aService); \ + NS_IMETHOD UnregisterService(const nsCID& aClass);\ + NS_IMETHOD GetService(const nsCID& aClass, const nsIID& aIID, nsISupports* *result, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD ReleaseService(const nsCID& aClass, nsISupports* service, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD RegisterService(const char* aContractID, nsISupports* aService);\ + NS_IMETHOD UnregisterService(const char* aContractID);\ + NS_IMETHOD GetService(const char* aContractID, const nsIID& aIID, nsISupports* *result, nsIShutdownListener* shutdownListener);\ + NS_IMETHOD ReleaseService(const char* aContractID, nsISupports* service, nsIShutdownListener* shutdownListener); + +//////////////////////////////////////////////////////////////////////////////// + +#define NS_ISHUTDOWNLISTENER_IID \ +{ /* 56decae0-3406-11d2-8163-006008119d7a */ \ + 0x56decae0, \ + 0x3406, \ + 0x11d2, \ + {0x81, 0x63, 0x00, 0x60, 0x08, 0x11, 0x9d, 0x7a} \ +} + +class nsIShutdownListener; + + +template +inline +nsresult +CallGetService( const nsCID &aClass, + nsIShutdownListener* shutdownListener, + DestinationType** aDestination) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + return nsServiceManager::GetService(aClass, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(nsISupports**, aDestination), + shutdownListener); +} + +template +inline +nsresult +CallGetService( const char *aContractID, + nsIShutdownListener* shutdownListener, + DestinationType** aDestination) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + return nsServiceManager::GetService(aContractID, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(nsISupports**, aDestination), + shutdownListener); +} + +//////////////////////////////////////////////////////////////////////////////// + + +#endif /* nsIServiceManagerObsolete_h___ */ + + + + + + + + + + diff --git a/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h new file mode 100644 index 00000000..b7b432af --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsIServiceManagerUtils.h @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 2; 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 XPCOM. + * + * 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): + * + * 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 ***** */ + +#ifndef nsIServiceManagerUtils_h__ +#define nsIServiceManagerUtils_h__ + +#include "nsIServiceManager.h" +#include "nsIServiceManagerObsolete.h" +#include "nsCOMPtr.h" + +//////////////////////////////////////////////////////////////////////////// +// Using servicemanager with COMPtrs +class NS_COM nsGetServiceByCID : public nsCOMPtr_helper +{ + public: + nsGetServiceByCID( const nsCID& aCID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mCID(aCID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const nsCID& mCID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, 0, error); +} + +inline +const nsGetServiceByCID +do_GetService( const nsCID& aCID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByCID(aCID, aServiceManager, error); +} + +class NS_COM nsGetServiceByContractID : public nsCOMPtr_helper +{ + public: + nsGetServiceByContractID( const char* aContractID, nsISupports* aServiceManager, nsresult* aErrorPtr ) + : mContractID(aContractID), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + // Implement a dummy destructor to workaround linking issue on Solaris gcc 4.8.2 (see @bugref{5838}) + ~nsGetServiceByContractID() {} + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + + private: + const char* mContractID; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, 0, error); +} + +inline +const nsGetServiceByContractID +do_GetService( const char* aContractID, nsISupports* aServiceManager, nsresult* error = 0 ) +{ + return nsGetServiceByContractID(aContractID, aServiceManager, error); +} + +class nsGetServiceFromCategory : public nsCOMPtr_helper +{ + public: + nsGetServiceFromCategory(const char* aCategory, const char* aEntry, + nsISupports* aServiceManager, + nsresult* aErrorPtr) + : mCategory(aCategory), + mEntry(aEntry), + mServiceManager( do_QueryInterface(aServiceManager) ), + mErrorPtr(aErrorPtr) + { + // nothing else to do + } + + virtual nsresult NS_FASTCALL operator()( const nsIID&, void** ) const; + protected: + const char* mCategory; + const char* mEntry; + nsCOMPtr mServiceManager; + nsresult* mErrorPtr; +}; + +inline +const nsGetServiceFromCategory +do_GetServiceFromCategory( const char* category, const char* entry, + nsresult* error = 0) +{ + return nsGetServiceFromCategory(category, entry, 0, error); +} + +// type-safe shortcuts for calling |GetService| +template +inline +nsresult +CallGetService( const nsCID &aClass, + DestinationType** aDestination) +{ + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetService(aClass, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +template +inline +nsresult +CallGetService( const char *aContractID, + DestinationType** aDestination) +{ + NS_PRECONDITION(aContractID, "null parameter"); + NS_PRECONDITION(aDestination, "null parameter"); + + nsCOMPtr mgr; + nsresult rv = NS_GetServiceManager(getter_AddRefs(mgr)); + + if (NS_FAILED(rv)) + return rv; + + return mgr->GetServiceByContractID(aContractID, + NS_GET_IID(DestinationType), + NS_REINTERPRET_CAST(void**, aDestination)); +} + +#endif diff --git a/src/libs/xpcom18a4/xpcom/components/nsModule.h b/src/libs/xpcom18a4/xpcom/components/nsModule.h new file mode 100644 index 00000000..56a06354 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsModule.h @@ -0,0 +1,58 @@ +/* -*- 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 + * Marco Pesenti Gritti + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#ifndef nsModule_h__ +#define nsModule_h__ + +#include "nsIModule.h" +#include "nsIFile.h" +#include "nsIComponentManager.h" + +// Exported Function from module dll to Create the nsIModule +#define NS_GET_MODULE_SYMBOL "NSGetModule" + +extern "C" NS_EXPORT nsresult PR_CALLBACK +NSGetModule(nsIComponentManager *aCompMgr, + nsIFile* location, + nsIModule** return_cobj); + +typedef nsresult (PR_CALLBACK *nsGetModuleProc)(nsIComponentManager *aCompMgr, + nsIFile* location, + nsIModule** return_cobj); + + +#endif /* nsModule_h__ */ diff --git a/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp new file mode 100644 index 00000000..a3fd5df8 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.cpp @@ -0,0 +1,1150 @@ +/* -*- 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) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** + * This Original Code has been modified by IBM Corporation. + * Modifications made by IBM described herein are + * Copyright (c) International Business Machines + * Corporation, 2000 + * + * Modifications to Mozilla code or documentation + * identified per MPL Section 3.3 + * + * Date Modified by Description of modification + * 04/20/2000 IBM Corp. Added PR_CALLBACK for Optlink use in OS2 + */ + +#include "prmem.h" +#include "prerror.h" +#include "prsystem.h" // PR_GetDirectorySeparator +#include "nsNativeComponentLoader.h" +#include "nsComponentManager.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" +#include "nsIModule.h" +#include "xcDll.h" +#include "nsHashtable.h" +#include "nsXPIDLString.h" +#include "nsCRT.h" +#include "nsIObserverService.h" + +#if defined(XP_MAC) // sdagley dougt fix +#include +#include +#include "nsILocalFileMac.h" +#endif + +#include "prlog.h" +extern PRLogModuleInfo *nsComponentManagerLog; + +static PRBool PR_CALLBACK +DLLStore_Destroy(nsHashKey *aKey, void *aData, void* closure) +{ + nsDll* entry = NS_STATIC_CAST(nsDll*, aData); + delete entry; + return PR_TRUE; +} + +nsNativeComponentLoader::nsNativeComponentLoader() : + mCompMgr(nsnull), + mLoadedDependentLibs(16, PR_TRUE), + mDllStore(nsnull, nsnull, DLLStore_Destroy, + nsnull, 256, PR_TRUE) +{ +} + +NS_IMPL_THREADSAFE_ISUPPORTS2(nsNativeComponentLoader, + nsIComponentLoader, + nsINativeComponentLoader) + +NS_IMETHODIMP +nsNativeComponentLoader::GetFactory(const nsIID & aCID, + const char *aLocation, + const char *aType, + nsIFactory **_retval) +{ + nsresult rv; + + if (!_retval) + return NS_ERROR_NULL_POINTER; + + /* use a hashtable of WeakRefs to store the factory object? */ + + /* Should this all live in xcDll? */ + nsDll *dll; + rv = CreateDll(nsnull, aLocation, &dll); + if (NS_FAILED(rv)) + return rv; + + if (!dll) + return NS_ERROR_OUT_OF_MEMORY; + + if (!dll->IsLoaded()) { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: loading \"%s\"", + displayPath.get())); +#endif + if (!dll->Load()) { + + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsNativeComponentLoader: load FAILED")); + + char errorMsg[1024] = ""; + + if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) + PR_GetErrorText(errorMsg); + + DumpLoadError(dll, "GetFactory", errorMsg); + + return NS_ERROR_FAILURE; + } + } + + /* Get service manager for factory */ + nsCOMPtr serviceMgr; + rv = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(rv)) + return rv; // XXX translate error code? + + rv = GetFactoryFromModule(dll, aCID, _retval); + + PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR, + ("nsNativeComponentLoader: Factory creation %s for %s", + (NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"), + aLocation)); + + // If the dll failed to get us a factory. But the dll registered that + // it would be able to create a factory for this CID. mmh! + // We cannot just delete the dll as the dll could be hosting + // other CID for which factory creation can pass. + // We will just let it be. The effect will be next time we try + // creating the object, we will query the dll again. Since the + // dll is loaded, this aint a big hit. So for optimized builds + // this is ok to limp along. + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Factory creation failed"); + + return rv; +} + +NS_IMETHODIMP +nsNativeComponentLoader::Init(nsIComponentManager *aCompMgr, nsISupports *aReg) +{ + mCompMgr = aCompMgr; + if (!mCompMgr) + return NS_ERROR_INVALID_ARG; + + return NS_OK; +} + +NS_IMETHODIMP +nsNativeComponentLoader::AutoRegisterComponents(PRInt32 aWhen, + nsIFile *aDirectory) +{ +#ifdef DEBUG + /* do we _really_ want to print this every time? */ + fprintf(stderr, "nsNativeComponentLoader: autoregistering begins.\n"); +#endif + + nsresult rv = RegisterComponentsInDir(aWhen, aDirectory); + +#ifdef DEBUG + fprintf(stderr, "nsNativeComponentLoader: autoregistering %s\n", + NS_FAILED(rv) ? "FAILED" : "succeeded"); +#endif + + return rv; +} + +nsresult +nsNativeComponentLoader::RegisterComponentsInDir(PRInt32 when, + nsIFile *dir) +{ + nsresult rv = NS_ERROR_FAILURE; + PRBool isDir = PR_FALSE; + +#if 0 + // Going to many of these checks is a performance hit on the mac. + // Since these routines are called relatively infrequently and + // we will fail anyway down the line if a directory aint there, + // we are commenting this check out. + + // Make sure we are dealing with a directory + rv = dir->IsDirectory(&isDir); + if (NS_FAILED(rv)) return rv; + + if (!isDir) + return NS_ERROR_INVALID_ARG; +#endif /* 0 */ + + // Create a directory iterator + nsCOMPtr dirIterator; + rv = dir->GetDirectoryEntries(getter_AddRefs(dirIterator)); + + if (NS_FAILED(rv)) return rv; + + // whip through the directory to register every file + nsCOMPtr dirEntry; + PRBool more = PR_FALSE; + + rv = dirIterator->HasMoreElements(&more); + if (NS_FAILED(rv)) return rv; + while (more == PR_TRUE) + { + rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(dirEntry)); + if (NS_SUCCEEDED(rv)) + { + rv = dirEntry->IsDirectory(&isDir); + if (NS_SUCCEEDED(rv)) + { + if (isDir == PR_TRUE) + { + // This is a directory. Grovel for components into the directory. +#ifdef RT_OS_DARWIN // But not if it's a debug bundle. + nsCAutoString leafName; + rv = dirEntry->GetNativeLeafName(leafName); + if ( NS_FAILED(rv) + || leafName.Length() < sizeof(".dSYM") + || PL_strcasecmp(leafName.get() + (leafName.Length() - sizeof(".dSYM") + 1), ".dSYM")) +#endif + rv = RegisterComponentsInDir(when, dirEntry); + } + else + { + PRBool registered; + // This is a file. Try to register it. + rv = AutoRegisterComponent(when, dirEntry, ®istered); + } + } + } + rv = dirIterator->HasMoreElements(&more); + if (NS_FAILED(rv)) return rv; + } + + return rv; +} + +static nsresult PR_CALLBACK +nsFreeLibrary(nsDll *dll, nsIServiceManager *serviceMgr, PRInt32 when) +{ + nsresult rv = NS_ERROR_FAILURE; + + if (!dll || dll->IsLoaded() == PR_FALSE) + { + return NS_ERROR_INVALID_ARG; + } + + // Get if the dll was marked for unload in an earlier round + PRBool dllMarkedForUnload = dll->IsMarkedForUnload(); + + // Reset dll marking for unload just in case we return with + // an error. + dll->MarkForUnload(PR_FALSE); + + PRBool canUnload = PR_FALSE; + + // Get the module object + nsCOMPtr mobj; + /* XXXshaver cheat and use the global component manager */ + rv = dll->GetModule(NS_STATIC_CAST(nsIComponentManager*, nsComponentManagerImpl::gComponentManager), + getter_AddRefs(mobj)); + if (NS_SUCCEEDED(rv)) + { + rv = mobj->CanUnload(nsComponentManagerImpl::gComponentManager, &canUnload); + } + + mobj = nsnull; // Release our reference to the module object + // When shutting down, whether we can unload the dll or not, + // we will shutdown the dll to release any memory it has got + if (when == nsIComponentManagerObsolete::NS_Shutdown) + { + dll->Shutdown(); + } + + // Check error status on CanUnload() call + if (NS_FAILED(rv)) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: nsIModule::CanUnload() returned error for %s.", + displayPath.get())); +#endif + return rv; + } + + if (canUnload) + { + if (dllMarkedForUnload) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + Unloading \"%s\".", displayPath.get())); +#endif + +#ifdef DEBUG_dougt + // XXX dlls aren't counting their outstanding instances correctly + // XXX hence, dont unload until this gets enforced. + rv = dll->Unload(); +#endif /* 0 */ + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: Ready for unload \"%s\".", displayPath.get())); +#endif + } + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: NOT ready for unload %s", displayPath.get())); +#endif + rv = NS_ERROR_FAILURE; + } + return rv; +} + +struct freeLibrariesClosure +{ + nsIServiceManager *serviceMgr; + PRInt32 when; +}; + +static PRBool PR_CALLBACK +nsFreeLibraryEnum(nsHashKey *aKey, void *aData, void* closure) +{ + nsDll *dll = (nsDll *) aData; + struct freeLibrariesClosure *callData = (struct freeLibrariesClosure *) closure; + nsFreeLibrary(dll, + (callData ? callData->serviceMgr : NULL), + (callData ? callData->when : nsIComponentManagerObsolete::NS_Timer)); + return PR_TRUE; +} + +/* + * SelfRegisterDll + * + * Given a dll abstraction, this will load, selfregister the dll and + * unload the dll. + * + */ +nsresult +nsNativeComponentLoader::SelfRegisterDll(nsDll *dll, + const char *registryLocation, + PRBool deferred) +{ + // Precondition: dll is not loaded already, unless we're deferred + PR_ASSERT(deferred || dll->IsLoaded() == PR_FALSE); + + nsresult res; + nsCOMPtr serviceMgr; + res = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(res)) return res; + + if (dll->Load() == PR_FALSE) + { + // Cannot load. Probably not a dll. + char errorMsg[1024] = "Cannot get error from nspr. Not enough memory."; + if (PR_GetErrorTextLength() < (int) sizeof(errorMsg)) + PR_GetErrorText(errorMsg); + + DumpLoadError(dll, "SelfRegisterDll", errorMsg); + + return NS_ERROR_FAILURE; + } + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: Loaded \"%s\".", displayPath.get())); +#endif + + // Tell the module to self register + nsCOMPtr fs; + nsCOMPtr mobj; + res = dll->GetModule(mCompMgr, getter_AddRefs(mobj)); + if (NS_SUCCEEDED(res)) + { + /************************************************************* + * WARNING: Why are use introducing 'res2' here and then * + * later assigning it to 'res' rather than just using 'res'? * + * This is because this code turns up a code-generation bug * + * in VC6 on NT. Assigning to 'res' on the next line causes * + * the value of 'dll' to get nulled out! The two seem to be * + * getting aliased together during compilation. * + *************************************************************/ + nsresult res2 = dll->GetDllSpec(getter_AddRefs(fs)); // don't change 'res2' -- see warning, above + if (NS_SUCCEEDED(res2)) { + // in the case of re-registering a component, we want to remove + // any optional data that this file may have had. + AddDependentLibrary(fs, nsnull); + + res = mobj->RegisterSelf(mCompMgr, fs, registryLocation, + nativeComponentType); + } + else + { + res = res2; // don't take this out -- see warning, above + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: dll->GetDllSpec() on %s FAILED.", + displayPath.get())); +#endif + } + mobj = NULL; // Force a release of the Module object before unload() + } + + // Update the timestamp and size of the dll in registry + // Don't enter deferred modules in the registry, because it might only be + // able to register on some later autoreg, after another component has been + // installed. + if (res != NS_ERROR_FACTORY_REGISTER_AGAIN) { + PRInt64 modTime; + if (!fs) + return res; + + fs->GetLastModifiedTime(&modTime); + nsCOMPtr manager = do_QueryInterface(mCompMgr); + if (!manager) + return NS_ERROR_FAILURE; + + nsCOMPtr fs; + res = dll->GetDllSpec(getter_AddRefs(fs)); + if (NS_FAILED(res)) return res; + + manager->SaveFileInfo(fs, registryLocation, modTime); + } + + return res; +} + +// +// MOZ_DEMANGLE_SYMBOLS is only a linux + MOZ_DEBUG thing. +// + +#if defined(MOZ_DEMANGLE_SYMBOLS) +#include "nsTraceRefcntImpl.h" // for nsTraceRefcntImpl::DemangleSymbol() +#endif + +nsresult +nsNativeComponentLoader::DumpLoadError(nsDll *dll, + const char *aCallerName, + const char *aNsprErrorMsg) +{ + PR_ASSERT(aCallerName != NULL); + + if (nsnull == dll || nsnull == aNsprErrorMsg) + return NS_OK; + + nsCAutoString errorMsg(aNsprErrorMsg); + +#if defined(MOZ_DEMANGLE_SYMBOLS) + // Demangle undefined symbols + nsCAutoString undefinedMagicString("undefined symbol:"); + + PRInt32 offset = errorMsg.Find(undefinedMagicString, PR_TRUE); + + if (offset != kNotFound) + { + nsCAutoString symbol(errorMsg); + nsCAutoString demangledSymbol; + + symbol.Cut(0,offset); + + symbol.Cut(0,undefinedMagicString.Length()); + + symbol.StripWhitespace(); + + char demangled[4096] = "\0"; + + nsTraceRefcntImpl::DemangleSymbol(symbol.get(),demangled,sizeof(demangled)); + + if (demangled && *demangled != '\0') + demangledSymbol = demangled; + + if (!demangledSymbol.IsEmpty()) + { + nsCAutoString tmp(errorMsg); + + + tmp.Cut(offset + undefinedMagicString.Length(), + tmp.Length() - offset - undefinedMagicString.Length()); + + tmp += " \n"; + + tmp += demangledSymbol; + + errorMsg = tmp; + } + } +#endif // MOZ_DEMANGLE_SYMBOLS + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + +#ifdef DEBUG + fprintf(stderr, + "nsNativeComponentLoader: %s(%s) Load FAILED with error: %s\n", + aCallerName, + displayPath.get(), + errorMsg.get()); +#endif + + // Do NSPR log +#ifdef PR_LOGGING + PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, + ("nsNativeComponentLoader: %s(%s) Load FAILED with error: %s", + aCallerName, + displayPath.get(), + errorMsg.get())); +#endif + return NS_OK; +} + +nsresult +nsNativeComponentLoader::SelfUnregisterDll(nsDll *dll) +{ + nsresult res; + nsCOMPtr serviceMgr; + res = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + if (NS_FAILED(res)) return res; + + if (dll->Load() == PR_FALSE) + { + // Cannot load. Probably not a dll. + return(NS_ERROR_FAILURE); + } + + // Tell the module to self register + nsCOMPtr mobj; + res = dll->GetModule(mCompMgr, getter_AddRefs(mobj)); + if (NS_SUCCEEDED(res)) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: %s using nsIModule to unregister self.", displayPath.get())); +#endif + nsCOMPtr fs; + res = dll->GetDllSpec(getter_AddRefs(fs)); + if (NS_FAILED(res)) return res; + // Get registry location for spec + nsXPIDLCString registryName; + + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &res); + if (obsoleteManager) + res = obsoleteManager->RegistryLocationForSpec(fs, getter_Copies(registryName)); + + if (NS_FAILED(res)) return res; + mobj->UnregisterSelf(mCompMgr, fs, registryName); + } + return res; +} + +nsresult +nsNativeComponentLoader::AutoUnregisterComponent(PRInt32 when, + nsIFile *component, + PRBool *unregistered) +{ + + nsresult rv = NS_ERROR_FAILURE; + + *unregistered = PR_FALSE; + + nsXPIDLCString persistentDescriptor; + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->RegistryLocationForSpec(component, + getter_Copies(persistentDescriptor)); + if (NS_FAILED(rv)) return rv; + + // Notify observers, if any, of autoregistration work + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) + { + (void) observerService->NotifyObservers(mgr, + NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + NS_LITERAL_STRING("Unregistering native component").get()); + } + } + + nsDll *dll = NULL; + rv = CreateDll(component, persistentDescriptor, &dll); + if (NS_FAILED(rv) || dll == NULL) return rv; + + rv = SelfUnregisterDll(dll); + +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, NS_SUCCEEDED(rv) ? PR_LOG_DEBUG : PR_LOG_ERROR, + ("nsNativeComponentLoader: AutoUnregistration for %s %s.", + (NS_FAILED(rv) ? "FAILED" : "succeeded"), displayPath.get())); +#endif + + if (NS_FAILED(rv)) + return rv; + + // Remove any autoreg info about this dll + nsCStringKey key(persistentDescriptor); + mDllStore.RemoveAndDelete(&key); + + nsCOMPtr manager = do_QueryInterface(mCompMgr); + NS_ASSERTION(manager, "Something is terribly wrong"); + + manager->RemoveFileInfo(component, nsnull); + + *unregistered = PR_TRUE; + return rv; +} + +nsresult +nsNativeComponentLoader::AutoRegisterComponent(PRInt32 when, + nsIFile *component, + PRBool *registered) +{ + nsresult rv; + if (!registered) + return NS_ERROR_NULL_POINTER; + + *registered = PR_FALSE; + +#ifndef VBOX + /* this should be a pref or registry entry, or something */ + static const char *ValidDllExtensions[] = { + ".dll", /* Windows */ + ".so", /* Unix */ + ".shlb", /* Mac ? */ + ".dso", /* Unix ? */ + ".dylib", /* Unix: Mach */ + ".so.1.0", /* Unix: BSD */ + ".sl", /* Unix: HP-UX */ +#if defined(VMS) + ".exe", /* Open VMS */ +#endif + ".dlm", /* new for all platforms */ + NULL + }; + + *registered = PR_FALSE; + +#if 0 + // This is a performance hit on mac. Since we have already checked + // this; plus is we dont, load will fail anyway later on, this + // is being commented out. + + // Ensure we are dealing with a file as opposed to a dir + PRBool b = PR_FALSE; + + rv = component->IsFile(&b); + if (NS_FAILED(rv) || !b) + return rv; +#endif /* 0 */ + + // deal only with files that have a valid extension + PRBool validExtension = PR_FALSE; + +#if defined(XP_MAC) // sdagley dougt fix + // rjc - on Mac, check the file's type code (skip checking the creator code) + + nsCOMPtr localFileMac = do_QueryInterface(component); + if (localFileMac) + { + OSType type; + rv = localFileMac->GetFileType(&type); + if (NS_SUCCEEDED(rv)) + { + // on Mac, Mozilla shared libraries are of type 'shlb' + // Note: we don't check the creator (which for Mozilla is 'MOZZ') + // so that 3rd party shared libraries will be noticed! + validExtension = ((type == 'shlb') || (type == 'NSPL')); + } + } + +#else + nsCAutoString leafName; + rv = component->GetNativeLeafName(leafName); + if (NS_FAILED(rv)) return rv; + int flen = leafName.Length(); + for (int i=0; ValidDllExtensions[i] != NULL; i++) + { + int extlen = PL_strlen(ValidDllExtensions[i]); + + // Does fullname end with this extension + if (flen >= extlen && + !PL_strcasecmp(leafName.get() + (flen - extlen), ValidDllExtensions[i]) + ) + { + validExtension = PR_TRUE; + break; + } + } +#endif + + if (validExtension == PR_FALSE) + // Skip invalid extensions + return NS_OK; + +#else /* VBOX */ + /* VBox: Only one valid suffix exist, so dispense with the the list. */ +# ifdef RT_OS_DARWIN +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.dylib"; +# else + static const char s_szSuff[] = ".dylib"; + static const char s_szSuffInvalid[] = "-x86.dylib"; +# endif +# elif defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.dll"; +#else + static const char s_szSuff[] = ".dll"; + static const char s_szSuffInvalid[] = "-x86.dll"; +# endif +# else +# ifdef VBOX_IN_32_ON_64_MAIN_API + static const char s_szSuff[] = "-x86.so"; +#else + static const char s_szSuff[] = ".so"; + static const char s_szSuffInvalid[] = "-x86.so"; +# endif +# endif + + nsCAutoString strLeafName; + rv = component->GetNativeLeafName(strLeafName); + if (NS_FAILED(rv)) + return rv; + size_t cchLeafName = strLeafName.Length(); + if ( cchLeafName <= sizeof(s_szSuff) + || PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuff) + 1, s_szSuff)) + { + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s'...", strLeafName.get())); + return NS_OK; /* skip */ + } +# ifndef VBOX_IN_32_ON_64_MAIN_API + if ( cchLeafName >= sizeof(s_szSuffInvalid) + && !PL_strcasecmp(strLeafName.get() + cchLeafName - sizeof(s_szSuffInvalid) + 1, s_szSuffInvalid)) + { + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("Skipping '%s' (#2)...", strLeafName.get())); + return NS_OK; /* skip */ + } +# endif + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("... '%s'", strLeafName.get())); +#endif /* VBOX */ + + nsXPIDLCString persistentDescriptor; + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->RegistryLocationForSpec(component, + getter_Copies(persistentDescriptor)); + if (NS_FAILED(rv)) + return rv; + + nsCStringKey key(persistentDescriptor); + + // Get the registry representation of the dll, if any + nsDll *dll; + rv = CreateDll(component, persistentDescriptor, &dll); + if (NS_FAILED(rv)) + return rv; + + if (dll != NULL) + { + // We already have seen this dll. Check if this dll changed + if (!dll->HasChanged()) + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + // Dll hasn't changed. Skip. + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + nsDll not changed \"%s\". Skipping...", + displayPath.get())); +#endif + *registered = PR_TRUE; + return NS_OK; + } + + // Aagh! the dll has changed since the last time we saw it. + // re-register dll + + + // Notify observers, if any, of autoregistration work + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_SUCCEEDED(rv)) + { + nsCOMPtr mgr; + rv = NS_GetServiceManager(getter_AddRefs(mgr)); + if (NS_SUCCEEDED(rv)) + { + // this string can't come from a string bundle, because we + // don't have string bundles yet. + NS_ConvertASCIItoUCS2 fileName("(no name)"); + + // get the file name + nsCOMPtr dllSpec; + if (NS_SUCCEEDED(dll->GetDllSpec(getter_AddRefs(dllSpec))) && dllSpec) + { + dllSpec->GetLeafName(fileName); + } + + // this string can't come from a string bundle, because we + // don't have string bundles yet. + (void) observerService-> + NotifyObservers(mgr, + NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID, + PromiseFlatString(NS_LITERAL_STRING("Registering native component ") + + fileName).get()); + } + } + + if (dll->IsLoaded()) + { + // We loaded the old version of the dll and now we find that the + // on-disk copy if newer. Try to unload the dll. + nsCOMPtr serviceMgr; + rv = NS_GetServiceManager(getter_AddRefs(serviceMgr)); + + rv = nsFreeLibrary(dll, serviceMgr, when); + if (NS_FAILED(rv)) + { + // THIS IS THE WORST SITUATION TO BE IN. + // Dll doesn't want to be unloaded. Cannot re-register + // this dll. +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: *** Dll already loaded. " + "Cannot unload either. Hence cannot re-register " + "\"%s\". Skipping...", displayPath.get())); +#endif + return rv; + } + else { + // dll doesn't have a CanUnload proc. Guess it is + // ok to unload it. + dll->Unload(); +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, + ("nsNativeComponentLoader: + Unloading \"%s\". (no CanUnloadProc).", + displayPath.get())); +#endif + } + + } // dll isloaded + + // Sanity. + if (dll->IsLoaded()) + { + // We went through all the above to make sure the dll + // is unloaded. And here we are with the dll still + // loaded. Whoever taught dp programming... +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: Dll still loaded. Cannot re-register " + "\"%s\". Skipping...", displayPath.get())); +#endif + return NS_ERROR_FAILURE; + } + } // dll != NULL + else + { + // Create and add the dll to the mDllStore + // It is ok to do this even if the creation of nsDll + // didnt succeed. That way we wont do this again + // when we encounter the same dll. + dll = new nsDll(component, this); + if (dll == NULL) + return NS_ERROR_OUT_OF_MEMORY; + mDllStore.Put(&key, (void *) dll); + } // dll == NULL + + // Either we are seeing the dll for the first time or the dll has + // changed since we last saw it and it is unloaded successfully. + // + // Now we can try register the dll for sure. + nsresult res = SelfRegisterDll(dll, persistentDescriptor, PR_FALSE); + if (NS_FAILED(res)) + { + if (res == NS_ERROR_FACTORY_REGISTER_AGAIN) { + /* defer for later loading */ + mDeferredComponents.AppendElement(dll); + *registered = PR_TRUE; + return NS_OK; + } else { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, + ("nsNativeComponentLoader: Autoregistration FAILED for " + "\"%s\". Skipping...", displayPath.get())); +#endif + return NS_ERROR_FACTORY_NOT_REGISTERED; + } + } + else + { +#ifdef PR_LOGGING + nsXPIDLCString displayPath; + dll->GetDisplayPath(displayPath); + + PR_LOG(nsComponentManagerLog, PR_LOG_WARNING, + ("nsNativeComponentLoader: Autoregistration Passed for " + "\"%s\".", displayPath.get())); +#endif + // Marking dll along with modified time and size in the + // registry happens at PlatformRegister(). No need to do it + // here again. + *registered = PR_TRUE; + } + return NS_OK; +} + +nsresult +nsNativeComponentLoader::RegisterDeferredComponents(PRInt32 aWhen, + PRBool *aRegistered) +{ +#ifdef DEBUG + fprintf(stderr, "nNCL: registering deferred (%d)\n", + mDeferredComponents.Count()); +#endif + *aRegistered = PR_FALSE; + if (!mDeferredComponents.Count()) + return NS_OK; + + for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) { + nsDll *dll = NS_STATIC_CAST(nsDll *, mDeferredComponents[i]); + nsresult rv = SelfRegisterDll(dll, + nsnull, + PR_TRUE); + if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) { + if (NS_SUCCEEDED(rv)) + *aRegistered = PR_TRUE; + mDeferredComponents.RemoveElementAt(i); + } + } +#ifdef DEBUG + if (*aRegistered) + fprintf(stderr, "nNCL: registered deferred, %d left\n", + mDeferredComponents.Count()); + else + fprintf(stderr, "nNCL: didn't register any components, %d left\n", + mDeferredComponents.Count()); +#endif + /* are there any fatal errors? */ + return NS_OK; +} + +nsresult +nsNativeComponentLoader::OnRegister(const nsIID &aCID, const char *aType, + const char *aClassName, + const char *aContractID, + const char *aLocation, + PRBool aReplace, + PRBool aPersist) +{ + return NS_OK; +} + +nsresult +nsNativeComponentLoader::UnloadAll(PRInt32 aWhen) +{ + PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsNativeComponentLoader: Unloading....")); + + struct freeLibrariesClosure callData; + callData.serviceMgr = NULL; // XXX need to get this as a parameter + callData.when = aWhen; + + // Cycle through the dlls checking to see if they want to be unloaded + mDllStore.Enumerate(nsFreeLibraryEnum, &callData); + return NS_OK; +} + +// +// CreateDll +// The only way to create a dll or get it from the dll cache. This will +// be called in multiple situations: +// +// 1. Autoregister will create one for each dll it is trying to register. This +// call will be passing a spec in. +// {spec, NULL, 0, 0} +// +// 2. GetFactory() This will call CreateDll() with a null spec but will give +// the registry represented name of the dll. If modtime and size are zero, +// we will go the registry to find the right modtime and size. +// {NULL, rel:libpref.so, 0, 0} +// +// 3. Prepopulation of dllCache A dll object created off a registry entry. +// Specifically dll name is stored in rel: or abs: or lib: formats in the +// registry along with its lastModTime and fileSize. +// {NULL, rel:libpref.so, 8985659, 20987} +nsresult +nsNativeComponentLoader::CreateDll(nsIFile *aSpec, + const char *aLocation, + nsDll **aDll) +{ + nsDll *dll; + nsCOMPtr dllSpec; + nsCOMPtr spec; + nsresult rv; + + nsCStringKey key(aLocation); + dll = (nsDll *)mDllStore.Get(&key); + if (dll) + { + *aDll = dll; + return NS_OK; + } + + if (!aSpec) + { + // what I want to do here is QI for a Component Registration Manager. Since this + // has not been invented yet, QI to the obsolete manager. Kids, don't do this at home. + nsCOMPtr obsoleteManager = do_QueryInterface(mCompMgr, &rv); + if (obsoleteManager) + rv = obsoleteManager->SpecForRegistryLocation(aLocation, + getter_AddRefs(spec)); + if (NS_FAILED(rv)) + return rv; + } + else + { + spec = aSpec; + } + + if (!dll) + { + dll = new nsDll(spec, this); + if (!dll) + return NS_ERROR_OUT_OF_MEMORY; + } + + *aDll = dll; + mDllStore.Put(&key, dll); + return NS_OK; +} + +nsresult +nsNativeComponentLoader::GetFactoryFromModule(nsDll *aDll, const nsCID &aCID, + nsIFactory **aFactory) +{ + nsresult rv; + + nsCOMPtr module; + rv = aDll->GetModule(mCompMgr, getter_AddRefs(module)); + + if (NS_FAILED(rv)) + return rv; + + return module->GetClassObject(mCompMgr, aCID, NS_GET_IID(nsIFactory), + (void **)aFactory); +} + + +NS_IMETHODIMP +nsNativeComponentLoader::AddDependentLibrary(nsIFile* aFile, const char* libName) +{ + nsCOMPtr manager = do_QueryInterface(mCompMgr); + if (!manager) + { + NS_WARNING("Something is terribly wrong"); + return NS_ERROR_FAILURE; + } + + // the native component loader uses the optional data + // to store a space delimited list of dependent library + // names + + if (!libName) + { + manager->SetOptionalData(aFile, nsnull, nsnull); + return NS_OK; + } + + nsXPIDLCString data; + manager->GetOptionalData(aFile, nsnull, getter_Copies(data)); + + if (!data.IsEmpty()) + data.AppendLiteral(" "); + + data.Append(nsDependentCString(libName)); + + manager->SetOptionalData(aFile, nsnull, data); + return NS_OK; +} diff --git a/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h new file mode 100644 index 00000000..818596ec --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsNativeComponentLoader.h @@ -0,0 +1,84 @@ +/* -*- 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) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#include "nsISupports.h" +#include "nsIComponentLoader.h" +#include "nsIComponentManager.h" +#include "nsDirectoryService.h" +#include "nsCOMPtr.h" +#include "nsHashtable.h" +#include "nsVoidArray.h" +#include "xcDll.h" +#include "nsINativeComponentLoader.h" + +#ifndef nsNativeComponentLoader_h__ +#define nsNativeComponentLoader_h__ + +class nsNativeComponentLoader : public nsIComponentLoader, public nsINativeComponentLoader { + + public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOMPONENTLOADER + NS_DECL_NSINATIVECOMPONENTLOADER + + nsNativeComponentLoader(); + + nsIComponentManager* mCompMgr; // weak reference -- backpointer + nsHashtable mLoadedDependentLibs; + + private: + nsObjectHashtable mDllStore; + nsVoidArray mDeferredComponents; + + ~nsNativeComponentLoader() {} + + NS_IMETHOD RegisterComponentsInDir(PRInt32 when, nsIFile *dir); + + nsresult CreateDll(nsIFile *aSpec, const char *aLocation, nsDll **aDll); + nsresult SelfRegisterDll(nsDll *dll, const char *registryLocation, + PRBool deferred); + nsresult SelfUnregisterDll(nsDll *dll); + nsresult GetFactoryFromModule(nsDll *aDll, const nsCID &aCID, + nsIFactory **aFactory); + + nsresult DumpLoadError(nsDll *dll, + const char *aCallerName, + const char *aNsprErrorMsg); +}; + +#endif /* nsNativeComponentLoader_h__ */ + diff --git a/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h b/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h new file mode 100644 index 00000000..da3e7a43 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsObsoleteModuleLoading.h @@ -0,0 +1,27 @@ + +#ifndef OBSOLETE_MODULE_LOADING +/* + * Prototypes for dynamic library export functions. Your DLL/DSO needs to export + * these methods to play in the component world. + * + * THIS IS OBSOLETE. Look at nsIModule.idl + */ + +extern "C" NS_EXPORT nsresult NSGetFactory(nsISupports* aServMgr, + const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory **aFactory); +extern "C" NS_EXPORT PRBool NSCanUnload(nsISupports* aServMgr); +extern "C" NS_EXPORT nsresult NSRegisterSelf(nsISupports* aServMgr, const char *fullpath); +extern "C" NS_EXPORT nsresult NSUnregisterSelf(nsISupports* aServMgr, const char *fullpath); + +typedef nsresult (*nsFactoryProc)(nsISupports* aServMgr, + const nsCID &aClass, + const char *aClassName, + const char *aContractID, + nsIFactory **aFactory); +typedef PRBool (*nsCanUnloadProc)(nsISupports* aServMgr); +typedef nsresult (*nsRegisterProc)(nsISupports* aServMgr, const char *path); +typedef nsresult (*nsUnregisterProc)(nsISupports* aServMgr, const char *path); +#endif /* OBSOLETE_MODULE_LOADING */ diff --git a/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp b/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp new file mode 100644 index 00000000..dd6856d6 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsServiceManagerObsolete.cpp @@ -0,0 +1,155 @@ +/* ***** 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 XPCOM. + * + * 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): + * + * 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 ***** */ + + +#include "nsIServiceManager.h" +#include "nsIServiceManagerObsolete.h" +#include "nsComponentManager.h" + +extern PRBool gXPCOMShuttingDown; + +// Global service manager interface (see nsIServiceManagerObsolete.h) + +nsresult +nsServiceManager::GetGlobalServiceManager(nsIServiceManager* *result) +{ + if (gXPCOMShuttingDown) + return NS_ERROR_UNEXPECTED; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + // this method does not addref for historical reasons. + // we return the nsIServiceManagerObsolete interface via a cast. + *result = (nsIServiceManager*) NS_STATIC_CAST(nsIServiceManagerObsolete*, + nsComponentManagerImpl::gComponentManager); + return NS_OK; +} + +nsresult +nsServiceManager::ShutdownGlobalServiceManager(nsIServiceManager* *result) +{ + return NS_OK; +} + +nsresult +nsServiceManager::GetService(const nsCID& aClass, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->GetService(aClass, aIID, (void**)result); +} + +nsresult +nsServiceManager::ReleaseService(const nsCID& aClass, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_IF_RELEASE(service); + return NS_OK; +} + +nsresult +nsServiceManager::RegisterService(const nsCID& aClass, nsISupports* aService) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->RegisterService(aClass, aService); +} + +nsresult +nsServiceManager::UnregisterService(const nsCID& aClass) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->UnregisterService(aClass); +} + +//////////////////////////////////////////////////////////////////////////////// +// let's do it again, this time with ContractIDs... + +nsresult +nsServiceManager::GetService(const char* aContractID, const nsIID& aIID, + nsISupports* *result, + nsIShutdownListener* shutdownListener) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->GetServiceByContractID(aContractID, aIID, (void**)result); +} + +nsresult +nsServiceManager::ReleaseService(const char* aContractID, nsISupports* service, + nsIShutdownListener* shutdownListener) +{ + NS_RELEASE(service); + return NS_OK; +} + +nsresult +nsServiceManager::RegisterService(const char* aContractID, nsISupports* aService) +{ + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->RegisterService(aContractID, aService); +} + +nsresult +nsServiceManager::UnregisterService(const char* aContractID) +{ + // Don't create the global service manager here because we might + // be shutting down, and releasing all the services in its + // destructor + if (gXPCOMShuttingDown) + return NS_OK; + + if (nsComponentManagerImpl::gComponentManager == nsnull) + return NS_ERROR_UNEXPECTED; + + return nsComponentManagerImpl::gComponentManager->UnregisterService(aContractID); +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h b/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h new file mode 100644 index 00000000..c770afdc --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsStaticComponent.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; 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) 1999 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#include "nsIModule.h" +#include "nsModule.h" + +struct nsStaticModuleInfo { + const char *name; + nsGetModuleProc getModule; +}; + +// Must be implemented by some part of the app, if we're building the +// static component loader. +extern "C" { +typedef nsresult (PR_CALLBACK *NSGetStaticModuleInfoFunc)(nsStaticModuleInfo **info, PRUint32 *count); +extern NS_COM NSGetStaticModuleInfoFunc NSGetStaticModuleInfo; +} + diff --git a/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp b/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp new file mode 100644 index 00000000..b17b74bb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/nsStaticComponentLoader.cpp @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 8; 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) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * 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 ***** */ + +#include "nsStaticComponent.h" +#include "nsIComponentLoader.h" +#include "nsVoidArray.h" +#include "pldhash.h" +#include NEW_H +#include + +struct StaticModuleInfo : public PLDHashEntryHdr { + nsStaticModuleInfo info; + nsCOMPtr module; +}; + +class nsStaticComponentLoader : public nsIComponentLoader +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSICOMPONENTLOADER + + nsStaticComponentLoader() : + mAutoRegistered(PR_FALSE), mLoadedInfo(PR_FALSE) { + } + + static NS_HIDDEN_(PLDHashOperator) PR_CALLBACK + info_RegisterSelf(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg); + +private: + ~nsStaticComponentLoader() { + if (mInfoHash.ops) + PL_DHashTableFinish(&mInfoHash); + } + +protected: + nsresult GetModuleInfo(); + nsresult GetInfoFor(const char *aLocation, StaticModuleInfo **retval); + + PRBool mAutoRegistered; + PRBool mLoadedInfo; + nsCOMPtr mComponentMgr; + PLDHashTable mInfoHash; + static PLDHashTableOps sInfoHashOps; + nsVoidArray mDeferredComponents; +}; + +PR_STATIC_CALLBACK(void) +info_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry) +{ + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, entry); + info->module = 0; + info->~StaticModuleInfo(); +} + +PR_STATIC_CALLBACK(PRBool) +info_InitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key) +{ + // Construct so that our nsCOMPtr is zeroed, etc. + new (NS_STATIC_CAST(void *, entry)) StaticModuleInfo(); + return PR_TRUE; +} + +/* static */ PLDHashTableOps nsStaticComponentLoader::sInfoHashOps = { + PL_DHashAllocTable, PL_DHashFreeTable, + PL_DHashGetKeyStub, PL_DHashStringKey, PL_DHashMatchStringKey, + PL_DHashMoveEntryStub, info_ClearEntry, + PL_DHashFinalizeStub, info_InitEntry +}; + +NS_IMPL_THREADSAFE_ISUPPORTS1(nsStaticComponentLoader, nsIComponentLoader) + +NS_COM NSGetStaticModuleInfoFunc NSGetStaticModuleInfo; + +nsresult +nsStaticComponentLoader::GetModuleInfo() +{ + if (mLoadedInfo) + return NS_OK; + + if (!mInfoHash.ops) { // creation failed in init, why are we here? + NS_WARNING("operating on uninitialized static component loader"); + return NS_ERROR_NOT_INITIALIZED; + } + + if (! NSGetStaticModuleInfo) { + // We're a static build with no static modules to + // register. This can happen in shared uses (such as the GRE) + return NS_OK; + } + + nsStaticModuleInfo *infoList; + PRUint32 count; + nsresult rv; + if (NS_FAILED(rv = (*NSGetStaticModuleInfo)(&infoList, &count))) + return rv; + for (PRUint32 i = 0; i < count; i++) { + StaticModuleInfo *info = + NS_STATIC_CAST(StaticModuleInfo *, + PL_DHashTableOperate(&mInfoHash, infoList[i].name, + PL_DHASH_ADD)); + if (!info) + return NS_ERROR_OUT_OF_MEMORY; + info->info = infoList[i]; + } + + mLoadedInfo = PR_TRUE; + return NS_OK; +} + +nsresult +nsStaticComponentLoader::GetInfoFor(const char *aLocation, + StaticModuleInfo **retval) +{ + nsresult rv; + if (NS_FAILED(rv = GetModuleInfo())) + return rv; + + StaticModuleInfo *info = + NS_STATIC_CAST(StaticModuleInfo *, + PL_DHashTableOperate(&mInfoHash, aLocation, + PL_DHASH_LOOKUP)); + + if (PL_DHASH_ENTRY_IS_FREE(info)) + return NS_ERROR_FACTORY_NOT_REGISTERED; + + if (!info->module) { + rv = info->info.getModule(mComponentMgr, nsnull, + getter_AddRefs(info->module)); +#ifdef DEBUG + fprintf(stderr, "nSCL: GetInfoFor(\"%s\"): %x\n", aLocation, rv); +#endif + if (NS_FAILED(rv)) + return rv; + } + + *retval = info; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::Init(nsIComponentManager *mgr, nsISupports *aReg) +{ + mComponentMgr = mgr; + if (!PL_DHashTableInit(&mInfoHash, &sInfoHashOps, nsnull, + sizeof(StaticModuleInfo), 1024)) { + mInfoHash.ops = nsnull; + return NS_ERROR_OUT_OF_MEMORY; + } + return NS_OK; +} + +PLDHashOperator PR_CALLBACK +nsStaticComponentLoader::info_RegisterSelf(PLDHashTable *table, + PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + nsStaticComponentLoader *loader = NS_STATIC_CAST(nsStaticComponentLoader *, + arg); + nsIComponentManager *mgr = loader->mComponentMgr; + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, hdr); + + nsresult rv; + if (!info->module) { + rv = info->info.getModule(mgr, nsnull, getter_AddRefs(info->module)); +#ifdef DEBUG + fprintf(stderr, "nSCL: getModule(\"%s\"): %x\n", info->info.name, rv); +#endif + if (NS_FAILED(rv)) + return PL_DHASH_NEXT; // oh well. + } + + rv = info->module->RegisterSelf(mgr, nsnull, info->info.name, + staticComponentType); +#ifdef DEBUG + fprintf(stderr, "nSCL: autoreg of \"%s\": %x\n", info->info.name, rv); +#endif + + if (rv == NS_ERROR_FACTORY_REGISTER_AGAIN) + loader->mDeferredComponents.AppendElement(info); + + return PL_DHASH_NEXT; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoRegisterComponents(PRInt32 when, nsIFile *dir) +{ + if (mAutoRegistered) + return NS_OK; + + // if a directory has been explicitly specified, then return early. we + // don't load static components from disk ;) + if (dir) + return NS_OK; + + nsresult rv; + if (NS_FAILED(rv = GetModuleInfo())) + return rv; + + PL_DHashTableEnumerate(&mInfoHash, info_RegisterSelf, this); + + mAutoRegistered = PR_TRUE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoUnregisterComponent(PRInt32 when, + nsIFile *component, + PRBool *retval) +{ + *retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::AutoRegisterComponent(PRInt32 when, nsIFile *component, + PRBool *retval) +{ + *retval = PR_FALSE; + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::RegisterDeferredComponents(PRInt32 when, + PRBool *aRegistered) +{ + *aRegistered = PR_FALSE; + if (!mDeferredComponents.Count()) + return NS_OK; + + for (int i = mDeferredComponents.Count() - 1; i >= 0; i--) { + StaticModuleInfo *info = NS_STATIC_CAST(StaticModuleInfo *, + mDeferredComponents[i]); + nsresult rv = info->module->RegisterSelf(mComponentMgr, nsnull, + info->info.name, + staticComponentType); + if (rv != NS_ERROR_FACTORY_REGISTER_AGAIN) { + if (NS_SUCCEEDED(rv)) + *aRegistered = PR_TRUE; + mDeferredComponents.RemoveElementAt(i); + } + } + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::OnRegister(const nsCID &aCID, const char *aType, + const char *aClassName, + const char *aContractID, + const char *aLocation, + PRBool aReplace, PRBool aPersist) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::UnloadAll(PRInt32 aWhen) +{ + return NS_OK; +} + +NS_IMETHODIMP +nsStaticComponentLoader::GetFactory(const nsCID &aCID, const char *aLocation, + const char *aType, nsIFactory **_retval) +{ + StaticModuleInfo *info; + nsresult rv; + + if (NS_FAILED(rv = GetInfoFor(aLocation, &info))) + return rv; + + return info->module->GetClassObject(mComponentMgr, aCID, + NS_GET_IID(nsIFactory), + (void **)_retval); +} + +nsresult +NS_NewStaticComponentLoader(nsIComponentLoader **retval) +{ + NS_IF_ADDREF(*retval = NS_STATIC_CAST(nsIComponentLoader *, + new nsStaticComponentLoader)); + return *retval ? NS_OK : NS_ERROR_OUT_OF_MEMORY; +} diff --git a/src/libs/xpcom18a4/xpcom/components/xcDll.cpp b/src/libs/xpcom18a4/xpcom/components/xcDll.cpp new file mode 100644 index 00000000..494cf174 --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/xcDll.cpp @@ -0,0 +1,457 @@ +/* -*- 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): + * + * 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 ***** */ + +/* nsDll + * + * Abstraction of a Dll. Stores modifiedTime and size for easy detection of + * change in dll. + * + * dp Suresh + */ + +#include "xcDll.h" +#include "nsDebug.h" +#include "nsIComponentManager.h" +#include "nsIComponentLoaderManager.h" +#include "nsIModule.h" +#include "nsILocalFile.h" +#include "nsDirectoryServiceDefs.h" +#include "nsDirectoryServiceUtils.h" +#include "nsCOMPtr.h" +#include "nsCRT.h" +#include "nsString.h" +#include "nsITimelineService.h" +#include "nsModule.h" +#ifdef DEBUG +#if defined(VMS) +#include +#include +#elif defined(XP_MACOSX) +#include +#endif +#endif /* defined(DEBUG) */ + +#include "nsTraceRefcntImpl.h" + +#define UNLOAD_DEPENDENT_LIBS +#ifdef HPUX +#undef UNLOAD_DEPENDENT_LIBS +#endif + +#include "nsNativeComponentLoader.h" +#ifdef VBOX_USE_IPRT_IN_XPCOM +# include "nsMemory.h" +#endif + +nsDll::nsDll(nsIFile *dllSpec, nsNativeComponentLoader *loader) + : m_dllSpec(do_QueryInterface(dllSpec)), + m_instance(NULL), + m_moduleObject(NULL), + m_loader(loader), + m_markForUnload(PR_FALSE) +{ + NS_ASSERTION(loader, "Null loader when creating a nsDLL"); +} + +nsDll::~nsDll(void) +{ + //#if DEBUG_dougt + // The dll gets deleted when the dllStore is destroyed. This happens on + // app shutdown. At that point, unloading dlls can cause crashes if we have + // - dll dependencies + // - callbacks + // - static dtors + // Hence turn it back on after all the above have been removed. + //Unload(); + //#endif +} + +void +nsDll::GetDisplayPath(nsACString& aLeafName) +{ + m_dllSpec->GetNativeLeafName(aLeafName); + + if (aLeafName.IsEmpty()) + aLeafName.AssignLiteral("unknown!"); +} + +PRBool +nsDll::HasChanged() +{ + nsCOMPtr manager = do_QueryInterface(m_loader->mCompMgr); + if (!manager) + return PR_TRUE; + + // If mod date has changed, then dll has changed + PRInt64 currentDate; + nsresult rv = m_dllSpec->GetLastModifiedTime(¤tDate); + if (NS_FAILED(rv)) + return PR_TRUE; + PRBool changed = PR_TRUE; + manager->HasFileChanged(m_dllSpec, nsnull, currentDate, &changed); + return changed; +} + +PRBool nsDll::Load(void) +{ + if (m_instance != NULL) + { + // Already loaded + return (PR_TRUE); + } + + if (m_dllSpec) + { +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + + // Load any library dependencies + // The Component Loader Manager may hold onto some extra data + // set by either the native component loader or the native + // component. We assume that this data is a space delimited + // listing of dependent libraries which are required to be + // loaded prior to us loading the given component. Once, the + // component is loaded into memory, we can release our hold + // on the dependent libraries with the assumption that the + // component library holds a reference via the OS so loader. + +#if defined(XP_UNIX) + nsCOMPtr manager = do_QueryInterface(m_loader->mCompMgr); + if (!manager) + return PR_TRUE; + + nsXPIDLCString extraData; + manager->GetOptionalData(m_dllSpec, nsnull, getter_Copies(extraData)); + +#ifdef UNLOAD_DEPENDENT_LIBS + nsVoidArray dependentLibArray; +#endif + + // if there was any extra data, treat it as a listing of dependent libs + if (extraData != nsnull) + { + // all dependent libraries are suppose to be in the "gre" directory. + // note that the gre directory is the same as the "bin" directory, + // when there isn't a real "gre" found. + + nsXPIDLCString path; + nsCOMPtr file; + NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(file)); + + if (!file) + return NS_ERROR_FAILURE; + + // we are talking about a file in the GRE dir. Lets append something + // stupid right now, so that later we can just set the leaf name. + file->AppendNative(NS_LITERAL_CSTRING("dummy")); + +# ifdef VBOX_USE_IPRT_IN_XPCOM + char *buffer = (char *)nsMemory::Clone(extraData, strlen(extraData) + 1); +# else + char *buffer = strdup(extraData); +# endif + if (!buffer) + return NS_ERROR_OUT_OF_MEMORY; + + char* newStr; + char *token = nsCRT::strtok(buffer, " ", &newStr); + while (token!=nsnull) + { + nsCStringKey key(token); + if (m_loader->mLoadedDependentLibs.Get(&key)) { + token = nsCRT::strtok(newStr, " ", &newStr); + continue; + } + + m_loader->mLoadedDependentLibs.Put(&key, (void*)1); + + nsXPIDLCString libpath; + file->SetNativeLeafName(nsDependentCString(token)); + file->GetNativePath(path); + if (!path) + return NS_ERROR_FAILURE; + + // Load this dependent library with the global flag and stash + // the result for later so that we can unload it. + PRLibSpec libSpec; + libSpec.type = PR_LibSpec_Pathname; + + // if the depend library path starts with a / we are + // going to assume that it is a full path and should + // be loaded without prepending the gre diretory + // location. We could have short circuited the + // SetNativeLeafName above, but this is clearer and + // the common case is a relative path. + + if (token[0] == '/') + libSpec.value.pathname = token; + else + libSpec.value.pathname = path; + + PRLibrary* lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_LAZY|PR_LD_GLOBAL); + // if we couldn't load the dependent library. We did the best we + // can. Now just let us fail later if this really was a required + // dependency. +#ifdef UNLOAD_DEPENDENT_LIBS + if (lib) + dependentLibArray.AppendElement((void*)lib); +#endif + + token = nsCRT::strtok(newStr, " ", &newStr); + } +# ifdef VBOX_USE_IPRT_IN_XPCOM + nsMemory::Free(buffer); +# else + free(buffer); +# endif + } +#endif + + // load the component + nsCOMPtr lf(do_QueryInterface(m_dllSpec)); + NS_ASSERTION(lf, "nsIFile here must implement a nsILocalFile"); + lf->Load(&m_instance); + +#if defined(XP_UNIX) + // Unload any of library dependencies we loaded earlier. The assumption + // here is that the component will have a "internal" reference count to + // the dependency library we just loaded. + // XXX should we unload later - or even at all? + +#ifdef UNLOAD_DEPENDENT_LIBS + if (extraData != nsnull) + { + PRInt32 arrayCount = dependentLibArray.Count(); + for (PRInt32 index = 0; index < arrayCount; index++) + PR_UnloadLibrary((PRLibrary*)dependentLibArray.ElementAt(index)); + } +#endif +#endif + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); + if (m_instance) { + // Inform refcnt tracer of new library so that calls through the + // new library can be traced. + nsXPIDLCString displayPath; + GetDisplayPath(displayPath); + nsTraceRefcntImpl::LoadLibrarySymbols(displayPath.get(), m_instance); + } +#endif + } + +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + // Debugging help for components. Component dlls need to have their + // symbols loaded before we can put a breakpoint in the debugger. + // This will help figureing out the point when the dll was loaded. + nsXPIDLCString displayPath; + GetDisplayPath(displayPath); + BreakAfterLoad(displayPath.get()); +#endif + + return ((m_instance == NULL) ? PR_FALSE : PR_TRUE); +} + +PRBool nsDll::Unload(void) +{ + if (m_instance == NULL) + return (PR_FALSE); + + // Shutdown the dll + Shutdown(); + +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); +#endif + PRStatus ret = PR_UnloadLibrary(m_instance); +#ifdef NS_BUILD_REFCNT_LOGGING + nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); +#endif + + if (ret == PR_SUCCESS) + { + m_instance = NULL; + return (PR_TRUE); + } + else + return (PR_FALSE); +} + +void * nsDll::FindSymbol(const char *symbol) +{ + if (symbol == NULL) + return (NULL); + + // If not already loaded, load it now. + if (Load() != PR_TRUE) + return (NULL); + + return(PR_FindSymbol(m_instance, symbol)); +} + + +// Component dll specific functions +nsresult nsDll::GetDllSpec(nsIFile **fsobj) +{ + NS_ASSERTION(m_dllSpec, "m_dllSpec NULL"); + NS_ASSERTION(fsobj, "xcDll::GetModule : Null argument" ); + + *fsobj = m_dllSpec; + NS_ADDREF(*fsobj); + return NS_OK; +} + +nsresult nsDll::GetModule(nsISupports *servMgr, nsIModule **cobj) +{ + // using the backpointer of the loader. + nsIComponentManager* compMgr = m_loader->mCompMgr; + NS_ASSERTION(compMgr, "Global Component Manager is null" ); + if (!compMgr) return NS_ERROR_UNEXPECTED; + + NS_ASSERTION(cobj, "xcDll::GetModule : Null argument" ); + + if (m_moduleObject) + { + NS_ADDREF(m_moduleObject); + *cobj = m_moduleObject; + return NS_OK; + } + + // If not already loaded, load it now. + if (Load() != PR_TRUE) return NS_ERROR_FAILURE; + + // We need a nsIFile for location + if (!m_dllSpec) + { + return NS_ERROR_FAILURE; + } + + nsGetModuleProc proc = + (nsGetModuleProc) FindSymbol(NS_GET_MODULE_SYMBOL); + + if (proc == NULL) + return NS_ERROR_FACTORY_NOT_LOADED; + + nsresult rv = (*proc) (compMgr, m_dllSpec, &m_moduleObject); + if (NS_SUCCEEDED(rv)) + { + NS_ADDREF(m_moduleObject); + *cobj = m_moduleObject; + } + return rv; +} + + +// These are used by BreakAfterLoad, below. +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD +static nsCString *sBreakList[16]; +static int sBreakListCount = 0; +#endif + +nsresult nsDll::Shutdown(void) +{ + // Release the module object if we got one + nsrefcnt refcnt; + if (m_moduleObject) + { + NS_RELEASE2(m_moduleObject, refcnt); + NS_ASSERTION(refcnt == 0, "Dll moduleObject refcount non zero"); + } +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + for (int i = 0; i < sBreakListCount; i++) + { + delete sBreakList[i]; + sBreakList[i] = nsnull; + } + sBreakListCount = 0; +#endif + return NS_OK; + +} +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD +void nsDll::BreakAfterLoad(const char *nsprPath) +{ + static PRBool firstTime = PR_TRUE; + + // return if invalid input + if (!nsprPath || !*nsprPath) return; + + // return if nothing to break on + if (!firstTime && sBreakListCount == 0) return; + + if (firstTime) + { + firstTime = PR_FALSE; + // Form the list of dlls to break on load + nsCAutoString envList(getenv("XPCOM_BREAK_ON_LOAD")); + if (envList.IsEmpty()) return; + PRInt32 ofset = 0; + PRInt32 start = 0; + do + { + ofset = envList.FindChar(':', start); + sBreakList[sBreakListCount] = new nsCString(); + envList.Mid(*(sBreakList[sBreakListCount]), start, ofset); + sBreakListCount++; + start = ofset + 1; + } + while (ofset != -1 && 16 > sBreakListCount); // avoiding vc6.0 compiler issue. count < thinks it is starting a template + } + + // Find the dllname part of the string + nsCString currentPath(nsprPath); + PRInt32 lastSep = currentPath.RFindCharInSet(":\\/"); + + for (int i=0; i 0) + { + // Loading a dll that we want to break on + // Put your breakpoint here + fprintf(stderr, "...Loading module %s\n", nsprPath); + // Break in the debugger here. +#if defined(__i386) && defined(__GNUC__) + asm("int $3"); +#elif defined(VMS) + lib$signal(SS$_DEBUG); +#elif defined(XP_MACOSX) + raise(SIGTRAP); +#endif + } + return; +} +#endif /* SHOULD_IMPLEMENT_BREAKAFTERLOAD */ diff --git a/src/libs/xpcom18a4/xpcom/components/xcDll.h b/src/libs/xpcom18a4/xpcom/components/xcDll.h new file mode 100644 index 00000000..5de5b0eb --- /dev/null +++ b/src/libs/xpcom18a4/xpcom/components/xcDll.h @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** 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): + * + * 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 ***** */ + +/* Dll + * + * Programmatic representation of a dll. Stores modifiedTime and size for + * easy detection of change in dll. + * + * dp Suresh + */ + +#ifndef xcDll_h__ +#define xcDll_h__ + +#include "prio.h" +#include "prlink.h" +#include "nsISupports.h" +#include "nsILocalFile.h" +#include "nsCOMPtr.h" +#include "nsString.h" + +class nsNativeComponentLoader; + +#if defined(DEBUG) && !defined(XP_BEOS) +#define SHOULD_IMPLEMENT_BREAKAFTERLOAD +#endif + +class nsIModule; +class nsIServiceManager; + +typedef enum nsDllStatus +{ + DLL_OK = 0, + DLL_NO_MEM = 1, + DLL_STAT_ERROR = 2, + DLL_NOT_FILE = 3, + DLL_INVALID_PARAM = 4 +} nsDllStatus; + +class nsDll +{ +private: + nsCOMPtr m_dllSpec; + PRLibrary *m_instance; + nsIModule *m_moduleObject; + nsNativeComponentLoader *m_loader; + PRBool m_markForUnload; + + void Init(nsIFile *dllSpec); + +#ifdef SHOULD_IMPLEMENT_BREAKAFTERLOAD + void BreakAfterLoad(const char *nsprPath); +#endif + +public: + + nsDll(nsIFile *dllSpec, nsNativeComponentLoader* loader); + ~nsDll(void); + + // Dll Loading + PRBool Load(void); + PRBool Unload(void); + PRBool IsLoaded(void) + { + return ((m_instance != 0) ? PR_TRUE : PR_FALSE); + } + void MarkForUnload(PRBool mark) { m_markForUnload = mark; } + PRBool IsMarkedForUnload(void) { return m_markForUnload; } + + // Shutdown the dll. This will call any on unload hook for the dll. + // This wont unload the dll. Unload() implicitly calls Shutdown(). + nsresult Shutdown(void); + + void *FindSymbol(const char *symbol); + + PRBool HasChanged(void); + + void GetDisplayPath(nsACString& string); + + PRLibrary *GetInstance(void) { return (m_instance); } + + // NS_RELEASE() is required to be done on objects returned + nsresult GetDllSpec(nsIFile **dllSpec); + nsresult GetModule(nsISupports *servMgr, nsIModule **mobj); +}; + +#endif /* xcDll_h__ */ -- cgit v1.2.3