Mozilla/mozilla/xpcom/components/nsRepository.cpp
ltabb 8ed5afe62c Free the lizard
git-svn-id: svn://10.0.0.236/trunk@10 18797224-902f-48f8-a5cc-f745e15eee43
1998-03-28 02:44:41 +00:00

503 lines
11 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include <stdlib.h>
#include <iostream.h>
#include "plstr.h"
#include "prlink.h"
#include "nsRepository.h"
#ifdef USE_NSREG
#define STANDALONE_REGISTRY
#define XP_BEGIN_PROTOS extern "C" {
#define XP_END_PROTOS };
#include "NSReg.h"
#endif
nsHashtable *NSRepository::factories = NULL;
PRMonitor *NSRepository::monitor = NULL;
static NS_DEFINE_IID(kFactoryIID, NS_IFACTORY_IID);
static NS_DEFINE_IID(kFactory2IID, NS_IFACTORY2_IID);
class FactoryEntry {
public:
nsCID cid;
nsIFactory *factory;
char *library;
PRLibrary *instance;
FactoryEntry(const nsCID &aClass, nsIFactory *aFactory,
const char *aLibrary) {
cid = aClass;
factory = aFactory;
if (aLibrary != NULL) {
library = PL_strdup(aLibrary);
} else {
library = NULL;
}
instance = NULL;
}
~FactoryEntry() {
if (library != NULL) {
free(library);
}
if (instance != NULL) {
PR_UnloadLibrary(instance);
}
if (factory != NULL) {
factory->Release();
}
}
};
class IDKey: public nsHashKey {
private:
nsID id;
public:
IDKey(const nsID &aID) {
id = aID;
}
PRUint32 HashValue() {
return id.m0;
}
PRBool Equals(nsHashKey *aKey) {
return (id.Equals(((IDKey *) aKey)->id));
}
nsHashKey *Clone() {
return new IDKey(id);
}
};
#ifdef USE_NSREG
#define USE_REGISTRY
static nsresult platformRegister(const nsCID &aCID, const char *aLibrary)
{
HREG hreg;
REGERR err = NR_RegOpen(NULL, &hreg);
if (err == REGERR_OK) {
RKEY key;
err = NR_RegAddKey(hreg, ROOTKEY_COMMON,
"SOFTWARE\\Netscape\\CID", &key);
if (err == REGERR_OK) {
char *cidString = aCID.ToString();
NR_RegSetEntryString(hreg, key, cidString, (char *) aLibrary);
delete [] cidString;
}
NR_RegClose(hreg);
}
return NS_OK;
}
static nsresult platformUnregister(const nsCID &aCID, const char *aLibrary)
{
HREG hreg;
REGERR err = NR_RegOpen(NULL, &hreg);
if (err == REGERR_OK) {
RKEY key;
err = NR_RegAddKey(hreg, ROOTKEY_COMMON,
"SOFTWARE\\Netscape\\CID", &key);
if (err == REGERR_OK) {
char *cidString = aCID.ToString();
NR_RegDeleteEntry(hreg, key, cidString);
delete [] cidString;
}
NR_RegClose(hreg);
}
return NS_OK;
}
static FactoryEntry *platformFind(const nsCID &aCID)
{
FactoryEntry *res = NULL;
HREG hreg;
REGERR err = NR_RegOpen(NULL, &hreg);
if (err == REGERR_OK) {
RKEY key;
err = NR_RegGetKey(hreg, ROOTKEY_COMMON,
"SOFTWARE\\Netscape\\CID", &key);
if (err == REGERR_OK) {
char *cidString = aCID.ToString();
char library[_MAX_PATH];
uint32 len = _MAX_PATH;
err = NR_RegGetEntryString(hreg, key, cidString, library, len);
delete [] cidString;
if (err == REGERR_OK) {
res = new FactoryEntry(aCID, NULL, library);
NR_RegClose(hreg);
}
}
}
return res;
}
#else // USE_NSREG
#ifdef XP_PC
#define USE_REGISTRY
static nsresult platformRegister(const nsCID &aCID, const char *aLibrary)
{
HKEY key;
LONG res = RegCreateKey(HKEY_CURRENT_USER, "SOFTWARE\\Netscape\\CID", &key);
if (res == ERROR_SUCCESS) {
char *cidString = aCID.ToString();
RegSetValue(key, cidString, REG_SZ, aLibrary, PL_strlen(aLibrary));
delete [] cidString;
RegCloseKey(key);
}
return NS_OK;
}
static nsresult platformUnregister(const nsCID &aCID, const char *aLibrary)
{
HKEY key;
nsresult res = NS_OK;
LONG err = RegCreateKey(HKEY_CURRENT_USER, "SOFTWARE\\Netscape\\CID", &key);
if (err == ERROR_SUCCESS) {
char *cidString = aCID.ToString();
err = RegDeleteKey(key, cidString);
if (err != ERROR_SUCCESS) {
res = NS_ERROR_FACTORY_NOT_UNREGISTERED;
}
delete [] cidString;
RegCloseKey(key);
}
return res;
}
static FactoryEntry *platformFind(const nsCID &aCID)
{
HKEY key;
LONG res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Netscape\\CID", &key);
if (res == ERROR_SUCCESS) {
char *cidString = aCID.ToString();
char library[_MAX_PATH];
LONG len = _MAX_PATH;
res = RegQueryValue(key, cidString, library, &len);
delete [] cidString;
if (res == ERROR_SUCCESS) {
FactoryEntry *entry = new FactoryEntry(aCID, NULL, library);
return entry;
}
}
return NULL;
}
#endif // XP_PC
#endif // USE_NSREG
static nsresult loadFactory(FactoryEntry *aEntry,
nsIFactory **aFactory)
{
if (aFactory == NULL) {
return NS_ERROR_NULL_POINTER;
}
*aFactory = NULL;
if (aEntry->instance == NULL) {
aEntry->instance = PR_LoadLibrary(aEntry->library);
}
if (aEntry->instance != NULL) {
nsFactoryProc proc = (nsFactoryProc) PR_FindSymbol(aEntry->instance,
"NSGetFactory");
if (proc != NULL) {
nsresult res = proc(aEntry->cid, aFactory);
return res;
}
}
return NS_ERROR_FACTORY_NOT_LOADED;
}
nsresult NSRepository::FindFactory(const nsCID &aClass,
nsIFactory **aFactory)
{
checkInitialized();
if (aFactory == NULL) {
return NS_ERROR_NULL_POINTER;
}
PR_EnterMonitor(monitor);
IDKey key(aClass);
FactoryEntry *entry = (FactoryEntry*) factories->Get(&key);
nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
#ifdef USE_REGISTRY
if (entry == NULL) {
entry = platformFind(aClass);
// If we got one, cache it in our hashtable
if (entry != NULL) {
factories->Put(&key, entry);
}
}
#endif
PR_ExitMonitor(monitor);
if (entry != NULL) {
if ((entry)->factory == NULL) {
res = loadFactory(entry, aFactory);
} else {
*aFactory = entry->factory;
(*aFactory)->AddRef();
res = NS_OK;
}
}
return res;
}
nsresult NSRepository::checkInitialized()
{
nsresult res = NS_OK;
if (factories == NULL) {
res = Initialize();
}
return res;
}
nsresult NSRepository::Initialize()
{
if (factories == NULL) {
factories = new nsHashtable();
}
if (monitor == NULL) {
monitor = PR_NewMonitor();
}
return NS_OK;
}
nsresult NSRepository::CreateInstance(const nsCID &aClass,
nsISupports *aDelegate,
const nsIID &aIID,
void **aResult)
{
if (aResult == NULL) {
return NS_ERROR_NULL_POINTER;
}
*aResult = NULL;
nsIFactory *factory = NULL;
nsresult res = FindFactory(aClass, &factory);
if (NS_SUCCEEDED(res)) {
res = factory->CreateInstance(aDelegate, aIID, aResult);
factory->Release();
return res;
}
return NS_ERROR_FACTORY_NOT_REGISTERED;
}
nsresult NSRepository::CreateInstance2(const nsCID &aClass,
nsISupports *aDelegate,
const nsIID &aIID,
void *aSignature,
void **aResult)
{
if (aResult == NULL) {
return NS_ERROR_NULL_POINTER;
}
*aResult = NULL;
nsIFactory *factory = NULL;
nsresult res = FindFactory(aClass, &factory);
if (NS_SUCCEEDED(res)) {
nsIFactory2 *factory2 = NULL;
res = NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT;
factory->QueryInterface(kFactory2IID, (void **) &factory2);
if (factory2 != NULL) {
res = factory2->CreateInstance2(aDelegate, aIID, aSignature, aResult);
factory2->Release();
}
factory->Release();
return res;
}
return NS_ERROR_FACTORY_NOT_REGISTERED;
}
nsresult NSRepository::RegisterFactory(const nsCID &aClass,
nsIFactory *aFactory,
PRBool aReplace)
{
checkInitialized();
nsIFactory *old = NULL;
FindFactory(aClass, &old);
if (old != NULL) {
old->Release();
if (!aReplace) {
return NS_ERROR_FACTORY_EXISTS;
}
}
PR_EnterMonitor(monitor);
IDKey key(aClass);
factories->Put(&key, new FactoryEntry(aClass, aFactory, NULL));
PR_ExitMonitor(monitor);
return NS_OK;
}
nsresult NSRepository::RegisterFactory(const nsCID &aClass,
const char *aLibrary,
PRBool aReplace,
PRBool aPersist)
{
checkInitialized();
nsIFactory *old = NULL;
FindFactory(aClass, &old);
if (old != NULL) {
old->Release();
if (!aReplace) {
return NS_ERROR_FACTORY_EXISTS;
}
}
PR_EnterMonitor(monitor);
#ifdef USE_REGISTRY
if (aPersist == PR_TRUE) {
platformRegister(aClass, aLibrary);
}
else
#endif
{
IDKey key(aClass);
factories->Put(&key, new FactoryEntry(aClass, NULL, aLibrary));
}
PR_ExitMonitor(monitor);
return NS_OK;
}
nsresult NSRepository::UnregisterFactory(const nsCID &aClass,
nsIFactory *aFactory)
{
checkInitialized();
nsIFactory *old = NULL;
FindFactory(aClass, &old);
nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
if (old != NULL) {
if (old == aFactory) {
PR_EnterMonitor(monitor);
IDKey key(aClass);
FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key);
delete entry;
PR_ExitMonitor(monitor);
res = NS_OK;
}
old->Release();
}
return res;
}
nsresult NSRepository::UnregisterFactory(const nsCID &aClass,
const char *aLibrary)
{
checkInitialized();
IDKey key(aClass);
FactoryEntry *old = (FactoryEntry *) factories->Get(&key);
nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
PR_EnterMonitor(monitor);
if (old != NULL) {
#ifdef XP_UNIX
if (old->library != NULL && PL_strcasecmp(old->library, aLibrary))
#else
if (old->library != NULL && PL_strcmp(old->library, aLibrary))
#endif
{
FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key);
delete entry;
res = NS_OK;
}
}
#ifdef USE_REGISTRY
res = platformUnregister(aClass, aLibrary);
#endif
PR_ExitMonitor(monitor);
return res;
}
static PRBool freeLibraryEnum(nsHashKey *aKey, void *aData)
{
FactoryEntry *entry = (FactoryEntry *) aData;
if (entry->instance != NULL) {
nsCanUnloadProc proc = (nsCanUnloadProc) PR_FindSymbol(entry->instance,
"NSCanUnload");
if (proc != NULL) {
PRBool res = proc();
if (res) {
PR_UnloadLibrary(entry->instance);
entry->instance = NULL;
}
}
}
return PR_TRUE;
}
nsresult NSRepository::FreeLibraries()
{
PR_EnterMonitor(monitor);
factories->Enumerate(freeLibraryEnum);
PR_ExitMonitor(monitor);
return NS_OK;
}