Back to index

lightning-sunbird  0.9+nobinonly
nsComponentManager.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK *****
00037  *
00038  * This Original Code has been modified by IBM Corporation.
00039  * Modifications made by IBM described herein are
00040  * Copyright (c) International Business Machines
00041  * Corporation, 2000
00042  *
00043  * Modifications to Mozilla code or documentation
00044  * identified per MPL Section 3.3
00045  *
00046  * Date             Modified by     Description of modification
00047  * 04/20/2000       IBM Corp.      Added PR_CALLBACK for Optlink use in OS2
00048  */
00049 #include <stdlib.h>
00050 #include "nscore.h"
00051 #include "nsISupports.h"
00052 #include "nspr.h"
00053 #include "nsCRT.h" // for atoll
00054 // Arena used by component manager for storing contractid string, dll
00055 // location strings and small objects
00056 // CAUTION: Arena align mask needs to be defined before including plarena.h
00057 //          currently from nsComponentManager.h
00058 #define PL_ARENA_CONST_ALIGN_MASK 7
00059 #define NS_CM_BLOCK_SIZE (1024 * 8)
00060 
00061 #include "nsAutoLock.h"
00062 #include "nsCOMPtr.h"
00063 #include "nsComponentManager.h"
00064 #include "nsDirectoryService.h"
00065 #include "nsDirectoryServiceDefs.h"
00066 #include "nsCategoryManager.h"
00067 #include "nsCategoryManagerUtils.h"
00068 #include "nsIComponentLoader.h"
00069 #include "nsIEnumerator.h"
00070 #include "nsIInterfaceInfoManager.h"
00071 #include "nsIModule.h"
00072 #include "nsIObserverService.h"
00073 #include "nsISimpleEnumerator.h"
00074 #include "nsXPCOM.h"
00075 #include "nsXPCOMPrivate.h"
00076 #include "nsISupportsPrimitives.h"
00077 #include "nsLocalFile.h"
00078 #include "nsNativeComponentLoader.h"
00079 #include "nsReadableUtils.h"
00080 #include "nsString.h"
00081 #include "nsXPIDLString.h"
00082 #include "prcmon.h"
00083 #include "xptinfo.h" // this after nsISupports, to pick up IID so that xpt stuff doesn't try to define it itself...
00084 
00085 #include "nsInt64.h"
00086 #include "nsManifestLineReader.h"
00087 
00088 #include NEW_H     // for placement new
00089 
00090 
00091 #ifdef XP_BEOS
00092 #include <FindDirectory.h>
00093 #include <Path.h>
00094 #endif
00095 
00096 #include "prlog.h"
00097 
00098 NS_COM PRLogModuleInfo* nsComponentManagerLog = nsnull;
00099 
00100 #if 0 || defined (DEBUG_timeless)
00101  #define SHOW_DENIED_ON_SHUTDOWN
00102  #define SHOW_CI_ON_EXISTING_SERVICE
00103  #define XPCOM_CHECK_PENDING_CIDS
00104 #endif
00105 
00106 // Loader Types
00107 #define NS_LOADER_DATA_ALLOC_STEP 6
00108 
00109 // Bloated registry buffer size to improve startup performance -- needs to
00110 // be big enough to fit the entire file into memory or it'll thrash.
00111 // 512K is big enough to allow for some future growth in the registry.
00112 #define BIG_REGISTRY_BUFLEN   (512*1024)
00113 
00114 // Common Key Names
00115 const char classIDKeyName[]="classID";
00116 const char classesKeyName[]="contractID";
00117 const char componentLoadersKeyName[]="componentLoaders";
00118 const char componentsKeyName[]="components";
00119 const char xpcomComponentsKeyName[]="software/mozilla/XPCOM/components";
00120 const char xpcomKeyName[]="software/mozilla/XPCOM";
00121 
00122 // Common Value Names
00123 const char classIDValueName[]="ClassID";
00124 const char classNameValueName[]="ClassName";
00125 const char componentCountValueName[]="ComponentsCount";
00126 const char componentTypeValueName[]="ComponentType";
00127 const char contractIDValueName[]="ContractID";
00128 const char fileSizeValueName[]="FileSize";
00129 const char inprocServerValueName[]="InprocServer";
00130 const char lastModValueName[]="LastModTimeStamp";
00131 const char nativeComponentType[]="application/x-mozilla-native";
00132 const char staticComponentType[]="application/x-mozilla-static";
00133 const char versionValueName[]="VersionString";
00134 
00135 const static char XPCOM_ABSCOMPONENT_PREFIX[] = "abs:";
00136 const static char XPCOM_RELCOMPONENT_PREFIX[] = "rel:";
00137 const static char XPCOM_GRECOMPONENT_PREFIX[] = "gre:";
00138 
00139 static const char gIDFormat[] =
00140   "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
00141 
00142 
00143 #define NS_EMPTY_IID                                 \
00144 {                                                    \
00145     0x00000000,                                      \
00146     0x0000,                                          \
00147     0x0000,                                          \
00148     {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} \
00149 }
00150 
00151 NS_DEFINE_CID(kEmptyCID, NS_EMPTY_IID);
00152 NS_DEFINE_CID(kCategoryManagerCID, NS_CATEGORYMANAGER_CID);
00153 
00154 #define UID_STRING_LENGTH 39
00155 
00156 // Set to true from NS_ShutdownXPCOM.
00157 extern PRBool gXPCOMShuttingDown;
00158 
00159 static void GetIDString(const nsID& aCID, char buf[UID_STRING_LENGTH])
00160 {
00161     PR_snprintf(buf, UID_STRING_LENGTH, gIDFormat,
00162                 aCID.m0, (PRUint32) aCID.m1, (PRUint32) aCID.m2,
00163                 (PRUint32) aCID.m3[0], (PRUint32) aCID.m3[1],
00164                 (PRUint32) aCID.m3[2], (PRUint32) aCID.m3[3],
00165                 (PRUint32) aCID.m3[4], (PRUint32) aCID.m3[5],
00166                 (PRUint32) aCID.m3[6], (PRUint32) aCID.m3[7]);
00167 }
00168 
00169 nsresult
00170 nsCreateInstanceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
00171 {
00172     /*
00173      * If I were a real man, I would consolidate this with
00174      * nsGetServiceFromContractID::operator().
00175      */
00176     nsresult rv;
00177     nsXPIDLCString value;
00178     nsCOMPtr<nsIComponentManager> compMgr;
00179     nsCOMPtr<nsICategoryManager> catman =
00180         do_GetService(kCategoryManagerCID, &rv);
00181 
00182     if (NS_FAILED(rv)) goto error;
00183 
00184     if (!mCategory || !mEntry) {
00185         // when categories have defaults, use that for null mEntry
00186         rv = NS_ERROR_NULL_POINTER;
00187         goto error;
00188     }
00189 
00190     /* find the contractID for category.entry */
00191     rv = catman->GetCategoryEntry(mCategory, mEntry,
00192                                   getter_Copies(value));
00193     if (NS_FAILED(rv)) goto error;
00194     if (!value) {
00195         rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
00196         goto error;
00197     }
00198     NS_GetComponentManager(getter_AddRefs(compMgr));
00199     if (!compMgr)
00200         return NS_ERROR_FAILURE;
00201     rv = compMgr->CreateInstanceByContractID(value, mOuter, aIID, aInstancePtr);
00202     if (NS_FAILED(rv)) {
00203     error:
00204         *aInstancePtr = 0;
00205     }
00206 
00207     if (mErrorPtr)
00208         *mErrorPtr = rv;
00209     return rv;
00210 }
00211 
00212 
00213 nsresult
00214 nsGetServiceFromCategory::operator()(const nsIID& aIID, void** aInstancePtr) const
00215 {
00216     nsresult rv;
00217     nsXPIDLCString value;
00218     nsCOMPtr<nsICategoryManager> catman;
00219     nsComponentManagerImpl *compMgr = nsComponentManagerImpl::gComponentManager;
00220     if (!compMgr) {
00221         rv = NS_ERROR_NOT_INITIALIZED;
00222         goto error;
00223     }
00224 
00225     if (!mCategory || !mEntry) {
00226         // when categories have defaults, use that for null mEntry
00227         rv = NS_ERROR_NULL_POINTER;
00228         goto error;
00229     }
00230 
00231     rv = compMgr->nsComponentManagerImpl::GetService(kCategoryManagerCID,
00232                                                      NS_GET_IID(nsICategoryManager),
00233                                                      getter_AddRefs(catman));
00234     if (NS_FAILED(rv)) goto error;
00235 
00236     /* find the contractID for category.entry */
00237     rv = catman->GetCategoryEntry(mCategory, mEntry,
00238                                   getter_Copies(value));
00239     if (NS_FAILED(rv)) goto error;
00240     if (!value) {
00241         rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
00242         goto error;
00243     }
00244 
00245     rv = compMgr->
00246         nsComponentManagerImpl::GetServiceByContractID(value,
00247                                                        aIID, aInstancePtr);
00248     if (NS_FAILED(rv)) {
00249     error:
00250         *aInstancePtr = 0;
00251     }
00252     if (mErrorPtr)
00253         *mErrorPtr = rv;
00254     return rv;
00255 }
00256 
00258 // Arena helper functions
00260 char *
00261 ArenaStrndup(const char *s, PRUint32 len, PLArenaPool *arena)
00262 {
00263     void *mem;
00264     // Include trailing null in the len
00265     PL_ARENA_ALLOCATE(mem, arena, len+1);
00266     if (mem)
00267         memcpy(mem, s, len+1);
00268     return NS_STATIC_CAST(char *, mem);
00269 }
00270 
00271 char*
00272 ArenaStrdup(const char *s, PLArenaPool *arena)
00273 {
00274     return ArenaStrndup(s, strlen(s), arena);
00275 }
00276 
00278 // Hashtable Callbacks
00280 
00281 PRBool PR_CALLBACK
00282 nsFactoryEntry_Destroy(nsHashKey *aKey, void *aData, void* closure);
00283 
00284 PR_STATIC_CALLBACK(const void *)
00285 factory_GetKey(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
00286 {
00287     nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
00288 
00289     return &entry->mFactoryEntry->mCid;
00290 }
00291 
00292 PR_STATIC_CALLBACK(PLDHashNumber)
00293 factory_HashKey(PLDHashTable *aTable, const void *aKey)
00294 {
00295     const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey);
00296 
00297     return cidp->m0;
00298 }
00299 
00300 PR_STATIC_CALLBACK(PRBool)
00301 factory_MatchEntry(PLDHashTable *aTable, const PLDHashEntryHdr *aHdr,
00302                    const void *aKey)
00303 {
00304     const nsFactoryTableEntry* entry =
00305         NS_STATIC_CAST(const nsFactoryTableEntry*, aHdr);
00306     const nsCID *cidp = NS_REINTERPRET_CAST(const nsCID*, aKey);
00307 
00308     return (entry->mFactoryEntry->mCid).Equals(*cidp);
00309 }
00310 
00311 PR_STATIC_CALLBACK(void)
00312 factory_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
00313 {
00314     nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
00315     // nsFactoryEntry is arena allocated. So we dont delete it.
00316     // We call the destructor by hand.
00317     entry->mFactoryEntry->~nsFactoryEntry();
00318     PL_DHashClearEntryStub(aTable, aHdr);
00319 }
00320 
00321 static const PLDHashTableOps factory_DHashTableOps = {
00322     PL_DHashAllocTable,
00323     PL_DHashFreeTable,
00324     factory_GetKey,
00325     factory_HashKey,
00326     factory_MatchEntry,
00327     PL_DHashMoveEntryStub,
00328     factory_ClearEntry,
00329     PL_DHashFinalizeStub,
00330 };
00331 
00332 PR_STATIC_CALLBACK(void)
00333 contractID_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr)
00334 {
00335     nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
00336     if (entry->mFactoryEntry->mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY &&
00337         entry->mFactoryEntry->mCid.Equals(kEmptyCID)) {
00338         // this object is owned by the hash.
00339         // nsFactoryEntry is arena allocated. So we dont delete it.
00340         // We call the destructor by hand.
00341         entry->mFactoryEntry->~nsFactoryEntry();
00342     }
00343 
00344     // contractIDs are arena allocated. No need to free them.
00345 
00346     PL_DHashClearEntryStub(aTable, aHdr);
00347 }
00348 
00349 static const PLDHashTableOps contractID_DHashTableOps = {
00350     PL_DHashAllocTable,
00351     PL_DHashFreeTable,
00352     PL_DHashGetKeyStub,
00353     PL_DHashStringKey,
00354     PL_DHashMatchStringKey,
00355     PL_DHashMoveEntryStub,
00356     contractID_ClearEntry,
00357     PL_DHashFinalizeStub,
00358 };
00359 
00361 // nsFactoryEntry
00363 
00364 MOZ_DECL_CTOR_COUNTER(nsFactoryEntry)
00365 nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
00366                                const char *aLocation,
00367                                PRUint32 locationlen,
00368                                int aType,
00369                                class nsFactoryEntry* parent)
00370 : mCid(aClass),
00371   mTypeIndex(aType),
00372   mParent(parent)
00373 {
00374     // Arena allocate the location string
00375     mLocation = ArenaStrndup(aLocation, locationlen, &nsComponentManagerImpl::gComponentManager->mArena);
00376 }
00377 
00378 nsFactoryEntry::nsFactoryEntry(const nsCID &aClass,
00379                                nsIFactory *aFactory,
00380                                class nsFactoryEntry* parent)
00381 : mCid(aClass),
00382   mFactory(aFactory),
00383   mTypeIndex(NS_COMPONENT_TYPE_FACTORY_ONLY),
00384   mLocation(nsnull),
00385   mParent(parent)
00386 {
00387 }
00388 
00389 // nsFactoryEntry is usually arena allocated including the strings it
00390 // holds. So we call destructor by hand.
00391 nsFactoryEntry::~nsFactoryEntry(void)
00392 {
00393     // Release the reference to the factory
00394     mFactory = nsnull;
00395 
00396     // Release any service reference
00397     mServiceObject = nsnull;
00398 
00399     // nsFactoryEntry is arena allocated. So we dont delete it.
00400     // We call the destructor by hand.
00401     if (mParent)
00402         mParent->~nsFactoryEntry();
00403 }
00404 
00405 nsresult
00406 nsFactoryEntry::ReInit(const nsCID &aClass, const char *aLocation, int aType)
00407 {
00408     NS_ENSURE_TRUE(mTypeIndex != NS_COMPONENT_TYPE_FACTORY_ONLY, NS_ERROR_INVALID_ARG);
00409     // cid has to match
00410     // SERVICE_ONLY entries can be promoted to an entry of another type
00411     NS_ENSURE_TRUE((mTypeIndex == NS_COMPONENT_TYPE_SERVICE_ONLY || mCid.Equals(aClass)),
00412                    NS_ERROR_INVALID_ARG);
00413 
00414     // Arena allocate the location string
00415     mLocation = ArenaStrdup(aLocation, &nsComponentManagerImpl::gComponentManager->mArena);
00416     if (!mLocation)
00417         return NS_ERROR_OUT_OF_MEMORY;
00418 
00419     mTypeIndex = aType;
00420     return NS_OK;
00421 }
00422 
00424 // Hashtable Enumeration
00426 typedef NS_CALLBACK(EnumeratorConverter)(PLDHashTable *table,
00427                                          const PLDHashEntryHdr *hdr,
00428                                          void *data,
00429                                          nsISupports **retval);
00430 
00431 class PLDHashTableEnumeratorImpl : public nsIBidirectionalEnumerator,
00432                                    public nsISimpleEnumerator
00433 {
00434 public:
00435     NS_DECL_ISUPPORTS
00436     NS_DECL_NSIENUMERATOR
00437     NS_DECL_NSIBIDIRECTIONALENUMERATOR
00438     NS_DECL_NSISIMPLEENUMERATOR
00439 
00440     PLDHashTableEnumeratorImpl(PLDHashTable *table,
00441                                EnumeratorConverter converter,
00442                                void *converterData);
00443     PRInt32 Count() { return mCount; }
00444 private:
00445     PLDHashTableEnumeratorImpl(); /* no implementation */
00446 
00447     ~PLDHashTableEnumeratorImpl();
00448     NS_IMETHODIMP ReleaseElements();
00449 
00450     nsVoidArray   mElements;
00451     PRInt32       mCount, mCurrent;
00452     PRMonitor*    mMonitor;
00453 
00454     struct Closure {
00455         PRBool                        succeeded;
00456         EnumeratorConverter           converter;
00457         void                          *data;
00458         PLDHashTableEnumeratorImpl    *impl;
00459     };
00460 
00461     static PLDHashOperator PR_CALLBACK Enumerator(PLDHashTable *table,
00462                                                   PLDHashEntryHdr *hdr,
00463                                                   PRUint32 number,
00464                                                   void *data);
00465 };
00466 
00467 // static
00468 PLDHashOperator PR_CALLBACK
00469 PLDHashTableEnumeratorImpl::Enumerator(PLDHashTable *table,
00470                                        PLDHashEntryHdr *hdr,
00471                                        PRUint32 number,
00472                                        void *data)
00473 {
00474     Closure *c = NS_REINTERPRET_CAST(Closure *, data);
00475     nsISupports *converted;
00476     if (NS_FAILED(c->converter(table, hdr, c->data, &converted)) ||
00477         !c->impl->mElements.AppendElement(converted)) {
00478         c->succeeded = PR_FALSE;
00479         return PL_DHASH_STOP;
00480     }
00481 
00482     c->succeeded = PR_TRUE;
00483     return PL_DHASH_NEXT;
00484 }
00485 
00486 PLDHashTableEnumeratorImpl::PLDHashTableEnumeratorImpl(PLDHashTable *table,
00487                                                        EnumeratorConverter converter,
00488                                                        void *converterData)
00489 : mCurrent(0)
00490 {
00491     mMonitor = nsAutoMonitor::NewMonitor("PLDHashTableEnumeratorImpl");
00492     NS_ASSERTION(mMonitor, "NULL Monitor");
00493 
00494     nsAutoMonitor mon(mMonitor);
00495 
00496     Closure c = { PR_FALSE, converter, converterData, this };
00497     mCount = PL_DHashTableEnumerate(table, Enumerator, &c);
00498     if (!c.succeeded) {
00499         ReleaseElements();
00500         mCount = 0;
00501     }
00502 }
00503 
00504 NS_IMPL_ISUPPORTS3(PLDHashTableEnumeratorImpl,
00505                    nsIBidirectionalEnumerator,
00506                    nsIEnumerator,
00507                    nsISimpleEnumerator)
00508 
00509 PLDHashTableEnumeratorImpl::~PLDHashTableEnumeratorImpl()
00510 {
00511     (void) ReleaseElements();
00512 
00513     // Destroy the Lock
00514     if (mMonitor)
00515         nsAutoMonitor::DestroyMonitor(mMonitor);
00516 }
00517 
00518 NS_IMETHODIMP
00519 PLDHashTableEnumeratorImpl::ReleaseElements()
00520 {
00521     for (PRInt32 i = 0; i < mCount; i++) {
00522         nsISupports *supports = NS_REINTERPRET_CAST(nsISupports *,
00523                                                     mElements[i]);
00524         NS_IF_RELEASE(supports);
00525     }
00526     return NS_OK;
00527 }
00528 
00529 NS_IMETHODIMP
00530 PL_NewDHashTableEnumerator(PLDHashTable *table,
00531                            EnumeratorConverter converter,
00532                            void *converterData,
00533                            PLDHashTableEnumeratorImpl **retval)
00534 {
00535     PLDHashTableEnumeratorImpl *impl =
00536         new PLDHashTableEnumeratorImpl(table, converter, converterData);
00537 
00538     if (!impl)
00539         return NS_ERROR_OUT_OF_MEMORY;
00540 
00541     NS_ADDREF(impl);
00542 
00543     if (impl->Count() == -1) {
00544         // conversion failed
00545         NS_RELEASE(impl);
00546         return NS_ERROR_FAILURE;
00547     }
00548 
00549     *retval = impl;
00550     return NS_OK;
00551 }
00552 
00553 NS_IMETHODIMP
00554 PLDHashTableEnumeratorImpl::First()
00555 {
00556     if (!mCount)
00557         return NS_ERROR_FAILURE;
00558 
00559     mCurrent = 0;
00560     return NS_OK;
00561 }
00562 
00563 NS_IMETHODIMP
00564 PLDHashTableEnumeratorImpl::Last()
00565 {
00566     if (!mCount)
00567         return NS_ERROR_FAILURE;
00568     mCurrent = mCount - 1;
00569     return NS_OK;
00570 }
00571 
00572 NS_IMETHODIMP
00573 PLDHashTableEnumeratorImpl::Prev()
00574 {
00575     if (!mCurrent)
00576         return NS_ERROR_FAILURE;
00577 
00578     mCurrent--;
00579     return NS_OK;
00580 }
00581 
00582 NS_IMETHODIMP
00583 PLDHashTableEnumeratorImpl::Next()
00584 {
00585     // If empty or we're past the end, or we are at the end return error
00586     if (!mCount || (mCurrent == mCount) || (++mCurrent == mCount))
00587         return NS_ERROR_FAILURE;
00588 
00589     return NS_OK;
00590 }
00591 
00592 NS_IMETHODIMP
00593 PLDHashTableEnumeratorImpl::CurrentItem(nsISupports **retval)
00594 {
00595     if (!mCount || mCurrent == mCount)
00596         return NS_ERROR_FAILURE;
00597 
00598     *retval = NS_REINTERPRET_CAST(nsISupports *, mElements[mCurrent]);
00599     if (*retval)
00600         NS_ADDREF(*retval);
00601 
00602     return NS_OK;
00603 }
00604 
00605 NS_IMETHODIMP
00606 PLDHashTableEnumeratorImpl::IsDone()
00607 {
00608     if (!mCount || (mCurrent == mCount))
00609         return NS_OK;
00610 
00611     return NS_ENUMERATOR_FALSE;
00612 }
00613 
00614 NS_IMETHODIMP
00615 PLDHashTableEnumeratorImpl::HasMoreElements(PRBool *_retval)
00616 {
00617     if (!mCount || (mCurrent >= mCount - 1))
00618         *_retval = PR_FALSE;
00619     else
00620         *_retval = PR_TRUE;
00621 
00622     return NS_OK;
00623 }
00624 
00625 NS_IMETHODIMP
00626 PLDHashTableEnumeratorImpl::GetNext(nsISupports **_retval)
00627 {
00628     nsresult rv = Next();
00629     if (NS_FAILED(rv)) return rv;
00630 
00631     return CurrentItem(_retval);
00632 }
00633 
00634 static NS_IMETHODIMP
00635 ConvertFactoryEntryToCID(PLDHashTable *table,
00636                          const PLDHashEntryHdr *hdr,
00637                          void *data, nsISupports **retval)
00638 {
00639     nsresult rv;
00640     nsCOMPtr<nsISupportsID> wrapper;
00641 
00642     nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data);
00643 
00644     rv = cm->CreateInstanceByContractID(NS_SUPPORTS_ID_CONTRACTID, nsnull,
00645            NS_GET_IID(nsISupportsID), getter_AddRefs(wrapper));
00646 
00647     NS_ENSURE_SUCCESS(rv, rv);
00648 
00649     const nsFactoryTableEntry *entry =
00650         NS_REINTERPRET_CAST(const nsFactoryTableEntry *, hdr);
00651     if (entry) {
00652         nsFactoryEntry *fe = entry->mFactoryEntry;
00653 
00654         wrapper->SetData(&fe->mCid);
00655         *retval = wrapper;
00656         NS_ADDREF(*retval);
00657         return NS_OK;
00658     }
00659     *retval = nsnull;
00660 
00661     return rv;
00662 }
00663 
00664 static NS_IMETHODIMP
00665 ConvertContractIDKeyToString(PLDHashTable *table,
00666                              const PLDHashEntryHdr *hdr,
00667                              void *data, nsISupports **retval)
00668 {
00669     nsresult rv;
00670     nsCOMPtr<nsISupportsCString> wrapper;
00671 
00672     nsComponentManagerImpl *cm = NS_STATIC_CAST(nsComponentManagerImpl *, data);
00673 
00674     rv = cm->CreateInstanceByContractID(NS_SUPPORTS_CSTRING_CONTRACTID, nsnull,
00675                 NS_GET_IID(nsISupportsCString), getter_AddRefs(wrapper));
00676 
00677     NS_ENSURE_SUCCESS(rv, rv);
00678 
00679     const nsContractIDTableEntry *entry =
00680         NS_REINTERPRET_CAST(const nsContractIDTableEntry *, hdr);
00681 
00682     wrapper->SetData(nsDependentCString(entry->mContractID,
00683                                         entry->mContractIDLen));
00684     *retval = wrapper;
00685     NS_ADDREF(*retval);
00686     return NS_OK;
00687 }
00688 
00689 // this is safe to call during InitXPCOM
00690 static nsresult GetLocationFromDirectoryService(const char* prop,
00691                                                 nsIFile** aDirectory)
00692 {
00693     nsCOMPtr<nsIProperties> directoryService;
00694     nsDirectoryService::Create(nsnull,
00695                                NS_GET_IID(nsIProperties),
00696                                getter_AddRefs(directoryService));
00697 
00698     if (!directoryService)
00699         return NS_ERROR_FAILURE;
00700 
00701     return directoryService->Get(prop,
00702                                  NS_GET_IID(nsIFile),
00703                                  (void**)aDirectory);
00704 }
00705 
00706 
00708 // nsComponentManagerImpl
00710 
00711 
00712 nsComponentManagerImpl::nsComponentManagerImpl()
00713     :
00714     mMon(NULL),
00715     mNativeComponentLoader(0),
00716     mStaticComponentLoader(0),
00717     mShuttingDown(NS_SHUTDOWN_NEVERHAPPENED),
00718     mLoaderData(nsnull),
00719     mRegistryDirty(PR_FALSE)
00720 {
00721     mFactories.ops = nsnull;
00722     mContractIDs.ops = nsnull;
00723 }
00724 
00725 nsresult nsComponentManagerImpl::Init(nsStaticModuleInfo const *aStaticModules,
00726                                       PRUint32 aStaticModuleCount)
00727 {
00728     PR_ASSERT(mShuttingDown != NS_SHUTDOWN_INPROGRESS);
00729     if (mShuttingDown == NS_SHUTDOWN_INPROGRESS)
00730         return NS_ERROR_FAILURE;
00731 
00732     mShuttingDown = NS_SHUTDOWN_NEVERHAPPENED;
00733 
00734     if (nsComponentManagerLog == nsnull)
00735     {
00736         nsComponentManagerLog = PR_NewLogModule("nsComponentManager");
00737     }
00738 
00739     // Initialize our arena
00740     PL_INIT_ARENA_POOL(&mArena, "ComponentManagerArena", NS_CM_BLOCK_SIZE);
00741 
00742     if (!mFactories.ops) {
00743         if (!PL_DHashTableInit(&mFactories, &factory_DHashTableOps,
00744                                0, sizeof(nsFactoryTableEntry),
00745                                1024)) {
00746             mFactories.ops = nsnull;
00747             return NS_ERROR_OUT_OF_MEMORY;
00748         }
00749 
00750         // Minimum alpha uses k=2 because nsFactoryTableEntry saves two
00751         // words compared to what a chained hash table requires.
00752         PL_DHashTableSetAlphaBounds(&mFactories,
00753                                     0.875,
00754                                     PL_DHASH_MIN_ALPHA(&mFactories, 2));
00755     }
00756 
00757     if (!mContractIDs.ops) {
00758         if (!PL_DHashTableInit(&mContractIDs, &contractID_DHashTableOps,
00759                                0, sizeof(nsContractIDTableEntry),
00760                                1024)) {
00761             mContractIDs.ops = nsnull;
00762             return NS_ERROR_OUT_OF_MEMORY;
00763         }
00764 
00765         // Minimum alpha uses k=1 because nsContractIDTableEntry saves one
00766         // word compared to what a chained hash table requires.
00767 #if 0
00768         PL_DHashTableSetAlphaBounds(&mContractIDs,
00769                                     0.875,
00770                                     PL_DHASH_MIN_ALPHA(&mContractIDs, 1));
00771 #endif
00772     }
00773     if (mMon == nsnull) {
00774         mMon = nsAutoMonitor::NewMonitor("nsComponentManagerImpl");
00775         if (mMon == nsnull)
00776             return NS_ERROR_OUT_OF_MEMORY;
00777     }
00778 
00779     if (mNativeComponentLoader == nsnull) {
00780         /* Create the NativeComponentLoader */
00781         mNativeComponentLoader = new nsNativeComponentLoader();
00782         if (!mNativeComponentLoader)
00783             return NS_ERROR_OUT_OF_MEMORY;
00784         NS_ADDREF(mNativeComponentLoader);
00785 
00786         nsresult rv = mNativeComponentLoader->Init(this, nsnull);
00787         if (NS_FAILED(rv))
00788             return rv;
00789     }
00790 
00791     // Add predefined loaders
00792     mLoaderData = (nsLoaderdata *) PR_Malloc(sizeof(nsLoaderdata) * NS_LOADER_DATA_ALLOC_STEP);
00793     if (!mLoaderData)
00794         return NS_ERROR_OUT_OF_MEMORY;
00795     mMaxNLoaderData = NS_LOADER_DATA_ALLOC_STEP;
00796 
00797     mNLoaderData = NS_COMPONENT_TYPE_NATIVE;
00798     mLoaderData[mNLoaderData].type = PL_strdup(nativeComponentType);
00799     mLoaderData[mNLoaderData].loader = mNativeComponentLoader;
00800     NS_ADDREF(mLoaderData[mNLoaderData].loader);
00801     mNLoaderData++;
00802 
00803     if (mStaticComponentLoader == nsnull) {
00804         nsresult rv = NewStaticComponentLoader(aStaticModules,
00805                                                aStaticModuleCount,
00806                                                &mStaticComponentLoader);
00807         if (NS_FAILED(rv))
00808             return rv;
00809     }
00810 
00811     mLoaderData[mNLoaderData].type = PL_strdup(staticComponentType);
00812     mLoaderData[mNLoaderData].loader = mStaticComponentLoader;
00813     NS_ADDREF(mLoaderData[mNLoaderData].loader);
00814     mNLoaderData++;
00815 
00816     if (mStaticComponentLoader) {
00817         /* Init the static loader */
00818         mStaticComponentLoader->Init(this, nsnull);
00819     }
00820     GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_DIR, getter_AddRefs(mComponentsDir));
00821     if (!mComponentsDir)
00822         return NS_ERROR_OUT_OF_MEMORY;
00823 
00824     nsCAutoString componentDescriptor;
00825     nsresult rv = mComponentsDir->GetNativePath(componentDescriptor);
00826     if (NS_FAILED(rv))
00827         return rv;
00828 
00829     mComponentsOffset = componentDescriptor.Length();
00830 
00831     GetLocationFromDirectoryService(NS_GRE_COMPONENT_DIR, getter_AddRefs(mGREComponentsDir));
00832     if (mGREComponentsDir) {
00833         nsresult rv = mGREComponentsDir->GetNativePath(componentDescriptor);
00834         if (NS_FAILED(rv)) {
00835             NS_WARNING("No GRE component manager");
00836             return rv;
00837         }
00838         mGREComponentsOffset = componentDescriptor.Length();
00839     }
00840 
00841     GetLocationFromDirectoryService(NS_XPCOM_COMPONENT_REGISTRY_FILE,
00842                                     getter_AddRefs(mRegistryFile));
00843 
00844     if(!mRegistryFile) {
00845         NS_WARNING("No Component Registry file was found in the directory service");
00846         return NS_ERROR_FAILURE;
00847     }
00848 
00849     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG,
00850            ("nsComponentManager: Initialized."));
00851 
00852     return NS_OK;
00853 }
00854 
00855 PRIntn PR_CALLBACK AutoRegEntryDestroy(nsHashKey *aKey, void *aData, void* aClosure)
00856 {
00857     delete (AutoRegEntry*)aData;
00858     return kHashEnumerateNext;
00859 }
00860 
00861 nsresult nsComponentManagerImpl::Shutdown(void)
00862 {
00863     PR_ASSERT(mShuttingDown == NS_SHUTDOWN_NEVERHAPPENED);
00864     if (mShuttingDown != NS_SHUTDOWN_NEVERHAPPENED)
00865         return NS_ERROR_FAILURE;
00866 
00867     mShuttingDown = NS_SHUTDOWN_INPROGRESS;
00868 
00869     // Shutdown the component manager
00870     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning Shutdown."));
00871 
00872     PRInt32 i;
00873 
00874     // Write out our component data file.
00875     if (mRegistryDirty) {
00876         nsresult rv = WritePersistentRegistry();
00877         if (NS_FAILED(rv)) {
00878             PR_LOG(nsComponentManagerLog, PR_LOG_ERROR, ("nsComponentManager: Could not write out perisistant registry."));
00879 #ifdef DEBUG
00880             printf("Could not write out perisistant registry!\n");
00881 #endif
00882         }
00883     }
00884 
00885     mAutoRegEntries.Reset(AutoRegEntryDestroy);
00886 
00887     // Release all cached factories
00888     if (mContractIDs.ops) {
00889         PL_DHashTableFinish(&mContractIDs);
00890         mContractIDs.ops = nsnull;
00891     }
00892     if (mFactories.ops) {
00893         PL_DHashTableFinish(&mFactories);
00894         mFactories.ops = nsnull;
00895     }
00896     // Unload libraries
00897     UnloadLibraries(nsnull, NS_Shutdown);
00898 
00899     // delete arena for strings and small objects
00900     PL_FinishArenaPool(&mArena);
00901 
00902     mComponentsDir = 0;
00903 
00904     mCategoryManager = 0;
00905 
00906     // Release all the component data - loaders and type strings
00907     for (i=0; i < mNLoaderData; i++) {
00908         NS_IF_RELEASE(mLoaderData[i].loader);
00909         PL_strfree((char *)mLoaderData[i].type);
00910     }
00911     PR_Free(mLoaderData);
00912     mLoaderData = nsnull;
00913 
00914     // we have an extra reference on this one, which is probably a good thing
00915     NS_IF_RELEASE(mNativeComponentLoader);
00916     NS_IF_RELEASE(mStaticComponentLoader);
00917 
00918     mShuttingDown = NS_SHUTDOWN_COMPLETE;
00919 
00920     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Shutdown complete."));
00921 
00922     return NS_OK;
00923 }
00924 
00925 nsComponentManagerImpl::~nsComponentManagerImpl()
00926 {
00927     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Beginning destruction."));
00928 
00929     if (mShuttingDown != NS_SHUTDOWN_COMPLETE)
00930         Shutdown();
00931 
00932     if (mMon) {
00933         nsAutoMonitor::DestroyMonitor(mMon);
00934     }
00935     PR_LOG(nsComponentManagerLog, PR_LOG_DEBUG, ("nsComponentManager: Destroyed."));
00936 }
00937 
00938 NS_IMPL_THREADSAFE_ISUPPORTS8(nsComponentManagerImpl,
00939                               nsIComponentManager,
00940                               nsIServiceManager,
00941                               nsISupportsWeakReference,
00942                               nsIInterfaceRequestor,
00943                               nsIComponentRegistrar,
00944                               nsIServiceManagerObsolete,
00945                               nsIComponentManagerObsolete,
00946                               nsIComponentLoaderManager)
00947 
00948 
00949 nsresult
00950 nsComponentManagerImpl::GetInterface(const nsIID & uuid, void **result)
00951 {
00952     NS_WARNING("This isn't supported");
00953     // fall through to QI as anything QIable is a superset of what can be
00954     // got via the GetInterface()
00955     return  QueryInterface(uuid, result);
00956 }
00957 
00959 // nsComponentManagerImpl: Platform methods
00961 
00962 #define PERSISTENT_REGISTRY_VERSION_MINOR 5
00963 #define PERSISTENT_REGISTRY_VERSION_MAJOR 0
00964 
00965 
00966 AutoRegEntry::AutoRegEntry(const nsACString& name, PRInt64* modDate) :
00967     mName(ToNewCString(name)),
00968     mNameLen(name.Length()),
00969     mData(nsnull),
00970     mModDate(*modDate)
00971 {
00972 }
00973 
00974 AutoRegEntry::~AutoRegEntry()
00975 {
00976     if (mName) PL_strfree(mName);
00977     if (mData) PL_strfree(mData);
00978 }
00979 
00980 PRBool
00981 AutoRegEntry::Modified(PRInt64 *date)
00982 {
00983     return !LL_EQ(*date, mModDate);
00984 }
00985 
00986 void
00987 AutoRegEntry::SetOptionalData(const char* data)
00988 {
00989     if (mData)
00990         PL_strfree(mData);
00991 
00992     if (!data) {
00993         mData = nsnull;
00994         return;
00995     }
00996 
00997     mData = PL_strdup(data);
00998 }
00999 
01000 static
01001 PRBool ReadSectionHeader(nsManifestLineReader& reader, const char *token)
01002 {
01003     while (1)
01004     {
01005         if (*reader.LinePtr() == '[')
01006         {
01007             char* p = reader.LinePtr() + (reader.LineLength() - 1);
01008             if (*p != ']')
01009                 break;
01010             *p = 0;
01011 
01012             char* values[1];
01013             int lengths[1];
01014             if (2 != reader.ParseLine(values, lengths, 1))
01015                 break;
01016 
01017             // ignore the leading '['
01018             if (0 != PL_strcmp(values[0]+1, token))
01019                 break;
01020 
01021             return PR_TRUE;
01022         }
01023 
01024         if (!reader.NextLine())
01025             break;
01026     }
01027     return PR_FALSE;
01028 }
01029 
01030 nsresult
01031 nsComponentManagerImpl::ReadPersistentRegistry()
01032 {
01033 
01034     // populate Category Manager. need to get this early so that we don't get
01035     // skipped by 'goto out'
01036     nsresult rv = GetService(kCategoryManagerCID,
01037                              NS_GET_IID(nsICategoryManager),
01038                              getter_AddRefs(mCategoryManager));
01039     if (NS_FAILED(rv))
01040         return rv;
01041 
01042     nsAutoMonitor mon(mMon);
01043     nsManifestLineReader reader;
01044 
01045     if (!mComponentsDir)
01046         return NS_ERROR_NOT_INITIALIZED;  // this should have been set by Init().
01047 
01048     PRFileDesc* fd = nsnull;
01049 
01050     // Set From Init
01051     if (!mRegistryFile) {
01052         return NS_ERROR_FILE_NOT_FOUND;
01053     }
01054 
01055     nsCOMPtr<nsIFile> file;
01056     mRegistryFile->Clone(getter_AddRefs(file));
01057     if (!file)
01058         return NS_ERROR_OUT_OF_MEMORY;
01059 
01060     nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
01061 
01062     rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &fd);
01063     if (NS_FAILED(rv))
01064         return rv;
01065 
01066     PRInt64 fileSize;
01067     rv = localFile->GetFileSize(&fileSize);
01068     if (NS_FAILED(rv))
01069     {
01070         PR_Close(fd);
01071         return rv;
01072     }
01073 
01074     PRInt32 flen = nsInt64(fileSize);
01075     if (flen == 0)
01076     {
01077         PR_Close(fd);
01078         NS_WARNING("Persistent Registry Empty!");
01079         return NS_OK; // ERROR CONDITION
01080     }
01081 
01082     char* registry = new char[flen+1];
01083     if (!registry)
01084         goto out;
01085 
01086     if (flen > PR_Read(fd, registry, flen))
01087     {
01088         rv = NS_ERROR_FAILURE;
01089         goto out;
01090     }
01091     registry[flen] = '\0';
01092 
01093     reader.Init(registry, flen);
01094 
01095     if (ReadSectionHeader(reader, "HEADER"))
01096         goto out;
01097 
01098     if (!reader.NextLine())
01099         goto out;
01100 
01101     char* values[6];
01102     int lengths[6];
01103 
01104     // VersionLiteral,major,minor
01105     if (3 != reader.ParseLine(values, lengths, 3))
01106         goto out;
01107 
01108     // VersionLiteral
01109     if (!nsDependentCString(values[0], lengths[0]).EqualsLiteral("Version"))
01110         goto out;
01111 
01112     // major
01113     if (PERSISTENT_REGISTRY_VERSION_MAJOR != atoi(values[1]))
01114         goto out;
01115 
01116     // minor
01117     if (PERSISTENT_REGISTRY_VERSION_MINOR != atoi(values[2]))
01118         goto out;
01119 
01120     if (ReadSectionHeader(reader, "COMPONENTS"))
01121         goto out;
01122 
01123     while (1)
01124     {
01125         if (!reader.NextLine())
01126             break;
01127 
01128         //name,last_modification_date[,optionaldata]
01129         int parts = reader.ParseLine(values, lengths, 3);
01130         if (2 > parts)
01131             break;
01132 
01133         PRInt64 a = nsCRT::atoll(values[1]);
01134         AutoRegEntry *entry =
01135             new AutoRegEntry(nsDependentCString(values[0], lengths[0]), &a);
01136 
01137         if (!entry) {
01138             rv = NS_ERROR_OUT_OF_MEMORY;
01139             goto out;
01140         }
01141 
01142         if (parts == 3)
01143             entry->SetOptionalData(values[2]);
01144 
01145         nsCStringKey key((const char*)values[0]);
01146         mAutoRegEntries.Put(&key, entry);
01147     }
01148 
01149     if (ReadSectionHeader(reader, "CLASSIDS"))
01150         goto out;
01151 
01152     while (1)
01153     {
01154         if (!reader.NextLine())
01155             break;
01156 
01157         // cid,contract_id,type,class_name,inproc_server
01158         if (5 != reader.ParseLine(values, lengths, 5))
01159             break;
01160 
01161         nsCID aClass;
01162         if (!aClass.Parse(values[0]))
01163             continue;
01164 
01165         int loadertype = GetLoaderType(values[2]);
01166         if (loadertype < 0) {
01167             rv = AddLoaderType(values[2], &loadertype);
01168             if (NS_FAILED(rv))
01169                 continue;
01170         }
01171 
01172         void *mem;
01173         PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
01174         if (!mem) {
01175             rv = NS_ERROR_OUT_OF_MEMORY;
01176             goto out;
01177         }
01178 
01179         nsFactoryEntry *entry = new (mem) nsFactoryEntry(aClass, values[4], lengths[4], loadertype);
01180         if (!entry->mLocation) {
01181             rv = NS_ERROR_OUT_OF_MEMORY;
01182             goto out;
01183         }
01184 
01185         nsFactoryTableEntry* factoryTableEntry =
01186             NS_STATIC_CAST(nsFactoryTableEntry*,
01187                            PL_DHashTableOperate(&mFactories,
01188                                                 &aClass,
01189                                                 PL_DHASH_ADD));
01190 
01191         if (!factoryTableEntry) {
01192             rv = NS_ERROR_OUT_OF_MEMORY;
01193             goto out;
01194         }
01195 
01196         factoryTableEntry->mFactoryEntry = entry;
01197 
01198     }
01199 
01200     if (ReadSectionHeader(reader, "CONTRACTIDS"))
01201         goto out;
01202 
01203     while (1)
01204     {
01205         if (!reader.NextLine())
01206             break;
01207 
01208         //contractID,cid
01209         if (2 != reader.ParseLine(values, lengths, 2))
01210             break;
01211 
01212         nsCID aClass;
01213         if (!aClass.Parse(values[1]))
01214             continue;
01215 
01216 
01217         //need to find the location for this cid.
01218         nsFactoryEntry *cidEntry = GetFactoryEntry(aClass);
01219         if (!cidEntry || cidEntry->mTypeIndex < 0)
01220             continue; //what should we really do?
01221 
01222         nsContractIDTableEntry* contractIDTableEntry =
01223                 NS_STATIC_CAST(nsContractIDTableEntry*,
01224                                PL_DHashTableOperate(&mContractIDs,
01225                                                     values[0],
01226                                                     PL_DHASH_ADD));
01227         if (!contractIDTableEntry) {
01228             continue;
01229         }
01230 
01231         if (!contractIDTableEntry->mContractID) {
01232             char *contractID = ArenaStrndup(values[0], lengths[0], &mArena);
01233             if (!contractID) {
01234                 rv = NS_ERROR_OUT_OF_MEMORY;
01235                 goto out; 
01236             }
01237             contractIDTableEntry->mContractID = contractID;
01238             contractIDTableEntry->mContractIDLen = lengths[0];
01239         }
01240 
01241         contractIDTableEntry->mFactoryEntry = cidEntry;
01242     }
01243 
01244 #ifdef XPCOM_CHECK_PENDING_CIDS
01245     {
01246 /*
01247  * If you get Asserts when you define SHOW_CI_ON_EXISTING_SERVICE and want to
01248  * track down their cause, then you should add the contracts listed by the
01249  * assertion to abusedContracts. The next time you run your xpcom app, xpcom
01250  * will assert the first time the object associated with the contract is
01251  * instantiated (which in many cases is the source of the problem).
01252  *
01253  * If you're doing this then you might want to NOP and soft breakpoint the
01254  * lines labeled: NOP_AND_BREAK.
01255  *
01256  * Otherwise XPCOM will refuse to create the object for the caller, which
01257  * while reasonable at some level, will almost certainly cause the app to
01258  * stop functioning normally.
01259  */
01260         static char abusedContracts[][128] = {
01261         /*// Example contracts:
01262             "@mozilla.org/rdf/container;1",
01263             "@mozilla.org/intl/charsetalias;1",
01264             "@mozilla.org/locale/win32-locale;1",
01265             "@mozilla.org/widget/lookandfeel/win;1",
01266         // */
01267             0
01268         };
01269         for (int i=0; abusedContracts[i] && *abusedContracts[i]; i++) {
01270             nsFactoryEntry *entry = nsnull;
01271             nsContractIDTableEntry* contractIDTableEntry =
01272                 NS_STATIC_CAST(nsContractIDTableEntry*,
01273                                PL_DHashTableOperate(&mContractIDs, abusedContracts[i],
01274                                                     PL_DHASH_LOOKUP));
01275 
01276             if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
01277                 entry = contractIDTableEntry->mFactoryEntry;
01278                 AddPendingCID(entry->mCid);
01279             }
01280         }
01281     }
01282 #endif
01283 
01284     if (ReadSectionHeader(reader, "CATEGORIES"))
01285         goto out;
01286 
01287     mCategoryManager->SuppressNotifications(PR_TRUE);
01288 
01289     while (1)
01290     {
01291         if (!reader.NextLine())
01292             break;
01293 
01294         //type,name,value
01295         if (3 != reader.ParseLine(values, lengths, 3))
01296             break;
01297 
01298         mCategoryManager->AddCategoryEntry(values[0],
01299                                            values[1],
01300                                            values[2],
01301                                            PR_TRUE,
01302                                            PR_TRUE,
01303                                            0);
01304     }
01305 
01306     mCategoryManager->SuppressNotifications(PR_FALSE);
01307 
01308     mRegistryDirty = PR_FALSE;
01309 out:
01310     if (fd)
01311         PR_Close(fd);
01312 
01313     if (registry)
01314         delete [] registry;
01315 
01316     return rv;
01317 }
01318 
01319 struct PersistentWriterArgs
01320 {
01321     PRFileDesc *mFD;
01322     nsLoaderdata *mLoaderData;
01323 };
01324 
01325 PR_STATIC_CALLBACK(PLDHashOperator)
01326 ContractIDWriter(PLDHashTable *table,
01327                  PLDHashEntryHdr *hdr,
01328                  PRUint32 number,
01329                  void *arg)
01330 {
01331     char *contractID   = ((nsContractIDTableEntry*)hdr)->mContractID;
01332     nsFactoryEntry *factoryEntry = ((nsContractIDTableEntry*)hdr)->mFactoryEntry;
01333 
01334     // for now, we only save out the top most parent.
01335     while (factoryEntry->mParent)
01336         factoryEntry = factoryEntry->mParent;
01337 
01338     if (factoryEntry->mTypeIndex < 0)
01339         return PL_DHASH_NEXT;
01340 
01341     PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
01342 
01343     char cidString[UID_STRING_LENGTH];
01344     GetIDString(factoryEntry->mCid, cidString);
01345     PR_fprintf(fd, "%s,%s\n", contractID, cidString); // what if this fails?
01346     return PL_DHASH_NEXT;
01347 }
01348 
01349 PR_STATIC_CALLBACK(PLDHashOperator)
01350 ClassIDWriter(PLDHashTable *table,
01351               PLDHashEntryHdr *hdr,
01352               PRUint32 number,
01353               void *arg)
01354 {
01355     nsFactoryEntry *factoryEntry = ((nsFactoryTableEntry*)hdr)->mFactoryEntry;
01356     PRFileDesc* fd = ((PersistentWriterArgs*)arg)->mFD;
01357     nsLoaderdata *loaderData = ((PersistentWriterArgs*)arg)->mLoaderData;
01358 
01359     // for now, we only save out the top most parent.
01360     while (factoryEntry->mParent)
01361         factoryEntry = factoryEntry->mParent;
01362 
01363     if (factoryEntry->mTypeIndex < 0) {
01364         return PL_DHASH_NEXT;
01365     }
01366 
01367     char cidString[UID_STRING_LENGTH];
01368     GetIDString(factoryEntry->mCid, cidString);
01369 
01370     char *contractID = nsnull, *className = nsnull;
01371 
01372     nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(factoryEntry->mFactory);
01373     if (classInfo)
01374     {
01375         classInfo->GetContractID(&contractID);
01376         classInfo->GetClassDescription(&className);
01377     }
01378 
01379     const char * loaderName = nsnull;
01380     if (factoryEntry->mTypeIndex)
01381         loaderName = loaderData[factoryEntry->mTypeIndex].type;
01382 
01383     char* location = factoryEntry->mLocation;
01384 
01385     // cid,contract_id,type,class_name,inproc_server
01386     PR_fprintf(fd,
01387                "%s,%s,%s,%s,%s\n",
01388                cidString,
01389                (contractID ? contractID : ""),
01390                (loaderName ? loaderName : ""),
01391                (className  ? className  : ""),
01392                (location   ? location   : ""));
01393 
01394     if (contractID)
01395         PR_Free(contractID);
01396     if (className)
01397         PR_Free(className);
01398 
01399     return PL_DHASH_NEXT;
01400 }
01401 
01402 PRIntn PR_CALLBACK
01403 AutoRegEntryWriter(nsHashKey *aKey, void *aData, void* aClosure)
01404 {
01405     PRFileDesc* fd = (PRFileDesc*) aClosure;
01406     AutoRegEntry* entry = (AutoRegEntry*) aData;
01407 
01408     const char* extraData = entry->GetOptionalData();
01409     const char *fmt;
01410     if (extraData)
01411         fmt = "%s,%lld,%s\n";
01412     else
01413         fmt = "%s,%lld\n";
01414     PR_fprintf(fd, fmt, entry->GetName().get(), entry->GetDate(), extraData);
01415 
01416     return PR_TRUE;
01417 }
01418 
01419 nsresult
01420 nsComponentManagerImpl::WritePersistentRegistry()
01421 {
01422     if (!mRegistryFile)
01423         return NS_ERROR_FAILURE;  // this should have been set by Init().
01424 
01425     nsCOMPtr<nsIFile> file;
01426     mRegistryFile->Clone(getter_AddRefs(file));
01427     if (!file)
01428         return NS_ERROR_OUT_OF_MEMORY;
01429 
01430     nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(file));
01431 
01432     nsCAutoString originalLeafName;
01433     localFile->GetNativeLeafName(originalLeafName);
01434 
01435     nsCAutoString leafName;
01436     leafName.Assign(originalLeafName + NS_LITERAL_CSTRING(".tmp"));
01437 
01438     localFile->SetNativeLeafName(leafName);
01439 
01440     PRFileDesc* fd = nsnull;
01441     // Owner and group can setup components, everyone else should be able to see but not poison them.
01442     nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0664, &fd);
01443     if (NS_FAILED(rv))
01444         return rv;
01445 
01446     if (PR_fprintf(fd, "Generated File. Do not edit.\n") == (PRUint32) -1) {
01447         rv = NS_ERROR_UNEXPECTED;
01448         goto out;
01449     }
01450 
01451     if (PR_fprintf(fd, "\n[HEADER]\nVersion,%d,%d\n",
01452                    PERSISTENT_REGISTRY_VERSION_MAJOR,
01453                    PERSISTENT_REGISTRY_VERSION_MINOR) == (PRUint32) -1) {
01454         rv = NS_ERROR_UNEXPECTED;
01455         goto out;
01456     }
01457 
01458     if (PR_fprintf(fd, "\n[COMPONENTS]\n") == (PRUint32) -1) {
01459         rv = NS_ERROR_UNEXPECTED;
01460         goto out;
01461     }
01462 
01463     mAutoRegEntries.Enumerate(AutoRegEntryWriter, (void*)fd);
01464 
01465     PersistentWriterArgs args;
01466     args.mFD = fd;
01467     args.mLoaderData = mLoaderData;
01468 
01469     if (PR_fprintf(fd, "\n[CLASSIDS]\n") == (PRUint32) -1) {
01470         rv = NS_ERROR_UNEXPECTED;
01471         goto out;
01472     }
01473 
01474 
01475     PL_DHashTableEnumerate(&mFactories, ClassIDWriter, (void*)&args);
01476 
01477     if (PR_fprintf(fd, "\n[CONTRACTIDS]\n") == (PRUint32) -1) {
01478         rv = NS_ERROR_UNEXPECTED;
01479         goto out;
01480     }
01481 
01482 
01483     PL_DHashTableEnumerate(&mContractIDs, ContractIDWriter, (void*)&args);
01484 
01485     if (PR_fprintf(fd, "\n[CATEGORIES]\n") == (PRUint32) -1) {
01486         rv = NS_ERROR_UNEXPECTED;
01487         goto out;
01488     }
01489 
01490 
01491     if (!mCategoryManager) {
01492         NS_WARNING("Could not access category manager.  Will not be able to save categories!");
01493         rv = NS_ERROR_UNEXPECTED;
01494     } else {
01495         rv = mCategoryManager->WriteCategoryManagerToRegistry(fd);
01496     }
01497 
01498 out:
01499     if (fd)
01500         PR_Close(fd);
01501 
01502     // don't create the file is there was a problem????
01503     NS_ENSURE_SUCCESS(rv, rv);
01504 
01505     if (!mRegistryFile)
01506         return NS_ERROR_NOT_INITIALIZED;
01507 
01508     PRBool exists;
01509     if(NS_FAILED(mRegistryFile->Exists(&exists)))
01510         return PR_FALSE;
01511 
01512     if(exists && NS_FAILED(mRegistryFile->Remove(PR_FALSE)))
01513         return PR_FALSE;
01514 
01515     nsCOMPtr<nsIFile> parent;
01516     mRegistryFile->GetParent(getter_AddRefs(parent));
01517 
01518     rv = localFile->MoveToNative(parent, originalLeafName);
01519     mRegistryDirty = PR_FALSE;
01520 
01521     return rv;
01522 }
01523 
01524 
01526 // Hash Functions
01528 nsresult
01529 nsComponentManagerImpl::HashContractID(const char *aContractID,
01530                                        PRUint32 aContractIDLen,
01531                                        nsFactoryEntry *fe)
01532 {
01533     if(!aContractID || !aContractIDLen)
01534         return NS_ERROR_NULL_POINTER;
01535 
01536     nsAutoMonitor mon(mMon);
01537 
01538     nsContractIDTableEntry* contractIDTableEntry =
01539         NS_STATIC_CAST(nsContractIDTableEntry*,
01540                        PL_DHashTableOperate(&mContractIDs, aContractID,
01541                                             PL_DHASH_ADD));
01542     if (!contractIDTableEntry)
01543         return NS_ERROR_OUT_OF_MEMORY;
01544 
01545     NS_ASSERTION(!contractIDTableEntry->mContractID || !strcmp(contractIDTableEntry->mContractID, aContractID), "contractid conflict");
01546 
01547     if (!contractIDTableEntry->mContractID) {
01548         char *contractID = ArenaStrndup(aContractID, aContractIDLen, &mArena);
01549         if (!contractID)
01550             return NS_ERROR_OUT_OF_MEMORY;
01551 
01552         contractIDTableEntry->mContractID = contractID;
01553         contractIDTableEntry->mContractIDLen = aContractIDLen;
01554     }
01555 
01556     contractIDTableEntry->mFactoryEntry = fe;
01557 
01558     return NS_OK;
01559 }
01560 
01570 nsresult
01571 nsComponentManagerImpl::LoadFactory(nsFactoryEntry *aEntry,
01572                                     nsIFactory **aFactory)
01573 {
01574 
01575     if (!aFactory)
01576         return NS_ERROR_NULL_POINTER;
01577     *aFactory = nsnull;
01578 
01579     nsresult rv;
01580     rv = aEntry->GetFactory(aFactory, this);
01581     if (NS_FAILED(rv)) {
01582         PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
01583                ("nsComponentManager: FAILED to load factory from %s (%s)\n",
01584                 (const char *)aEntry->mLocation, mLoaderData[aEntry->mTypeIndex].type));
01585         return rv;
01586     }
01587 
01588     return NS_OK;
01589 }
01590 
01591 nsFactoryEntry *
01592 nsComponentManagerImpl::GetFactoryEntry(const char *aContractID,
01593                                         PRUint32 aContractIDLen)
01594 {
01595     nsFactoryEntry *fe = nsnull;
01596     {
01597         nsAutoMonitor mon(mMon);
01598 
01599         nsContractIDTableEntry* contractIDTableEntry =
01600             NS_STATIC_CAST(nsContractIDTableEntry*,
01601                            PL_DHashTableOperate(&mContractIDs, aContractID,
01602                                                 PL_DHASH_LOOKUP));
01603 
01604 
01605         if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
01606             fe = contractIDTableEntry->mFactoryEntry;
01607         }
01608     }   //exit monitor
01609 
01610     return fe;
01611 }
01612 
01613 
01614 nsFactoryEntry *
01615 nsComponentManagerImpl::GetFactoryEntry(const nsCID &aClass)
01616 {
01617     nsFactoryEntry *entry = nsnull;
01618     {
01619         nsAutoMonitor mon(mMon);
01620 
01621         nsFactoryTableEntry* factoryTableEntry =
01622             NS_STATIC_CAST(nsFactoryTableEntry*,
01623                            PL_DHashTableOperate(&mFactories, &aClass,
01624                                                 PL_DHASH_LOOKUP));
01625 
01626         if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
01627             entry = factoryTableEntry->mFactoryEntry;
01628         }
01629     }   // exit monitor
01630 
01631     return entry;
01632 }
01633 
01634 
01644 nsresult
01645 nsComponentManagerImpl::FindFactory(const nsCID &aClass,
01646                                     nsIFactory **aFactory)
01647 {
01648     PR_ASSERT(aFactory != nsnull);
01649 
01650     nsFactoryEntry *entry = GetFactoryEntry(aClass);
01651 
01652     if (!entry)
01653         return NS_ERROR_FACTORY_NOT_REGISTERED;
01654 
01655     return entry->GetFactory(aFactory, this);
01656 }
01657 
01658 
01659 nsresult
01660 nsComponentManagerImpl::FindFactory(const char *contractID,
01661                                     PRUint32 aContractIDLen,
01662                                     nsIFactory **aFactory)
01663 {
01664     PR_ASSERT(aFactory != nsnull);
01665 
01666     nsFactoryEntry *entry = GetFactoryEntry(contractID, aContractIDLen);
01667 
01668     if (!entry)
01669         return NS_ERROR_FACTORY_NOT_REGISTERED;
01670 
01671     return entry->GetFactory(aFactory, this);
01672 }
01673 
01680 nsresult
01681 nsComponentManagerImpl::GetClassObject(const nsCID &aClass, const nsIID &aIID,
01682                                        void **aResult)
01683 {
01684     nsresult rv;
01685 
01686     nsCOMPtr<nsIFactory> factory;
01687 
01688 #ifdef PR_LOGGING
01689     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
01690     {
01691         char *buf = aClass.ToString();
01692         PR_LogPrint("nsComponentManager: GetClassObject(%s)", buf);
01693         if (buf)
01694             PR_Free(buf);
01695     }
01696 #endif
01697 
01698     PR_ASSERT(aResult != nsnull);
01699 
01700     rv = FindFactory(aClass, getter_AddRefs(factory));
01701     if (NS_FAILED(rv)) return rv;
01702 
01703     rv = factory->QueryInterface(aIID, aResult);
01704 
01705     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
01706            ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
01707 
01708     return rv;
01709 }
01710 
01711 
01712 nsresult
01713 nsComponentManagerImpl::GetClassObjectByContractID(const char *contractID,
01714                                                    const nsIID &aIID,
01715                                                    void **aResult)
01716 {
01717     nsresult rv;
01718 
01719     nsCOMPtr<nsIFactory> factory;
01720 
01721 #ifdef PR_LOGGING
01722     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_DEBUG))
01723     {
01724         PR_LogPrint("nsComponentManager: GetClassObject(%s)", contractID);
01725     }
01726 #endif
01727 
01728     PR_ASSERT(aResult != nsnull);
01729 
01730     rv = FindFactory(contractID, strlen(contractID), getter_AddRefs(factory));
01731     if (NS_FAILED(rv)) return rv;
01732 
01733     rv = factory->QueryInterface(aIID, aResult);
01734 
01735     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
01736            ("\t\tGetClassObject() %s", NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
01737 
01738     return rv;
01739 }
01740 
01747 nsresult
01748 nsComponentManagerImpl::ContractIDToClassID(const char *aContractID, nsCID *aClass)
01749 {
01750     NS_PRECONDITION(aContractID != nsnull, "null ptr");
01751     if (!aContractID)
01752         return NS_ERROR_NULL_POINTER;
01753 
01754     NS_PRECONDITION(aClass != nsnull, "null ptr");
01755     if (!aClass)
01756         return NS_ERROR_NULL_POINTER;
01757 
01758     nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
01759 
01760     nsFactoryEntry *fe = GetFactoryEntry(aContractID, strlen(aContractID));
01761     if (fe) {
01762         *aClass = fe->mCid;
01763         rv = NS_OK;
01764     }
01765 #ifdef PR_LOGGING
01766     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING)) {
01767         char *buf = 0;
01768         if (NS_SUCCEEDED(rv))
01769             buf = aClass->ToString();
01770         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
01771                ("nsComponentManager: ContractIDToClassID(%s)->%s", aContractID,
01772                 NS_SUCCEEDED(rv) ? buf : "[FAILED]"));
01773         if (buf)
01774             PR_Free(buf);
01775     }
01776 #endif
01777     return rv;
01778 }
01779 
01788 nsresult
01789 nsComponentManagerImpl::CLSIDToContractID(const nsCID &aClass,
01790                                           char* *aClassName,
01791                                           char* *aContractID)
01792 {
01793     NS_WARNING("Need to implement CLSIDToContractID");
01794 
01795     nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
01796 #ifdef PR_LOGGING
01797     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
01798     {
01799         char *buf = aClass.ToString();
01800         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
01801                ("nsComponentManager: CLSIDToContractID(%s)->%s", buf,
01802                 NS_SUCCEEDED(rv) ? *aContractID : "[FAILED]"));
01803         if (buf)
01804             PR_Free(buf);
01805     }
01806 #endif
01807     return rv;
01808 }
01809 
01810 #ifdef XPCOM_CHECK_PENDING_CIDS
01811 
01812 // This method must be called from within the mMon monitor
01813 nsresult
01814 nsComponentManagerImpl::AddPendingCID(const nsCID &aClass)
01815 {
01816     int max = mPendingCIDs.Count();
01817     for (int index = 0; index < max; index++)
01818     {
01819         nsCID *cidp = (nsCID*) mPendingCIDs.ElementAt(index);
01820         NS_ASSERTION(cidp, "Bad CID in pending list");
01821         if (cidp->Equals(aClass)) {
01822             nsXPIDLCString cid;
01823             cid.Adopt(aClass.ToString());
01824             nsCAutoString message;
01825             message = NS_LITERAL_CSTRING("Creation of \"") +
01826                       cid + NS_LITERAL_CSTRING("\" in progress (Reentrant GS - see bug 194568)");
01827             // Note that you may see this assertion by near-simultaneous
01828             // calls to GetService on multiple threads.
01829             NS_WARNING(message.get());
01830             return NS_ERROR_NOT_AVAILABLE;
01831         }
01832     }
01833     mPendingCIDs.AppendElement((void*)&aClass);
01834     return NS_OK;
01835 }
01836 
01837 // This method must be called from within the mMon monitor
01838 void
01839 nsComponentManagerImpl::RemovePendingCID(const nsCID &aClass)
01840 {
01841     mPendingCIDs.RemoveElement((void*)&aClass);
01842 }
01843 #endif
01844 
01851 nsresult
01852 nsComponentManagerImpl::CreateInstance(const nsCID &aClass,
01853                                        nsISupports *aDelegate,
01854                                        const nsIID &aIID,
01855                                        void **aResult)
01856 {
01857     // test this first, since there's no point in creating a component during
01858     // shutdown -- whether it's available or not would depend on the order it
01859     // occurs in the list
01860     if (gXPCOMShuttingDown) {
01861         // When processing shutdown, dont process new GetService() requests
01862 #ifdef SHOW_DENIED_ON_SHUTDOWN
01863         nsXPIDLCString cid, iid;
01864         cid.Adopt(aClass.ToString());
01865         iid.Adopt(aIID.ToString());
01866         fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
01867                "         CID: %s\n         IID: %s\n", cid.get(), iid.get());
01868 #endif /* SHOW_DENIED_ON_SHUTDOWN */
01869         return NS_ERROR_UNEXPECTED;
01870     }
01871 
01872     if (aResult == nsnull)
01873     {
01874         return NS_ERROR_NULL_POINTER;
01875     }
01876     *aResult = nsnull;
01877 
01878     nsFactoryEntry *entry = GetFactoryEntry(aClass);
01879 
01880     if (!entry)
01881         return NS_ERROR_FACTORY_NOT_REGISTERED;
01882 
01883 #ifdef SHOW_CI_ON_EXISTING_SERVICE
01884     if (entry->mServiceObject) {
01885         nsXPIDLCString cid;
01886         cid.Adopt(aClass.ToString());
01887         nsCAutoString message;
01888         message = NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
01889                   cid + NS_LITERAL_CSTRING("\" when a service for this CID already exists!");
01890         NS_ERROR(message.get());
01891     }
01892 #endif
01893 
01894     nsIFactory *factory = nsnull;
01895     nsresult rv = entry->GetFactory(&factory, this);
01896 
01897     if (NS_SUCCEEDED(rv))
01898     {
01899         rv = factory->CreateInstance(aDelegate, aIID, aResult);
01900         NS_RELEASE(factory);
01901     }
01902     else
01903     {
01904         // Translate error values
01905         rv = NS_ERROR_FACTORY_NOT_REGISTERED;
01906     }
01907 
01908 #ifdef PR_LOGGING
01909     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
01910     {
01911         char *buf = aClass.ToString();
01912         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
01913                ("nsComponentManager: CreateInstance(%s) %s", buf,
01914                 NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
01915         if (buf)
01916             PR_Free(buf);
01917     }
01918 #endif
01919 
01920     return rv;
01921 }
01922 
01932 nsresult
01933 nsComponentManagerImpl::CreateInstanceByContractID(const char *aContractID,
01934                                                    nsISupports *aDelegate,
01935                                                    const nsIID &aIID,
01936                                                    void **aResult)
01937 {
01938     // test this first, since there's no point in creating a component during
01939     // shutdown -- whether it's available or not would depend on the order it
01940     // occurs in the list
01941     if (gXPCOMShuttingDown) {
01942         // When processing shutdown, dont process new GetService() requests
01943 #ifdef SHOW_DENIED_ON_SHUTDOWN
01944         nsXPIDLCString iid;
01945         iid.Adopt(aIID.ToString());
01946         fprintf(stderr, "Creating new instance on shutdown. Denied.\n"
01947                "  ContractID: %s\n         IID: %s\n", aContractID, iid.get());
01948 #endif /* SHOW_DENIED_ON_SHUTDOWN */
01949         return NS_ERROR_UNEXPECTED;
01950     }
01951 
01952     if (aResult == nsnull)
01953     {
01954         return NS_ERROR_NULL_POINTER;
01955     }
01956     *aResult = nsnull;
01957 
01958     nsFactoryEntry *entry = GetFactoryEntry(aContractID, strlen(aContractID));
01959 
01960     if (!entry)
01961         return NS_ERROR_FACTORY_NOT_REGISTERED;
01962 
01963 #ifdef SHOW_CI_ON_EXISTING_SERVICE
01964     if (entry->mServiceObject) {
01965         nsCAutoString message;
01966         message =
01967           NS_LITERAL_CSTRING("You are calling CreateInstance \"") +
01968           nsDependentCString(aContractID) +
01969           NS_LITERAL_CSTRING("\" when a service for this CID already exists! "
01970             "Add it to abusedContracts to track down the service consumer.");
01971         NS_ERROR(message.get());
01972     }
01973 #endif
01974 
01975     nsIFactory *factory = nsnull;
01976     nsresult rv = entry->GetFactory(&factory, this);
01977 
01978     if (NS_SUCCEEDED(rv))
01979     {
01980 
01981         rv = factory->CreateInstance(aDelegate, aIID, aResult);
01982         NS_RELEASE(factory);
01983     }
01984     else
01985     {
01986         // Translate error values
01987         rv = NS_ERROR_FACTORY_NOT_REGISTERED;
01988     }
01989 
01990     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
01991            ("nsComponentManager: CreateInstanceByContractID(%s) %s", aContractID,
01992             NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
01993 
01994     return rv;
01995 }
01996 
01997 // Service Manager Impl
01998 static
01999 PLDHashOperator PR_CALLBACK
02000 FreeServiceFactoryEntryEnumerate(PLDHashTable *aTable,
02001                                  PLDHashEntryHdr *aHdr,
02002                                  PRUint32 aNumber,
02003                                  void *aData)
02004 {
02005     nsFactoryTableEntry* entry = NS_STATIC_CAST(nsFactoryTableEntry*, aHdr);
02006 
02007     if (!entry->mFactoryEntry)
02008         return PL_DHASH_NEXT;
02009 
02010     nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
02011     factoryEntry->mServiceObject = nsnull;
02012     return PL_DHASH_NEXT;
02013 }
02014 
02015 static
02016 PLDHashOperator PR_CALLBACK
02017 FreeServiceContractIDEntryEnumerate(PLDHashTable *aTable,
02018                                     PLDHashEntryHdr *aHdr,
02019                                     PRUint32 aNumber,
02020                                     void *aData)
02021 {
02022     nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
02023 
02024     if (!entry->mFactoryEntry)
02025         return PL_DHASH_NEXT;
02026 
02027     nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
02028     factoryEntry->mServiceObject = nsnull;
02029     return PL_DHASH_NEXT;
02030 }
02031 
02032 nsresult
02033 nsComponentManagerImpl::FreeServices()
02034 {
02035     NS_ASSERTION(gXPCOMShuttingDown, "Must be shutting down in order to free all services");
02036 
02037     if (!gXPCOMShuttingDown)
02038         return NS_ERROR_FAILURE;
02039 
02040     if (mContractIDs.ops) {
02041         PL_DHashTableEnumerate(&mContractIDs, FreeServiceContractIDEntryEnumerate, nsnull);
02042     }
02043 
02044 
02045     if (mFactories.ops) {
02046         PL_DHashTableEnumerate(&mFactories, FreeServiceFactoryEntryEnumerate, nsnull);
02047     }
02048 
02049     return NS_OK;
02050 }
02051 
02052 NS_IMETHODIMP
02053 nsComponentManagerImpl::GetService(const nsCID& aClass,
02054                                    const nsIID& aIID,
02055                                    void* *result)
02056 {
02057     // test this first, since there's no point in returning a service during
02058     // shutdown -- whether it's available or not would depend on the order it
02059     // occurs in the list
02060     if (gXPCOMShuttingDown) {
02061         // When processing shutdown, dont process new GetService() requests
02062 #ifdef SHOW_DENIED_ON_SHUTDOWN
02063         nsXPIDLCString cid, iid;
02064         cid.Adopt(aClass.ToString());
02065         iid.Adopt(aIID.ToString());
02066         fprintf(stderr, "Getting service on shutdown. Denied.\n"
02067                "         CID: %s\n         IID: %s\n", cid.get(), iid.get());
02068 #endif /* SHOW_DENIED_ON_SHUTDOWN */
02069         return NS_ERROR_UNEXPECTED;
02070     }
02071 
02072     nsAutoMonitor mon(mMon);
02073 
02074     nsresult rv = NS_OK;
02075     nsIDKey key(aClass);
02076     nsFactoryEntry* entry = nsnull;
02077     nsFactoryTableEntry* factoryTableEntry =
02078         NS_STATIC_CAST(nsFactoryTableEntry*,
02079                        PL_DHashTableOperate(&mFactories, &aClass,
02080                                             PL_DHASH_LOOKUP));
02081 
02082     if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
02083         entry = factoryTableEntry->mFactoryEntry;
02084     }
02085 
02086     if (entry && entry->mServiceObject) {
02087         nsCOMPtr<nsISupports> supports = entry->mServiceObject;
02088         mon.Exit();
02089         return supports->QueryInterface(aIID, result);
02090     }
02091 
02092 #ifdef XPCOM_CHECK_PENDING_CIDS
02093     rv = AddPendingCID(aClass);
02094     if (NS_FAILED(rv))
02095         return rv; // NOP_AND_BREAK
02096 #endif
02097     nsCOMPtr<nsISupports> service;
02098     // We need to not be holding the service manager's monitor while calling
02099     // CreateInstance, because it invokes user code which could try to re-enter
02100     // the service manager:
02101     mon.Exit();
02102 
02103     rv = CreateInstance(aClass, nsnull, aIID, getter_AddRefs(service));
02104 
02105     mon.Enter();
02106 
02107 #ifdef XPCOM_CHECK_PENDING_CIDS
02108     RemovePendingCID(aClass);
02109 #endif
02110 
02111     if (NS_FAILED(rv))
02112         return rv;
02113 
02114     if (!entry) { // second hash lookup for GetService
02115         nsFactoryTableEntry* factoryTableEntry =
02116             NS_STATIC_CAST(nsFactoryTableEntry*,
02117                            PL_DHashTableOperate(&mFactories, &aClass,
02118                                                 PL_DHASH_LOOKUP));
02119         if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
02120             entry = factoryTableEntry->mFactoryEntry;
02121         }
02122         NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
02123         if (!entry) return NS_ERROR_FAILURE;
02124     }
02125 
02126     entry->mServiceObject = service;
02127     *result = service.get();
02128     NS_ADDREF(NS_STATIC_CAST(nsISupports*, (*result)));
02129     return rv;
02130 }
02131 
02132 NS_IMETHODIMP
02133 nsComponentManagerImpl::RegisterService(const nsCID& aClass, nsISupports* aService)
02134 {
02135     nsAutoMonitor mon(mMon);
02136 
02137     // check to see if we have a factory entry for the service
02138     nsFactoryEntry *entry = GetFactoryEntry(aClass);
02139 
02140     if (!entry) { // XXXdougt - should we require that all services register factories??  probably not.
02141         void *mem;
02142         PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
02143         if (!mem)
02144             return NS_ERROR_OUT_OF_MEMORY;
02145         entry = new (mem) nsFactoryEntry(aClass, nsnull);
02146 
02147         entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
02148         nsFactoryTableEntry* factoryTableEntry =
02149             NS_STATIC_CAST(nsFactoryTableEntry*,
02150                            PL_DHashTableOperate(&mFactories, &aClass,
02151                                                 PL_DHASH_ADD));
02152         if (!factoryTableEntry)
02153             return NS_ERROR_OUT_OF_MEMORY;
02154 
02155         factoryTableEntry->mFactoryEntry = entry;
02156     }
02157     else {
02158         if (entry->mServiceObject)
02159             return NS_ERROR_FAILURE;
02160     }
02161 
02162     entry->mServiceObject = aService;
02163     return NS_OK;
02164 }
02165 
02166 NS_IMETHODIMP
02167 nsComponentManagerImpl::UnregisterService(const nsCID& aClass)
02168 {
02169     nsresult rv = NS_OK;
02170 
02171     nsFactoryEntry* entry = nsnull;
02172 
02173     nsAutoMonitor mon(mMon);
02174 
02175     nsFactoryTableEntry* factoryTableEntry =
02176         NS_STATIC_CAST(nsFactoryTableEntry*,
02177                        PL_DHashTableOperate(&mFactories, &aClass,
02178                                             PL_DHASH_LOOKUP));
02179 
02180     if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
02181         entry = factoryTableEntry->mFactoryEntry;
02182     }
02183 
02184     if (!entry || !entry->mServiceObject)
02185         return NS_ERROR_SERVICE_NOT_AVAILABLE;
02186 
02187     entry->mServiceObject = nsnull;
02188     return rv;
02189 }
02190 
02191 NS_IMETHODIMP
02192 nsComponentManagerImpl::RegisterService(const char* aContractID, nsISupports* aService)
02193 {
02194 
02195     nsAutoMonitor mon(mMon);
02196 
02197     // check to see if we have a factory entry for the service
02198     PRUint32 contractIDLen = strlen(aContractID);
02199     nsFactoryEntry *entry = GetFactoryEntry(aContractID, contractIDLen);
02200 
02201     if (!entry) { // XXXdougt - should we require that all services register factories??  probably not.
02202         void *mem;
02203         PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
02204         if (!mem)
02205             return NS_ERROR_OUT_OF_MEMORY;
02206         entry = new (mem) nsFactoryEntry(kEmptyCID, nsnull);
02207 
02208         entry->mTypeIndex = NS_COMPONENT_TYPE_SERVICE_ONLY;
02209 
02210         nsContractIDTableEntry* contractIDTableEntry =
02211             NS_STATIC_CAST(nsContractIDTableEntry*,
02212                            PL_DHashTableOperate(&mContractIDs, aContractID,
02213                                                 PL_DHASH_ADD));
02214         if (!contractIDTableEntry) {
02215             delete entry;
02216             return NS_ERROR_OUT_OF_MEMORY;
02217         }
02218 
02219         if (!contractIDTableEntry->mContractID) {
02220             char *contractID = ArenaStrndup(aContractID, contractIDLen, &mArena);
02221             if (!contractID)
02222                 return NS_ERROR_OUT_OF_MEMORY;
02223 
02224             contractIDTableEntry->mContractID = contractID;
02225             contractIDTableEntry->mContractIDLen = contractIDLen;
02226         }
02227 
02228         contractIDTableEntry->mFactoryEntry = entry;
02229     }
02230     else {
02231         if (entry->mServiceObject)
02232             return NS_ERROR_FAILURE;
02233     }
02234 
02235     entry->mServiceObject = aService;
02236     return NS_OK;
02237 }
02238 
02239 
02240 NS_IMETHODIMP
02241 nsComponentManagerImpl::IsServiceInstantiated(const nsCID & aClass,
02242                                               const nsIID& aIID,
02243                                               PRBool *result)
02244 {
02245     // Now we want to get the service if we already got it. If not, we dont want
02246     // to create an instance of it. mmh!
02247 
02248     // test this first, since there's no point in returning a service during
02249     // shutdown -- whether it's available or not would depend on the order it
02250     // occurs in the list
02251     if (gXPCOMShuttingDown) {
02252         // When processing shutdown, dont process new GetService() requests
02253 #ifdef SHOW_DENIED_ON_SHUTDOWN
02254         nsXPIDLCString cid, iid;
02255         cid.Adopt(aClass.ToString());
02256         iid.Adopt(aIID.ToString());
02257         fprintf(stderr, "Checking for service on shutdown. Denied.\n"
02258                "         CID: %s\n         IID: %s\n", cid.get(), iid.get());
02259 #endif /* SHOW_DENIED_ON_SHUTDOWN */
02260         return NS_ERROR_UNEXPECTED;
02261     }
02262 
02263     nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
02264     nsFactoryEntry* entry = nsnull;
02265     nsFactoryTableEntry* factoryTableEntry =
02266         NS_STATIC_CAST(nsFactoryTableEntry*,
02267                        PL_DHashTableOperate(&mFactories, &aClass,
02268                                             PL_DHASH_LOOKUP));
02269 
02270     if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
02271         entry = factoryTableEntry->mFactoryEntry;
02272     }
02273 
02274     if (entry && entry->mServiceObject) {
02275         nsCOMPtr<nsISupports> service;
02276         rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
02277         *result = (service!=nsnull);
02278     }
02279     return rv;
02280 
02281 }
02282 
02283 NS_IMETHODIMP nsComponentManagerImpl::IsServiceInstantiatedByContractID(const char *aContractID,
02284                                                                         const nsIID& aIID,
02285                                                                         PRBool *result)
02286 {
02287     // Now we want to get the service if we already got it. If not, we dont want
02288     // to create an instance of it. mmh!
02289 
02290     // test this first, since there's no point in returning a service during
02291     // shutdown -- whether it's available or not would depend on the order it
02292     // occurs in the list
02293     if (gXPCOMShuttingDown) {
02294         // When processing shutdown, dont process new GetService() requests
02295 #ifdef SHOW_DENIED_ON_SHUTDOWN
02296         nsXPIDLCString iid;
02297         iid.Adopt(aIID.ToString());
02298         fprintf(stderr, "Checking for service on shutdown. Denied.\n"
02299                "  ContractID: %s\n         IID: %s\n", aContractID, iid.get());
02300 #endif /* SHOW_DENIED_ON_SHUTDOWN */
02301         return NS_ERROR_UNEXPECTED;
02302     }
02303 
02304     nsresult rv = NS_ERROR_SERVICE_NOT_AVAILABLE;
02305     nsFactoryEntry *entry = nsnull;
02306     {
02307         nsAutoMonitor mon(mMon);
02308 
02309         nsContractIDTableEntry* contractIDTableEntry =
02310             NS_STATIC_CAST(nsContractIDTableEntry*,
02311                            PL_DHashTableOperate(&mContractIDs, aContractID,
02312                                                 PL_DHASH_LOOKUP));
02313 
02314         if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
02315             entry = contractIDTableEntry->mFactoryEntry;
02316         }
02317     }   // exit monitor
02318 
02319     if (entry && entry->mServiceObject) {
02320         nsCOMPtr<nsISupports> service;
02321         rv = entry->mServiceObject->QueryInterface(aIID, getter_AddRefs(service));
02322         *result = (service!=nsnull);
02323     }
02324     return rv;
02325 }
02326 
02327 
02328 NS_IMETHODIMP
02329 nsComponentManagerImpl::UnregisterService(const char* aContractID)
02330 {
02331     nsresult rv = NS_OK;
02332 
02333     nsAutoMonitor mon(mMon);
02334 
02335     nsFactoryEntry *entry = nsnull;
02336     nsContractIDTableEntry* contractIDTableEntry =
02337        NS_STATIC_CAST(nsContractIDTableEntry*,
02338                       PL_DHashTableOperate(&mContractIDs, aContractID,
02339                                            PL_DHASH_LOOKUP));
02340 
02341    if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
02342        entry = contractIDTableEntry->mFactoryEntry;
02343    }
02344 
02345    if (!entry || !entry->mServiceObject)
02346         return NS_ERROR_SERVICE_NOT_AVAILABLE;
02347 
02348    entry->mServiceObject = nsnull;
02349    return rv;
02350 }
02351 
02352 NS_IMETHODIMP
02353 nsComponentManagerImpl::GetServiceByContractID(const char* aContractID,
02354                                                const nsIID& aIID,
02355                                                void* *result)
02356 {
02357     // test this first, since there's no point in returning a service during
02358     // shutdown -- whether it's available or not would depend on the order it
02359     // occurs in the list
02360     if (gXPCOMShuttingDown) {
02361         // When processing shutdown, dont process new GetService() requests
02362 #ifdef SHOW_DENIED_ON_SHUTDOWN
02363         nsXPIDLCString iid;
02364         iid.Adopt(aIID.ToString());
02365         fprintf(stderr, "Getting service on shutdown. Denied.\n"
02366                "  ContractID: %s\n         IID: %s\n", aContractID, iid.get());
02367 #endif /* SHOW_DENIED_ON_SHUTDOWN */
02368         return NS_ERROR_UNEXPECTED;
02369     }
02370 
02371     nsAutoMonitor mon(mMon);
02372 
02373     nsresult rv = NS_OK;
02374     nsFactoryEntry *entry = nsnull;
02375     nsContractIDTableEntry* contractIDTableEntry =
02376         NS_STATIC_CAST(nsContractIDTableEntry*,
02377                        PL_DHashTableOperate(&mContractIDs, aContractID,
02378                                             PL_DHASH_LOOKUP));
02379 
02380     if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
02381         entry = contractIDTableEntry->mFactoryEntry;
02382     }
02383 
02384     if (entry) {
02385         if (entry->mServiceObject) {
02386             nsCOMPtr<nsISupports> serviceObject = entry->mServiceObject;
02387 
02388             // We need to not be holding the service manager's monitor while calling
02389             // QueryInterface, because it invokes user code which could try to re-enter
02390             // the service manager, or try to grab some other lock/monitor/condvar
02391             // and deadlock, e.g. bug 282743.
02392             mon.Exit();
02393             return serviceObject->QueryInterface(aIID, result);
02394         }
02395 #ifdef XPCOM_CHECK_PENDING_CIDS
02396         rv = AddPendingCID(entry->mCid);
02397         if (NS_FAILED(rv))
02398             return rv; // NOP_AND_BREAK
02399 #endif
02400     }
02401 
02402     nsCOMPtr<nsISupports> service;
02403     // We need to not be holding the service manager's monitor while calling
02404     // CreateInstance, because it invokes user code which could try to re-enter
02405     // the service manager:
02406     mon.Exit();
02407 
02408     rv = CreateInstanceByContractID(aContractID, nsnull, aIID, getter_AddRefs(service));
02409 
02410     mon.Enter();
02411 
02412 #ifdef XPCOM_CHECK_PENDING_CIDS 
02413     if (entry)
02414         RemovePendingCID(entry->mCid);
02415 #endif
02416 
02417     if (NS_FAILED(rv))
02418         return rv;
02419 
02420     if (!entry) { // second hash lookup for GetService
02421         nsContractIDTableEntry* contractIDTableEntry =
02422             NS_STATIC_CAST(nsContractIDTableEntry*,
02423                            PL_DHashTableOperate(&mContractIDs, aContractID,
02424                                                 PL_DHASH_LOOKUP));
02425 
02426         if (PL_DHASH_ENTRY_IS_BUSY(contractIDTableEntry)) {
02427             entry = contractIDTableEntry->mFactoryEntry;
02428         }
02429         NS_ASSERTION(entry, "we should have a factory entry since CI succeeded - we should not get here");
02430         if (!entry) return NS_ERROR_FAILURE;
02431     }
02432 
02433     entry->mServiceObject = service;
02434     *result = service.get();
02435     NS_ADDREF(NS_STATIC_CAST(nsISupports*, *result));
02436     return rv;
02437 }
02438 
02439 NS_IMETHODIMP
02440 nsComponentManagerImpl::GetService(const nsCID& aClass, const nsIID& aIID,
02441                                      nsISupports* *result,
02442                                      nsIShutdownListener* shutdownListener)
02443 {
02444     return GetService(aClass, aIID, (void**)result);
02445 }
02446 
02447 NS_IMETHODIMP
02448 nsComponentManagerImpl::GetService(const char* aContractID, const nsIID& aIID,
02449                                      nsISupports* *result,
02450                                      nsIShutdownListener* shutdownListener)
02451 {
02452     return GetServiceByContractID(aContractID, aIID, (void**)result);
02453 }
02454 
02455 
02456 NS_IMETHODIMP
02457 nsComponentManagerImpl::ReleaseService(const nsCID& aClass, nsISupports* service,
02458                                          nsIShutdownListener* shutdownListener)
02459 {
02460     NS_IF_RELEASE(service);
02461     return NS_OK;
02462 }
02463 
02464 NS_IMETHODIMP
02465 nsComponentManagerImpl::ReleaseService(const char* aContractID, nsISupports* service,
02466                                        nsIShutdownListener* shutdownListener)
02467 {
02468     NS_IF_RELEASE(service);
02469     return NS_OK;
02470 }
02471 
02472 /*
02473  * I want an efficient way to allocate a buffer to the right size
02474  * and stick the prefix and dllName in, then be able to hand that buffer
02475  * off to the FactoryEntry.  Is that so wrong?
02476  *
02477  * *regName is allocated on success.
02478  *
02479  * This should live in nsNativeComponentLoader.cpp, I think.
02480  */
02481 static nsresult
02482 MakeRegistryName(const char *aDllName, const char *prefix, char **regName)
02483 {
02484     char *registryName;
02485 
02486     PRUint32 len = strlen(prefix);
02487 
02488     PRUint32 registryNameLen = strlen(aDllName) + len;
02489     registryName = (char *)nsMemory::Alloc(registryNameLen + 1);
02490 
02491     // from here on it, we want len sans terminating NUL
02492 
02493     if (!registryName)
02494         return NS_ERROR_OUT_OF_MEMORY;
02495 
02496     memcpy(registryName, prefix, len);
02497     strcpy(registryName + len, aDllName);
02498     registryName[registryNameLen] = '\0';
02499     *regName = registryName;
02500 
02501 #ifdef DEBUG_shaver_off
02502     fprintf(stderr, "MakeRegistryName(%s, %s, &[%s])\n",
02503             aDllName, prefix, *regName);
02504 #endif
02505 
02506     return NS_OK;
02507 }
02508 
02509 nsresult
02510 nsComponentManagerImpl::RegistryLocationForSpec(nsIFile *aSpec,
02511                                                 char **aRegistryName)
02512 {
02513     nsresult rv;
02514 
02515     if (!mComponentsDir)
02516         return NS_ERROR_NOT_INITIALIZED;
02517 
02518     if (!aSpec) {
02519         *aRegistryName = PL_strdup("");
02520         return NS_OK;
02521     }
02522 
02523 
02524     // First check to see if this component is in the application
02525     // components directory
02526     PRBool containedIn;
02527     mComponentsDir->Contains(aSpec, PR_TRUE, &containedIn);
02528 
02529     nsCAutoString nativePathString;
02530 
02531     if (containedIn){
02532         rv = aSpec->GetNativePath(nativePathString);
02533         if (NS_FAILED(rv))
02534             return rv;
02535 
02536         const char* relativeLocation = nativePathString.get() + mComponentsOffset + 1;
02537         return MakeRegistryName(relativeLocation, XPCOM_RELCOMPONENT_PREFIX, aRegistryName);
02538     }
02539 
02540     // Next check to see if this component is in the GRE
02541     // components directory
02542 
02543     mGREComponentsDir->Contains(aSpec, PR_TRUE, &containedIn);
02544 
02545     if (containedIn){
02546         rv = aSpec->GetNativePath(nativePathString);
02547         if (NS_FAILED(rv))
02548             return rv;
02549 
02550         const char* relativeLocation = nativePathString.get() + mGREComponentsOffset + 1;
02551         return MakeRegistryName(relativeLocation, XPCOM_GRECOMPONENT_PREFIX, aRegistryName);
02552     }
02553 
02554     /* absolute names include volume info on Mac, so persistent descriptor */
02555     rv = aSpec->GetNativePath(nativePathString);
02556     if (NS_FAILED(rv))
02557         return rv;
02558     return MakeRegistryName(nativePathString.get(), XPCOM_ABSCOMPONENT_PREFIX, aRegistryName);
02559 }
02560 
02561 nsresult
02562 nsComponentManagerImpl::SpecForRegistryLocation(const char *aLocation,
02563                                                 nsIFile **aSpec)
02564 {
02565     // i18n: assuming aLocation is encoded for the current locale
02566 
02567     nsresult rv;
02568     if (!aLocation || !aSpec)
02569         return NS_ERROR_NULL_POINTER;
02570 
02571     /* abs:/full/path/to/libcomponent.so */
02572     if (!strncmp(aLocation, XPCOM_ABSCOMPONENT_PREFIX, 4)) {
02573 
02574         nsLocalFile* file = new nsLocalFile;
02575         if (!file) return NS_ERROR_FAILURE;
02576 
02577         rv = file->InitWithNativePath(nsDependentCString((char *)aLocation + 4));
02578         file->QueryInterface(NS_GET_IID(nsILocalFile), (void**)aSpec);
02579         return rv;
02580     }
02581 
02582     if (!strncmp(aLocation, XPCOM_RELCOMPONENT_PREFIX, 4)) {
02583 
02584         if (!mComponentsDir)
02585             return NS_ERROR_NOT_INITIALIZED;
02586 
02587         nsILocalFile* file = nsnull;
02588         rv = mComponentsDir->Clone((nsIFile**)&file);
02589 
02590         if (NS_FAILED(rv)) return rv;
02591 
02592         rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4));
02593         *aSpec = file;
02594         return rv;
02595     }
02596 
02597     if (!strncmp(aLocation, XPCOM_GRECOMPONENT_PREFIX, 4)) {
02598 
02599         if (!mGREComponentsDir)
02600             return NS_ERROR_NOT_INITIALIZED;
02601 
02602         nsILocalFile* file = nsnull;
02603         rv = mGREComponentsDir->Clone((nsIFile**)&file);
02604 
02605         if (NS_FAILED(rv)) return rv;
02606 
02607         rv = file->AppendRelativeNativePath(nsDependentCString(aLocation + 4));
02608         *aSpec = file;
02609         return rv;
02610     }
02611 
02612     *aSpec = nsnull;
02613     return NS_ERROR_INVALID_ARG;
02614 }
02615 
02632 nsresult
02633 nsComponentManagerImpl::RegisterFactory(const nsCID &aClass,
02634                                         const char *aClassName,
02635                                         const char *aContractID,
02636                                         nsIFactory *aFactory,
02637                                         PRBool aReplace)
02638 {
02639     nsAutoMonitor mon(mMon);
02640 #ifdef PR_LOGGING
02641     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
02642     {
02643         char *buf = aClass.ToString();
02644         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
02645                ("nsComponentManager: RegisterFactory(%s, %s)", buf,
02646                 (aContractID ? aContractID : "(null)")));
02647         if (buf)
02648             PR_Free(buf);
02649     }
02650 #endif
02651     nsFactoryEntry *entry = nsnull;
02652     nsFactoryTableEntry* factoryTableEntry = NS_STATIC_CAST(nsFactoryTableEntry*,
02653                                                             PL_DHashTableOperate(&mFactories,
02654                                                                                  &aClass,
02655                                                                                  PL_DHASH_ADD));
02656 
02657     if (!factoryTableEntry)
02658         return NS_ERROR_OUT_OF_MEMORY;
02659 
02660 
02661     if (PL_DHASH_ENTRY_IS_BUSY(factoryTableEntry)) {
02662         entry = factoryTableEntry->mFactoryEntry;
02663     }
02664 
02665     if (entry && !aReplace)
02666     {
02667         // Already registered
02668         PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
02669                ("\t\tFactory already registered."));
02670         return NS_ERROR_FACTORY_EXISTS;
02671     }
02672 
02673     void *mem;
02674     PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
02675     if (!mem)
02676         return NS_ERROR_OUT_OF_MEMORY;
02677 
02678     entry = new (mem) nsFactoryEntry(aClass, aFactory, entry);
02679 
02680     factoryTableEntry->mFactoryEntry = entry;
02681 
02682     // Update the ContractID->CLSID Map
02683     if (aContractID) {
02684         nsresult rv = HashContractID(aContractID, strlen(aContractID), entry);
02685         if (NS_FAILED(rv)) {
02686             PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
02687                    ("\t\tFactory register succeeded. "
02688                     "Hashing contractid (%s) FAILED.", aContractID));
02689             return rv;
02690         }
02691     }
02692 
02693     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
02694            ("\t\tFactory register succeeded contractid=%s.",
02695             aContractID ? aContractID : "<none>"));
02696 
02697     return NS_OK;
02698 }
02699 
02700 nsresult
02701 nsComponentManagerImpl::RegisterComponent(const nsCID &aClass,
02702                                           const char *aClassName,
02703                                           const char *aContractID,
02704                                           const char *aPersistentDescriptor,
02705                                           PRBool aReplace,
02706                                           PRBool aPersist)
02707 {
02708     return RegisterComponentCommon(aClass, aClassName,
02709                                    aContractID,
02710                                    aContractID ? strlen(aContractID) : 0,
02711                                    aPersistentDescriptor,
02712                                    aPersistentDescriptor ?
02713                                    strlen(aPersistentDescriptor) : 0,
02714                                    aReplace, aPersist,
02715                                    nativeComponentType);
02716 }
02717 
02718 nsresult
02719 nsComponentManagerImpl::RegisterComponentWithType(const nsCID &aClass,
02720                                                   const char *aClassName,
02721                                                   const char *aContractID,
02722                                                   nsIFile *aSpec,
02723                                                   const char *aLocation,
02724                                                   PRBool aReplace,
02725                                                   PRBool aPersist,
02726                                                   const char *aType)
02727 {
02728     return RegisterComponentCommon(aClass, aClassName,
02729                                    aContractID,
02730                                    aContractID ? strlen(aContractID) : 0,
02731                                    aLocation,
02732                                    aLocation ? strlen(aLocation) : 0,
02733                                    aReplace, aPersist,
02734                                    aType);
02735 }
02736 
02737 /*
02738  * Register a component, using whatever they stuck in the nsIFile.
02739  */
02740 nsresult
02741 nsComponentManagerImpl::RegisterComponentSpec(const nsCID &aClass,
02742                                               const char *aClassName,
02743                                               const char *aContractID,
02744                                               nsIFile *aLibrarySpec,
02745                                               PRBool aReplace,
02746                                               PRBool aPersist)
02747 {
02748     nsXPIDLCString registryName;
02749     nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName));
02750     if (NS_FAILED(rv))
02751         return rv;
02752 
02753     rv = RegisterComponentWithType(aClass, aClassName,
02754                                    aContractID,
02755                                    aLibrarySpec,
02756                                    registryName,
02757                                    aReplace, aPersist,
02758                                    nativeComponentType);
02759     return rv;
02760 }
02761 
02762 nsresult
02763 nsComponentManagerImpl::RegisterComponentLib(const nsCID &aClass,
02764                                              const char *aClassName,
02765                                              const char *aContractID,
02766                                              const char *aDllName,
02767                                              PRBool aReplace,
02768                                              PRBool aPersist)
02769 {
02770     // deprecated and obsolete.
02771     return NS_ERROR_NOT_IMPLEMENTED;
02772 }
02773 
02774 /*
02775  * Add a component to the known universe of components.
02776 
02777  * Once we enter this function, we own aRegistryName, and must free it
02778  * or hand it to nsFactoryEntry.  Common exit point ``out'' helps keep us
02779  * sane.
02780  */
02781 
02782 nsresult
02783 nsComponentManagerImpl::RegisterComponentCommon(const nsCID &aClass,
02784                                                 const char *aClassName,
02785                                                 const char *aContractID,
02786                                                 PRUint32 aContractIDLen,
02787                                                 const char *aRegistryName,
02788                                                 PRUint32 aRegistryNameLen,
02789                                                 PRBool aReplace,
02790                                                 PRBool aPersist,
02791                                                 const char *aType)
02792 {
02793     nsIDKey key(aClass);
02794     nsAutoMonitor mon(mMon);
02795 
02796     nsFactoryEntry *entry = GetFactoryEntry(aClass);
02797 
02798     // Normalize proid and classname
02799     const char *contractID = (aContractID && *aContractID) ? aContractID : nsnull;
02800 #ifdef PR_LOGGING
02801     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
02802     {
02803         char *buf = aClass.ToString();
02804         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
02805                ("nsComponentManager: RegisterComponentCommon(%s, %s, %s, %s)",
02806                 buf,
02807                 contractID ? contractID : "(null)",
02808                 aRegistryName, aType));
02809         if (buf)
02810             PR_Free(buf);
02811     }
02812 #endif
02813     if (entry && !aReplace) {
02814         PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
02815                ("\t\tFactory already registered."));
02816         return NS_ERROR_FACTORY_EXISTS;
02817     }
02818 
02819     int typeIndex = GetLoaderType(aType);
02820 
02821     nsCOMPtr<nsIComponentLoader> loader;
02822     nsresult rv = GetLoaderForType(typeIndex, getter_AddRefs(loader));
02823     if (NS_FAILED(rv)) {
02824         PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
02825                ("\t\tgetting loader for %s FAILED\n", aType));
02826         return rv;
02827     }
02828 
02829     if (entry) {
02830         entry->ReInit(aClass, aRegistryName, typeIndex);
02831     }
02832     else {
02833 
02834         // Arena allocate the nsFactoryEntry
02835         void *mem;
02836         PL_ARENA_ALLOCATE(mem, &mArena, sizeof(nsFactoryEntry));
02837         if (!mem)
02838             return NS_ERROR_OUT_OF_MEMORY;
02839 
02840         mRegistryDirty = PR_TRUE;
02841         entry = new (mem) nsFactoryEntry(aClass,
02842                                          aRegistryName, aRegistryNameLen,
02843                                          typeIndex);
02844         if (!entry->mLocation)
02845             return NS_ERROR_OUT_OF_MEMORY;
02846 
02847         nsFactoryTableEntry* factoryTableEntry =
02848             NS_STATIC_CAST(nsFactoryTableEntry*,
02849                            PL_DHashTableOperate(&mFactories, &aClass,
02850                                                 PL_DHASH_ADD));
02851 
02852         if (!factoryTableEntry)
02853             return NS_ERROR_OUT_OF_MEMORY;
02854 
02855         factoryTableEntry->mFactoryEntry = entry;
02856     }
02857 
02858     // Update the ContractID->CLSID Map
02859     if (contractID) {
02860         rv = HashContractID(contractID, aContractIDLen, entry);
02861         if (NS_FAILED(rv)) {
02862             PR_LOG(nsComponentManagerLog, PR_LOG_ERROR,
02863                    ("\t\tHashContractID(%s) FAILED\n", contractID));
02864             return rv;
02865         }
02866     }
02867     return rv;
02868 }
02869 
02870 
02871 nsresult
02872 nsComponentManagerImpl::GetLoaderForType(int aType,
02873                                          nsIComponentLoader **aLoader)
02874 {
02875     nsresult rv;
02876 
02877     // Make sure we have a valid type
02878     if (aType < 0 || aType >= mNLoaderData)
02879         return NS_ERROR_INVALID_ARG;
02880 
02881     *aLoader = mLoaderData[aType].loader;
02882     if (*aLoader) {
02883         NS_ADDREF(*aLoader);
02884         return NS_OK;
02885     }
02886 
02887     nsCOMPtr<nsIComponentLoader> loader;
02888     loader = do_GetServiceFromCategory("component-loader", mLoaderData[aType].type, &rv);
02889     if (NS_FAILED(rv))
02890         return rv;
02891 
02892     rv = loader->Init(this, nsnull);
02893 
02894     if (NS_SUCCEEDED(rv)) {
02895         mLoaderData[aType].loader = loader;
02896         NS_ADDREF(mLoaderData[aType].loader);
02897         *aLoader = loader;
02898         NS_ADDREF(*aLoader);
02899     }
02900     return rv;
02901 }
02902 
02903 
02904 
02905 // Convert a loader type string into an index into the component data
02906 // array. Empty loader types are converted to NATIVE. Returns -1 if
02907 // loader type cannot be determined.
02908 int
02909 nsComponentManagerImpl::GetLoaderType(const char *typeStr)
02910 {
02911     if (!typeStr || !*typeStr) {
02912         // Empty type strings are NATIVE
02913         return NS_COMPONENT_TYPE_NATIVE;
02914     }
02915 
02916     for (int i=NS_COMPONENT_TYPE_NATIVE; i<mNLoaderData; i++) {
02917         if (!strcmp(typeStr, mLoaderData[i].type))
02918             return i;
02919     }
02920     // Not found
02921     return NS_COMPONENT_TYPE_FACTORY_ONLY;
02922 }
02923 
02924 // Add a loader type if not already known. Out the typeIndex
02925 // if the loader type is either added or already there.
02926 nsresult
02927 nsComponentManagerImpl::AddLoaderType(const char *typeStr, int *aTypeIndex)
02928 {
02929     int typeIndex = GetLoaderType(typeStr);
02930     if (typeIndex >= 0) {
02931         *aTypeIndex = typeIndex;
02932         return NS_OK;
02933     }
02934 
02935     // Add the loader type
02936     if (mNLoaderData >= mMaxNLoaderData) {
02937         NS_ASSERTION(mNLoaderData == mMaxNLoaderData,
02938                      "Memory corruption. nsComponentManagerImpl::mLoaderData array overrun.");
02939         // Need to increase our loader array
02940         nsLoaderdata *new_mLoaderData = (nsLoaderdata *) PR_Realloc(mLoaderData, (mMaxNLoaderData + NS_LOADER_DATA_ALLOC_STEP) * sizeof(nsLoaderdata));
02941         if (!new_mLoaderData)
02942             return NS_ERROR_OUT_OF_MEMORY;
02943         mLoaderData = new_mLoaderData;
02944         mMaxNLoaderData += NS_LOADER_DATA_ALLOC_STEP;
02945     }
02946 
02947     typeIndex = mNLoaderData;
02948     mLoaderData[typeIndex].type = PL_strdup(typeStr);
02949     if (!mLoaderData[typeIndex].type) {
02950         // mmh! no memory. return failure.
02951         return NS_ERROR_OUT_OF_MEMORY;
02952     }
02953     mLoaderData[typeIndex].loader = nsnull;
02954     mNLoaderData++;
02955 
02956     *aTypeIndex = typeIndex;
02957     return NS_OK;
02958 }
02959 
02960 typedef struct
02961 {
02962     const nsCID* cid;
02963     const char* regName;
02964     nsIFactory* factory;
02965 } UnregisterConditions;
02966 
02967 static PLDHashOperator PR_CALLBACK
02968 DeleteFoundCIDs(PLDHashTable *aTable,
02969                 PLDHashEntryHdr *aHdr,
02970                 PRUint32 aNumber,
02971                 void *aData)
02972 {
02973     nsContractIDTableEntry* entry = NS_STATIC_CAST(nsContractIDTableEntry*, aHdr);
02974 
02975     if (!entry->mFactoryEntry)
02976         return PL_DHASH_NEXT;
02977 
02978     UnregisterConditions* data = (UnregisterConditions*)aData;
02979 
02980     nsFactoryEntry* factoryEntry = entry->mFactoryEntry;
02981     if (data->cid->Equals(factoryEntry->mCid) &&
02982         ((data->regName && !PL_strcasecmp(factoryEntry->mLocation, data->regName)) ||
02983          (data->factory && data->factory == factoryEntry->mFactory.get())))
02984         return PL_DHASH_REMOVE;
02985 
02986     return PL_DHASH_NEXT;
02987 }
02988 
02989 void
02990 nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, const char*registryName)
02991 {
02992     UnregisterConditions aData;
02993     aData.cid     = aClass;
02994     aData.regName = registryName;
02995     aData.factory = nsnull;
02996     PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData);
02997 
02998 }
02999 
03000 void
03001 nsComponentManagerImpl::DeleteContractIDEntriesByCID(const nsCID* aClass, nsIFactory* factory)
03002 {
03003     UnregisterConditions aData;
03004     aData.cid     = aClass;
03005     aData.regName = nsnull;
03006     aData.factory = factory;
03007     PL_DHashTableEnumerate(&mContractIDs, DeleteFoundCIDs, (void*)&aData);
03008 }
03009 
03010 nsresult
03011 nsComponentManagerImpl::UnregisterFactory(const nsCID &aClass,
03012                                           nsIFactory *aFactory)
03013 {
03014 #ifdef PR_LOGGING
03015     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
03016     {
03017         char *buf = aClass.ToString();
03018         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
03019                ("nsComponentManager: UnregisterFactory(%s)", buf));
03020         if (buf)
03021             PR_Free(buf);
03022     }
03023 #endif
03024     nsFactoryEntry *old;
03025 
03026     // first delete all contract id entries that are registered with this cid.
03027     DeleteContractIDEntriesByCID(&aClass, aFactory);
03028 
03029     // next check to see if there is a CID registered
03030     nsresult rv = NS_ERROR_FACTORY_NOT_REGISTERED;
03031     old = GetFactoryEntry(aClass);
03032 
03033     if (old && (old->mFactory.get() == aFactory))
03034     {
03035         nsAutoMonitor mon(mMon);
03036         PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
03037         rv = NS_OK;
03038     }
03039 
03040     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
03041            ("\t\tUnregisterFactory() %s",
03042             NS_SUCCEEDED(rv) ? "succeeded" : "FAILED"));
03043     return rv;
03044 }
03045 
03046 nsresult
03047 nsComponentManagerImpl::UnregisterComponent(const nsCID &aClass,
03048                                             const char *registryName)
03049 {
03050 #ifdef PR_LOGGING
03051     if (PR_LOG_TEST(nsComponentManagerLog, PR_LOG_WARNING))
03052     {
03053         char *buf = aClass.ToString();
03054         PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
03055                ("nsComponentManager: UnregisterComponent(%s)", buf));
03056         if (buf)
03057             PR_Free(buf);
03058     }
03059 #endif
03060 
03061     NS_ENSURE_ARG_POINTER(registryName);
03062     nsFactoryEntry *old;
03063 
03064     // first delete all contract id entries that are registered with this cid.
03065     DeleteContractIDEntriesByCID(&aClass, registryName);
03066 
03067     // next check to see if there is a CID registered
03068     old = GetFactoryEntry(aClass);
03069     if (old && old->mLocation && !PL_strcasecmp(old->mLocation, registryName))
03070     {
03071         nsAutoMonitor mon(mMon);
03072         PL_DHashTableOperate(&mFactories, &aClass, PL_DHASH_REMOVE);
03073     }
03074 
03075     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
03076            ("nsComponentManager: Factory unregister(%s) succeeded.", registryName));
03077 
03078     return NS_OK;
03079 }
03080 
03081 nsresult
03082 nsComponentManagerImpl::UnregisterComponentSpec(const nsCID &aClass,
03083                                                 nsIFile *aLibrarySpec)
03084 {
03085     nsXPIDLCString registryName;
03086     nsresult rv = RegistryLocationForSpec(aLibrarySpec, getter_Copies(registryName));
03087     if (NS_FAILED(rv)) return rv;
03088     return UnregisterComponent(aClass, registryName);
03089 }
03090 
03091 // XXX Need to pass in aWhen and servicemanager
03092 nsresult
03093 nsComponentManagerImpl::FreeLibraries(void)
03094 {
03095     return UnloadLibraries(NS_STATIC_CAST(nsIServiceManager*, this), NS_Timer); // XXX when
03096 }
03097 
03098 // Private implementation of unloading libraries
03099 nsresult
03100 nsComponentManagerImpl::UnloadLibraries(nsIServiceManager *serviceMgr, PRInt32 aWhen)
03101 {
03102     nsresult rv = NS_OK;
03103 
03104     nsAutoMonitor mon(mMon);
03105 
03106     PR_LOG(nsComponentManagerLog, PR_LOG_WARNING,
03107            ("nsComponentManager: Unloading Libraries."));
03108 
03109     // UnloadAll the loaders
03110     // iterate over all known loaders and ask them to Unload.
03111     // Skip mNativeComponentLoader
03112     for (int i=NS_COMPONENT_TYPE_NATIVE + 1; i<mNLoaderData; i++) {
03113         if (mLoaderData[i].loader) {
03114             rv = mLoaderData[i].loader->UnloadAll(aWhen);
03115             if (NS_FAILED(rv))
03116                 break;
03117         }
03118     }
03119 
03120     // UnloadAll the native loader
03121     rv = mNativeComponentLoader->UnloadAll(aWhen);
03122     return rv;
03123 }
03124 
03126 
03143 nsresult
03144 nsComponentManagerImpl::AutoRegister(PRInt32 when, nsIFile *inDirSpec)
03145 {
03146     return AutoRegisterImpl(when, inDirSpec);
03147 }
03148 
03149 nsresult
03150 nsComponentManagerImpl::AutoRegisterImpl(PRInt32 when,
03151                                          nsIFile *inDirSpec,
03152                                          PRBool fileIsCompDir)
03153 {
03154     nsCOMPtr<nsIFile> dir;
03155     nsresult rv;
03156 
03157 #ifdef DEBUG
03158     // testing release behaviour
03159     if (getenv("XPCOM_NO_AUTOREG"))
03160         return NS_OK;
03161 #endif
03162     if (inDirSpec)
03163     {
03164         // Use supplied components' directory
03165         dir = inDirSpec;
03166     }
03167     else
03168     {
03169         mComponentsDir->Clone(getter_AddRefs(dir));
03170         if (!dir)
03171             return NS_ERROR_NOT_INITIALIZED;
03172     }
03173 
03174     nsCOMPtr<nsIInterfaceInfoManager> iim =
03175         dont_AddRef(XPTI_GetInterfaceInfoManager());
03176 
03177     if (!iim)
03178         return NS_ERROR_UNEXPECTED;
03179 
03180     // Notify observers of xpcom autoregistration start
03181     NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
03182                                   nsnull,
03183                                   "start");
03184 
03185     /* Load static components first, then the native component loader,
03186      * which can find other loaders.
03187      */
03188     rv = mStaticComponentLoader->AutoRegisterComponents((PRInt32)when, inDirSpec);
03189     if (NS_FAILED(rv)) return rv;
03190 
03191     rv = mNativeComponentLoader->AutoRegisterComponents((PRInt32)when, dir);
03192     if (NS_FAILED(rv)) return rv;
03193 
03194     /* do InterfaceInfoManager after native loader so it can use components. */
03195     rv = iim->AutoRegisterInterfaces();
03196     if (NS_FAILED(rv)) return rv;
03197 
03198     if (!mCategoryManager) {
03199         NS_WARNING("mCategoryManager is null");
03200         return NS_ERROR_UNEXPECTED;
03201     }
03202 
03203     nsCOMPtr<nsISimpleEnumerator> loaderEnum;
03204     rv = mCategoryManager->EnumerateCategory("component-loader",
03205                                    getter_AddRefs(loaderEnum));
03206     if (NS_FAILED(rv)) return rv;
03207 
03208     PRBool hasMore;
03209     while (NS_SUCCEEDED(loaderEnum->HasMoreElements(&hasMore)) && hasMore) {
03210         nsCOMPtr<nsISupports> supports;
03211         if (NS_FAILED(loaderEnum->GetNext(getter_AddRefs(supports))))
03212             continue;
03213 
03214         nsCOMPtr<nsISupportsCString> supStr = do_QueryInterface(supports);
03215         if (!supStr)
03216             continue;
03217 
03218         nsCAutoString loaderType;
03219         if (NS_FAILED(supStr->GetData(loaderType)))
03220             continue;
03221 
03222         // We depend on the loader being created. Add the loader type and
03223         // create the loader object too.
03224         nsCOMPtr<nsIComponentLoader> loader;
03225         int typeIndex;
03226         rv = AddLoaderType(loaderType.get(), &typeIndex);
03227         if (NS_FAILED(rv))
03228             return rv;
03229         GetLoaderForType(typeIndex, getter_AddRefs(loader));
03230     }
03231 
03232     rv = AutoRegisterNonNativeComponents(dir.get());
03233 
03234     // Notify observers of xpcom autoregistration completion
03235     NS_CreateServicesFromCategory(NS_XPCOM_AUTOREGISTRATION_OBSERVER_ID,
03236                                   nsnull,
03237                                   "end");
03238 
03239     if (mRegistryDirty)
03240         FlushPersistentStore(PR_TRUE);
03241     return rv;
03242 }
03243 
03244 nsresult
03245 nsComponentManagerImpl::AutoRegisterNonNativeComponents(nsIFile* spec)
03246 {
03247     nsresult rv = NS_OK;
03248     nsCOMPtr<nsIFile> directory = spec;
03249 
03250     if (!directory) {
03251         mComponentsDir->Clone(getter_AddRefs(directory));
03252         if (!directory)
03253             return NS_ERROR_NOT_INITIALIZED;
03254     }
03255 
03256     for (int i = 1; i < mNLoaderData; i++) {
03257         if (!mLoaderData[i].loader) {
03258             rv = GetLoaderForType(i, &mLoaderData[i].loader);
03259             if (NS_FAILED(rv))
03260                 continue;
03261         }
03262         rv = mLoaderData[i].loader->AutoRegisterComponents(0, directory);
03263         if (NS_FAILED(rv))
03264             break;
03265     }
03266 
03267     if (NS_SUCCEEDED(rv))
03268     {
03269         PRBool registered;
03270         do {
03271             registered = PR_FALSE;
03272             for (int i = 0; i < mNLoaderData; i++) {
03273                 PRBool b = PR_FALSE;
03274                 if (mLoaderData[i].loader) {
03275                     rv = mLoaderData[i].loader->RegisterDeferredComponents(0, &b);
03276                     if (NS_FAILED(rv))
03277                         continue;
03278                     registered |= b;
03279                 }
03280             }
03281         } while (NS_SUCCEEDED(rv) && registered);
03282     }
03283     return rv;
03284 }
03285 nsresult
03286 nsComponentManagerImpl::AutoRegisterComponent(PRInt32 when,
03287                                               nsIFile *component)
03288 {
03289     nsresult rv = NS_OK, res = NS_ERROR_FACTORY_NOT_REGISTERED;
03290     /*
03291      * Do we have to give the native loader first crack at it?
03292      * I vote ``no''.
03293      */
03294     for (int i = 0; i < mNLoaderData; i++) {
03295         PRBool didRegister;
03296         if (!mLoaderData[i].loader) {
03297             nsCOMPtr<nsIComponentLoader> loader;
03298             rv = GetLoaderForType(i, getter_AddRefs(loader));
03299             if (NS_FAILED(rv))
03300                 continue;
03301             // |GetLoaderForType| has filled in |mLoaderData[i].loader|:
03302             NS_ASSERTION(loader == mLoaderData[i].loader, "oops");
03303         }
03304         rv = mLoaderData[i].loader->AutoRegisterComponent((int)when, component, &didRegister);
03305         if (NS_FAILED(rv)) {
03306             res = rv;
03307         } else if (didRegister) {
03308             return rv;
03309         }
03310     }
03311     return res;
03312 }
03313 
03314 nsresult
03315 nsComponentManagerImpl::AutoUnregisterComponent(PRInt32 when,
03316                                                 nsIFile *component)
03317 {
03318     nsresult rv = NS_OK;
03319     for (int i = 0; i < mNLoaderData; i++) {
03320         PRBool didUnRegister;
03321         if (!mLoaderData[i].loader) {
03322             rv = GetLoaderForType(i, &mLoaderData[i].loader);
03323             if (NS_FAILED(rv))
03324                 continue;
03325         }
03326         rv = mLoaderData[i].loader->AutoUnregisterComponent(when, component, &didUnRegister);
03327         if (NS_SUCCEEDED(rv) && didUnRegister) {
03328             // we need to remove this file from our list of known libraries.
03329             RemoveFileInfo(component, nsnull);
03330             mRegistryDirty = PR_TRUE;
03331             break;
03332         }
03333     }
03334     return NS_FAILED(rv) ? NS_ERROR_FACTORY_NOT_REGISTERED : NS_OK;
03335 }
03336 
03337 nsresult
03338 nsComponentManagerImpl::IsRegistered(const nsCID &aClass,
03339                                      PRBool *aRegistered)
03340 {
03341     if (!aRegistered)
03342     {
03343         NS_ASSERTION(0, "null ptr");
03344         return NS_ERROR_NULL_POINTER;
03345     }
03346     *aRegistered = (nsnull != GetFactoryEntry(aClass));
03347     return NS_OK;
03348 }
03349 
03350 nsresult
03351 nsComponentManagerImpl::EnumerateCLSIDs(nsIEnumerator** aEnumerator)
03352 {
03353     NS_ASSERTION(aEnumerator != nsnull, "null ptr");
03354     if (!aEnumerator)
03355     {
03356         return NS_ERROR_NULL_POINTER;
03357     }
03358     *aEnumerator = nsnull;
03359 
03360     nsresult rv;
03361 
03362     PLDHashTableEnumeratorImpl *aEnum;
03363     rv = PL_NewDHashTableEnumerator(&mFactories,
03364                                     ConvertFactoryEntryToCID,
03365                                     (void*)this,
03366                                     &aEnum);
03367     if (NS_FAILED(rv))
03368         return rv;
03369 
03370     *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum);
03371     return NS_OK;
03372 }
03373 
03374 nsresult
03375 nsComponentManagerImpl::EnumerateContractIDs(nsIEnumerator** aEnumerator)
03376 {
03377     NS_ASSERTION(aEnumerator != nsnull, "null ptr");
03378     if (!aEnumerator)
03379     {
03380         return NS_ERROR_NULL_POINTER;
03381     }
03382 
03383     *aEnumerator = nsnull;
03384 
03385     nsresult rv;
03386     PLDHashTableEnumeratorImpl *aEnum;
03387     rv = PL_NewDHashTableEnumerator(&mContractIDs,
03388                                     ConvertContractIDKeyToString,
03389                                     (void*)this,
03390                                     &aEnum);
03391     if (NS_FAILED(rv))
03392         return rv;
03393 
03394     *aEnumerator = NS_STATIC_CAST(nsIEnumerator*, aEnum);
03395     return NS_OK;
03396 }
03397 
03398 // nsIComponentRegistrar
03399 
03400 NS_IMETHODIMP
03401 nsComponentManagerImpl::AutoRegister(nsIFile *aSpec)
03402 {
03403     if (aSpec == nsnull)
03404         return AutoRegisterImpl(0, aSpec);
03405 
03406     PRBool directory;
03407     aSpec->IsDirectory(&directory);
03408 
03409     if (directory)
03410         return AutoRegisterImpl(0, aSpec, PR_FALSE);
03411 
03412     return AutoRegisterComponent(0, aSpec);
03413 }
03414 
03415 NS_IMETHODIMP
03416 nsComponentManagerImpl::AutoUnregister(nsIFile *aSpec)
03417 {
03418     // unregistering a complete directory is not implmeneted yet...FIX
03419     if (aSpec == nsnull)
03420         return NS_ERROR_NOT_IMPLEMENTED;
03421 
03422     PRBool directory;
03423     aSpec->IsDirectory(&directory);
03424 
03425     if (directory)
03426         return NS_ERROR_NOT_IMPLEMENTED;
03427 
03428     return AutoUnregisterComponent(0, aSpec);
03429 }
03430 
03431 NS_IMETHODIMP
03432 nsComponentManagerImpl::RegisterFactory(const nsCID & aClass,
03433                                         const char *aClassName,
03434                                         const char *aContractID,
03435                                         nsIFactory *aFactory)
03436 {
03437     return RegisterFactory(aClass,
03438                            aClassName,
03439                            aContractID,
03440                            aFactory,
03441                            PR_TRUE);
03442 }
03443 
03444 NS_IMETHODIMP
03445 nsComponentManagerImpl::RegisterFactoryLocation(const nsCID & aClass,
03446                                                 const char *aClassName,
03447                                                 const char *aContractID,
03448                                                 nsIFile *aFile,
03449                                                 const char *loaderStr,
03450                                                 const char *aType)
03451 {
03452     nsXPIDLCString registryName;
03453 
03454     if (!loaderStr)
03455     {
03456         nsresult rv = RegistryLocationForSpec(aFile, getter_Copies(registryName));
03457         if (NS_FAILED(rv))
03458             return rv;
03459     }
03460 
03461     nsresult rv;
03462     rv = RegisterComponentWithType(aClass,
03463                                    aClassName,
03464                                    aContractID,
03465                                    aFile,
03466                                    (loaderStr ? loaderStr : registryName.get()),
03467                                    PR_TRUE,
03468                                    PR_TRUE,
03469                                    (aType ? aType : nativeComponentType));
03470     return rv;
03471 }
03472 
03473 NS_IMETHODIMP
03474 nsComponentManagerImpl::UnregisterFactoryLocation(const nsCID & aClass,
03475                                                   nsIFile *aFile)
03476 {
03477     return UnregisterComponentSpec(aClass, aFile);
03478 }
03479 
03480 NS_IMETHODIMP
03481 nsComponentManagerImpl::IsCIDRegistered(const nsCID & aClass,
03482                                         PRBool *_retval)
03483 {
03484     return IsRegistered(aClass, _retval);
03485 }
03486 
03487 NS_IMETHODIMP
03488 nsComponentManagerImpl::IsContractIDRegistered(const char *aClass,
03489                                                PRBool *_retval)
03490 {
03491     nsFactoryEntry *entry = GetFactoryEntry(aClass, strlen(aClass));
03492 
03493     if (entry)
03494         *_retval = PR_TRUE;
03495     else
03496         *_retval = PR_FALSE;
03497     return NS_OK;
03498 }
03499 
03500 NS_IMETHODIMP
03501 nsComponentManagerImpl::EnumerateCIDs(nsISimpleEnumerator **aEnumerator)
03502 {
03503     NS_ASSERTION(aEnumerator != nsnull, "null ptr");
03504 
03505     if (!aEnumerator)
03506         return NS_ERROR_NULL_POINTER;
03507 
03508     *aEnumerator = nsnull;
03509 
03510     nsresult rv;
03511     PLDHashTableEnumeratorImpl *aEnum;
03512     rv = PL_NewDHashTableEnumerator(&mFactories,
03513                                     ConvertFactoryEntryToCID,
03514                                     (void*)this,
03515                                     &aEnum);
03516     if (NS_FAILED(rv))
03517         return rv;
03518 
03519     *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum);
03520     return NS_OK;
03521 }
03522 
03523 NS_IMETHODIMP
03524 nsComponentManagerImpl::EnumerateContractIDs(nsISimpleEnumerator **aEnumerator)
03525 {
03526     NS_ASSERTION(aEnumerator != nsnull, "null ptr");
03527     if (!aEnumerator)
03528         return NS_ERROR_NULL_POINTER;
03529 
03530     *aEnumerator = nsnull;
03531 
03532     nsresult rv;
03533     PLDHashTableEnumeratorImpl *aEnum;
03534     rv = PL_NewDHashTableEnumerator(&mContractIDs,
03535                                     ConvertContractIDKeyToString,
03536                                     (void*)this,
03537                                     &aEnum);
03538     if (NS_FAILED(rv))
03539         return rv;
03540 
03541     *aEnumerator = NS_STATIC_CAST(nsISimpleEnumerator*, aEnum);
03542     return NS_OK;
03543 }
03544 
03545 NS_IMETHODIMP
03546 nsComponentManagerImpl::CIDToContractID(const nsCID & aClass,
03547                                         char **_retval)
03548 {
03549     return CLSIDToContractID(aClass,
03550                              nsnull,
03551                              _retval);
03552 }
03553 
03554 NS_IMETHODIMP
03555 nsComponentManagerImpl::ContractIDToCID(const char *aContractID,
03556                                         nsCID * *_retval)
03557 {
03558     *_retval = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
03559     if (!*_retval)
03560        return NS_ERROR_OUT_OF_MEMORY;
03561 
03562     nsresult rv = ContractIDToClassID(aContractID, *_retval);
03563     if (NS_FAILED(rv)) {
03564         nsMemory::Free(*_retval);
03565         *_retval = nsnull;
03566     }
03567     return rv;
03568 }
03569 
03570 // end nsIComponentRegistrar
03571 
03572 
03573 
03574 
03575 NS_IMETHODIMP
03576 nsComponentManagerImpl::HasFileChanged(nsIFile *file, const char *loaderString, PRInt64 modDate, PRBool *_retval)
03577 {
03578     *_retval = PR_TRUE;
03579 
03580     nsXPIDLCString registryName;
03581     nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
03582     if (NS_FAILED(rv))
03583         return rv;
03584 
03585     nsCStringKey key(registryName);
03586     AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
03587     if (entry)
03588         *_retval = entry->Modified(&modDate);
03589     else
03590         *_retval = PR_TRUE;
03591 
03592     return NS_OK;
03593 }
03594 
03595 NS_IMETHODIMP
03596 nsComponentManagerImpl::SaveFileInfo(nsIFile *file, const char *loaderString, PRInt64 modDate)
03597 {
03598     mRegistryDirty = PR_TRUE;
03599     nsXPIDLCString registryName;
03600     nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
03601     if (NS_FAILED(rv))
03602         return rv;
03603 
03604     // check to see if exists in the array before adding it so that we don't have dups.
03605     nsCStringKey key(registryName);
03606     AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
03607 
03608     if (entry)
03609     {
03610         entry->SetDate(&modDate);
03611         return NS_OK;
03612     }
03613 
03614     entry = new AutoRegEntry(registryName, &modDate);
03615     if (!entry)
03616         return NS_ERROR_OUT_OF_MEMORY;
03617 
03618     mAutoRegEntries.Put(&key, entry);
03619     return NS_OK;
03620 }
03621 
03622 NS_IMETHODIMP
03623 nsComponentManagerImpl::RemoveFileInfo(nsIFile *file, const char *loaderString)
03624 {
03625     mRegistryDirty = PR_TRUE;
03626     nsXPIDLCString registryName;
03627     nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
03628     if (NS_FAILED(rv))
03629         return rv;
03630 
03631     nsCStringKey key(registryName);
03632     AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Remove(&key);
03633     if (entry)
03634         delete entry;
03635 
03636     return NS_OK;
03637 }
03638 
03639 NS_IMETHODIMP
03640 nsComponentManagerImpl::GetOptionalData(nsIFile *file,
03641                                         const char *loaderString,
03642                                         char **_retval)
03643 {
03644     nsXPIDLCString registryName;
03645     nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
03646     if (NS_FAILED(rv))
03647         return rv;
03648 
03649     nsCStringKey key(registryName);
03650     AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
03651     if (!entry) {
03652         return NS_ERROR_NOT_INITIALIZED;
03653     }
03654     const char* opData = entry->GetOptionalData();
03655 
03656     if (opData)
03657         *_retval = ToNewCString(nsDependentCString(opData));
03658     else
03659         *_retval = nsnull;
03660     return NS_OK;
03661  }
03662 
03663 NS_IMETHODIMP
03664 nsComponentManagerImpl::SetOptionalData(nsIFile *file,
03665                                         const char *loaderString,
03666                                         const char *data)
03667 {
03668     nsXPIDLCString registryName;
03669     nsresult rv = RegistryLocationForSpec(file, getter_Copies(registryName));
03670     if (NS_FAILED(rv))
03671         return rv;
03672 
03673     nsCStringKey key(registryName);
03674     AutoRegEntry* entry = (AutoRegEntry*)mAutoRegEntries.Get(&key);
03675 
03676     if (!entry) {
03677         PRInt64 zero = LL_Zero();
03678         entry = new AutoRegEntry(registryName, &zero);
03679         if (!entry)
03680             return NS_ERROR_OUT_OF_MEMORY;
03681 
03682         mAutoRegEntries.Put(&key, entry);
03683     }
03684 
03685     entry->SetOptionalData(data);
03686 
03687     return NS_OK;
03688  }
03689 
03690 
03691 NS_IMETHODIMP
03692 nsComponentManagerImpl::FlushPersistentStore(PRBool now)
03693 {
03694     mRegistryDirty = PR_TRUE;
03695     if (now)
03696         return WritePersistentRegistry();
03697 
03698     return NS_OK;
03699 }
03700 
03701 
03703 // Static Access Functions
03705 
03706 NS_COM nsresult
03707 NS_GetComponentManager(nsIComponentManager* *result)
03708 {
03709     if (nsComponentManagerImpl::gComponentManager == nsnull)
03710     {
03711         // XPCOM needs initialization.
03712         nsresult rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
03713         if (NS_FAILED(rv))
03714             return rv;
03715     }
03716 
03717     *result = NS_STATIC_CAST(nsIComponentManager*,
03718                              nsComponentManagerImpl::gComponentManager);
03719     NS_IF_ADDREF(*result);
03720     return NS_OK;
03721 }
03722 
03723 NS_COM nsresult
03724 NS_GetServiceManager(nsIServiceManager* *result)
03725 {
03726     nsresult rv = NS_OK;
03727 
03728     if (nsComponentManagerImpl::gComponentManager == nsnull)
03729     {
03730         // XPCOM needs initialization.
03731         rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
03732     }
03733 
03734     if (NS_FAILED(rv))
03735         return rv;
03736 
03737     *result = NS_STATIC_CAST(nsIServiceManager*,
03738                              nsComponentManagerImpl::gComponentManager);
03739     NS_IF_ADDREF(*result);
03740     return NS_OK;
03741 }
03742 
03743 
03744 NS_COM nsresult
03745 NS_GetComponentRegistrar(nsIComponentRegistrar* *result)
03746 {
03747     nsresult rv = NS_OK;
03748 
03749     if (nsComponentManagerImpl::gComponentManager == nsnull)
03750     {
03751         // XPCOM needs initialization.
03752         rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
03753     }
03754 
03755     if (NS_FAILED(rv))
03756         return rv;
03757 
03758     *result = NS_STATIC_CAST(nsIComponentRegistrar*,
03759                              nsComponentManagerImpl::gComponentManager);
03760     NS_IF_ADDREF(*result);
03761     return NS_OK;
03762 }
03763 
03764 
03765 // nsIComponentLoaderManager is not frozen, but is defined here
03766 // so that I can use it internally in xpcom.
03767 nsresult
03768 NS_GetComponentLoaderManager(nsIComponentLoaderManager* *result)
03769 {
03770     nsresult rv = NS_OK;
03771 
03772     if (nsComponentManagerImpl::gComponentManager == NULL)
03773     {
03774         // XPCOM needs initialization.
03775         rv = NS_InitXPCOM2(nsnull, nsnull, nsnull);
03776     }
03777 
03778     if (NS_FAILED(rv))
03779         return rv;
03780 
03781     *result = NS_STATIC_CAST(nsIComponentLoaderManager*,
03782                              nsComponentManagerImpl::gComponentManager);
03783     NS_IF_ADDREF(*result);
03784     return NS_OK;
03785 }