home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / xpcom / src / nsRepository.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  11.8 KB  |  503 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include <stdlib.h>
  20. #include <iostream.h>
  21. #include "plstr.h"
  22. #include "prlink.h"
  23. #include "nsRepository.h"
  24. #ifdef USE_NSREG
  25. #define STANDALONE_REGISTRY
  26. #define XP_BEGIN_PROTOS extern "C" {
  27. #define XP_END_PROTOS };
  28. #include "NSReg.h"
  29. #endif
  30.  
  31. nsHashtable *NSRepository::factories = NULL;
  32. PRMonitor *NSRepository::monitor = NULL;
  33.  
  34. static NS_DEFINE_IID(kFactoryIID, NS_IFACTORY_IID);
  35. static NS_DEFINE_IID(kFactory2IID, NS_IFACTORY2_IID);
  36.  
  37. class FactoryEntry {
  38. public:
  39.   nsCID cid;
  40.   nsIFactory *factory;
  41.   char *library;
  42.   PRLibrary *instance;
  43.  
  44.   FactoryEntry(const nsCID &aClass, nsIFactory *aFactory, 
  45.                const char *aLibrary) {
  46.     cid = aClass;
  47.     factory = aFactory;
  48.     if (aLibrary != NULL) {
  49.       library = PL_strdup(aLibrary);
  50.     } else {
  51.       library = NULL;
  52.     }
  53.     instance = NULL;
  54.   }
  55.   ~FactoryEntry() {
  56.     if (library != NULL) {
  57.       free(library);
  58.     }
  59.     if (instance != NULL) {
  60.       PR_UnloadLibrary(instance);
  61.     }
  62.     if (factory != NULL) {
  63.       factory->Release();
  64.     }
  65.   }
  66. };
  67.  
  68. class IDKey: public nsHashKey {
  69. private:
  70.   nsID id;
  71.   
  72. public:
  73.   IDKey(const nsID &aID) {
  74.     id = aID;
  75.   }
  76.   
  77.   PRUint32 HashValue() {
  78.     return id.m0;
  79.   }
  80.  
  81.   PRBool Equals(nsHashKey *aKey) {
  82.     return (id.Equals(((IDKey *) aKey)->id));
  83.   }
  84.  
  85.   nsHashKey *Clone() {
  86.     return new IDKey(id);
  87.   }
  88. };
  89.  
  90. #ifdef USE_NSREG
  91. #define USE_REGISTRY
  92.  
  93. static nsresult platformRegister(const nsCID &aCID, const char *aLibrary)
  94. {
  95.   HREG hreg;
  96.   REGERR err = NR_RegOpen(NULL, &hreg);
  97.   if (err == REGERR_OK) {
  98.     RKEY key;
  99.     err = NR_RegAddKey(hreg, ROOTKEY_COMMON, 
  100.                        "SOFTWARE\\Netscape\\CID", &key);
  101.     if (err == REGERR_OK) {
  102.       char *cidString = aCID.ToString();
  103.       NR_RegSetEntryString(hreg, key, cidString, (char *) aLibrary);
  104.       delete [] cidString;
  105.     }
  106.     NR_RegClose(hreg);
  107.   }
  108.   return NS_OK;
  109. }
  110.  
  111. static nsresult platformUnregister(const nsCID &aCID, const char *aLibrary) 
  112. {  
  113.   HREG hreg;
  114.   REGERR err = NR_RegOpen(NULL, &hreg);
  115.   if (err == REGERR_OK) {
  116.     RKEY key;
  117.     err = NR_RegAddKey(hreg, ROOTKEY_COMMON, 
  118.                        "SOFTWARE\\Netscape\\CID", &key);
  119.     if (err == REGERR_OK) {
  120.       char *cidString = aCID.ToString();
  121.       NR_RegDeleteEntry(hreg, key, cidString);
  122.       delete [] cidString;
  123.     }
  124.     NR_RegClose(hreg);
  125.   }
  126.   return NS_OK;
  127. }
  128.  
  129. static FactoryEntry *platformFind(const nsCID &aCID)
  130. {
  131.   FactoryEntry *res = NULL;
  132.   HREG hreg;
  133.   REGERR err = NR_RegOpen(NULL, &hreg);
  134.   if (err == REGERR_OK) {
  135.     RKEY key;
  136.     err = NR_RegGetKey(hreg, ROOTKEY_COMMON, 
  137.                        "SOFTWARE\\Netscape\\CID", &key);
  138.     if (err == REGERR_OK) {
  139.       char *cidString = aCID.ToString();
  140.       char library[_MAX_PATH];
  141.       uint32 len = _MAX_PATH;
  142.       err = NR_RegGetEntryString(hreg, key, cidString, library, len);
  143.                                  
  144.       delete [] cidString;
  145.       if (err == REGERR_OK) {
  146.         res = new FactoryEntry(aCID, NULL, library);
  147.         NR_RegClose(hreg);
  148.       }
  149.     }
  150.   }
  151.   return res;
  152. }
  153.  
  154. #else // USE_NSREG
  155.  
  156. #ifdef XP_PC
  157. #define USE_REGISTRY
  158.  
  159. static nsresult platformRegister(const nsCID &aCID, const char *aLibrary)
  160. {
  161.   HKEY key;
  162.   LONG res = RegCreateKey(HKEY_CURRENT_USER, "SOFTWARE\\Netscape\\CID", &key);
  163.   if (res == ERROR_SUCCESS) {
  164.     char *cidString = aCID.ToString();
  165.     RegSetValue(key, cidString, REG_SZ, aLibrary, PL_strlen(aLibrary));
  166.     delete [] cidString;
  167.     RegCloseKey(key);
  168.   }
  169.   return NS_OK;
  170. }
  171.  
  172. static nsresult platformUnregister(const nsCID &aCID, const char *aLibrary)
  173. {
  174.   HKEY key;
  175.   nsresult res = NS_OK;
  176.   LONG err = RegCreateKey(HKEY_CURRENT_USER, "SOFTWARE\\Netscape\\CID", &key);
  177.   if (err == ERROR_SUCCESS) {
  178.     char *cidString = aCID.ToString();
  179.     err = RegDeleteKey(key, cidString);
  180.     if (err != ERROR_SUCCESS) {
  181.       res = NS_ERROR_FACTORY_NOT_UNREGISTERED;
  182.     }
  183.     delete [] cidString;
  184.     RegCloseKey(key);
  185.   }
  186.   return res;
  187. }
  188.  
  189. static FactoryEntry *platformFind(const nsCID &aCID)
  190. {
  191.   HKEY key;
  192.   LONG res = RegOpenKey(HKEY_CURRENT_USER, "SOFTWARE\\Netscape\\CID", &key);
  193.  
  194.   if (res == ERROR_SUCCESS) {
  195.     char *cidString = aCID.ToString();
  196.     char library[_MAX_PATH];
  197.     LONG len = _MAX_PATH;
  198.     res = RegQueryValue(key, cidString, library, &len);
  199.     delete [] cidString;
  200.     if (res == ERROR_SUCCESS) {
  201.       FactoryEntry *entry = new FactoryEntry(aCID, NULL, library);
  202.       return entry;
  203.     }
  204.   }
  205.   return NULL;
  206. }
  207.  
  208. #endif // XP_PC
  209.  
  210. #endif // USE_NSREG
  211.  
  212. static nsresult loadFactory(FactoryEntry *aEntry,
  213.                             nsIFactory **aFactory)
  214. {
  215.   if (aFactory == NULL) {
  216.     return NS_ERROR_NULL_POINTER;
  217.   }
  218.   *aFactory = NULL;
  219.  
  220.   if (aEntry->instance == NULL) {
  221.     aEntry->instance = PR_LoadLibrary(aEntry->library);
  222.   }
  223.   if (aEntry->instance != NULL) {
  224.     nsFactoryProc proc = (nsFactoryProc) PR_FindSymbol(aEntry->instance,
  225.                                                        "NSGetFactory");
  226.     if (proc != NULL) {
  227.       nsresult res = proc(aEntry->cid, aFactory);
  228.       return res;
  229.     }
  230.   }
  231.  
  232.   return NS_ERROR_FACTORY_NOT_LOADED;
  233. }
  234.  
  235. nsresult NSRepository::FindFactory(const nsCID &aClass,
  236.                                    nsIFactory **aFactory) 
  237. {
  238.   checkInitialized();
  239.  
  240.   if (aFactory == NULL) {
  241.     return NS_ERROR_NULL_POINTER;
  242.   }
  243.  
  244.   PR_EnterMonitor(monitor);
  245.  
  246.   IDKey key(aClass);
  247.   FactoryEntry *entry = (FactoryEntry*) factories->Get(&key);
  248.  
  249.   nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
  250.  
  251. #ifdef USE_REGISTRY
  252.   if (entry == NULL) {
  253.     entry = platformFind(aClass);
  254.     // If we got one, cache it in our hashtable
  255.     if (entry != NULL) {
  256.       factories->Put(&key, entry);
  257.     }
  258.   }
  259. #endif
  260.  
  261.   PR_ExitMonitor(monitor);
  262.  
  263.   if (entry != NULL) {
  264.     if ((entry)->factory == NULL) {
  265.       res = loadFactory(entry, aFactory);
  266.     } else {
  267.       *aFactory = entry->factory;
  268.       (*aFactory)->AddRef();
  269.       res = NS_OK;
  270.     }
  271.   }
  272.  
  273.   return res;
  274. }
  275.  
  276. nsresult NSRepository::checkInitialized() 
  277. {
  278.   nsresult res = NS_OK;
  279.   if (factories == NULL) {
  280.     res = Initialize();
  281.   }
  282.   return res;
  283. }
  284.  
  285. nsresult NSRepository::Initialize() 
  286. {
  287.   if (factories == NULL) {
  288.     factories = new nsHashtable();
  289.   }
  290.   if (monitor == NULL) {
  291.     monitor = PR_NewMonitor();
  292.   }
  293.  
  294.   return NS_OK;
  295. }
  296.  
  297. nsresult NSRepository::CreateInstance(const nsCID &aClass, 
  298.                                       nsISupports *aDelegate,
  299.                                       const nsIID &aIID,
  300.                                       void **aResult)
  301. {
  302.   if (aResult == NULL) {
  303.     return NS_ERROR_NULL_POINTER;
  304.   }
  305.   *aResult = NULL;
  306.  
  307.   nsIFactory *factory = NULL;
  308.   nsresult res = FindFactory(aClass, &factory);
  309.   if (NS_SUCCEEDED(res)) {
  310.     res = factory->CreateInstance(aDelegate, aIID, aResult);
  311.     factory->Release();
  312.  
  313.     return res;
  314.   }
  315.   
  316.   return NS_ERROR_FACTORY_NOT_REGISTERED;
  317. }
  318.  
  319. nsresult NSRepository::CreateInstance2(const nsCID &aClass, 
  320.                                        nsISupports *aDelegate,
  321.                                        const nsIID &aIID,
  322.                                        void *aSignature,
  323.                                        void **aResult)
  324. {
  325.   if (aResult == NULL) {
  326.     return NS_ERROR_NULL_POINTER;
  327.   }
  328.   *aResult = NULL;
  329.  
  330.   nsIFactory *factory = NULL;
  331.  
  332.   nsresult res = FindFactory(aClass, &factory);
  333.  
  334.   if (NS_SUCCEEDED(res)) {
  335.     nsIFactory2 *factory2 = NULL;
  336.     res = NS_ERROR_FACTORY_NO_SIGNATURE_SUPPORT;
  337.     
  338.     factory->QueryInterface(kFactory2IID, (void **) &factory2);
  339.  
  340.     if (factory2 != NULL) {
  341.       res = factory2->CreateInstance2(aDelegate, aIID, aSignature, aResult);
  342.       factory2->Release();
  343.     }
  344.  
  345.     factory->Release();
  346.     return res;
  347.   }
  348.   
  349.   return NS_ERROR_FACTORY_NOT_REGISTERED;
  350. }
  351.  
  352. nsresult NSRepository::RegisterFactory(const nsCID &aClass,
  353.                                        nsIFactory *aFactory, 
  354.                                        PRBool aReplace)
  355. {
  356.   checkInitialized();
  357.  
  358.   nsIFactory *old = NULL;
  359.   FindFactory(aClass, &old);
  360.   
  361.   if (old != NULL) {
  362.     old->Release();
  363.     if (!aReplace) {
  364.       return NS_ERROR_FACTORY_EXISTS;
  365.     }
  366.   }
  367.  
  368.   PR_EnterMonitor(monitor);
  369.  
  370.   IDKey key(aClass);
  371.   factories->Put(&key, new FactoryEntry(aClass, aFactory, NULL));
  372.  
  373.   PR_ExitMonitor(monitor);
  374.  
  375.   return NS_OK;
  376. }
  377.  
  378. nsresult NSRepository::RegisterFactory(const nsCID &aClass,
  379.                                        const char *aLibrary,
  380.                                        PRBool aReplace,
  381.                                        PRBool aPersist)
  382. {
  383.   checkInitialized();
  384.  
  385.   nsIFactory *old = NULL;
  386.   FindFactory(aClass, &old);
  387.   
  388.   if (old != NULL) {
  389.     old->Release();
  390.     if (!aReplace) {
  391.       return NS_ERROR_FACTORY_EXISTS;
  392.     }
  393.   }
  394.  
  395.   PR_EnterMonitor(monitor);
  396.  
  397. #ifdef USE_REGISTRY
  398.   if (aPersist == PR_TRUE) {
  399.     platformRegister(aClass, aLibrary);
  400.   } 
  401.   else
  402. #endif
  403.   {
  404.     IDKey key(aClass);
  405.     factories->Put(&key, new FactoryEntry(aClass, NULL, aLibrary));
  406.   }
  407.  
  408.   PR_ExitMonitor(monitor);
  409.  
  410.   return NS_OK;
  411. }
  412.  
  413. nsresult NSRepository::UnregisterFactory(const nsCID &aClass,
  414.                                          nsIFactory *aFactory)
  415. {
  416.   checkInitialized();
  417.  
  418.   nsIFactory *old = NULL;
  419.   FindFactory(aClass, &old);
  420.  
  421.   nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
  422.   if (old != NULL) {
  423.     if (old == aFactory) {
  424.       PR_EnterMonitor(monitor);
  425.  
  426.       IDKey key(aClass);
  427.       FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key);
  428.       delete entry;
  429.  
  430.       PR_ExitMonitor(monitor);
  431.   
  432.       res = NS_OK;
  433.     }
  434.     old->Release();
  435.   }
  436.  
  437.   return res;
  438. }
  439.  
  440. nsresult NSRepository::UnregisterFactory(const nsCID &aClass,
  441.                                          const char *aLibrary)
  442. {
  443.   checkInitialized();
  444.  
  445.   IDKey key(aClass);
  446.   FactoryEntry *old = (FactoryEntry *) factories->Get(&key);
  447.  
  448.   nsresult res = NS_ERROR_FACTORY_NOT_REGISTERED;
  449.  
  450.   PR_EnterMonitor(monitor);
  451.  
  452.   if (old != NULL) {
  453. #ifdef XP_UNIX
  454.     if (old->library != NULL && PL_strcasecmp(old->library, aLibrary))
  455. #else
  456.     if (old->library != NULL && PL_strcmp(old->library, aLibrary))
  457. #endif
  458.     {
  459.       FactoryEntry *entry = (FactoryEntry *) factories->Remove(&key);
  460.       delete entry;
  461.       res = NS_OK;
  462.     }
  463.   }
  464. #ifdef USE_REGISTRY
  465.   res = platformUnregister(aClass, aLibrary);
  466. #endif
  467.  
  468.   PR_ExitMonitor(monitor);
  469.  
  470.   return res;
  471. }
  472.  
  473. static PRBool freeLibraryEnum(nsHashKey *aKey, void *aData) 
  474. {
  475.   FactoryEntry *entry = (FactoryEntry *) aData;
  476.  
  477.   if (entry->instance != NULL) {
  478.     nsCanUnloadProc proc = (nsCanUnloadProc) PR_FindSymbol(entry->instance,
  479.                                                            "NSCanUnload");
  480.     if (proc != NULL) {
  481.       PRBool res = proc();
  482.       if (res) {
  483.         PR_UnloadLibrary(entry->instance);
  484.         entry->instance = NULL;
  485.       }
  486.     }    
  487.   }
  488.  
  489.   return PR_TRUE;
  490. }
  491.  
  492. nsresult NSRepository::FreeLibraries() 
  493. {
  494.   PR_EnterMonitor(monitor);
  495.  
  496.   factories->Enumerate(freeLibraryEnum);
  497.  
  498.   PR_ExitMonitor(monitor);
  499.  
  500.   return NS_OK;
  501. }
  502.  
  503.