Moved nsFileSpec and related classes into this obsolete library. Moved nsRegistry and related libreg functionality into the obsolete library. Updated many callers using the obsolete nsFile spec to use nsIFile and Necko to do file IO. Combined the following DLLs (source -> dest) uriloader -> docshell shistory -> docshell jsurl -> jsdom gkview -> gklayout Moved nsAdapterEnumerator out of xpcom/ds and into mailnews, since they're the only consumer Modifed the xpt_link tool so that you can specify a �only include� cid list that can mask CID�s that you are not interested in. Added build options: Prevent the building of xpinstall (--disable-xpinstall) Prevent the building js component loader (--disable-jsloader) A build option to only build a single profile (--enable-single-profile) A build flag to only built the required xpfe components (--disable-xpfe-components). Removal or hiding of unused functions and classes including nsEscape*, nsDequeIterator, nsRecyclingAllocatorImpl, nsDiscriminatedUnion, nsOpaqueKey, nsCRT::strlen, NS_NewCommandLineService Bug 194240, r/sr = darin, alec.
3810 lines
113 KiB
C++
3810 lines
113 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* The contents of this file are subject to the Netscape 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/NPL/
|
|
*
|
|
* 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 Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* 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 <stdlib.h>
|
|
#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 "nsICategoryManager.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 <FindDirectory.h>
|
|
#include <Path.h>
|
|
#endif
|
|
|
|
// Logging of debug output
|
|
#ifdef MOZ_LOGGING
|
|
#define FORCE_PR_LOG /* Allow logging in the release build */
|
|
#endif
|
|
#include "prlog.h"
|
|
|
|
PRLogModuleInfo* nsComponentManagerLog = nsnull;
|
|
|
|
#if defined(DEBUG)
|
|
// #define SHOW_DENIED_ON_SHUTDOWN
|
|
// #define SHOW_CI_ON_EXISTING_SERVICE
|
|
#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}";
|
|
|
|
// Nonexistent factory entry
|
|
// This is used to mark non-existent contractid mappings
|
|
static nsFactoryEntry * kNonExistentContractID = (nsFactoryEntry*) 1;
|
|
|
|
|
|
#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<nsIComponentManager> compMgr;
|
|
nsCOMPtr<nsICategoryManager> 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_FOUND;
|
|
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<nsICategoryManager> 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_FOUND;
|
|
goto error;
|
|
}
|
|
if (mServiceManager) {
|
|
rv = mServiceManager->GetServiceByContractID(value, aIID, (void**)aInstancePtr);
|
|
} else {
|
|
nsCOMPtr<nsIServiceManager> 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->cid;
|
|
}
|
|
|
|
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->cid).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 PLDHashTableOps factory_DHashTableOps = {
|
|
PL_DHashAllocTable,
|
|
PL_DHashFreeTable,
|
|
factory_GetKey,
|
|
factory_HashKey,
|
|
factory_MatchEntry,
|
|
PL_DHashMoveEntryStub,
|
|
factory_ClearEntry,
|
|
PL_DHashFinalizeStub,
|
|
};
|
|
|
|
PR_STATIC_CALLBACK(const void *)
|
|
contractID_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
|
|
{
|
|
nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
|
|
|
|
return entry->mContractID;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(PRBool)
|
|
contractID_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr,
|
|
const void *aKey)
|
|
{
|
|
const nsContractIDTableEntry* entry =
|
|
NS_STATIC_CAST(const nsContractIDTableEntry*, aHdr);
|
|
|
|
const char* contractID = NS_REINTERPRET_CAST(const char*, aKey);
|
|
|
|
return strcmp(entry->mContractID, contractID) == 0;
|
|
}
|
|
|
|
PR_STATIC_CALLBACK(void)
|
|
contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
|
|
{
|
|
nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
|
|
if (entry->mFactoryEntry != kNonExistentContractID &&
|
|
entry->mFactoryEntry->typeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY &&
|
|
entry->mFactoryEntry->cid.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 PLDHashTableOps contractID_DHashTableOps = {
|
|
PL_DHashAllocTable,
|
|
PL_DHashFreeTable,
|
|
contractID_GetKey,
|
|
PL_DHashStringKey,
|
|
contractID_MatchEntry,
|
|
PL_DHashMoveEntryStub,
|
|
contractID_ClearEntry,
|
|
PL_DHashFinalizeStub,
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// nsFactoryEntry
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
MOZ_DECL_CTOR_COUNTER(nsFactoryEntry)
|
|
nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
|
|
const char *aLocation,
|
|
PRUint32 locationlen,
|
|
int aType)
|
|
: cid(aClass), typeIndex(aType)
|
|
{
|
|
// Arena allocate the location string
|
|
location = ArenaStrndup(aLocation, locationlen, &nsComponentManagerImpl::gComponentManager->mArena);
|
|
}
|
|
|
|
nsFactoryEntry::nsFactoryEntry(const nsCID &aClass, nsIFactory *aFactory)
|
|
: cid(aClass), typeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY)
|
|
{
|
|
factory = aFactory;
|
|
location = 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
|
|
factory = nsnull;
|
|
|
|
// Release any service reference
|
|
mServiceObject = nsnull;
|
|
}
|
|
|
|
nsresult
|
|
nsFactoryEntry::ReInit(const nsCID &aClass, const char *aLocation, int aType)
|
|
{
|
|
NS_ENSURE_TRUE(typeIndex != 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((typeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || cid.Equals(aClass)),
|
|
NS_ERROR_INVALID_ARG);
|
|
|
|
// Arena allocate the location string
|
|
location = ArenaStrdup(aLocation, &nsComponentManagerImpl::gComponentManager->mArena);
|
|
|
|
typeIndex = aType;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsFactoryEntry::ReInit(const nsCID &aClass, nsIFactory *aFactory)
|
|
{
|
|
// cids has to match
|
|
// SERVICE_ONLY entries can be promoted to an entry of another type
|
|
NS_ENSURE_TRUE((typeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || cid.Equals(aClass)),
|
|
NS_ERROR_INVALID_ARG);
|
|
// We are going to let native component be overridden by a factory.
|
|
factory = aFactory;
|
|
typeIndex = NS_COMPONENT_TYPE_FACTORY_ONLY;
|
|
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
|
|
|
|
virtual ~PLDHashTableEnumeratorImpl();
|
|
PLDHashTableEnumeratorImpl(PLDHashTable *table,
|
|
EnumeratorConverter converter,
|
|
void *converterData);
|
|
PRInt32 Count() { return mCount; }
|
|
private:
|
|
PLDHashTableEnumeratorImpl(); /* no implementation */
|
|
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;
|
|
|
|
if (impl->Count() == -1) {
|
|
// conversion failed
|
|
delete impl;
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
NS_ADDREF(*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<nsISupportsID> 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->cid);
|
|
*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<nsISupportsCString> 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<nsIProperties> 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_ALWAYS,
|
|
("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_ALWAYS, ("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_ALWAYS, ("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_ALWAYS, ("nsComponentManager: Shutdown complete."));
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsComponentManagerImpl::~nsComponentManagerImpl()
|
|
{
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("nsComponentManager: Beginning destruction."));
|
|
|
|
if (mShuttingDown != NS_SHUTDOWN_COMPLETE)
|
|
Shutdown();
|
|
|
|
if (mMon) {
|
|
nsAutoMonitor::DestroyMonitor(mMon);
|
|
}
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS, ("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<nsIFile> file;
|
|
mRegistryFile->Clone(getter_AddRefs(file));
|
|
if (!file)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsCOMPtr<nsILocalFile> 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]).Equals(NS_LITERAL_CSTRING("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) {
|
|
loadertype = AddLoaderType(values[2]);
|
|
}
|
|
|
|
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->typeIndex < 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;
|
|
}
|
|
|
|
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;
|
|
if (factoryEntry == kNonExistentContractID || factoryEntry->typeIndex < 0)
|
|
return PL_DHASH_NEXT;
|
|
|
|
PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
|
|
|
|
char cidString[UID_STRING_LENGTH];
|
|
GetIDString(factoryEntry->cid, 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;
|
|
|
|
if (factoryEntry->typeIndex < 0)
|
|
return PL_DHASH_NEXT;
|
|
|
|
|
|
char cidString[UID_STRING_LENGTH];
|
|
GetIDString(factoryEntry->cid, cidString);
|
|
|
|
char *contractID = nsnull, *className = nsnull;
|
|
|
|
nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(factoryEntry->factory);
|
|
if (classInfo)
|
|
{
|
|
classInfo->GetContractID(&contractID);
|
|
classInfo->GetClassDescription(&className);
|
|
}
|
|
|
|
const char * loaderName = nsnull;
|
|
if (factoryEntry->typeIndex)
|
|
loaderName = loaderData[factoryEntry->typeIndex].type;
|
|
|
|
char* location = factoryEntry->location;
|
|
|
|
// 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::WriteCategoryManagerToRegistry(PRFileDesc* fd)
|
|
{
|
|
nsCOMPtr<nsICategoryManager> catMan;
|
|
nsCOMPtr<nsISimpleEnumerator> outerEnum;
|
|
nsCOMPtr<nsISimpleEnumerator> innerEnum;
|
|
nsCOMPtr<nsISupports> supports;
|
|
nsCOMPtr<nsISupportsCString> supStr;
|
|
|
|
if (!mCategoryManager) {
|
|
NS_WARNING("Could not access category manager. Will not be able to save categories!");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
nsresult rv = mCategoryManager->EnumerateCategories(getter_AddRefs(outerEnum));
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
PRBool hasMore;
|
|
while (NS_SUCCEEDED(outerEnum->HasMoreElements(&hasMore)) && hasMore) {
|
|
|
|
if (NS_FAILED(outerEnum->GetNext(getter_AddRefs(supports))))
|
|
continue;
|
|
|
|
supStr = do_QueryInterface(supports);
|
|
if (!supStr)
|
|
continue;
|
|
|
|
nsCAutoString categoryType;
|
|
if (NS_FAILED(supStr->GetData(categoryType)))
|
|
continue;
|
|
|
|
rv = mCategoryManager->EnumerateCategory(categoryType.get(), getter_AddRefs(innerEnum));
|
|
if (NS_FAILED(rv))
|
|
continue;
|
|
|
|
PRBool hasMore2;
|
|
while (NS_SUCCEEDED(innerEnum->HasMoreElements(&hasMore2)) && hasMore2) {
|
|
if (NS_FAILED(innerEnum->GetNext(getter_AddRefs(supports))))
|
|
continue;
|
|
|
|
supStr = do_QueryInterface(supports);
|
|
if (!supStr)
|
|
continue;
|
|
|
|
nsCAutoString category;
|
|
if (NS_FAILED(supStr->GetData(category)))
|
|
continue;
|
|
|
|
nsXPIDLCString value;
|
|
rv = mCategoryManager->GetCategoryEntry(categoryType.get(),
|
|
category.get(),
|
|
getter_Copies(value));
|
|
|
|
if (NS_FAILED(rv)) continue;
|
|
|
|
// categoryType, categoryName, value
|
|
PR_fprintf(fd,
|
|
"%s,%s,%s\n",
|
|
categoryType.get(),
|
|
category.get(),
|
|
value.get());
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::WritePersistentRegistry()
|
|
{
|
|
if (!mRegistryFile)
|
|
return NS_ERROR_FAILURE; // this should have been set by Init().
|
|
|
|
nsCOMPtr<nsIFile> file;
|
|
mRegistryFile->Clone(getter_AddRefs(file));
|
|
if (!file)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
nsCOMPtr<nsILocalFile> 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, 0666, &fd);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
if (!PR_fprintf(fd, "Generated File. Do not edit.\n"))
|
|
goto out;
|
|
|
|
if (!PR_fprintf(fd, "\n[HEADER]\nVersion,%d,%d\n",
|
|
PERSISTENT_REGISTRY_VERSION_MAJOR,
|
|
PERSISTENT_REGISTRY_VERSION_MINOR))
|
|
goto out;
|
|
|
|
if (!PR_fprintf(fd, "\n[COMPONENTS]\n"))
|
|
goto out;
|
|
|
|
mAutoRegEntries.Enumerate(AutoRegEntryWriter, (void*)fd);
|
|
|
|
PersistentWriterArgs args;
|
|
args.mFD = fd;
|
|
args.mLoaderData = mLoaderData;
|
|
|
|
if (!PR_fprintf(fd, "\n[CLASSIDS]\n"))
|
|
goto out;
|
|
|
|
PL_DHashTableEnumerate(&mFactories, ClassIDWriter, (void*)&args);
|
|
|
|
if (!PR_fprintf(fd, "\n[CONTRACTIDS]\n"))
|
|
goto out;
|
|
|
|
PL_DHashTableEnumerate(&mContractIDs, ContractIDWriter, (void*)&args);
|
|
|
|
if (!PR_fprintf(fd, "\n[CATEGORIES]\n"))
|
|
goto out;
|
|
|
|
// slow slow slow slow....
|
|
rv = WriteCategoryManagerToRegistry(fd);
|
|
|
|
|
|
out:
|
|
if (fd)
|
|
PR_Close(fd);
|
|
|
|
// don't create the file is there was a problem????
|
|
if (NS_FAILED(rv))
|
|
return 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<nsIFile> 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,
|
|
const nsCID &aClass,
|
|
nsFactoryEntry **pfe)
|
|
{
|
|
nsIDKey cidKey(aClass);
|
|
return HashContractID(aContractID, aContractIDLen, aClass, cidKey, pfe);
|
|
}
|
|
|
|
|
|
nsresult
|
|
nsComponentManagerImpl::HashContractID(const char *aContractID,
|
|
PRUint32 aContractIDLen,
|
|
const nsCID &aClass,
|
|
nsIDKey &cidKey, nsFactoryEntry **pfe)
|
|
{
|
|
if(!aContractID || !aContractIDLen)
|
|
{
|
|
return NS_ERROR_NULL_POINTER;
|
|
}
|
|
|
|
// Find the factory entry corresponding to the CID.
|
|
nsFactoryEntry *entry = GetFactoryEntry(aClass, cidKey);
|
|
if (!entry) {
|
|
// Non existent. We use the special kNonExistentContractID to mark
|
|
// that this contractid does not have a mapping.
|
|
entry = kNonExistentContractID;
|
|
}
|
|
|
|
nsresult rv = HashContractID(aContractID, aContractIDLen, entry);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
|
|
// Fill the entry out parameter
|
|
if (pfe) *pfe = entry;
|
|
return NS_OK;
|
|
}
|
|
|
|
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->location, mLoaderData[aEntry->typeIndex].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
|
|
|
|
// If no mapping found, add a special non-existent mapping
|
|
// so the next time around, we dont have to waste time doing the
|
|
// same mapping over and over again
|
|
if (!fe) {
|
|
fe = kNonExistentContractID;
|
|
HashContractID(aContractID, aContractIDLen, fe);
|
|
}
|
|
|
|
return fe;
|
|
}
|
|
|
|
|
|
nsFactoryEntry *
|
|
nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass)
|
|
{
|
|
nsIDKey cidKey(aClass);
|
|
return GetFactoryEntry(aClass, cidKey);
|
|
}
|
|
|
|
|
|
nsFactoryEntry *
|
|
nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass, nsIDKey &cidKey)
|
|
{
|
|
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 || entry == kNonExistentContractID)
|
|
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<nsIFactory> factory;
|
|
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
char *buf = aClass.ToString();
|
|
PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
|
|
if (buf)
|
|
PR_Free(buf);
|
|
}
|
|
|
|
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<nsIFactory> factory;
|
|
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID);
|
|
}
|
|
|
|
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 && fe != kNonExistentContractID) {
|
|
*aClass = fe->cid;
|
|
rv = NS_OK;
|
|
}
|
|
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS)) {
|
|
char *buf = 0;
|
|
if (NS_SUCCEEDED(rv))
|
|
buf = aClass->ToString();
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID,
|
|
NS_SUCCEEDED(rv) ? buf : "[FAILED]"));
|
|
if (buf)
|
|
PR_Free(buf);
|
|
}
|
|
|
|
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;
|
|
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
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);
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
#ifdef XPCOM_CHECK_PENDING_CIDS
|
|
nsresult
|
|
nsComponentManagerImpl::AddPendingCID(const nsCID &aClass)
|
|
{
|
|
nsAutoMonitor mon(mMon);
|
|
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)) {
|
|
NS_WARNING("Creation in progress (Reentrant CI - see bug 194568)");
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
}
|
|
mPendingCIDs.AppendElement((void*)&aClass);
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
nsComponentManagerImpl::RemovePendingCID(const nsCID &aClass)
|
|
{
|
|
nsAutoMonitor mon(mMon);
|
|
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 || entry == kNonExistentContractID)
|
|
return NS_ERROR_FACTORY_NOT_REGISTERED;
|
|
|
|
#ifdef SHOW_CI_ON_EXISTING_SERVICE
|
|
NS_WARN_IF_FALSE(!entry->mServiceObject,
|
|
"You are calling CreateInstance when a service for this CID already exists!");
|
|
#endif
|
|
|
|
nsIFactory *factory = nsnull;
|
|
nsresult rv = entry->GetFactory(&factory, this);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
#ifdef XPCOM_CHECK_PENDING_CIDS
|
|
rv = AddPendingCID(aClass);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
#endif
|
|
rv = factory->CreateInstance(aDelegate, aIID, aResult);
|
|
NS_RELEASE(factory);
|
|
|
|
#ifdef XPCOM_CHECK_PENDING_CIDS
|
|
RemovePendingCID(aClass);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Translate error values
|
|
rv = NS_ERROR_FACTORY_NOT_REGISTERED;
|
|
}
|
|
|
|
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
char *buf = aClass.ToString();
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsComponentManager: CreateInstance(%s) %s", buf,
|
|
NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
|
|
if (buf)
|
|
PR_Free(buf);
|
|
}
|
|
|
|
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 || entry == kNonExistentContractID)
|
|
return NS_ERROR_FACTORY_NOT_REGISTERED;
|
|
|
|
#ifdef SHOW_CI_ON_EXISTING_SERVICE
|
|
NS_WARN_IF_FALSE(!entry->mServiceObject,
|
|
"You are calling CreateInstance when a service for this CID already exist!");
|
|
#endif
|
|
|
|
nsIFactory *factory = nsnull;
|
|
nsresult rv = entry->GetFactory(&factory, this);
|
|
|
|
if (NS_SUCCEEDED(rv))
|
|
{
|
|
#ifdef XPCOM_CHECK_PENDING_CIDS
|
|
rv = AddPendingCID(entry->cid);
|
|
if (NS_FAILED(rv))
|
|
return rv;
|
|
#endif
|
|
rv = factory->CreateInstance(aDelegate, aIID, aResult);
|
|
NS_RELEASE(factory);
|
|
|
|
#ifdef XPCOM_CHECK_PENDING_CIDS
|
|
RemovePendingCID(entry->cid);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Translate error values
|
|
rv = NS_ERROR_FACTORY_NOT_REGISTERED;
|
|
}
|
|
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("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 || entry->mFactoryEntry == kNonExistentContractID)
|
|
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 || entry->mFactoryEntry == kNonExistentContractID)
|
|
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);
|
|
}
|
|
|
|
nsCOMPtr<nsISupports> 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();
|
|
|
|
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
|
|
nsIDKey key(aClass);
|
|
nsFactoryEntry *entry = GetFactoryEntry(aClass, key);
|
|
|
|
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->typeIndex = 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_FOUND;
|
|
|
|
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 == kNonExistentContractID)
|
|
entry = nsnull;
|
|
|
|
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->typeIndex = 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_FOUND;
|
|
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<nsISupports> 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_FOUND;
|
|
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 != kNonExistentContractID && entry->mServiceObject) {
|
|
nsCOMPtr<nsISupports> 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 == nsnull || entry == kNonExistentContractID || entry->mServiceObject == nsnull)
|
|
return NS_ERROR_SERVICE_NOT_FOUND;
|
|
|
|
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 && entry != kNonExistentContractID && entry->mServiceObject) {
|
|
return entry->mServiceObject->QueryInterface(aIID, result);
|
|
}
|
|
|
|
nsCOMPtr<nsISupports> 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();
|
|
|
|
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)
|
|
{
|
|
nsFactoryEntry *entry = nsnull;
|
|
nsIDKey key(aClass);
|
|
|
|
nsAutoMonitor mon(mMon);
|
|
|
|
entry = GetFactoryEntry(aClass, key);
|
|
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
char *buf = aClass.ToString();
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ALWAYS,
|
|
("nsComponentManager: RegisterFactory(%s, %s)", buf,
|
|
(aContractID ? aContractID : "(null)")));
|
|
if (buf)
|
|
PR_Free(buf);
|
|
}
|
|
|
|
|
|
if (entry && !aReplace) {
|
|
// Already registered
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("\t\tFactory already registered."));
|
|
return NS_ERROR_FACTORY_EXISTS;
|
|
}
|
|
|
|
if (entry) {
|
|
entry->ReInit(aClass, aFactory);
|
|
}
|
|
else {
|
|
void *mem;
|
|
PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
|
|
if (!mem)
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
entry = new (mem) nsFactoryEntry(aClass, aFactory);
|
|
|
|
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 (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 : "<none>"));
|
|
|
|
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;
|
|
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
char *buf = aClass.ToString();
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
|
|
("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)",
|
|
buf,
|
|
contractID ? contractID : "(null)",
|
|
aRegistryName, aType));
|
|
if (buf)
|
|
PR_Free(buf);
|
|
}
|
|
|
|
if (entry && !aReplace) {
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
|
|
("\t\tFactory already registered."));
|
|
return NS_ERROR_FACTORY_EXISTS;
|
|
}
|
|
|
|
int typeIndex = GetLoaderType(aType);
|
|
|
|
nsCOMPtr<nsIComponentLoader> 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<nsIComponentLoader> 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<mNLoaderData; i++) {
|
|
if (!strcmp(typeStr, mLoaderData[i].type))
|
|
return i;
|
|
}
|
|
// Not found
|
|
return NS_COMPONENT_TYPE_FACTORY_ONLY;
|
|
}
|
|
|
|
// Add a loader type if not already known. Return the typeIndex
|
|
// if the loader type is either added or already there.
|
|
int
|
|
nsComponentManagerImpl::AddLoaderType(const char *typeStr)
|
|
{
|
|
int typeIndex = GetLoaderType(typeStr);
|
|
if (typeIndex >= 0) {
|
|
return typeIndex;
|
|
}
|
|
|
|
// 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++;
|
|
|
|
return typeIndex;
|
|
}
|
|
|
|
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 || entry->mFactoryEntry == kNonExistentContractID)
|
|
return PL_DHASH_NEXT;
|
|
|
|
UnregisterConditions* data = (UnregisterConditions*)aData;
|
|
|
|
nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
|
|
if (data->cid->Equals(factoryEntry->cid) &&
|
|
((data->regName && !PL_strcasecmp(factoryEntry->location, data->regName)) ||
|
|
(data->factory && data->factory == factoryEntry->factory.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)
|
|
{
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
char *buf = aClass.ToString();
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
|
|
("nsComponentManager: UnregisterFactory(%s)", buf));
|
|
if (buf)
|
|
PR_Free(buf);
|
|
}
|
|
|
|
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
|
|
nsIDKey key(aClass);
|
|
nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
|
|
old = GetFactoryEntry(aClass, key);
|
|
|
|
if (old && (old->factory.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)
|
|
{
|
|
if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_ALWAYS))
|
|
{
|
|
char *buf = aClass.ToString();
|
|
PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
|
|
("nsComponentManager: UnregisterComponent(%s)", buf));
|
|
if (buf)
|
|
PR_Free(buf);
|
|
}
|
|
|
|
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
|
|
nsIDKey key(aClass);
|
|
old = GetFactoryEntry(aClass, key);
|
|
if (old && old->location && !PL_strcasecmp(old->location, 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_ALWAYS,
|
|
("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; i<mNLoaderData; i++) {
|
|
if (mLoaderData[i].loader) {
|
|
rv = mLoaderData[i].loader->UnloadAll(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<nsIFile> 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<nsIInterfaceInfoManager> 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, dir);
|
|
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<nsISimpleEnumerator> 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<nsISupports> supports;
|
|
if (NS_FAILED(loaderEnum->GetNext(getter_AddRefs(supports))))
|
|
continue;
|
|
|
|
nsCOMPtr<nsISupportsCString> 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<nsIComponentLoader> loader;
|
|
GetLoaderForType(AddLoaderType(loaderType.get()), 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<nsIFile> 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;
|
|
/*
|
|
* 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<nsIComponentLoader> 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_SUCCEEDED(rv) && didRegister)
|
|
break;
|
|
}
|
|
return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK;
|
|
|
|
}
|
|
|
|
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)
|
|
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 || entry == kNonExistentContractID)
|
|
*_retval = PR_FALSE;
|
|
else
|
|
*_retval = PR_TRUE;
|
|
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)
|
|
{
|
|
// XPCOM needs initialization.
|
|
rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
|
|
}
|
|
|
|
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;
|
|
}
|